Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGCleanup.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ struct EHPersonality {
static const EHPersonality GNU_ObjC_SJLJ;
static const EHPersonality GNU_ObjC_SEH;
static const EHPersonality GNUstep_ObjC;
static const EHPersonality GNUstep_Wasm_ObjC;
static const EHPersonality GNU_ObjCXX;
static const EHPersonality NeXT_ObjC;
static const EHPersonality GNU_CPlusPlus;
Expand Down
10 changes: 8 additions & 2 deletions clang/lib/CodeGen/CGException.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,11 @@ static const EHPersonality &getObjCPersonality(const TargetInfo &Target,
case ObjCRuntime::WatchOS:
return EHPersonality::NeXT_ObjC;
case ObjCRuntime::GNUstep:
if (CGOpts.hasWasmExceptions())
return EHPersonality::GNU_Wasm_CPlusPlus;
if (T.isOSCygMing())
return EHPersonality::GNU_CPlusPlus_SEH;
else if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
if (L.ObjCRuntime.getVersion() >= VersionTuple(1, 7))
return EHPersonality::GNUstep_ObjC;
[[fallthrough]];
case ObjCRuntime::GCC:
Expand Down Expand Up @@ -218,6 +220,8 @@ static const EHPersonality &getObjCXXPersonality(const TargetInfo &Target,
return getObjCPersonality(Target, CGOpts, L);

case ObjCRuntime::GNUstep:
if (CGOpts.hasWasmExceptions())
return EHPersonality::GNU_Wasm_CPlusPlus;
return Target.getTriple().isOSCygMing() ? EHPersonality::GNU_CPlusPlus_SEH
: EHPersonality::GNU_ObjCXX;

Expand Down Expand Up @@ -1203,11 +1207,13 @@ static void emitCatchDispatchBlock(CodeGenFunction &CGF,
}
}

void CodeGenFunction::popCatchScope() {
llvm::BasicBlock *CodeGenFunction::popCatchScope() {
EHCatchScope &catchScope = cast<EHCatchScope>(*EHStack.begin());
llvm::BasicBlock *dispatchBlock = catchScope.getCachedEHDispatchBlock();
if (catchScope.hasEHBranches())
emitCatchDispatchBlock(*this, catchScope);
EHStack.popCatch();
return dispatchBlock;
}

void CodeGenFunction::ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock) {
Expand Down
66 changes: 58 additions & 8 deletions clang/lib/CodeGen/CGObjCRuntime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/CodeGen/CodeGenABITypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/Support/SaveAndRestore.h"

using namespace clang;
Expand Down Expand Up @@ -120,6 +122,8 @@ namespace {
llvm::Constant *TypeInfo;
/// Flags used to differentiate cleanups and catchalls in Windows SEH
unsigned Flags;

bool isCatchAll() const { return TypeInfo == nullptr; }
};

struct CallObjCEndCatch final : EHScopeStack::Cleanup {
Expand Down Expand Up @@ -148,13 +152,13 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
Cont = CGF.getJumpDestInCurrentScope("eh.cont");

bool useFunclets = EHPersonality::get(CGF).usesFuncletPads();
bool hasWasmExceptions = CGF.CGM.getCodeGenOpts().hasWasmExceptions();

CodeGenFunction::FinallyInfo FinallyInfo;
if (!useFunclets)
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt())
FinallyInfo.enter(CGF, Finally->getFinallyBody(),
beginCatchFn, endCatchFn, exceptionRethrowFn);

SmallVector<CatchHandler, 8> Handlers;


Expand Down Expand Up @@ -187,8 +191,12 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
Catch->setHandler(I, { Handlers[I].TypeInfo, Handlers[I].Flags }, Handlers[I].Block);
}

if (useFunclets)
if (useFunclets) {
if (const ObjCAtFinallyStmt *Finally = S.getFinallyStmt()) {
if (hasWasmExceptions) {
CGF.ErrorUnsupported(Finally, "@finally for WASM");
}

CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
if (!CGF.CurSEHParent)
CGF.CurSEHParent = cast<NamedDecl>(CGF.CurFuncDecl);
Expand All @@ -207,36 +215,59 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
// Push a cleanup for __finally blocks.
CGF.pushSEHCleanup(NormalAndEHCleanup, FinallyFunc);
}
}


// Emit the try body.
CGF.EmitStmt(S.getTryBody());

// Leave the try.
llvm::BasicBlock* dispatchBlock{};
if (S.getNumCatchStmts())
CGF.popCatchScope();
dispatchBlock = CGF.popCatchScope();

// Remember where we were.
CGBuilderTy::InsertPoint SavedIP = CGF.Builder.saveAndClearIP();

// Wasm uses Windows-style EH instructions, but merges all catch clauses into
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: This is taken from CGException.cpp, we may want to refactor it into a shared helper.

// one big catchpad. So we save the old funclet pad here before we traverse
// each catch handler.
SaveAndRestore RestoreCurrentFuncletPad(CGF.CurrentFuncletPad);
llvm::BasicBlock *WasmCatchStartBlock = nullptr;
llvm::CatchPadInst* CatchPadInst{};
if (!!dispatchBlock && hasWasmExceptions) {
auto *CatchSwitch =
cast<llvm::CatchSwitchInst>(dispatchBlock->getFirstNonPHIIt());
WasmCatchStartBlock = CatchSwitch->hasUnwindDest()
? CatchSwitch->getSuccessor(1)
: CatchSwitch->getSuccessor(0);
CatchPadInst = cast<llvm::CatchPadInst>(WasmCatchStartBlock->getFirstNonPHIIt());
CGF.CurrentFuncletPad = CatchPadInst;
}

// Emit the handlers.
bool HasCatchAll = false;
for (CatchHandler &Handler : Handlers) {
HasCatchAll |= Handler.isCatchAll();
CGF.EmitBlock(Handler.Block);

CodeGenFunction::LexicalScope Cleanups(CGF, Handler.Body->getSourceRange());
SaveAndRestore RevertAfterScope(CGF.CurrentFuncletPad);
if (useFunclets) {

if (useFunclets && !hasWasmExceptions) {
llvm::BasicBlock::iterator CPICandidate =
Handler.Block->getFirstNonPHIIt();
if (CPICandidate != Handler.Block->end()) {
if (auto *CPI = dyn_cast_or_null<llvm::CatchPadInst>(CPICandidate)) {
CGF.CurrentFuncletPad = CPI;
CPI->setOperand(2, CGF.getExceptionSlot().emitRawPointer(CGF));
CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CPI);
if ((CatchPadInst = dyn_cast_or_null<llvm::CatchPadInst>(CPICandidate))) {
CGF.CurrentFuncletPad = CatchPadInst;
CatchPadInst->setOperand(2, CGF.getExceptionSlot().emitRawPointer(CGF));
}
}
}

if (CatchPadInst)
CGF.EHStack.pushCleanup<CatchRetScope>(NormalCleanup, CatchPadInst);

llvm::Value *RawExn = CGF.getExceptionFromSlot();

// Enter the catch.
Expand Down Expand Up @@ -272,6 +303,25 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF,
CGF.EmitBranchThroughCleanup(Cont);
}

if (!!dispatchBlock && hasWasmExceptions && !HasCatchAll) {
assert(WasmCatchStartBlock);
// Navigate for the "rethrow" block we created in emitWasmCatchPadBlock().
// Wasm uses landingpad-style conditional branches to compare selectors, so
// we follow the false destination for each of the cond branches to reach
// the rethrow block.
llvm::BasicBlock *RethrowBlock = WasmCatchStartBlock;
while (llvm::Instruction *TI = RethrowBlock->getTerminator()) {
auto *BI = cast<llvm::BranchInst>(TI);
assert(BI->isConditional());
RethrowBlock = BI->getSuccessor(1);
}
assert(RethrowBlock != WasmCatchStartBlock && RethrowBlock->empty());
CGF.Builder.SetInsertPoint(RethrowBlock);
llvm::Function *RethrowInCatchFn =
CGM.getIntrinsic(llvm::Intrinsic::wasm_rethrow);
CGF.EmitNoreturnRuntimeCallOrInvoke(RethrowInCatchFn, {});
}

// Go back to the try-statement fallthrough.
CGF.Builder.restoreIP(SavedIP);

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1307,7 +1307,7 @@ class CodeGenFunction : public CodeGenTypeCache {
/// popCatchScope - Pops the catch scope at the top of the EHScope
/// stack, emitting any required code (other than the catch handlers
/// themselves).
void popCatchScope();
llvm::BasicBlock* popCatchScope();

llvm::BasicBlock *getEHResumeBlock(bool isCleanup);
llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope);
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8004,7 +8004,8 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args,
if ((runtime.getKind() == ObjCRuntime::GNUstep) &&
(runtime.getVersion() >= VersionTuple(2, 0)))
if (!getToolChain().getTriple().isOSBinFormatELF() &&
!getToolChain().getTriple().isOSBinFormatCOFF()) {
!getToolChain().getTriple().isOSBinFormatCOFF() &&
!getToolChain().getTriple().isOSBinFormatWasm()) {
getToolChain().getDriver().Diag(
diag::err_drv_gnustep_objc_runtime_incompatible_binary)
<< runtime.getVersion().getMajor();
Expand Down
Loading