2323#include " ir/intrinsics.h"
2424#include " pass.h"
2525#include " support/name.h"
26- #include " support/utilities.h"
2726#include " wasm-traversal.h"
2827#include " wasm-type.h"
2928#include " wasm.h"
@@ -44,8 +43,8 @@ class EffectAnalyzer {
4443 readsMutableArray(false ), writesArray(false ),
4544 readsSharedMutableArray(false ), writesSharedArray(false ), trap(false ),
4645 implicitTrap(false ), throws_(false ), danglingPop(false ),
47- mayNotReturn(false ), hasReturnCallThrow(false ), module( module ),
48- features(module .features) {}
46+ mayNotReturn(false ), hasReturnCallThrow(false ), suspends( false ),
47+ module( module ), features(module .features) {}
4948
5049 EffectAnalyzer (const PassOptions& passOptions,
5150 const Module& module ,
@@ -138,6 +137,8 @@ class EffectAnalyzer {
138137 // more here.)
139138 bool hasReturnCallThrow : 1 ;
140139
140+ bool suspends : 1 ;
141+
141142 const Module& module ;
142143 FeatureSet features;
143144
@@ -228,15 +229,17 @@ class EffectAnalyzer {
228229 return calls || readsSharedMutableArray || writesSharedArray;
229230 }
230231 bool throws () const { return throws_ || !delegateTargets.empty (); }
232+
231233 // Check whether this may transfer control flow to somewhere outside of this
232- // expression (aside from just flowing out normally). That includes a break
233- // or a throw (if the throw is not known to be caught inside this expression;
234+ // expression (aside from just flowing out normally). That includes a break,
235+ // a throw (if the throw is not known to be caught inside this expression;
234236 // note that if the throw is not caught in this expression then it might be
235237 // caught in this function but outside of this expression, or it might not be
236238 // caught in the function at all, which would mean control flow cannot be
237- // transferred inside the function, but this expression does not know that).
239+ // transferred inside the function, but this expression does not know that),
240+ // or a suspension.
238241 bool transfersControlFlow () const {
239- return branchesOut || throws () || hasExternalBreakTargets ();
242+ return branchesOut || suspends || throws () || hasExternalBreakTargets ();
240243 }
241244
242245 // Changes something in globally-stored state.
@@ -480,6 +483,7 @@ class EffectAnalyzer {
480483 danglingPop = danglingPop || other.danglingPop ;
481484 mayNotReturn = mayNotReturn || other.mayNotReturn ;
482485 hasReturnCallThrow = hasReturnCallThrow || other.hasReturnCallThrow ;
486+ suspends = suspends || other.suspends ;
483487 readOrder = std::max (readOrder, other.readOrder );
484488 writeOrder = std::max (writeOrder, other.writeOrder );
485489
@@ -1271,8 +1275,9 @@ class EffectAnalyzer {
12711275 parent.calls = true ;
12721276 }
12731277 void visitSuspend (Suspend* curr) {
1274- // Similar to resume/call: Suspending means that we execute arbitrary
1275- // other code before we may resume here.
1278+ // Suspending transfers control to an enclosing handler and executes
1279+ // arbitrary other code before we may resume here.
1280+ parent.suspends = true ;
12761281 parent.calls = true ;
12771282 if (parent.features .hasExceptionHandling () && parent.tryDepth == 0 ) {
12781283 parent.throws_ = true ;
@@ -1370,6 +1375,11 @@ class EffectAnalyzer {
13701375 parent.throws_ = true ;
13711376 }
13721377 }
1378+ // If stack switching is enabled and we don't have global effects
1379+ // information, assume that the call target may suspend.
1380+ if (parent.features .hasStackSwitching ()) {
1381+ parent.suspends = true ;
1382+ }
13731383 }
13741384 };
13751385
@@ -1407,7 +1417,8 @@ class EffectAnalyzer {
14071417 Throws = 1 << 12 ,
14081418 DanglingPop = 1 << 13 ,
14091419 TrapsNeverHappen = 1 << 14 ,
1410- Any = (1 << 15 ) - 1
1420+ Suspends = 1 << 15 ,
1421+ Any = (1 << 16 ) - 1
14111422 };
14121423 uint32_t getSideEffects () const {
14131424 uint32_t effects = 0 ;
@@ -1459,12 +1470,15 @@ class EffectAnalyzer {
14591470 if (danglingPop) {
14601471 effects |= SideEffects::DanglingPop;
14611472 }
1473+ if (suspends) {
1474+ effects |= SideEffects::Suspends;
1475+ }
14621476 return effects;
14631477 }
14641478
1465- // Ignores all forms of control flow transfers: breaks, returns, and
1466- // exceptions . (Note that traps are not considered relevant here - a trap does
1467- // not just transfer control flow, but can be seen as halting the entire
1479+ // Ignores all forms of control flow transfers: breaks, returns, exceptions,
1480+ // and suspensions . (Note that traps are not considered relevant here - a trap
1481+ // does not just transfer control flow, but can be seen as halting the entire
14681482 // program.)
14691483 //
14701484 // This function matches transfersControlFlow(), that is, after calling this
@@ -1474,6 +1488,7 @@ class EffectAnalyzer {
14741488 breakTargets.clear ();
14751489 throws_ = false ;
14761490 delegateTargets.clear ();
1491+ suspends = false ;
14771492 assert (!transfersControlFlow ());
14781493 }
14791494
0 commit comments