50
50
// /
51
51
// / In detail, this pass does following things:
52
52
// /
53
- // / 1) Assumes the existence of global variables: __THREW__, __threwValue, and
54
- // / __tempRet0.
55
- // / __tempRet0 will be set within __cxa_find_matching_catch() function in
56
- // / JS library, and __THREW__ and __threwValue will be set in invoke wrappers
53
+ // / 1) Assumes the existence of global variables: __THREW__, __threwValue
54
+ // / __THREW__ and __threwValue will be set in invoke wrappers
57
55
// / in JS glue code. For what invoke wrappers are, refer to 3). These
58
56
// / variables are used for both exceptions and setjmp/longjmps.
59
57
// / __THREW__ indicates whether an exception or a longjmp occurred or not. 0
60
58
// / means nothing occurred, 1 means an exception occurred, and other numbers
61
59
// / mean a longjmp occurred. In the case of longjmp, __threwValue variable
62
60
// / indicates the corresponding setjmp buffer the longjmp corresponds to.
63
- // / In exception handling, __tempRet0 indicates the type of an exception
64
- // / caught, and in setjmp/longjmp, it means the second argument to longjmp
65
- // / function.
66
61
// /
67
62
// / * Exception handling
68
63
// /
69
- // / 2) We assume the existence of setThrew and setTempRet0 functions at link
70
- // / time.
64
+ // / 2) We assume the existence of setThrew and setTempRet0/getTempRet0 functions
65
+ // / at link time.
71
66
// / The global variables in 1) will exist in wasm address space,
72
67
// / but their values should be set in JS code, so these functions
73
68
// / as interfaces to JS glue code. These functions are equivalent to the
80
75
// / __threwValue = value;
81
76
// / }
82
77
// / }
78
+ //
79
+ // / setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
83
80
// /
84
- // / function setTempRet0(value) {
85
- // / __tempRet0 = value;
86
- // / }
81
+ // / In exception handling, getTempRet0 indicates the type of an exception
82
+ // / caught, and in setjmp/longjmp, it means the second argument to longjmp
83
+ // / function.
87
84
// /
88
85
// / 3) Lower
89
86
// / invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad
120
117
// / ... use %val ...
121
118
// / into
122
119
// / %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
123
- // / %val = {%fmc, __tempRet0 }
120
+ // / %val = {%fmc, getTempRet0() }
124
121
// / ... use %val ...
125
122
// / Here N is a number calculated based on the number of clauses.
126
- // / Global variable __tempRet0 is set within __cxa_find_matching_catch() in
127
- // / JS glue code.
123
+ // / setTempRet0 is called from __cxa_find_matching_catch() in JS glue code.
128
124
// /
129
125
// / 5) Lower
130
126
// / resume {%a, %b}
162
158
// / setjmp(buf)
163
159
// / into
164
160
// / setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
165
- // / setjmpTableSize = __tempRet0 ;
161
+ // / setjmpTableSize = getTempRet0() ;
166
162
// / For each dynamic setjmp call, setjmpTable stores its ID (a number which
167
163
// / is incrementally assigned from 0) and its label (a unique number that
168
164
// / represents each callsite of setjmp). When we need more entries in
169
165
// / setjmpTable, it is reallocated in saveSetjmp() in JS code and it will
170
166
// / return the new table address, and assign the new table size in
171
- // / __tempRet0 . saveSetjmp also stores the setjmp's ID into the buffer buf.
172
- // / A BB with setjmp is split into two after setjmp call in order to make the
173
- // / post-setjmp BB the possible destination of longjmp BB.
167
+ // / setTempRet0() . saveSetjmp also stores the setjmp's ID into the buffer
168
+ // / buf. A BB with setjmp is split into two after setjmp call in order to
169
+ // / make the post-setjmp BB the possible destination of longjmp BB.
174
170
// /
175
171
// /
176
172
// / 4) Lower every call that might longjmp into
183
179
// / setjmpTableSize);
184
180
// / if (%label == 0)
185
181
// / emscripten_longjmp(%__THREW__.val, __threwValue);
186
- // / __tempRet0 = __threwValue;
182
+ // / setTempRet0( __threwValue) ;
187
183
// / } else {
188
184
// / %label = -1;
189
185
// / }
190
- // / longjmp_result = __tempRet0 ;
186
+ // / longjmp_result = getTempRet0() ;
191
187
// / switch label {
192
188
// / label 1: goto post-setjmp BB 1
193
189
// / label 2: goto post-setjmp BB 2
@@ -246,7 +242,8 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
246
242
247
243
GlobalVariable *ThrewGV;
248
244
GlobalVariable *ThrewValueGV;
249
- GlobalVariable *TempRet0GV;
245
+ Function *GetTempRet0Func;
246
+ Function *SetTempRet0Func;
250
247
Function *ResumeF;
251
248
Function *EHTypeIDF;
252
249
Function *EmLongjmpF;
@@ -286,9 +283,10 @@ class WebAssemblyLowerEmscriptenEHSjLj final : public ModulePass {
286
283
287
284
WebAssemblyLowerEmscriptenEHSjLj (bool EnableEH = true , bool EnableSjLj = true )
288
285
: ModulePass(ID), EnableEH(EnableEH), EnableSjLj(EnableSjLj),
289
- ThrewGV (nullptr ), ThrewValueGV(nullptr ), TempRet0GV(nullptr ),
290
- ResumeF(nullptr ), EHTypeIDF(nullptr ), EmLongjmpF(nullptr ),
291
- EmLongjmpJmpbufF(nullptr ), SaveSetjmpF(nullptr ), TestSetjmpF(nullptr ) {
286
+ ThrewGV (nullptr ), ThrewValueGV(nullptr ), GetTempRet0Func(nullptr ),
287
+ SetTempRet0Func(nullptr ), ResumeF(nullptr ), EHTypeIDF(nullptr ),
288
+ EmLongjmpF(nullptr ), EmLongjmpJmpbufF(nullptr ), SaveSetjmpF(nullptr ),
289
+ TestSetjmpF(nullptr ) {
292
290
EHWhitelistSet.insert (EHWhitelist.begin (), EHWhitelist.end ());
293
291
}
294
292
bool runOnModule (Module &M) override ;
@@ -514,7 +512,8 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
514
512
Function *ThrowF = M.getFunction (" __cxa_throw" );
515
513
Function *TerminateF = M.getFunction (" __clang_call_terminate" );
516
514
if (Callee == BeginCatchF || Callee == EndCatchF ||
517
- Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF)
515
+ Callee == AllocExceptionF || Callee == ThrowF || Callee == TerminateF ||
516
+ Callee == GetTempRet0Func || Callee == SetTempRet0Func)
518
517
return false ;
519
518
520
519
// Otherwise we don't know
@@ -527,11 +526,11 @@ bool WebAssemblyLowerEmscriptenEHSjLj::canLongjmp(Module &M,
527
526
// %label = _testSetjmp(mem[%__THREW__.val], setjmpTable, setjmpTableSize);
528
527
// if (%label == 0)
529
528
// emscripten_longjmp(%__THREW__.val, threwValue);
530
- // __tempRet0 = threwValue;
529
+ // setTempRet0( threwValue) ;
531
530
// } else {
532
531
// %label = -1;
533
532
// }
534
- // %longjmp_result = __tempRet0 ;
533
+ // %longjmp_result = getTempRet0() ;
535
534
//
536
535
// As output parameters. returns %label, %longjmp_result, and the BB the last
537
536
// instruction (%longjmp_result = ...) is in.
@@ -575,15 +574,15 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
575
574
IRB.CreateCall (EmLongjmpF, {Threw, ThrewValue});
576
575
IRB.CreateUnreachable ();
577
576
578
- // __tempRet0 = threwValue;
577
+ // setTempRet0( threwValue) ;
579
578
IRB.SetInsertPoint (EndBB2);
580
- IRB.CreateStore (ThrewValue, TempRet0GV );
579
+ IRB.CreateCall (SetTempRet0Func, ThrewValue );
581
580
IRB.CreateBr (EndBB1);
582
581
583
582
IRB.SetInsertPoint (ElseBB1);
584
583
IRB.CreateBr (EndBB1);
585
584
586
- // longjmp_result = __tempRet0 ;
585
+ // longjmp_result = getTempRet0() ;
587
586
IRB.SetInsertPoint (EndBB1);
588
587
PHINode *LabelPHI = IRB.CreatePHI (IRB.getInt32Ty (), 2 , " label" );
589
588
LabelPHI->addIncoming (ThenLabel, EndBB2);
@@ -593,7 +592,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::wrapTestSetjmp(
593
592
// Output parameter assignment
594
593
Label = LabelPHI;
595
594
EndBB = EndBB1;
596
- LongjmpResult = IRB.CreateLoad (TempRet0GV , " longjmp_result" );
595
+ LongjmpResult = IRB.CreateCall (GetTempRet0Func, None , " longjmp_result" );
597
596
}
598
597
599
598
void WebAssemblyLowerEmscriptenEHSjLj::rebuildSSA (Function &F) {
@@ -633,12 +632,19 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runOnModule(Module &M) {
633
632
bool LongjmpUsed = LongjmpF && !LongjmpF->use_empty ();
634
633
bool DoSjLj = EnableSjLj && (SetjmpUsed || LongjmpUsed);
635
634
636
- // Declare (or get) global variables __THREW__, __threwValue, and __tempRet0,
637
- // which are used in common for both exception handling and setjmp/longjmp
638
- // handling
635
+ // Declare (or get) global variables __THREW__, __threwValue, and
636
+ // getTempRet0/setTempRet0 function which are used in common for both
637
+ // exception handling and setjmp/longjmp handling
639
638
ThrewGV = getGlobalVariableI32 (M, IRB, " __THREW__" );
640
639
ThrewValueGV = getGlobalVariableI32 (M, IRB, " __threwValue" );
641
- TempRet0GV = getGlobalVariableI32 (M, IRB, " __tempRet0" );
640
+ GetTempRet0Func =
641
+ Function::Create (FunctionType::get (IRB.getInt32Ty (), false ),
642
+ GlobalValue::ExternalLinkage, " getTempRet0" , &M);
643
+ SetTempRet0Func = Function::Create (
644
+ FunctionType::get (IRB.getVoidTy (), IRB.getInt32Ty (), false ),
645
+ GlobalValue::ExternalLinkage, " setTempRet0" , &M);
646
+ GetTempRet0Func->setDoesNotThrow ();
647
+ SetTempRet0Func->setDoesNotThrow ();
642
648
643
649
bool Changed = false ;
644
650
@@ -848,8 +854,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) {
848
854
CallInst *FMCI = IRB.CreateCall (FMCF, FMCArgs, " fmc" );
849
855
Value *Undef = UndefValue::get (LPI->getType ());
850
856
Value *Pair0 = IRB.CreateInsertValue (Undef, FMCI, 0 , " pair0" );
851
- Value *TempRet0 =
852
- IRB.CreateLoad (TempRet0GV, TempRet0GV->getName () + " .val" );
857
+ Value *TempRet0 = IRB.CreateCall (GetTempRet0Func, None, " tempret0" );
853
858
Value *Pair1 = IRB.CreateInsertValue (Pair0, TempRet0, 1 , " pair1" );
854
859
855
860
LPI->replaceAllUsesWith (Pair1);
@@ -930,7 +935,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
930
935
Instruction *NewSetjmpTable =
931
936
IRB.CreateCall (SaveSetjmpF, Args, " setjmpTable" );
932
937
Instruction *NewSetjmpTableSize =
933
- IRB.CreateLoad (TempRet0GV , " setjmpTableSize" );
938
+ IRB.CreateCall (GetTempRet0Func, None , " setjmpTableSize" );
934
939
SetjmpTableInsts.push_back (NewSetjmpTable);
935
940
SetjmpTableSizeInsts.push_back (NewSetjmpTableSize);
936
941
ToErase.push_back (CI);
@@ -1052,7 +1057,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runSjLjOnFunction(Function &F) {
1052
1057
// ...
1053
1058
// somebb:
1054
1059
// setjmpTable = saveSetjmp(buf, label, setjmpTable, setjmpTableSize);
1055
- // setjmpTableSize = __tempRet0 ;
1060
+ // setjmpTableSize = getTempRet0() ;
1056
1061
// So we need to make sure the SSA for these variables is valid so that every
1057
1062
// saveSetjmp and testSetjmp calls have the correct arguments.
1058
1063
SSAUpdater SetjmpTableSSA;
0 commit comments