diff options
Diffstat (limited to 'include/llvm/IR/Statepoint.h')
-rw-r--r-- | include/llvm/IR/Statepoint.h | 255 |
1 files changed, 197 insertions, 58 deletions
diff --git a/include/llvm/IR/Statepoint.h b/include/llvm/IR/Statepoint.h index e3c4243e9d81b..cd09618e3eee4 100644 --- a/include/llvm/IR/Statepoint.h +++ b/include/llvm/IR/Statepoint.h @@ -17,21 +17,35 @@ #define __LLVM_IR_STATEPOINT_H #include "llvm/ADT/iterator_range.h" +#include "llvm/IR/BasicBlock.h" #include "llvm/IR/CallSite.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/Support/Compiler.h" namespace llvm { +/// The statepoint intrinsic accepts a set of flags as its third argument. +/// Valid values come out of this set. +enum class StatepointFlags { + None = 0, + GCTransition = 1, ///< Indicates that this statepoint is a transition from + ///< GC-aware code to code that is not GC-aware. + + MaskAll = GCTransition ///< A bitmask that includes all valid flags. +}; + +class GCRelocateOperands; +class ImmutableStatepoint; bool isStatepoint(const ImmutableCallSite &CS); -bool isStatepoint(const Instruction *inst); -bool isStatepoint(const Instruction &inst); +bool isStatepoint(const Value *inst); +bool isStatepoint(const Value &inst); -bool isGCRelocate(const Instruction *inst); +bool isGCRelocate(const Value *inst); bool isGCRelocate(const ImmutableCallSite &CS); -bool isGCResult(const Instruction *inst); +bool isGCResult(const Value *inst); bool isGCResult(const ImmutableCallSite &CS); /// Analogous to CallSiteBase, this provides most of the actual @@ -45,10 +59,10 @@ bool isGCResult(const ImmutableCallSite &CS); template <typename InstructionTy, typename ValueTy, typename CallSiteTy> class StatepointBase { CallSiteTy StatepointCS; - void *operator new(size_t, unsigned) LLVM_DELETED_FUNCTION; - void *operator new(size_t s) LLVM_DELETED_FUNCTION; + void *operator new(size_t, unsigned) = delete; + void *operator new(size_t s) = delete; - protected: +protected: explicit StatepointBase(InstructionTy *I) : StatepointCS(I) { assert(isStatepoint(I)); } @@ -56,38 +70,68 @@ class StatepointBase { assert(isStatepoint(CS)); } - public: +public: typedef typename CallSiteTy::arg_iterator arg_iterator; + enum { + IDPos = 0, + NumPatchBytesPos = 1, + ActualCalleePos = 2, + NumCallArgsPos = 3, + FlagsPos = 4, + CallArgsBeginPos = 5, + }; + /// Return the underlying CallSite. - CallSiteTy getCallSite() { - return StatepointCS; + CallSiteTy getCallSite() { return StatepointCS; } + + uint64_t getFlags() const { + return cast<ConstantInt>(StatepointCS.getArgument(FlagsPos)) + ->getZExtValue(); + } + + /// Return the ID associated with this statepoint. + uint64_t getID() { + const Value *IDVal = StatepointCS.getArgument(IDPos); + return cast<ConstantInt>(IDVal)->getZExtValue(); + } + + /// Return the number of patchable bytes associated with this statepoint. + uint32_t getNumPatchBytes() { + const Value *NumPatchBytesVal = StatepointCS.getArgument(NumPatchBytesPos); + uint64_t NumPatchBytes = + cast<ConstantInt>(NumPatchBytesVal)->getZExtValue(); + assert(isInt<32>(NumPatchBytes) && "should fit in 32 bits!"); + return NumPatchBytes; } /// Return the value actually being called or invoked. - ValueTy *actualCallee() { - return StatepointCS.getArgument(0); + ValueTy *getActualCallee() { + return StatepointCS.getArgument(ActualCalleePos); } - /// Number of arguments to be passed to the actual callee. - int numCallArgs() { - return cast<ConstantInt>(StatepointCS.getArgument(1))->getZExtValue(); + + /// Return the type of the value returned by the call underlying the + /// statepoint. + Type *getActualReturnType() { + auto *FTy = cast<FunctionType>( + cast<PointerType>(getActualCallee()->getType())->getElementType()); + return FTy->getReturnType(); } - /// Number of additional arguments excluding those intended - /// for garbage collection. - int numTotalVMSArgs() { - return cast<ConstantInt>(StatepointCS.getArgument(3 + numCallArgs()))->getZExtValue(); + + /// Number of arguments to be passed to the actual callee. + int getNumCallArgs() { + const Value *NumCallArgsVal = StatepointCS.getArgument(NumCallArgsPos); + return cast<ConstantInt>(NumCallArgsVal)->getZExtValue(); } typename CallSiteTy::arg_iterator call_args_begin() { - // 3 = callTarget, #callArgs, flag - int Offset = 3; - assert(Offset <= (int)StatepointCS.arg_size()); - return StatepointCS.arg_begin() + Offset; + assert(CallArgsBeginPos <= (int)StatepointCS.arg_size()); + return StatepointCS.arg_begin() + CallArgsBeginPos; } typename CallSiteTy::arg_iterator call_args_end() { - int Offset = 3 + numCallArgs(); - assert(Offset <= (int)StatepointCS.arg_size()); - return StatepointCS.arg_begin() + Offset; + auto I = call_args_begin() + getNumCallArgs(); + assert((StatepointCS.arg_end() - I) >= 0); + return I; } /// range adapter for call arguments @@ -95,13 +139,44 @@ class StatepointBase { return iterator_range<arg_iterator>(call_args_begin(), call_args_end()); } + /// Number of GC transition args. + int getNumTotalGCTransitionArgs() { + const Value *NumGCTransitionArgs = *call_args_end(); + return cast<ConstantInt>(NumGCTransitionArgs)->getZExtValue(); + } + typename CallSiteTy::arg_iterator gc_transition_args_begin() { + auto I = call_args_end() + 1; + assert((StatepointCS.arg_end() - I) >= 0); + return I; + } + typename CallSiteTy::arg_iterator gc_transition_args_end() { + auto I = gc_transition_args_begin() + getNumTotalGCTransitionArgs(); + assert((StatepointCS.arg_end() - I) >= 0); + return I; + } + + /// range adapter for GC transition arguments + iterator_range<arg_iterator> gc_transition_args() { + return iterator_range<arg_iterator>(gc_transition_args_begin(), + gc_transition_args_end()); + } + + /// Number of additional arguments excluding those intended + /// for garbage collection. + int getNumTotalVMSArgs() { + const Value *NumVMSArgs = *gc_transition_args_end(); + return cast<ConstantInt>(NumVMSArgs)->getZExtValue(); + } + typename CallSiteTy::arg_iterator vm_state_begin() { - return call_args_end(); + auto I = gc_transition_args_end() + 1; + assert((StatepointCS.arg_end() - I) >= 0); + return I; } typename CallSiteTy::arg_iterator vm_state_end() { - int Offset = 3 + numCallArgs() + 1 + numTotalVMSArgs(); - assert(Offset <= (int)StatepointCS.arg_size()); - return StatepointCS.arg_begin() + Offset; + auto I = vm_state_begin() + getNumTotalVMSArgs(); + assert((StatepointCS.arg_end() - I) >= 0); + return I; } /// range adapter for vm state arguments @@ -109,15 +184,7 @@ class StatepointBase { return iterator_range<arg_iterator>(vm_state_begin(), vm_state_end()); } - typename CallSiteTy::arg_iterator first_vm_state_stack_begin() { - // 6 = numTotalVMSArgs, 1st_objectID, 1st_bci, - // 1st_#stack, 1st_#local, 1st_#monitor - return vm_state_begin() + 6; - } - - typename CallSiteTy::arg_iterator gc_args_begin() { - return vm_state_end(); - } + typename CallSiteTy::arg_iterator gc_args_begin() { return vm_state_end(); } typename CallSiteTy::arg_iterator gc_args_end() { return StatepointCS.arg_end(); } @@ -127,18 +194,25 @@ class StatepointBase { return iterator_range<arg_iterator>(gc_args_begin(), gc_args_end()); } + /// Get list of all gc reloactes linked to this statepoint + /// May contain several relocations for the same base/derived pair. + /// For example this could happen due to relocations on unwinding + /// path of invoke. + std::vector<GCRelocateOperands> getRelocates(ImmutableStatepoint &IS); #ifndef NDEBUG /// Asserts if this statepoint is malformed. Common cases for failure /// include incorrect length prefixes for variable length sections or /// illegal values for parameters. void verify() { - assert(numCallArgs() >= 0 && + assert(getNumCallArgs() >= 0 && "number of arguments to actually callee can't be negative"); // The internal asserts in the iterator accessors do the rest. (void)call_args_begin(); (void)call_args_end(); + (void)gc_transition_args_begin(); + (void)gc_transition_args_end(); (void)vm_state_begin(); (void)vm_state_end(); (void)gc_args_begin(); @@ -150,8 +224,7 @@ class StatepointBase { /// A specialization of it's base class for read only access /// to a gc.statepoint. class ImmutableStatepoint - : public StatepointBase<const Instruction, const Value, - ImmutableCallSite> { + : public StatepointBase<const Instruction, const Value, ImmutableCallSite> { typedef StatepointBase<const Instruction, const Value, ImmutableCallSite> Base; @@ -176,40 +249,106 @@ public: class GCRelocateOperands { ImmutableCallSite RelocateCS; - public: - GCRelocateOperands(const User* U) : RelocateCS(U) { - assert(isGCRelocate(U)); - } +public: + GCRelocateOperands(const User *U) : RelocateCS(U) { assert(isGCRelocate(U)); } GCRelocateOperands(const Instruction *inst) : RelocateCS(inst) { assert(isGCRelocate(inst)); } - GCRelocateOperands(CallSite CS) : RelocateCS(CS) { - assert(isGCRelocate(CS)); + GCRelocateOperands(CallSite CS) : RelocateCS(CS) { assert(isGCRelocate(CS)); } + + /// Return true if this relocate is tied to the invoke statepoint. + /// This includes relocates which are on the unwinding path. + bool isTiedToInvoke() const { + const Value *Token = RelocateCS.getArgument(0); + + return isa<ExtractValueInst>(Token) || isa<InvokeInst>(Token); } + /// Get enclosed relocate intrinsic + ImmutableCallSite getUnderlyingCallSite() { return RelocateCS; } + /// The statepoint with which this gc.relocate is associated. - const Instruction *statepoint() { - return cast<Instruction>(RelocateCS.getArgument(0)); + const Instruction *getStatepoint() { + const Value *Token = RelocateCS.getArgument(0); + + // This takes care both of relocates for call statepoints and relocates + // on normal path of invoke statepoint. + if (!isa<ExtractValueInst>(Token)) { + return cast<Instruction>(Token); + } + + // This relocate is on exceptional path of an invoke statepoint + const BasicBlock *InvokeBB = + cast<Instruction>(Token)->getParent()->getUniquePredecessor(); + + assert(InvokeBB && "safepoints should have unique landingpads"); + assert(InvokeBB->getTerminator() && + "safepoint block should be well formed"); + assert(isStatepoint(InvokeBB->getTerminator())); + + return InvokeBB->getTerminator(); } + /// The index into the associate statepoint's argument list /// which contains the base pointer of the pointer whose /// relocation this gc.relocate describes. - int basePtrIndex() { + unsigned getBasePtrIndex() { return cast<ConstantInt>(RelocateCS.getArgument(1))->getZExtValue(); } + /// The index into the associate statepoint's argument list which /// contains the pointer whose relocation this gc.relocate describes. - int derivedPtrIndex() { + unsigned getDerivedPtrIndex() { return cast<ConstantInt>(RelocateCS.getArgument(2))->getZExtValue(); } - Value *basePtr() { - ImmutableCallSite CS(statepoint()); - return *(CS.arg_begin() + basePtrIndex()); + + Value *getBasePtr() { + ImmutableCallSite CS(getStatepoint()); + return *(CS.arg_begin() + getBasePtrIndex()); } - Value *derivedPtr() { - ImmutableCallSite CS(statepoint()); - return *(CS.arg_begin() + derivedPtrIndex()); + + Value *getDerivedPtr() { + ImmutableCallSite CS(getStatepoint()); + return *(CS.arg_begin() + getDerivedPtrIndex()); } }; + +template <typename InstructionTy, typename ValueTy, typename CallSiteTy> +std::vector<GCRelocateOperands> +StatepointBase<InstructionTy, ValueTy, CallSiteTy>::getRelocates( + ImmutableStatepoint &IS) { + + std::vector<GCRelocateOperands> Result; + + ImmutableCallSite StatepointCS = IS.getCallSite(); + + // Search for relocated pointers. Note that working backwards from the + // gc_relocates ensures that we only get pairs which are actually relocated + // and used after the statepoint. + for (const User *U : StatepointCS.getInstruction()->users()) + if (isGCRelocate(U)) + Result.push_back(GCRelocateOperands(U)); + + if (!StatepointCS.isInvoke()) + return Result; + + // We need to scan thorough exceptional relocations if it is invoke statepoint + LandingPadInst *LandingPad = + cast<InvokeInst>(StatepointCS.getInstruction())->getLandingPadInst(); + + // Search for extract value from landingpad instruction to which + // gc relocates will be attached + for (const User *LandingPadUser : LandingPad->users()) { + if (!isa<ExtractValueInst>(LandingPadUser)) + continue; + + // gc relocates should be attached to this extract value + for (const User *U : LandingPadUser->users()) + if (isGCRelocate(U)) + Result.push_back(GCRelocateOperands(U)); + } + return Result; +} } + #endif |