1//===-- llvm/IR/Statepoint.h - gc.statepoint utilities ------ --*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file contains utility functions and a wrapper class analogous to
11// CallSite for accessing the fields of gc.statepoint, gc.relocate, and
12// gc.result intrinsics
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef __LLVM_IR_STATEPOINT_H
17#define __LLVM_IR_STATEPOINT_H
18
19#include "llvm/ADT/iterator_range.h"
20#include "llvm/IR/BasicBlock.h"
21#include "llvm/IR/CallSite.h"
22#include "llvm/IR/Instructions.h"
23#include "llvm/IR/Intrinsics.h"
24#include "llvm/Support/Compiler.h"
25
26namespace llvm {
27
28class GCRelocateOperands;
29class ImmutableStatepoint;
30
31bool isStatepoint(const ImmutableCallSite &CS);
32bool isStatepoint(const Value *inst);
33bool isStatepoint(const Value &inst);
34
35bool isGCRelocate(const Value *inst);
36bool isGCRelocate(const ImmutableCallSite &CS);
37
38bool isGCResult(const Value *inst);
39bool isGCResult(const ImmutableCallSite &CS);
40
41/// Analogous to CallSiteBase, this provides most of the actual
42/// functionality for Statepoint and ImmutableStatepoint.  It is
43/// templatized to allow easily specializing of const and non-const
44/// concrete subtypes.  This is structured analogous to CallSite
45/// rather than the IntrinsicInst.h helpers since we want to support
46/// invokable statepoints in the near future.
47/// TODO: This does not currently allow the if(Statepoint S = ...)
48///   idiom used with CallSites.  Consider refactoring to support.
49template <typename InstructionTy, typename ValueTy, typename CallSiteTy>
50class StatepointBase {
51  CallSiteTy StatepointCS;
52  void *operator new(size_t, unsigned) = delete;
53  void *operator new(size_t s) = delete;
54
55 protected:
56  explicit StatepointBase(InstructionTy *I) : StatepointCS(I) {
57    assert(isStatepoint(I));
58  }
59  explicit StatepointBase(CallSiteTy CS) : StatepointCS(CS) {
60    assert(isStatepoint(CS));
61  }
62
63 public:
64  typedef typename CallSiteTy::arg_iterator arg_iterator;
65
66  /// Return the underlying CallSite.
67  CallSiteTy getCallSite() {
68    return StatepointCS;
69  }
70
71  /// Return the value actually being called or invoked.
72  ValueTy *actualCallee() {
73    return StatepointCS.getArgument(0);
74  }
75  /// Number of arguments to be passed to the actual callee.
76  int numCallArgs() {
77    return cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue();
78  }
79  /// Number of additional arguments excluding those intended
80  /// for garbage collection.
81  int numTotalVMSArgs() {
82    return cast<ConstantInt>(StatepointCS.getArgument(3 + numCallArgs()))->getZExtValue();
83  }
84
85  typename CallSiteTy::arg_iterator call_args_begin() {
86    // 3 = callTarget, #callArgs, flag
87    int Offset = 3;
88    assert(Offset <= (int)StatepointCS.arg_size());
89    return StatepointCS.arg_begin() + Offset;
90  }
91  typename CallSiteTy::arg_iterator call_args_end() {
92    int Offset = 3 + numCallArgs();
93    assert(Offset <= (int)StatepointCS.arg_size());
94    return StatepointCS.arg_begin() + Offset;
95  }
96
97  /// range adapter for call arguments
98  iterator_range<arg_iterator> call_args() {
99    return iterator_range<arg_iterator>(call_args_begin(), call_args_end());
100  }
101
102  typename CallSiteTy::arg_iterator vm_state_begin() {
103    return call_args_end();
104  }
105  typename CallSiteTy::arg_iterator vm_state_end() {
106    int Offset = 3 + numCallArgs() + 1 + numTotalVMSArgs();
107    assert(Offset <= (int)StatepointCS.arg_size());
108    return StatepointCS.arg_begin() + Offset;
109  }
110
111  /// range adapter for vm state arguments
112  iterator_range<arg_iterator> vm_state_args() {
113    return iterator_range<arg_iterator>(vm_state_begin(), vm_state_end());
114  }
115
116  typename CallSiteTy::arg_iterator first_vm_state_stack_begin() {
117    // 6 = numTotalVMSArgs, 1st_objectID, 1st_bci,
118    //     1st_#stack, 1st_#local, 1st_#monitor
119    return vm_state_begin() + 6;
120  }
121
122  typename CallSiteTy::arg_iterator gc_args_begin() {
123    return vm_state_end();
124  }
125  typename CallSiteTy::arg_iterator gc_args_end() {
126    return StatepointCS.arg_end();
127  }
128
129  /// range adapter for gc arguments
130  iterator_range<arg_iterator> gc_args() {
131    return iterator_range<arg_iterator>(gc_args_begin(), gc_args_end());
132  }
133
134  /// Get list of all gc reloactes linked to this statepoint
135  /// May contain several relocations for the same base/derived pair.
136  /// For example this could happen due to relocations on unwinding
137  /// path of invoke.
138  std::vector<GCRelocateOperands> getRelocates(ImmutableStatepoint &IS);
139
140#ifndef NDEBUG
141  /// Asserts if this statepoint is malformed.  Common cases for failure
142  /// include incorrect length prefixes for variable length sections or
143  /// illegal values for parameters.
144  void verify() {
145    assert(numCallArgs() >= 0 &&
146           "number of arguments to actually callee can't be negative");
147
148    // The internal asserts in the iterator accessors do the rest.
149    (void)call_args_begin();
150    (void)call_args_end();
151    (void)vm_state_begin();
152    (void)vm_state_end();
153    (void)gc_args_begin();
154    (void)gc_args_end();
155  }
156#endif
157};
158
159/// A specialization of it's base class for read only access
160/// to a gc.statepoint.
161class ImmutableStatepoint
162    : public StatepointBase<const Instruction, const Value,
163                            ImmutableCallSite> {
164  typedef StatepointBase<const Instruction, const Value, ImmutableCallSite>
165      Base;
166
167public:
168  explicit ImmutableStatepoint(const Instruction *I) : Base(I) {}
169  explicit ImmutableStatepoint(ImmutableCallSite CS) : Base(CS) {}
170};
171
172/// A specialization of it's base class for read-write access
173/// to a gc.statepoint.
174class Statepoint : public StatepointBase<Instruction, Value, CallSite> {
175  typedef StatepointBase<Instruction, Value, CallSite> Base;
176
177public:
178  explicit Statepoint(Instruction *I) : Base(I) {}
179  explicit Statepoint(CallSite CS) : Base(CS) {}
180};
181
182/// Wraps a call to a gc.relocate and provides access to it's operands.
183/// TODO: This should likely be refactored to resememble the wrappers in
184/// InstrinsicInst.h.
185class GCRelocateOperands {
186  ImmutableCallSite RelocateCS;
187
188 public:
189  GCRelocateOperands(const User* U) : RelocateCS(U) {
190    assert(isGCRelocate(U));
191  }
192  GCRelocateOperands(const Instruction *inst) : RelocateCS(inst) {
193    assert(isGCRelocate(inst));
194  }
195  GCRelocateOperands(CallSite CS) : RelocateCS(CS) {
196    assert(isGCRelocate(CS));
197  }
198
199  /// Return true if this relocate is tied to the invoke statepoint.
200  /// This includes relocates which are on the unwinding path.
201  bool isTiedToInvoke() const {
202    const Value *Token = RelocateCS.getArgument(0);
203
204    return isa<ExtractValueInst>(Token) ||
205      isa<InvokeInst>(Token);
206  }
207
208  /// Get enclosed relocate intrinsic
209  ImmutableCallSite getUnderlyingCallSite() {
210    return RelocateCS;
211  }
212
213  /// The statepoint with which this gc.relocate is associated.
214  const Instruction *statepoint() {
215    const Value *token = RelocateCS.getArgument(0);
216
217    // This takes care both of relocates for call statepoints and relocates
218    // on normal path of invoke statepoint.
219    if (!isa<ExtractValueInst>(token)) {
220      return cast<Instruction>(token);
221    }
222
223    // This relocate is on exceptional path of an invoke statepoint
224    const BasicBlock *invokeBB =
225      cast<Instruction>(token)->getParent()->getUniquePredecessor();
226
227    assert(invokeBB && "safepoints should have unique landingpads");
228    assert(invokeBB->getTerminator() && "safepoint block should be well formed");
229    assert(isStatepoint(invokeBB->getTerminator()));
230
231    return invokeBB->getTerminator();
232  }
233  /// The index into the associate statepoint's argument list
234  /// which contains the base pointer of the pointer whose
235  /// relocation this gc.relocate describes.
236  unsigned basePtrIndex() {
237    return cast<ConstantInt>(RelocateCS.getArgument(1))->getZExtValue();
238  }
239  /// The index into the associate statepoint's argument list which
240  /// contains the pointer whose relocation this gc.relocate describes.
241  unsigned derivedPtrIndex() {
242    return cast<ConstantInt>(RelocateCS.getArgument(2))->getZExtValue();
243  }
244  Value *basePtr() {
245    ImmutableCallSite CS(statepoint());
246    return *(CS.arg_begin() + basePtrIndex());
247  }
248  Value *derivedPtr() {
249    ImmutableCallSite CS(statepoint());
250    return *(CS.arg_begin() + derivedPtrIndex());
251  }
252};
253
254template <typename InstructionTy, typename ValueTy, typename CallSiteTy>
255std::vector<GCRelocateOperands>
256  StatepointBase<InstructionTy, ValueTy, CallSiteTy>::
257    getRelocates(ImmutableStatepoint &IS) {
258
259  std::vector<GCRelocateOperands> res;
260
261  ImmutableCallSite StatepointCS = IS.getCallSite();
262
263  // Search for relocated pointers.  Note that working backwards from the
264  // gc_relocates ensures that we only get pairs which are actually relocated
265  // and used after the statepoint.
266  for (const User *U : StatepointCS.getInstruction()->users()) {
267    if (isGCRelocate(U)) {
268      res.push_back(GCRelocateOperands(U));
269    }
270  }
271
272  if (!StatepointCS.isInvoke()) {
273    return res;
274  }
275
276  // We need to scan thorough exceptional relocations if it is invoke statepoint
277  LandingPadInst *LandingPad =
278    cast<InvokeInst>(StatepointCS.getInstruction())->getLandingPadInst();
279
280  // Search for extract value from landingpad instruction to which
281  // gc relocates will be attached
282  for (const User *LandingPadUser : LandingPad->users()) {
283    if (!isa<ExtractValueInst>(LandingPadUser)) {
284      continue;
285    }
286
287    // gc relocates should be attached to this extract value
288    for (const User *U : LandingPadUser->users()) {
289      if (isGCRelocate(U)) {
290        res.push_back(GCRelocateOperands(U));
291      }
292    }
293  }
294  return res;
295}
296
297}
298#endif
299