diff --git a/include/Reader/abisignature.h b/include/Reader/abisignature.h index c056b44d55e..c4cd764bf3e 100644 --- a/include/Reader/abisignature.h +++ b/include/Reader/abisignature.h @@ -68,13 +68,14 @@ class ABICallSignature : public ABISignature { /// \param Reader The \p GenIR instance that will be used to emit /// IR. /// \param Target The call target. + /// \param MayThrow True iff the callee may raise an exception /// \param Args The arguments to the call. /// \param IndirectionCell The indirection cell argument for the call, if /// any. /// \param CallNode [out] The call instruction. /// /// \returns The result of the call to the target. - llvm::Value *emitCall(GenIR &Reader, llvm::Value *Target, + llvm::Value *emitCall(GenIR &Reader, llvm::Value *Target, bool mayThrow, llvm::ArrayRef Args, llvm::Value *IndirectionCell, llvm::Value **CallNode) const; diff --git a/include/Reader/reader.h b/include/Reader/reader.h index 399d0780998..0e79082ecd3 100644 --- a/include/Reader/reader.h +++ b/include/Reader/reader.h @@ -3134,15 +3134,16 @@ class ReaderBase { IRNode *ThisArg) = 0; // Helper callback used by rdrCall to emit call code. - virtual IRNode *genCall(ReaderCallTargetData *CallTargetData, + virtual IRNode *genCall(ReaderCallTargetData *CallTargetData, bool MayThrow, std::vector Args, IRNode **CallNode) = 0; virtual bool canMakeDirectCall(ReaderCallTargetData *CallTargetData) = 0; // Generate call to helper - virtual IRNode *callHelper(CorInfoHelpFunc HelperID, IRNode *Dst, - IRNode *Arg1 = nullptr, IRNode *Arg2 = nullptr, - IRNode *Arg3 = nullptr, IRNode *Arg4 = nullptr, + virtual IRNode *callHelper(CorInfoHelpFunc HelperID, bool MayThrow, + IRNode *Dst, IRNode *Arg1 = nullptr, + IRNode *Arg2 = nullptr, IRNode *Arg3 = nullptr, + IRNode *Arg4 = nullptr, ReaderAlignType Alignment = Reader_AlignUnknown, bool IsVolatile = false, bool NoCtor = false, bool CanMoveUp = false) = 0; diff --git a/include/Reader/readerir.h b/include/Reader/readerir.h index b093e2c1710..cc3296b4d78 100644 --- a/include/Reader/readerir.h +++ b/include/Reader/readerir.h @@ -24,6 +24,7 @@ #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/CallSite.h" #include "reader.h" #include "abi.h" #include "abisignature.h" @@ -719,13 +720,13 @@ class GenIR : public ReaderBase { IRNode *ThisArg) override; // Helper callback used by rdrCall to emit call code. - IRNode *genCall(ReaderCallTargetData *CallTargetInfo, + IRNode *genCall(ReaderCallTargetData *CallTargetInfo, bool MayThrow, std::vector Args, IRNode **CallNode) override; bool canMakeDirectCall(ReaderCallTargetData *CallTargetData) override; // Generate call to helper - IRNode *callHelper(CorInfoHelpFunc HelperID, IRNode *Dst, + IRNode *callHelper(CorInfoHelpFunc HelperID, bool MayThrow, IRNode *Dst, IRNode *Arg1 = nullptr, IRNode *Arg2 = nullptr, IRNode *Arg3 = nullptr, IRNode *Arg4 = nullptr, ReaderAlignType Alignment = Reader_AlignUnknown, @@ -733,12 +734,13 @@ class GenIR : public ReaderBase { bool CanMoveUp = false) override; // Generate call to helper - IRNode *callHelperImpl(CorInfoHelpFunc HelperID, llvm::Type *ReturnType, - IRNode *Arg1 = nullptr, IRNode *Arg2 = nullptr, - IRNode *Arg3 = nullptr, IRNode *Arg4 = nullptr, - ReaderAlignType Alignment = Reader_AlignUnknown, - bool IsVolatile = false, bool NoCtor = false, - bool CanMoveUp = false); + llvm::CallSite callHelperImpl(CorInfoHelpFunc HelperID, bool MayThrow, + llvm::Type *ReturnType, IRNode *Arg1 = nullptr, + IRNode *Arg2 = nullptr, IRNode *Arg3 = nullptr, + IRNode *Arg4 = nullptr, + ReaderAlignType Alignment = Reader_AlignUnknown, + bool IsVolatile = false, bool NoCtor = false, + bool CanMoveUp = false); /// Generate special generics helper that might need to insert flow. The /// helper is called if NullCheckArg is null at compile-time or if it @@ -1031,17 +1033,19 @@ class GenIR : public ReaderBase { /// /// \param Condition Condition that will trigger the call. /// \param HelperId Id of the call helper. + /// \param MayThrow true if the helper call may raise an exception. /// \param ReturnType Return type of the call helper. /// \param Arg1 First helper argument. /// \param Arg2 Second helper argument. /// \param CallReturns true iff the helper call returns. /// \param CallBlockName Name of the basic block that will contain the call. - /// \returns Generated call instruction. - llvm::CallInst *genConditionalHelperCall(llvm::Value *Condition, - CorInfoHelpFunc HelperId, - llvm::Type *ReturnType, IRNode *Arg1, - IRNode *Arg2, bool CallReturns, - const llvm::Twine &CallBlockName); + /// \returns Generated call/invoke instruction. + llvm::CallSite genConditionalHelperCall(llvm::Value *Condition, + CorInfoHelpFunc HelperId, + bool MayThrow, llvm::Type *ReturnType, + IRNode *Arg1, IRNode *Arg2, + bool CallReturns, + const llvm::Twine &CallBlockName); /// Generate a call to the throw helper if the condition is met. /// @@ -1144,6 +1148,17 @@ class GenIR : public ReaderBase { return makeLoad(Address, IsVolatile, false); } + /// \brief Create a call or invoke instruction + /// + /// The call is inserted at the LLVMBuilder's current insertion point. + /// + /// \param Callee Target of the call + /// \param MayThrow True if the callee may raise an exception + /// \param Args Arguments to pass to the callee + /// \returns A \p CallSite wrapping the CallInst or InvokeInst + llvm::CallSite makeCall(llvm::Value *Callee, bool MayThrow, + llvm::ArrayRef Args); + /// Store a value to an argument passed indirectly. /// /// The storage backing such arguments may be loacted on the heap; any stores diff --git a/lib/Reader/abisignature.cpp b/lib/Reader/abisignature.cpp index 140c2483cca..235f4fdc069 100644 --- a/lib/Reader/abisignature.cpp +++ b/lib/Reader/abisignature.cpp @@ -87,7 +87,7 @@ ABICallSignature::ABICallSignature(const ReaderCallSignature &TheSignature, : ABISignature(TheSignature, Reader, TheABIInfo), Signature(TheSignature) {} Value *ABICallSignature::emitCall(GenIR &Reader, llvm::Value *Target, - llvm::ArrayRef Args, + bool MayThrow, llvm::ArrayRef Args, llvm::Value *IndirectionCell, llvm::Value **CallNode) const { assert(Target->getType()->isIntegerTy(Reader.TargetPointerSizeInBits)); @@ -150,7 +150,7 @@ Value *ABICallSignature::emitCall(GenIR &Reader, llvm::Value *Target, Type *FunctionPtrTy = Reader.getUnmanagedPointerType(FunctionTy); Target = Builder.CreateIntToPtr(Target, FunctionPtrTy); - CallInst *Call = Builder.CreateCall(Target, Arguments); + CallSite Call = Reader.makeCall(Target, MayThrow, Arguments); CallingConv::ID CC; if (HasIndirectionCell) { @@ -159,18 +159,18 @@ Value *ABICallSignature::emitCall(GenIR &Reader, llvm::Value *Target, } else { CC = getLLVMCallingConv(Signature.getCallingConvention()); } - Call->setCallingConv(CC); + Call.setCallingConv(CC); if (ResultNode == nullptr) { assert(!HasIndirectResult); const CallArgType &SigResultType = Signature.getResultType(); Type *Ty = Reader.getType(SigResultType.CorType, SigResultType.Class); - ResultNode = coerce(Reader, Ty, Call); + ResultNode = coerce(Reader, Ty, Call.getInstruction()); } else { ResultNode = Builder.CreateLoad(ResultNode); } - *CallNode = Call; + *CallNode = Call.getInstruction(); return ResultNode; } diff --git a/lib/Reader/reader.cpp b/lib/Reader/reader.cpp index c52599d5855..25afbbddbf9 100644 --- a/lib/Reader/reader.cpp +++ b/lib/Reader/reader.cpp @@ -1309,7 +1309,8 @@ void ReaderBase::insertHelperCall( HelperArgNodes[Index] = CurrentArg; } - callHelper(AccessAllowedInfo.helperNum, nullptr, HelperArgNodes[0], + const bool MayThrow = true; + callHelper(AccessAllowedInfo.helperNum, MayThrow, nullptr, HelperArgNodes[0], HelperArgNodes[1], HelperArgNodes[2], HelperArgNodes[3]); } @@ -3685,8 +3686,9 @@ void ReaderBase::cpBlk(IRNode *Count, // byte count IRNode *SrcAddr, // source address IRNode *DestAddr, // dest address ReaderAlignType Alignment, bool IsVolatile) { - callHelper(CORINFO_HELP_MEMCPY, nullptr, DestAddr, SrcAddr, Count, nullptr, - Alignment, IsVolatile); + const bool MayThrow = true; + callHelper(CORINFO_HELP_MEMCPY, MayThrow, nullptr, DestAddr, SrcAddr, Count, + nullptr, Alignment, IsVolatile); } // InitBlk - Creates a memset helper call/intrinsic. @@ -3694,8 +3696,9 @@ void ReaderBase::initBlk(IRNode *Count, // byte count IRNode *Value, // Value IRNode *DestAddr, // dest address ReaderAlignType Alignment, bool IsVolatile) { - callHelper(CORINFO_HELP_MEMSET, nullptr, DestAddr, Value, Count, nullptr, - Alignment, IsVolatile); + const bool MayThrow = true; + callHelper(CORINFO_HELP_MEMSET, MayThrow, nullptr, DestAddr, Value, Count, + nullptr, Alignment, IsVolatile); } void ReaderBase::initObj(CORINFO_RESOLVED_TOKEN *ResolvedToken, @@ -3738,7 +3741,8 @@ IRNode *ReaderBase::box(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg2, // from the token. Arg1 = genericTokenToNode(ResolvedToken, true); - RetVal = callHelper(getBoxHelper(Class), Dst, Arg1, Arg2); + const bool MayThrow = true; + RetVal = callHelper(getBoxHelper(Class), MayThrow, Dst, Arg1, Arg2); return RetVal; } @@ -3770,12 +3774,14 @@ IRNode *ReaderBase::refAnyVal(IRNode *RefAny, Dst = makePtrDstGCOperand(true); // Make the helper call - return callHelper(CORINFO_HELP_GETREFANY, Dst, Arg1, RefAny); + const bool MayThrow = true; + return callHelper(CORINFO_HELP_GETREFANY, MayThrow, Dst, Arg1, RefAny); } void ReaderBase::storeElemRefAny(IRNode *Value, IRNode *Index, IRNode *Obj) { // Make the helper call - callHelper(CORINFO_HELP_ARRADDR_ST, nullptr, Obj, Index, Value); + const bool MayThrow = true; + callHelper(CORINFO_HELP_ARRADDR_ST, MayThrow, nullptr, Obj, Index, Value); } // StoreIndir - Creates an instruction to assign the value on @@ -3921,7 +3927,8 @@ IRNode *ReaderBase::unboxAny(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg, // Break - Default reader processing for CEE_BREAK. void ReaderBase::breakOpcode() { // Make the helper call - callHelper(CORINFO_HELP_USER_BREAKPOINT, nullptr); + const bool MayThrow = true; + callHelper(CORINFO_HELP_USER_BREAKPOINT, MayThrow, nullptr); } // InsertClassConstructor - Insert a call to the class constructor helper. @@ -3944,30 +3951,38 @@ void ReaderBase::insertClassConstructor() { methodNeedsToKeepAliveGenericsContext(true); switch (Kind.runtimeLookupKind) { - case CORINFO_LOOKUP_THISOBJ: + case CORINFO_LOOKUP_THISOBJ: { // call CORINFO_HELP_INITINSTCLASS(thisobj, embedMethodHandle(M)) Method = embedMethodHandle(Method, &IsIndirect); // TODO: Aliasing -- always readonly? MethodNode = handleToIRNode(MethodToken, Method, 0, IsIndirect, IsIndirect, true, false); ClassNode = derefAddress(thisObj(), false, false); - callHelper(CORINFO_HELP_INITINSTCLASS, nullptr, ClassNode, MethodNode); + const bool MayThrow = true; + callHelper(CORINFO_HELP_INITINSTCLASS, MayThrow, nullptr, ClassNode, + MethodNode); return; - case CORINFO_LOOKUP_CLASSPARAM: + } + case CORINFO_LOOKUP_CLASSPARAM: { // will only be returned when you are compiling code that takes // a hidden parameter P. You should emit a call // CORINFO_HELP_INITCLASS(P) ClassNode = instParam(); - callHelper(CORINFO_HELP_INITCLASS, nullptr, ClassNode); + const bool MayThrow = true; + callHelper(CORINFO_HELP_INITCLASS, MayThrow, nullptr, ClassNode); return; - case CORINFO_LOOKUP_METHODPARAM: + } + case CORINFO_LOOKUP_METHODPARAM: { // will only be returned when you are compiling code that takes // a hidden parameter P. You should emit a call // CORINFO_HELP_INITINSTCLASS(nullptr, P) MethodNode = instParam(); ClassNode = loadConstantI8(0); - callHelper(CORINFO_HELP_INITINSTCLASS, nullptr, ClassNode, MethodNode); + const bool MayThrow = true; + callHelper(CORINFO_HELP_INITINSTCLASS, MayThrow, nullptr, ClassNode, + MethodNode); return; + } default: ASSERTNR(!"NYI"); } @@ -3987,7 +4002,8 @@ void ReaderBase::insertClassConstructor() { ClassNode = handleToIRNode(MethodToken, ClassHandle, Class, IsIndirect, IsIndirect, true, false); - callHelper(HelperId, nullptr, ClassNode); + const bool MayThrow = false; + callHelper(HelperId, MayThrow, nullptr, ClassNode); } else { rdrCallGetStaticBase(Class, MethodToken, HelperId, false, false, nullptr); } @@ -4032,14 +4048,16 @@ IRNode *ReaderBase::rdrGetCritSect() { // In this case, the hidden param is the class handle. HandleNode = instParam(); break; - case CORINFO_LOOKUP_METHODPARAM: + case CORINFO_LOOKUP_METHODPARAM: { // In this case, the hidden param is the method handle. HandleNode = instParam(); // Call helper CORINFO_HELP_GETCLASSFROMMETHODPARAM to get the // class handle from the method handle. - HandleNode = callHelper(CORINFO_HELP_GETCLASSFROMMETHODPARAM, + const bool MayThrow = false; + HandleNode = callHelper(CORINFO_HELP_GETCLASSFROMMETHODPARAM, MayThrow, makePtrNode(), HandleNode); break; + } default: ASSERTNR(!"Unknown LOOKUP_KIND"); break; @@ -4049,8 +4067,9 @@ IRNode *ReaderBase::rdrGetCritSect() { // CORINFO_CLASS_HANDLE for the exact class. // Given the class handle, get the pointer to the Monitor. - HandleNode = callHelper(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, makePtrNode(), - HandleNode); + const bool MayThrow = false; + HandleNode = callHelper(CORINFO_HELP_GETSYNCFROMCLASSHANDLE, MayThrow, + makePtrNode(), HandleNode); } ASSERTNR(HandleNode); @@ -4101,7 +4120,8 @@ void ReaderBase::rdrCallFieldHelper( IsIndirect, IsIndirect, true, false); // Make the helper call - callHelper(HelperId, nullptr, Arg1, Arg2, Arg3, Arg4, Alignment, + const bool MayThrow = true; + callHelper(HelperId, MayThrow, nullptr, Arg1, Arg2, Arg3, Arg4, Alignment, IsVolatile); } else { // OTHER LOAD @@ -4113,8 +4133,9 @@ void ReaderBase::rdrCallFieldHelper( Arg1 = Obj; // Make the helper call - callHelper(HelperId, Dst, Arg1, Arg2, nullptr, nullptr, Alignment, - IsVolatile); + const bool MayThrow = true; + callHelper(HelperId, MayThrow, Dst, Arg1, Arg2, nullptr, nullptr, + Alignment, IsVolatile); } } else { // STORE @@ -4147,7 +4168,8 @@ void ReaderBase::rdrCallFieldHelper( Arg1 = Obj; // Make the helper call - callHelper(HelperId, nullptr, Arg1, Arg2, Arg3, Arg4, Alignment, + const bool MayThrow = true; + callHelper(HelperId, MayThrow, nullptr, Arg1, Arg2, Arg3, Arg4, Alignment, IsVolatile); } else { // assert that the helper id is expected @@ -4168,8 +4190,9 @@ void ReaderBase::rdrCallFieldHelper( Arg1 = Obj; // Make the helper call - callHelper(HelperId, nullptr, Arg1, Arg2, Arg3, nullptr, Alignment, - IsVolatile); + const bool MayThrow = true; + callHelper(HelperId, MayThrow, nullptr, Arg1, Arg2, Arg3, nullptr, + Alignment, IsVolatile); } } } @@ -4202,9 +4225,10 @@ void ReaderBase::rdrCallWriteBarrierHelper( // writing to a field in a class which happens to be a GC pointer. // // HCIMPL2(void, JIT_CheckedWriteBarrier, Object** dest, Object * value) - callHelper(IsUnchecked ? CORINFO_HELP_ASSIGN_REF - : CORINFO_HELP_CHECKED_ASSIGN_REF, - nullptr, Dst, Src, nullptr, nullptr, Alignment, IsVolatile); + const bool MayThrow = true; + callHelper( + IsUnchecked ? CORINFO_HELP_ASSIGN_REF : CORINFO_HELP_CHECKED_ASSIGN_REF, + MayThrow, nullptr, Dst, Src, nullptr, nullptr, Alignment, IsVolatile); } else { // This is the case in which we will be copying a value class into // the field of this struct. The runtime will need to be passed @@ -4242,13 +4266,15 @@ void ReaderBase::rdrCallWriteBarrierHelper( handleToIRNode(ResolvedToken->token, ClassHandle, Class, IsIndirect, IsIndirect, true, false); - callHelper(CORINFO_HELP_ASSIGN_STRUCT, nullptr, Dst, Src, ClassHandleNode, - nullptr, Alignment, IsVolatile); + const bool MayThrow = true; + callHelper(CORINFO_HELP_ASSIGN_STRUCT, MayThrow, nullptr, Dst, Src, + ClassHandleNode, nullptr, Alignment, IsVolatile); } else { // If the class doesn't have a gc layout then use a memcopy IRNode *Size = loadConstantI4(getClassSize(Class)); - callHelper(CORINFO_HELP_MEMCPY, nullptr, Dst, Src, Size, nullptr, - Alignment, IsVolatile); + const bool MayThrow = true; + callHelper(CORINFO_HELP_MEMCPY, MayThrow, nullptr, Dst, Src, Size, + nullptr, Alignment, IsVolatile); } } } @@ -4285,9 +4311,10 @@ IRNode *ReaderBase::rdrCallGetStaticBase(CORINFO_CLASS_HANDLE Class, Token, EmbedClassDomainID, (CORINFO_CLASS_HANDLE)((size_t)Class | 1), IsIndirect2, IsIndirect2, IsIndirect2, false); - return callHelper(HelperId, Dst, ModuleDomainIDNode, ClassDomainIDNode, - nullptr, nullptr, Reader_AlignUnknown, false, NoCtor, - CanMoveUp); + const bool MayThrow = false; + return callHelper(HelperId, MayThrow, Dst, ModuleDomainIDNode, + ClassDomainIDNode, nullptr, nullptr, Reader_AlignUnknown, + false, NoCtor, CanMoveUp); } IRNode * @@ -4308,7 +4335,9 @@ ReaderBase::rdrGetStaticFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *PointerNode = makePtrDstGCOperand(true); // Now make the call and attach the arguments. - return callHelper(FieldInfo->helper, PointerNode, FieldHandleNode); + const bool MayThrow = false; + return callHelper(FieldInfo->helper, MayThrow, PointerNode, + FieldHandleNode); } case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: @@ -4331,8 +4360,9 @@ ReaderBase::rdrGetStaticFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *TempNode = makePtrNode(Reader_PtrGcInterior); // Now make the call and attach the arguments. + const bool MayThrow = false; SharedStaticsBaseNode = - callHelper(FieldInfo->helper, TempNode, ClassHandleNode); + callHelper(FieldInfo->helper, MayThrow, TempNode, ClassHandleNode); } else { CorInfoHelpFunc HelperId = FieldInfo->helper; CORINFO_CLASS_HANDLE Class = ResolvedToken->hClass; @@ -4585,7 +4615,8 @@ IRNode *ReaderBase::rdrGetFieldAddress(CORINFO_RESOLVED_TOKEN *ResolvedToken, Dst = makePtrNode(); } - return callHelper(FieldInfo->helper, Dst, Arg1, Arg2); + const bool MayThrow = true; + return callHelper(FieldInfo->helper, MayThrow, Dst, Arg1, Arg2); } else { // Get the offset, add it to the this pointer to calculate the // actual address of the field. @@ -4812,6 +4843,7 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode, // For certain intrinsics, we can determine that the call has no // side effects ... bool CallCanSideEffect = true; + bool MayThrow = true; // TODO: readonly work for calls @@ -5304,7 +5336,7 @@ ReaderBase::rdrCall(ReaderCallTargetData *Data, ReaderBaseNS::CallOpcode Opcode, } // Ask GenIR to emit call, optionally returns a ReturnNode. - ReturnNode = genCall(Data, Arguments, CallNode); + ReturnNode = genCall(Data, MayThrow, Arguments, CallNode); if (Data->isNewObj()) { ReturnNode = rdrMakeNewObjReturnNode(Data, NewObjThisArg, ReturnNode); @@ -5508,7 +5540,8 @@ IRNode *ReaderBase::rdrGetIndirectVirtualCallTarget( // Get the address of the target function by calling helper. // Type it as a native int, it will be recast later. IRNode *Dst = loadConstantI(0); - return callHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR, Dst, ThisPtrCopy, + const bool MayThrow = true; + return callHelper(CORINFO_HELP_VIRTUAL_FUNC_PTR, MayThrow, Dst, ThisPtrCopy, ClassHandle, MethodHandle); } @@ -5635,7 +5668,9 @@ void ReaderBase::rdrInsertCalloutForDelegate(CORINFO_CLASS_HANDLE DelegateType, IsIndirect, IsIndirect, true, false); // Make the helper call - callHelper(CORINFO_HELP_DELEGATE_SECURITY_CHECK, nullptr, Arg1, Arg2); + const bool MayThrow = true; + callHelper(CORINFO_HELP_DELEGATE_SECURITY_CHECK, MayThrow, nullptr, Arg1, + Arg2); } } @@ -6191,7 +6226,8 @@ void ReaderBase::domInfoRecordClassInit(FlowGraphNode *Fg, // Default routine to insert verification throw. void ReaderBase::insertThrow(CorInfoHelpFunc ThrowHelper, uint32_t Offset) { IRNode *IntConstant = loadConstantI4(Offset); - callHelper(ThrowHelper, nullptr, IntConstant); + const bool MayThrow = true; + callHelper(ThrowHelper, MayThrow, nullptr, IntConstant); } // Macro used by main reader loop for distinguishing verify-only passes diff --git a/lib/Reader/readerir.cpp b/lib/Reader/readerir.cpp index edd5f3d022e..fcee053a72b 100644 --- a/lib/Reader/readerir.cpp +++ b/lib/Reader/readerir.cpp @@ -410,10 +410,11 @@ void GenIR::readerPrePass(uint8_t *Buffer, uint32_t NumBytes) { Value *Condition = LLVMBuilder->CreateIsNotNull(JustMyCodeFlag, "JMC"); IRNode *Zero = loadConstantI4(0); Type *Void = Type::getVoidTy(*JitContext->LLVMContext); + const bool MayThrow = false; const bool CallReturns = true; genConditionalHelperCall( - Condition, CorInfoHelpFunc::CORINFO_HELP_DBG_IS_JUST_MY_CODE, Void, - JustMyCodeFlag, Zero, CallReturns, "JustMyCodeHook"); + Condition, CorInfoHelpFunc::CORINFO_HELP_DBG_IS_JUST_MY_CODE, + MayThrow, Void, JustMyCodeFlag, Zero, CallReturns, "JustMyCodeHook"); } } @@ -510,7 +511,8 @@ void GenIR::insertIRToKeepGenericContextAlive() { Value *FrameEscape = Intrinsic::getDeclaration(JitContext->CurrentModule, Intrinsic::frameescape); Value *Args[] = {ContextLocalAddress}; - LLVMBuilder->CreateCall(FrameEscape, Args); + const bool MayThrow = false; + makeCall(FrameEscape, MayThrow, Args); // Don't move TempInsertionPoint up since what we added was not an alloca LLVMBuilder->restoreIP(SavedInsertPoint); @@ -545,7 +547,8 @@ void GenIR::insertIRForSecurityObject() { IsIndirect, IsRelocatable, IsCallTarget); CorInfoHelpFunc SecurityHelper = JitContext->JitInfo->getSecurityPrologHelper(MethodHandle); - callHelper(SecurityHelper, nullptr, MethodNode, + const bool MayThrow = true; + callHelper(SecurityHelper, MayThrow, nullptr, MethodNode, (IRNode *)SecurityObjectAddress); LLVMBuilder->restoreIP(SavedInsertPoint); @@ -566,7 +569,8 @@ void GenIR::callMonitorHelper(bool IsEnter) { } else { HelperId = IsEnter ? CORINFO_HELP_MON_ENTER : CORINFO_HELP_MON_EXIT; } - callHelperImpl(HelperId, Type::getVoidTy(*JitContext->LLVMContext), + const bool MayThrow = false; + callHelperImpl(HelperId, MayThrow, Type::getVoidTy(*JitContext->LLVMContext), MethodSyncHandle, (IRNode *)SyncFlag); } @@ -2499,13 +2503,17 @@ IRNode *GenIR::binaryOp(ReaderBaseNS::BinaryOpcode Opcode, IRNode *Arg1, llvm_unreachable("Bad floating point type!"); } - Result = callHelperImpl(Helper, ResultType, Arg1, Arg2); + const bool MayThrow = false; + Result = (IRNode *)callHelperImpl(Helper, MayThrow, ResultType, Arg1, Arg2) + .getInstruction(); } else if (IsOverflow) { // Call the appropriate intrinsic. Its result is a pair of the arithmetic // result and a bool indicating whether the operation overflows. Value *Intrinsic = Intrinsic::getDeclaration( JitContext->CurrentModule, Triple[Opcode].Op.Intrinsic, ResultType); - Value *Pair = LLVMBuilder->CreateCall2(Intrinsic, Arg1, Arg2); + Value *Args[] = {Arg1, Arg2}; + const bool MayThrow = false; + Value *Pair = makeCall(Intrinsic, MayThrow, Args).getInstruction(); // Extract the bool and raise an overflow exception if set. Value *OvfBool = LLVMBuilder->CreateExtractValue(Pair, 1, "Ovf"); @@ -3067,6 +3075,13 @@ LoadInst *GenIR::makeLoad(Value *Address, bool IsVolatile, return LLVMBuilder->CreateLoad(Address, IsVolatile); } +CallSite GenIR::makeCall(Value *Callee, bool MayThrow, ArrayRef Args) { + if (MayThrow) { + // TODO: Generate an invoke with an appropriate unwind label. + } + return LLVMBuilder->CreateCall(Callee, Args); +} + void GenIR::storeStaticField(CORINFO_RESOLVED_TOKEN *FieldToken, IRNode *ValueToStore, bool IsVolatile) { // Gather information about the field @@ -3233,8 +3248,10 @@ IRNode *GenIR::loadElemA(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Index, if (!IsReadOnly && ((ClassAttribs & CORINFO_FLG_VALUECLASS) == 0)) { IRNode *HandleNode = genericTokenToNode(ResolvedToken); PointerType *ElementAddressTy = getManagedPointerType(ElementTy); - return callHelperImpl(CORINFO_HELP_LDELEMA_REF, ElementAddressTy, Array, - Index, HandleNode); + const bool MayThrow = true; + return (IRNode *)callHelperImpl(CORINFO_HELP_LDELEMA_REF, MayThrow, + ElementAddressTy, Array, Index, + HandleNode).getInstruction(); } return genArrayElemAddress(Array, Index, ElementTy); @@ -3402,21 +3419,23 @@ bool isNonVolatileWriteHelperCall(CorInfoHelpFunc HelperId) { } // Generate call to helper -IRNode *GenIR::callHelper(CorInfoHelpFunc HelperID, IRNode *Dst, IRNode *Arg1, - IRNode *Arg2, IRNode *Arg3, IRNode *Arg4, - ReaderAlignType Alignment, bool IsVolatile, - bool NoCtor, bool CanMoveUp) { +IRNode *GenIR::callHelper(CorInfoHelpFunc HelperID, bool MayThrow, IRNode *Dst, + IRNode *Arg1, IRNode *Arg2, IRNode *Arg3, + IRNode *Arg4, ReaderAlignType Alignment, + bool IsVolatile, bool NoCtor, bool CanMoveUp) { LLVMContext &LLVMContext = *this->JitContext->LLVMContext; Type *ReturnType = (Dst == nullptr) ? Type::getVoidTy(LLVMContext) : Dst->getType(); - return callHelperImpl(HelperID, ReturnType, Arg1, Arg2, Arg3, Arg4, Alignment, - IsVolatile, NoCtor, CanMoveUp); + return (IRNode *)callHelperImpl(HelperID, MayThrow, ReturnType, Arg1, Arg2, + Arg3, Arg4, Alignment, IsVolatile, NoCtor, + CanMoveUp).getInstruction(); } -IRNode *GenIR::callHelperImpl(CorInfoHelpFunc HelperID, Type *ReturnType, - IRNode *Arg1, IRNode *Arg2, IRNode *Arg3, - IRNode *Arg4, ReaderAlignType Alignment, - bool IsVolatile, bool NoCtor, bool CanMoveUp) { +CallSite GenIR::callHelperImpl(CorInfoHelpFunc HelperID, bool MayThrow, + Type *ReturnType, IRNode *Arg1, IRNode *Arg2, + IRNode *Arg3, IRNode *Arg4, + ReaderAlignType Alignment, bool IsVolatile, + bool NoCtor, bool CanMoveUp) { ASSERT(HelperID != CORINFO_HELP_UNDEF); // TODO: We can turn some of these helper calls into intrinsics. @@ -3463,7 +3482,7 @@ IRNode *GenIR::callHelperImpl(CorInfoHelpFunc HelperID, Type *ReturnType, // This is an intermediate result. Callers must handle // transitioning to a valid stack type, if appropriate. - IRNode *Call = (IRNode *)LLVMBuilder->CreateCall(Target, Arguments); + CallSite Call = makeCall(Target, MayThrow, Arguments); if (IsVolatile && isNonVolatileWriteHelperCall(HelperID)) { // TODO: this is only needed where CLRConfig::INTERNAL_JitLockWrite is set @@ -3500,7 +3519,9 @@ IRNode *GenIR::callRuntimeHandleHelper(CorInfoHelpFunc Helper, IRNode *Arg1, // Call the helper unconditionally if NullCheckArg is null. if ((NullCheckArg == nullptr) || isConstantNull(NullCheckArg)) { - return callHelperImpl(Helper, ReturnType, Arg1, Arg2); + const bool MayThrow = true; + return (IRNode *)callHelperImpl(Helper, MayThrow, ReturnType, Arg1, Arg2) + .getInstruction(); } BasicBlock *SaveBlock = LLVMBuilder->GetInsertBlock(); @@ -3509,10 +3530,11 @@ IRNode *GenIR::callRuntimeHandleHelper(CorInfoHelpFunc Helper, IRNode *Arg1, Value *Compare = LLVMBuilder->CreateIsNull(NullCheckArg, "NullCheck"); // Generate conditional helper call. - bool CallReturns = true; - CallInst *HelperCall = - genConditionalHelperCall(Compare, Helper, ReturnType, Arg1, Arg2, - CallReturns, "RuntimeHandleHelperCall"); + const bool MayThrow = true; + const bool CallReturns = true; + CallSite HelperCall = + genConditionalHelperCall(Compare, Helper, MayThrow, ReturnType, Arg1, + Arg2, CallReturns, "RuntimeHandleHelperCall"); // The result is a PHI of NullCheckArg and the generated call. // The generated code is equivalent to @@ -3523,9 +3545,9 @@ IRNode *GenIR::callRuntimeHandleHelper(CorInfoHelpFunc Helper, IRNode *Arg1, // return x; BasicBlock *CurrentBlock = LLVMBuilder->GetInsertBlock(); BasicBlock *CallBlock = HelperCall->getParent(); - PHINode *PHI = - mergeConditionalResults(CurrentBlock, NullCheckArg, SaveBlock, HelperCall, - CallBlock, "RuntimeHandle"); + PHINode *PHI = mergeConditionalResults(CurrentBlock, NullCheckArg, SaveBlock, + HelperCall.getInstruction(), CallBlock, + "RuntimeHandle"); return (IRNode *)PHI; } @@ -3546,11 +3568,12 @@ IRNode *GenIR::convertHandle(IRNode *GetTokenNumericNode, // Get the value that should be assigned to the struct's field, e.g., an // instance of RuntimeType. Type *HelperResultType = FieldAddress->getType()->getPointerElementType(); - IRNode *HelperResult = - callHelperImpl(HelperID, HelperResultType, GetTokenNumericNode); + const bool MayThrow = true; + CallSite HelperResult = + callHelperImpl(HelperID, MayThrow, HelperResultType, GetTokenNumericNode); // Assign the field of the result struct. - LLVMBuilder->CreateStore(HelperResult, FieldAddress); + LLVMBuilder->CreateStore(HelperResult.getInstruction(), FieldAddress); const bool IsVolatile = false; return (IRNode *)LLVMBuilder->CreateLoad(Result, IsVolatile); @@ -3652,7 +3675,8 @@ IRNode *GenIR::genNewMDArrayCall(ReaderCallTargetData *CallTargetData, getUnmanagedPointerType(FunctionType)); // Replace the old call instruction with the new one. - *CallNode = (IRNode *)LLVMBuilder->CreateCall(Callee, Arguments); + const bool MayThrow = true; + *CallNode = (IRNode *)makeCall(Callee, MayThrow, Arguments).getInstruction(); return *CallNode; } @@ -3704,8 +3728,10 @@ IRNode *GenIR::genNewObjThisArg(ReaderCallTargetData *CallTargetData, // Create the address operand for the newobj helper. CorInfoHelpFunc HelperId = getNewHelper(CallTargetData->getResolvedToken()); + const bool MayThrow = true; Value *ThisPointer = - callHelperImpl(HelperId, ThisType, CallTargetData->getClassHandleNode()); + callHelperImpl(HelperId, MayThrow, ThisType, + CallTargetData->getClassHandleNode()).getInstruction(); return (IRNode *)ThisPointer; } @@ -3736,7 +3762,7 @@ IRNode *GenIR::genNewObjReturnNode(ReaderCallTargetData *CallTargetData, return ThisArg; } -IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo, +IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo, bool MayThrow, std::vector Args, IRNode **CallNode) { IRNode *Call = nullptr, *ReturnNode = nullptr; IRNode *TargetNode = CallTargetInfo->getCallTargetNode(); @@ -3815,7 +3841,7 @@ IRNode *GenIR::genCall(ReaderCallTargetData *CallTargetInfo, ABICallSignature ABICallSig(Signature, *this, *JitContext->TheABIInfo); Value *ResultNode = ABICallSig.emitCall( - *this, (Value *)TargetNode, Arguments, + *this, (Value *)TargetNode, MayThrow, Arguments, (Value *)CallTargetInfo->getIndirectionCellNode(), (Value **)&Call); // Add VarArgs cookie to outgoing param list @@ -3907,7 +3933,9 @@ Value *GenIR::genConvertOverflowCheck(Value *Source, IntegerType *TargetTy, } // Call the helper to convert to int. - Source = callHelperImpl(Helper, HelperResultTy, (IRNode *)Source); + const bool MayThrow = true; + Source = callHelperImpl(Helper, MayThrow, HelperResultTy, (IRNode *)Source) + .getInstruction(); SourceTy = HelperResultTy; // The result of the helper call already has the requested signedness. @@ -4372,7 +4400,10 @@ IRNode *GenIR::unbox(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Object, // Call helper to do the type check and get the address of the unbox payload. Type *PtrTy = getType(CorInfoType::CORINFO_TYPE_BYREF, ClassHandle); - IRNode *Result = callHelperImpl(HelperId, PtrTy, ClassHandleArgument, Object); + const bool MayThrow = true; + IRNode *Result = + (IRNode *)callHelperImpl(HelperId, MayThrow, PtrTy, ClassHandleArgument, + Object).getInstruction(); // If requested, load the object onto the evaluation stack. if (AndLoad) { @@ -4417,26 +4448,26 @@ void GenIR::switchOpcode(IRNode *Opr) { void GenIR::throwOpcode(IRNode *Arg1) { // Using a call for now; this will need to be invoke // when we get EH flow properly modeled. - CallInst *ThrowCall = - (CallInst *)callHelper(CORINFO_HELP_THROW, nullptr, Arg1); + Type *Void = Type::getVoidTy(*JitContext->LLVMContext); + const bool MayThrow = true; + CallSite ThrowCall = callHelperImpl(CORINFO_HELP_THROW, MayThrow, Void, Arg1); // Annotate the helper - ThrowCall->setDoesNotReturn(); + ThrowCall.setDoesNotReturn(); } -CallInst *GenIR::genConditionalHelperCall(Value *Condition, - CorInfoHelpFunc HelperId, - Type *ReturnType, IRNode *Arg1, - IRNode *Arg2, bool CallReturns, - const Twine &CallBlockName) { +CallSite GenIR::genConditionalHelperCall( + Value *Condition, CorInfoHelpFunc HelperId, bool MayThrow, Type *ReturnType, + IRNode *Arg1, IRNode *Arg2, bool CallReturns, const Twine &CallBlockName) { // Create the call block and fill it in. BasicBlock *CallBlock = createPointBlock(CallBlockName); IRBuilder<>::InsertPoint SavedInsertPoint = LLVMBuilder->saveIP(); LLVMBuilder->SetInsertPoint(CallBlock); - CallInst *HelperCall = - (CallInst *)callHelperImpl(HelperId, ReturnType, Arg1, Arg2); + CallSite HelperCall = + callHelperImpl(HelperId, MayThrow, ReturnType, Arg1, Arg2); + if (!CallReturns) { - HelperCall->setDoesNotReturn(); + HelperCall.setDoesNotReturn(); LLVMBuilder->CreateUnreachable(); } LLVMBuilder->restoreIP(SavedInsertPoint); @@ -4453,9 +4484,10 @@ void GenIR::genConditionalThrow(Value *Condition, CorInfoHelpFunc HelperId, const Twine &ThrowBlockName) { IRNode *Arg1 = nullptr, *Arg2 = nullptr; Type *ReturnType = Type::getVoidTy(*JitContext->LLVMContext); - bool CallReturns = false; - genConditionalHelperCall(Condition, HelperId, ReturnType, Arg1, Arg2, - CallReturns, ThrowBlockName); + const bool MayThrow = true; + const bool CallReturns = false; + genConditionalHelperCall(Condition, HelperId, MayThrow, ReturnType, Arg1, + Arg2, CallReturns, ThrowBlockName); } IRNode *GenIR::genNullCheck(IRNode *Node) { @@ -4943,8 +4975,10 @@ IRNode *GenIR::loadVirtFunc(IRNode *Arg1, CORINFO_RESOLVED_TOKEN *ResolvedToken, Type *Ty = Type::getIntNTy(*this->JitContext->LLVMContext, TargetPointerSizeInBits); - IRNode *CodeAddress = callHelperImpl(CORINFO_HELP_VIRTUAL_FUNC_PTR, Ty, Arg1, - TypeToken, MethodToken); + const bool MayThrow = true; + IRNode *CodeAddress = + (IRNode *)callHelperImpl(CORINFO_HELP_VIRTUAL_FUNC_PTR, MayThrow, Ty, + Arg1, TypeToken, MethodToken).getInstruction(); return CodeAddress; } @@ -5335,8 +5369,9 @@ IRNode *GenIR::newArr(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *Arg1) { getType(CorInfoType::CORINFO_TYPE_CLASS, ResolvedToken->hClass); Value *Destination = Constant::getNullValue(ArrayType); - return callHelper(getNewArrHelper(ElementType), (IRNode *)Destination, Token, - NumOfElements); + const bool MayThrow = true; + return callHelper(getNewArrHelper(ElementType), MayThrow, + (IRNode *)Destination, Token, NumOfElements); } // CastOp - Generates code for castclass or isinst. @@ -5388,9 +5423,11 @@ IRNode *GenIR::castOp(CORINFO_RESOLVED_TOKEN *ResolvedToken, IRNode *ObjRefNode, // Generate the helper call or intrinsic const bool IsVolatile = false; const bool DoesNotInvokeStaticCtor = Optimize; - return callHelperImpl(HelperId, ResultType, ClassHandleNode, ObjRefNode, - nullptr, nullptr, Reader_AlignUnknown, IsVolatile, - DoesNotInvokeStaticCtor); + const bool MayThrow = true; + return (IRNode *)callHelperImpl(HelperId, MayThrow, ResultType, + ClassHandleNode, ObjRefNode, nullptr, nullptr, + Reader_AlignUnknown, IsVolatile, + DoesNotInvokeStaticCtor).getInstruction(); } // Override the cast class optimization @@ -5416,7 +5453,8 @@ bool GenIR::abs(IRNode *Argument, IRNode **Result) { Type *Types[] = {Ty}; Value *FAbs = Intrinsic::getDeclaration(JitContext->CurrentModule, Intrinsic::fabs, Types); - Value *Abs = LLVMBuilder->CreateCall(FAbs, Argument); + bool MayThrow = false; + Value *Abs = makeCall(FAbs, MayThrow, Argument).getInstruction(); *Result = (IRNode *)Abs; return true; } @@ -5438,9 +5476,10 @@ IRNode *GenIR::localAlloc(IRNode *Arg, bool ZeroInit) { // Zero the allocated region if so requested. if (ZeroInit) { - Value *ZeroByte = ConstantInt::get(Context, APInt(8, 0, true)); + const bool MayThrow = false; Type *VoidTy = Type::getVoidTy(Context); - callHelperImpl(CORINFO_HELP_MEMSET, VoidTy, (IRNode *)LocAlloc, + Value *ZeroByte = ConstantInt::get(Context, APInt(8, 0, true)); + callHelperImpl(CORINFO_HELP_MEMSET, MayThrow, VoidTy, (IRNode *)LocAlloc, (IRNode *)ZeroByte, Arg); }