Skip to content

Commit 6a6e06f

Browse files
committed
Merge remote-tracking branch 'origin/main' into rebranch
2 parents caa196d + fedf86f commit 6a6e06f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1005
-45
lines changed

lib/IRGen/CallEmission.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,25 @@ class CallEmission {
6363
/// RemainingArgsForCallee, at least between calls.
6464
bool EmittedCall;
6565

66+
/// The basic block to which the call to a potentially throwing foreign
67+
/// function should jump to continue normal execution of the program.
68+
llvm::BasicBlock *invokeNormalDest = nullptr;
69+
70+
/// The basic block to which the call to a potentially throwing foreign
71+
/// function should jump to in case an exception has been thrown during the
72+
/// invocation of the call.
73+
llvm::BasicBlock *invokeUnwindDest = nullptr;
74+
6675
virtual void setFromCallee();
6776
void emitToUnmappedMemory(Address addr);
6877
void emitToUnmappedExplosion(Explosion &out);
69-
virtual void emitCallToUnmappedExplosion(llvm::CallInst *call, Explosion &out) = 0;
78+
virtual void emitCallToUnmappedExplosion(llvm::CallBase *call,
79+
Explosion &out) = 0;
7080
void emitYieldsToExplosion(Explosion &out);
7181
virtual FunctionPointer getCalleeFunctionPointer() = 0;
72-
llvm::CallInst *emitCallSite();
82+
llvm::CallBase *emitCallSite();
7383

74-
virtual llvm::CallInst *createCall(const FunctionPointer &fn,
84+
virtual llvm::CallBase *createCall(const FunctionPointer &fn,
7585
ArrayRef<llvm::Value *> args) = 0;
7686

7787
CallEmission(IRGenFunction &IGF, llvm::Value *selfValue, Callee &&callee)
@@ -105,7 +115,7 @@ class CallEmission {
105115
bool isOutlined);
106116
void emitToExplosion(Explosion &out, bool isOutlined);
107117

108-
llvm::CallInst *emitCoroutineAsOrdinaryFunction() {
118+
llvm::CallBase *emitCoroutineAsOrdinaryFunction() {
109119
assert(IsCoroutine);
110120
IsCoroutine = false;
111121

lib/IRGen/Callee.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@ namespace irgen {
331331
llvm::Type *awaitSignature = nullptr;
332332
bool useSignature = false;
333333

334+
// True when this function pointer points to a non-throwing foreign
335+
// function.
336+
bool isForeignNoThrow = false;
337+
338+
// True when this function pointer points to a foreign function that traps
339+
// on exception in the always_inline thunk.
340+
bool foreignCallCatchesExceptionInThunk = false;
341+
334342
explicit FunctionPointer(Kind kind, llvm::Value *value,
335343
const Signature &signature)
336344
: FunctionPointer(kind, value, PointerAuthInfo(), signature) {}
@@ -491,6 +499,24 @@ namespace irgen {
491499
bool shouldSuppressPolymorphicArguments() const {
492500
return kind.shouldSuppressPolymorphicArguments();
493501
}
502+
503+
void setForeignNoThrow() { isForeignNoThrow = true; }
504+
505+
bool canThrowForeignException() const {
506+
return getForeignInfo().canThrow && !isForeignNoThrow;
507+
}
508+
509+
void setForeignCallCatchesExceptionInThunk() {
510+
foreignCallCatchesExceptionInThunk = true;
511+
}
512+
513+
bool doesForeignCallCatchExceptionInThunk() {
514+
return foreignCallCatchesExceptionInThunk;
515+
}
516+
517+
bool shouldUseInvoke() const {
518+
return canThrowForeignException() && !foreignCallCatchesExceptionInThunk;
519+
}
494520
};
495521

496522
class Callee {

lib/IRGen/GenCall.cpp

Lines changed: 102 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,9 @@ Signature SignatureExpansion::getSignature() {
19841984
result.Attributes = Attrs;
19851985
using ExtraData = Signature::ExtraData;
19861986
if (FnType->getLanguage() == SILFunctionLanguage::C) {
1987+
// This is a potentially throwing function. The use of 'noexcept' /
1988+
// 'nothrow' is applied at the call site in the \c FunctionPointer class.
1989+
ForeignInfo.canThrow = IGM.isForeignExceptionHandlingEnabled();
19871990
result.ExtraDataKind = ExtraData::kindForMember<ForeignFunctionInfo>();
19881991
result.ExtraDataStorage.emplace<ForeignFunctionInfo>(result.ExtraDataKind,
19891992
ForeignInfo);
@@ -2230,9 +2233,10 @@ class SyncCallEmission final : public CallEmission {
22302233
index, IGF.IGM.getMaximalTypeExpansionContext());
22312234
}
22322235

2233-
llvm::CallInst *createCall(const FunctionPointer &fn,
2236+
llvm::CallBase *createCall(const FunctionPointer &fn,
22342237
ArrayRef<llvm::Value *> args) override {
2235-
return IGF.Builder.CreateCall(fn, Args);
2238+
return IGF.Builder.CreateCallOrInvoke(fn, Args, invokeNormalDest,
2239+
invokeUnwindDest);
22362240
}
22372241

22382242
void begin() override { super::begin(); }
@@ -2379,7 +2383,8 @@ class SyncCallEmission final : public CallEmission {
23792383
}
23802384
super::setArgs(adjusted, isOutlined, witnessMetadata);
23812385
}
2382-
void emitCallToUnmappedExplosion(llvm::CallInst *call, Explosion &out) override {
2386+
void emitCallToUnmappedExplosion(llvm::CallBase *call,
2387+
Explosion &out) override {
23832388
// Bail out immediately on a void result.
23842389
llvm::Value *result = call;
23852390
if (result->getType()->isVoidTy())
@@ -2682,7 +2687,8 @@ class AsyncCallEmission final : public CallEmission {
26822687
saveValue(resumeParentField, fnVal, isOutlined);
26832688
}
26842689
}
2685-
void emitCallToUnmappedExplosion(llvm::CallInst *call, Explosion &out) override {
2690+
void emitCallToUnmappedExplosion(llvm::CallBase *call,
2691+
Explosion &out) override {
26862692
// Bail out on a void result type.
26872693
auto &IGM = IGF.IGM;
26882694
llvm::Value *result = call;
@@ -2774,7 +2780,7 @@ class AsyncCallEmission final : public CallEmission {
27742780
return IGF.getCalleeErrorResultSlot(errorType);
27752781
}
27762782

2777-
llvm::CallInst *createCall(const FunctionPointer &fn,
2783+
llvm::CallBase *createCall(const FunctionPointer &fn,
27782784
ArrayRef<llvm::Value *> args) override {
27792785
auto &IGM = IGF.IGM;
27802786
auto &Builder = IGF.Builder;
@@ -2904,7 +2910,7 @@ void CallEmission::emitToUnmappedMemory(Address result) {
29042910
}
29052911

29062912
/// The private routine to ultimately emit a call or invoke instruction.
2907-
llvm::CallInst *CallEmission::emitCallSite() {
2913+
llvm::CallBase *CallEmission::emitCallSite() {
29082914
assert(state == State::Emitting);
29092915
assert(LastArgWritten == 0);
29102916
assert(!EmittedCall);
@@ -2925,8 +2931,16 @@ llvm::CallInst *CallEmission::emitCallSite() {
29252931
Args[i] = IGF.coerceValue(Args[i], paramTy, IGF.IGM.DataLayout);
29262932
}
29272933

2928-
// TODO: exceptions!
2934+
if (fn.canThrowForeignException()) {
2935+
if (!fn.doesForeignCallCatchExceptionInThunk()) {
2936+
invokeNormalDest = IGF.createBasicBlock("invoke.cont");
2937+
invokeUnwindDest = IGF.createExceptionUnwindBlock();
2938+
} else
2939+
IGF.setCallsThunksWithForeignExceptionTraps();
2940+
}
29292941
auto call = createCall(fn, Args);
2942+
if (invokeNormalDest)
2943+
IGF.Builder.emitBlock(invokeNormalDest);
29302944

29312945
// Make coroutines calls opaque to LLVM analysis.
29322946
if (IsCoroutine) {
@@ -2988,8 +3002,9 @@ assertTypesInByValAndStructRetAttributes(llvm::FunctionType *fnType,
29883002
return attrList;
29893003
}
29903004

2991-
llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
2992-
ArrayRef<llvm::Value*> args) {
3005+
llvm::CallBase *IRBuilder::CreateCallOrInvoke(
3006+
const FunctionPointer &fn, ArrayRef<llvm::Value *> args,
3007+
llvm::BasicBlock *invokeNormalDest, llvm::BasicBlock *invokeUnwindDest) {
29933008
assert(fn.getKind() == FunctionPointer::Kind::Function);
29943009
SmallVector<llvm::OperandBundleDef, 1> bundles;
29953010

@@ -3003,8 +3018,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
30033018

30043019
assert(!isTrapIntrinsic(fn.getRawPointer()) && "Use CreateNonMergeableTrap");
30053020
auto fnTy = cast<llvm::FunctionType>(fn.getFunctionType());
3006-
llvm::CallInst *call =
3007-
IRBuilderBase::CreateCall(fnTy, fn.getRawPointer(), args, bundles);
3021+
llvm::CallBase *call;
3022+
if (!fn.shouldUseInvoke())
3023+
call = IRBuilderBase::CreateCall(fnTy, fn.getRawPointer(), args, bundles);
3024+
else
3025+
call =
3026+
IRBuilderBase::CreateInvoke(fnTy, fn.getRawPointer(), invokeNormalDest,
3027+
invokeUnwindDest, args, bundles);
30083028

30093029
llvm::AttributeList attrs = fn.getAttributes();
30103030
// If a parameter of a function is SRet, the corresponding argument should be
@@ -3028,6 +3048,13 @@ llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
30283048
return call;
30293049
}
30303050

3051+
llvm::CallInst *IRBuilder::CreateCall(const FunctionPointer &fn,
3052+
ArrayRef<llvm::Value *> args) {
3053+
assert(!fn.shouldUseInvoke());
3054+
return cast<llvm::CallInst>(CreateCallOrInvoke(
3055+
fn, args, /*invokeNormalDest=*/nullptr, /*invokeUnwindDest=*/nullptr));
3056+
}
3057+
30313058
/// Emit the result of this call to memory.
30323059
void CallEmission::emitToMemory(Address addr,
30333060
const LoadableTypeInfo &indirectedResultTI,
@@ -4425,6 +4452,40 @@ void IRGenFunction::emitBBForReturn() {
44254452
CurFn->getBasicBlockList().push_back(ReturnBB);
44264453
}
44274454

4455+
llvm::BasicBlock *IRGenFunction::createExceptionUnwindBlock() {
4456+
auto *result = createBasicBlock("exception.unwind");
4457+
IRBuilder::SavedInsertionPointRAII insertRAII(Builder, result);
4458+
4459+
// Create a catch-all landing pad.
4460+
// FIXME: Refactor Clang/lib/CodeGen to call into Clang here.
4461+
// FIXME: MSVC support.
4462+
llvm::LandingPadInst *lpad = Builder.CreateLandingPad(
4463+
llvm::StructType::get(IGM.Int8PtrTy, IGM.Int32Ty), 0);
4464+
lpad->addClause(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
4465+
4466+
// The trap with a message informs the user that the exception hasn't
4467+
// been caught. The trap creates a new debug inline frame for the message,
4468+
// so ensure that the current debug location is preserved.
4469+
auto oldDebugLoc = Builder.getCurrentDebugLocation();
4470+
emitTrap(IGM.Context.LangOpts.EnableObjCInterop
4471+
? "unhandled C++ / Objective-C exception"
4472+
: "unhandled C++ exception",
4473+
/*Unreachable=*/true);
4474+
Builder.SetCurrentDebugLocation(oldDebugLoc);
4475+
4476+
ExceptionUnwindBlocks.push_back(result);
4477+
return result;
4478+
}
4479+
4480+
void IRGenFunction::createExceptionTrapScope(
4481+
llvm::function_ref<void(llvm::BasicBlock *, llvm::BasicBlock *)>
4482+
invokeEmitter) {
4483+
auto *invokeNormalDest = createBasicBlock("invoke.cont");
4484+
auto *invokeUnwindDest = createExceptionUnwindBlock();
4485+
invokeEmitter(invokeNormalDest, invokeUnwindDest);
4486+
Builder.emitBlock(invokeNormalDest);
4487+
}
4488+
44284489
/// Emit the prologue for the function.
44294490
void IRGenFunction::emitPrologue() {
44304491
// Set up the IRBuilder.
@@ -4475,12 +4536,42 @@ bool IRGenFunction::emitBranchToReturnBB() {
44754536
return true;
44764537
}
44774538

4539+
llvm::Function *IRGenModule::getForeignExceptionHandlingPersonalityFunc() {
4540+
if (foreignExceptionHandlingPersonalityFunc)
4541+
return foreignExceptionHandlingPersonalityFunc;
4542+
foreignExceptionHandlingPersonalityFunc = llvm::Function::Create(
4543+
llvm::FunctionType::get(Int32Ty, true), llvm::Function::ExternalLinkage,
4544+
"__gxx_personality_v0", getModule());
4545+
return foreignExceptionHandlingPersonalityFunc;
4546+
}
4547+
4548+
bool IRGenModule::isForeignExceptionHandlingEnabled() const {
4549+
// FIXME: Support exceptions on windows MSVC.
4550+
if (Triple.isWindowsMSVCEnvironment())
4551+
return false;
4552+
const auto &clangLangOpts =
4553+
Context.getClangModuleLoader()->getClangASTContext().getLangOpts();
4554+
return Context.LangOpts.EnableCXXInterop && clangLangOpts.Exceptions &&
4555+
!clangLangOpts.IgnoreExceptions;
4556+
}
4557+
44784558
/// Emit the epilogue for the function.
44794559
void IRGenFunction::emitEpilogue() {
44804560
if (EarliestIP != AllocaIP)
44814561
EarliestIP->eraseFromParent();
44824562
// Destroy the alloca insertion point.
44834563
AllocaIP->eraseFromParent();
4564+
// Add exception unwind blocks and additional exception handling info
4565+
// if needed.
4566+
if (!ExceptionUnwindBlocks.empty() ||
4567+
callsAnyAlwaysInlineThunksWithForeignExceptionTraps) {
4568+
// The function should have an unwind table when catching exceptions.
4569+
CurFn->addFnAttr(llvm::Attribute::getWithUWTableKind(
4570+
*IGM.LLVMContext, llvm::UWTableKind::Default));
4571+
CurFn->setPersonalityFn(IGM.getForeignExceptionHandlingPersonalityFunc());
4572+
}
4573+
for (auto *bb : ExceptionUnwindBlocks)
4574+
CurFn->getBasicBlockList().push_back(bb);
44844575
}
44854576

44864577
std::pair<Address, Size>

lib/IRGen/GenDecl.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3236,12 +3236,35 @@ llvm::Constant *swift::irgen::emitCXXConstructorThunkIfNeeded(
32363236
Args.push_back(arg);
32373237
}
32383238

3239-
subIGF.Builder.CreateCall(ctorFnType, ctorAddress, Args);
3239+
auto *call =
3240+
emitCXXConstructorCall(subIGF, ctor, ctorFnType, ctorAddress, Args);
3241+
if (isa<llvm::InvokeInst>(call))
3242+
IGM.emittedForeignFunctionThunksWithExceptionTraps.insert(thunk);
32403243
subIGF.Builder.CreateRetVoid();
32413244

32423245
return thunk;
32433246
}
32443247

3248+
llvm::CallBase *swift::irgen::emitCXXConstructorCall(
3249+
IRGenFunction &IGF, const clang::CXXConstructorDecl *ctor,
3250+
llvm::FunctionType *ctorFnType, llvm::Constant *ctorAddress,
3251+
llvm::ArrayRef<llvm::Value *> args) {
3252+
bool canThrow = IGF.IGM.isForeignExceptionHandlingEnabled();
3253+
if (auto *fpt = ctor->getType()->getAs<clang::FunctionProtoType>()) {
3254+
if (fpt->isNothrow())
3255+
canThrow = false;
3256+
}
3257+
if (!canThrow)
3258+
return IGF.Builder.CreateCall(ctorFnType, ctorAddress, args);
3259+
llvm::CallBase *result;
3260+
IGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest,
3261+
llvm::BasicBlock *invokeUnwindDest) {
3262+
result = IGF.Builder.createInvoke(ctorFnType, ctorAddress, args,
3263+
invokeNormalDest, invokeUnwindDest);
3264+
});
3265+
return result;
3266+
}
3267+
32453268
StackProtectorMode IRGenModule::shouldEmitStackProtector(SILFunction *f) {
32463269
const SILOptions &opts = IRGen.SIL.getOptions();
32473270
return (opts.EnableStackProtection && f->needsStackProtection()) ?

lib/IRGen/GenDecl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ namespace llvm {
2929
class AttributeList;
3030
class Function;
3131
class FunctionType;
32+
class CallBase;
3233
}
3334
namespace swift {
3435
namespace irgen {
@@ -69,6 +70,12 @@ namespace irgen {
6970
emitCXXConstructorThunkIfNeeded(IRGenModule &IGM, Signature signature,
7071
const clang::CXXConstructorDecl *ctor,
7172
StringRef name, llvm::Constant *ctorAddress);
73+
74+
llvm::CallBase *emitCXXConstructorCall(IRGenFunction &IGF,
75+
const clang::CXXConstructorDecl *ctor,
76+
llvm::FunctionType *ctorFnType,
77+
llvm::Constant *ctorAddress,
78+
llvm::ArrayRef<llvm::Value *> args);
7279
}
7380
}
7481

lib/IRGen/GenStruct.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ namespace {
579579
auto callee = cast<llvm::Function>(clangFnAddr->stripPointerCasts());
580580
Signature signature = IGF.IGM.getSignature(fnType);
581581
std::string name = "__swift_cxx_copy_ctor" + callee->getName().str();
582+
auto *origClangFnAddr = clangFnAddr;
582583
clangFnAddr = emitCXXConstructorThunkIfNeeded(
583584
IGF.IGM, signature, copyConstructor, name, clangFnAddr);
584585
callee = cast<llvm::Function>(clangFnAddr);
@@ -588,7 +589,19 @@ namespace {
588589
src = IGF.coerceValue(src, callee->getFunctionType()->getParamType(1),
589590
IGF.IGM.DataLayout);
590591
}
591-
IGF.Builder.CreateCall(callee->getFunctionType(), callee, {dest, src});
592+
llvm::Value *args[] = {dest, src};
593+
if (clangFnAddr == origClangFnAddr) {
594+
// Ensure we can use 'invoke' to trap on uncaught exceptions when
595+
// calling original copy constructor without going through the thunk.
596+
emitCXXConstructorCall(IGF, copyConstructor, callee->getFunctionType(),
597+
callee, args);
598+
return;
599+
}
600+
// Check if we're calling a thunk that traps on exception thrown from copy
601+
// constructor.
602+
if (IGF.IGM.emittedForeignFunctionThunksWithExceptionTraps.count(callee))
603+
IGF.setCallsThunksWithForeignExceptionTraps();
604+
IGF.Builder.CreateCall(callee->getFunctionType(), callee, args);
592605
}
593606

594607
public:
@@ -653,6 +666,23 @@ namespace {
653666
IGF.IGM.DataLayout);
654667
args.push_back(implicitParam);
655668
}
669+
bool canThrow = false;
670+
if (IGF.IGM.isForeignExceptionHandlingEnabled()) {
671+
if (auto *fpt =
672+
destructor->getType()->getAs<clang::FunctionProtoType>()) {
673+
if (!fpt->isNothrow())
674+
canThrow = true;
675+
}
676+
}
677+
if (canThrow) {
678+
IGF.createExceptionTrapScope([&](llvm::BasicBlock *invokeNormalDest,
679+
llvm::BasicBlock *invokeUnwindDest) {
680+
IGF.Builder.createInvoke(destructorFnAddr->getFunctionType(),
681+
destructorFnAddr, args, invokeNormalDest,
682+
invokeUnwindDest);
683+
});
684+
return;
685+
}
656686

657687
IGF.Builder.CreateCall(destructorFnAddr->getFunctionType(),
658688
destructorFnAddr, args);

0 commit comments

Comments
 (0)