Ejemplo n.º 1
0
CallSite ABICallSignature::emitUnmanagedCall(GenIR &Reader, Value *Target,
                                             bool MayThrow,
                                             ArrayRef<Value *> Arguments,
                                             Value *&Result) const {
  const LLILCJitContext &JitContext = *Reader.JitContext;
  const struct CORINFO_EE_INFO::InlinedCallFrameInfo &CallFrameInfo =
      JitContext.EEInfo.inlinedCallFrameInfo;
  LLVMContext &LLVMContext = *JitContext.LLVMContext;
  Type *Int8Ty = Type::getInt8Ty(LLVMContext);
  Type *Int32Ty = Type::getInt32Ty(LLVMContext);
  Type *Int64Ty = Type::getInt64Ty(LLVMContext);
  Type *Int8PtrTy = Reader.getUnmanagedPointerType(Int8Ty);
  IRBuilder<> &Builder = *Reader.LLVMBuilder;

  Reader.insertIRForUnmanagedCallFrame();

  Value *CallFrame = Reader.UnmanagedCallFrame;
  Value *Thread = Reader.ThreadPointer;
  assert(CallFrame != nullptr);
  assert(Thread != nullptr);

  // Set m_pDatum if necessary
  //
  // TODO: this needs to be updated for direct unmanaged calls, which require
  //       the target method handle instead of the stub secret parameter.
  if (Reader.MethodSignature.hasSecretParameter()) {
    Value *SecretParameter = Reader.secretParam();
    Value *CallTargetAddress =
        getFieldAddress(Builder, CallFrame, CallFrameInfo.offsetOfCallTarget,
                        SecretParameter->getType());
    Builder.CreateStore(SecretParameter, CallTargetAddress);
  }

  // Push the unmanaged call frame
  Value *FrameVPtr = getFieldAddress(Builder, CallFrame,
                                     CallFrameInfo.offsetOfFrameVptr, Int8Ty);
  Value *ThreadBase = Builder.CreateLoad(Thread);
  Value *ThreadFrameAddress = getFieldAddress(
      Builder, ThreadBase, JitContext.EEInfo.offsetOfThreadFrame, Int8PtrTy);
  Builder.CreateStore(FrameVPtr, ThreadFrameAddress);

  // Compute the address of the return address field
  Value *ReturnAddressAddress = getFieldAddress(
      Builder, CallFrame, CallFrameInfo.offsetOfReturnAddress, Int8PtrTy);

  // Compute the address of the GC mode field
  Value *GCStateAddress = getFieldAddress(
      Builder, ThreadBase, JitContext.EEInfo.offsetOfGCState, Int8Ty);

  // Compute address of the thread trap field
  Value *ThreadTrapAddress = nullptr;
  Type *ThreadTrapAddressTy = Reader.getUnmanagedPointerType(Int32Ty);
  void *IndirectAddrOfCaptureThreadGlobal = nullptr;
  void *AddrOfCaptureThreadGlobal =
      (void *)JitContext.JitInfo->getAddrOfCaptureThreadGlobal(
          &IndirectAddrOfCaptureThreadGlobal);
  if (AddrOfCaptureThreadGlobal != nullptr) {
    Value *RawThreadTrapAddress = ConstantInt::get(
        LLVMContext, APInt(Reader.TargetPointerSizeInBits,
                           (uint64_t)AddrOfCaptureThreadGlobal));
    ThreadTrapAddress =
        Builder.CreateIntToPtr(RawThreadTrapAddress, ThreadTrapAddressTy);
  } else {
    Value *IndirectThreadTrapAddress = ConstantInt::get(
        LLVMContext, APInt(Reader.TargetPointerSizeInBits,
                           (uint64_t)IndirectAddrOfCaptureThreadGlobal));
    Type *IndirectAddressTy =
        Reader.getUnmanagedPointerType(ThreadTrapAddressTy);
    Value *TypedIndirectAddress =
        Builder.CreateIntToPtr(IndirectThreadTrapAddress, IndirectAddressTy);
    ThreadTrapAddress = Builder.CreateLoad(TypedIndirectAddress);
  }

  // Compute address of GC pause helper
  Value *PauseHelperAddress =
      (Value *)Reader.getHelperCallAddress(CORINFO_HELP_STOP_FOR_GC);

  // Construct the call.
  //
  // The signature of the intrinsic is:
  // @llvm.experimental_gc_transition(
  //   fn_ptr target,
  //   i32 numCallArgs,
  //   i32 flags,
  //   ... call args ...,
  //   i32 numTransitionArgs,
  //   ... transition args...,
  //   i32 numDeoptArgs,
  //   ... deopt args...)
  //
  // In the case of CoreCLR, there are 4 transition args and 0 deopt args.
  //
  // The transition args are:
  // 0) Address of the return address field
  // 1) Address of the GC mode field
  // 2) Address of the thread trap global
  // 3) Address of CORINFO_HELP_STOP_FOR_GC
  Module *M = Reader.Function->getParent();
  Type *CallTypeArgs[] = {Target->getType()};
  Function *CallIntrinsic = Intrinsic::getDeclaration(
      M, Intrinsic::experimental_gc_statepoint, CallTypeArgs);

  const uint32_t PrefixArgCount = 5;
  const uint32_t TransitionArgCount = 4;
  const uint32_t PostfixArgCount = TransitionArgCount + 2;
  const uint32_t TargetArgCount = Arguments.size();
  SmallVector<Value *, 24> IntrinsicArgs(PrefixArgCount + TargetArgCount +
                                         PostfixArgCount);

  // ID, nop bytes, call target and target arguments
  IntrinsicArgs[0] = ConstantInt::get(Int64Ty, 0);
  IntrinsicArgs[1] = ConstantInt::get(Int32Ty, 0);
  IntrinsicArgs[2] = Target;
  IntrinsicArgs[3] = ConstantInt::get(Int32Ty, TargetArgCount);
  IntrinsicArgs[4] =
      ConstantInt::get(Int32Ty, (uint32_t)StatepointFlags::GCTransition);

  uint32_t I, J;
  for (I = 0, J = PrefixArgCount; I < TargetArgCount; I++, J++) {
    IntrinsicArgs[J] = Arguments[I];
  }

  // GC transition arguments
  IntrinsicArgs[J] = ConstantInt::get(Int32Ty, TransitionArgCount);
  IntrinsicArgs[J + 1] = ReturnAddressAddress;
  IntrinsicArgs[J + 2] = GCStateAddress;
  IntrinsicArgs[J + 3] = ThreadTrapAddress;
  IntrinsicArgs[J + 4] = PauseHelperAddress;

  // Deopt arguments
  IntrinsicArgs[J + 5] = ConstantInt::get(Int32Ty, 0);

  CallSite Call = Reader.makeCall(CallIntrinsic, MayThrow, IntrinsicArgs);

  // Get the call result if necessary
  if (!FuncResultType->isVoidTy()) {
    Type *ResultTypeArgs[] = {FuncResultType};
    Function *ResultIntrinsic = Intrinsic::getDeclaration(
        M, Intrinsic::experimental_gc_result, ResultTypeArgs);
    Result = Builder.CreateCall(ResultIntrinsic, Call.getInstruction());
  }

  // Deactivate the unmanaged call frame
  Builder.CreateStore(Constant::getNullValue(Int8PtrTy), ReturnAddressAddress);

  // Pop the unmanaged call frame
  Value *FrameLinkAddress = getFieldAddress(
      Builder, CallFrame, CallFrameInfo.offsetOfFrameLink, Int8PtrTy);
  Value *FrameLink = Builder.CreateLoad(FrameLinkAddress);
  Builder.CreateStore(FrameLink, ThreadFrameAddress);

  return Call;
}
Ejemplo n.º 2
0
CallSite
ABICallSignature::emitUnmanagedCall(GenIR &Reader, Value *Target, bool MayThrow,
                                    ArrayRef<Value *> Arguments) const {
  const LLILCJitContext &JitContext = *Reader.JitContext;
  const struct CORINFO_EE_INFO::InlinedCallFrameInfo &CallFrameInfo =
      JitContext.EEInfo.inlinedCallFrameInfo;
  LLVMContext &LLVMContext = *JitContext.LLVMContext;
  Type *Int8Ty = Type::getInt8Ty(LLVMContext);
  Type *Int32Ty = Type::getInt32Ty(LLVMContext);
  Type *Int8PtrTy = Reader.getUnmanagedPointerType(Int8Ty);
  IRBuilder<> &Builder = *Reader.LLVMBuilder;

  Reader.insertIRForUnmanagedCallFrame();

  Value *CallFrame = Reader.UnmanagedCallFrame;
  Value *Thread = Reader.ThreadPointer;
  assert(CallFrame != nullptr);
  assert(Thread != nullptr);

  // Set m_pDatum if necessary
  //
  // TODO: this needs to be updated for direct unmanaged calls, which require
  //       the target method handle instead of the stub secret parameter.
  if (Reader.MethodSignature.hasSecretParameter()) {
    Value *SecretParameter = Reader.secretParam();
    Value *CallTargetAddress =
        getFieldAddress(Builder, CallFrame, CallFrameInfo.offsetOfCallTarget,
                        SecretParameter->getType());
    Builder.CreateStore(SecretParameter, CallTargetAddress);
  }

  // Push the unmanaged call frame
  Value *FrameVPtr = getFieldAddress(Builder, CallFrame,
                                     CallFrameInfo.offsetOfFrameVptr, Int8Ty);
  Value *ThreadBase = Builder.CreateLoad(Thread);
  Value *ThreadFrameAddress = getFieldAddress(
      Builder, ThreadBase, JitContext.EEInfo.offsetOfThreadFrame, Int8PtrTy);
  Builder.CreateStore(FrameVPtr, ThreadFrameAddress);

  // Compute the address of the return address field
  Value *ReturnAddressAddress = getFieldAddress(
      Builder, CallFrame, CallFrameInfo.offsetOfReturnAddress, Int8PtrTy);

  // Compute the address of the GC mode field
  Value *GCStateAddress = getFieldAddress(
      Builder, ThreadBase, JitContext.EEInfo.offsetOfGCState, Int8Ty);

  // Compute address of the thread trap field
  Value *ThreadTrapAddress = nullptr;
  Type *ThreadTrapAddressTy = Reader.getUnmanagedPointerType(Int32Ty);
  void *IndirectAddrOfCaptureThreadGlobal = nullptr;
  void *AddrOfCaptureThreadGlobal =
      (void *)JitContext.JitInfo->getAddrOfCaptureThreadGlobal(
          &IndirectAddrOfCaptureThreadGlobal);
  void *AddrOfCaptureThreadHandle;
  bool IsIndirect;
  const bool IsReadOnly = true;
  const bool IsRelocatable = true;
  const bool IsCallTarget = false;
  if (AddrOfCaptureThreadGlobal != nullptr) {
    AddrOfCaptureThreadHandle = AddrOfCaptureThreadGlobal;
    IsIndirect = false;
  } else {
    AddrOfCaptureThreadHandle = IndirectAddrOfCaptureThreadGlobal;
    IsIndirect = true;
  }
  Value *RawThreadTrapAddress =
      Reader.handleToIRNode(mdtCaptureThreadGlobal, AddrOfCaptureThreadHandle,
                            AddrOfCaptureThreadHandle, IsIndirect, IsReadOnly,
                            IsRelocatable, IsCallTarget);
  ThreadTrapAddress =
      Builder.CreateIntToPtr(RawThreadTrapAddress, ThreadTrapAddressTy);

  // Compute address of GC pause helper
  Value *PauseHelperAddress =
      (Value *)Reader.getHelperCallAddress(CORINFO_HELP_STOP_FOR_GC);

  // Construct the call.
  //
  // The transition args are:
  // 0) Address of the return address field
  // 1) Address of the GC mode field
  // 2) Address of the thread trap global
  // 3) Address of CORINFO_HELP_STOP_FOR_GC
  Value *TransitionArgs[] = {ReturnAddressAddress, GCStateAddress,
                             ThreadTrapAddress, PauseHelperAddress};
  OperandBundleDef TransitionBundle("gc-transition", TransitionArgs);

  CallSite Call =
      Reader.makeCall(Target, MayThrow, Arguments, {TransitionBundle});
  assert(Call.getOperandBundle(LLVMContext::OB_gc_transition).hasValue() &&
         "tag string mismatch?");

  // Deactivate the unmanaged call frame
  Builder.CreateStore(Constant::getNullValue(Int8PtrTy), ReturnAddressAddress);

  // Pop the unmanaged call frame
  Value *FrameLinkAddress = getFieldAddress(
      Builder, CallFrame, CallFrameInfo.offsetOfFrameLink, Int8PtrTy);
  Value *FrameLink = Builder.CreateLoad(FrameLinkAddress);
  Builder.CreateStore(FrameLink, ThreadFrameAddress);

  return Call;
}