@@ -230,6 +230,7 @@ struct ContData {
230230 // executed a second time.
231231 bool executed = false ;
232232
233+ ContData () {}
233234 ContData (Literal func, HeapType type) : func(func), type(type) {}
234235};
235236
@@ -338,8 +339,14 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
338339
339340#if WASM_INTERPRETER_DEBUG
340341 std::string indent () {
341- std::string ret =
342- ' [' + std::to_string (reinterpret_cast <size_t >(this )) + " ] " ;
342+ std::string id;
343+ if (auto * module = getModule ()) {
344+ id = module ->name .toString ();
345+ }
346+ if (id.empty ()) {
347+ id = std::to_string (reinterpret_cast <size_t >(this ));
348+ }
349+ auto ret = ' [' + id + " ] " ;
343350 for (Index i = 0 ; i < depth; i++) {
344351 ret += ' ' ;
345352 }
@@ -581,9 +588,10 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
581588 // Outside the scope of StackValueNoter, the scope of our own child values
582589 // has been removed (we don't need those values any more). What is now on
583590 // the top of |valueStack| is the list of child values of our parent,
584- // which is the place our own value can go, if we have one (and if we are
585- // not suspending - suspending is handled above).
586- if (!ret.suspendTag && ret.getType ().isConcrete ()) {
591+ // which is the place our own value can go, if we have one (we only save
592+ // values on the stack, not values sent on a break/suspend; suspending is
593+ // handled above).
594+ if (!ret.breaking () && ret.getType ().isConcrete ()) {
587595 assert (!valueStack.empty ());
588596 auto & values = valueStack.back ();
589597 values.push_back (ret.values );
@@ -4841,6 +4849,10 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
48414849 }
48424850
48434851 if (self ()->isResuming ()) {
4852+ #if WASM_INTERPRETER_DEBUG
4853+ std::cout << self ()->indent ()
4854+ << " returned to suspend; continuing normally\n " ;
4855+ #endif
48444856 // This is a resume, so we have found our way back to where we
48454857 // suspended.
48464858 auto currContinuation = self ()->getCurrContinuation ();
@@ -4864,12 +4876,15 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
48644876 if (!old) {
48654877 return Flow (SUSPEND_FLOW, tag, std::move (arguments));
48664878 }
4867- // An old one exists, so we can create a proper new one.
48684879 assert (old->executed );
4869- auto new_ = std::make_shared<ContData>(old->func , old->type );
4880+ // An old one exists, so we can create a proper new one. It starts out
4881+ // empty here, and as we unwind, info will be added to it (and the function
4882+ // to resume as well, once we find the right resume handler).
4883+ //
48704884 // Note we cannot update the type yet, so it will be wrong in debug
48714885 // logging. To update it, we must find the block that receives this value,
48724886 // which means we cannot do it here (we don't even know what that block is).
4887+ auto new_ = std::make_shared<ContData>();
48734888
48744889 // Switch to the new continuation, so that as we unwind, we will save the
48754890 // information we need to resume it later in the proper place.
@@ -4893,22 +4908,29 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
48934908
48944909 // Get and execute the continuation.
48954910 auto contData = flow.getSingleValue ().getContData ();
4896- if (contData->executed ) {
4897- trap (" continuation already executed" );
4898- }
4899- contData->executed = true ;
4900- if (contData->resumeArguments .empty ()) {
4901- // The continuation has no bound arguments. For now, we just handle the
4902- // simple case of binding all of them, so that means we can just use all
4903- // the immediate ones here. TODO
4904- contData->resumeArguments = arguments;
4905- }
49064911 auto func = contData->func ;
4907- self ()->pushCurrContinuation (contData);
4908- self ()->continuationStore ->resuming = true ;
4912+
4913+ // If we are resuming a nested suspend then we should just rewind the call
4914+ // stack, and therefore do not change or test the state here.
4915+ if (!self ()->isResuming ()) {
4916+ if (contData->executed ) {
4917+ trap (" continuation already executed" );
4918+ }
4919+ contData->executed = true ;
4920+ if (contData->resumeArguments .empty ()) {
4921+ // The continuation has no bound arguments. For now, we just handle the
4922+ // simple case of binding all of them, so that means we can just use all
4923+ // the immediate ones here. TODO
4924+ contData->resumeArguments = arguments;
4925+ }
4926+ self ()->pushCurrContinuation (contData);
4927+ self ()->continuationStore ->resuming = true ;
49094928#if WASM_INTERPRETER_DEBUG
4910- std::cout << self ()->indent () << " resuming func " << func.getFunc () << ' \n ' ;
4929+ std::cout << self ()->indent () << " resuming func " << func.getFunc ()
4930+ << ' \n ' ;
49114931#endif
4932+ }
4933+
49124934 Flow ret;
49134935 {
49144936 // Create a stack value scope. This ensures that we always have a scope,
@@ -4919,7 +4941,10 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
49194941 ret = func.getFuncData ()->doCall (arguments);
49204942 }
49214943#if WASM_INTERPRETER_DEBUG
4922- std::cout << self ()->indent () << " finished resuming, with " << ret << ' \n ' ;
4944+ if (!self ()->isResuming ()) {
4945+ std::cout << self ()->indent () << " finished resuming, with " << ret
4946+ << ' \n ' ;
4947+ }
49234948#endif
49244949 if (!ret.suspendTag ) {
49254950 // No suspension: the coroutine finished normally. Mark it as no longer
@@ -4953,11 +4978,14 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
49534978 assert (finder.type .isConcrete ());
49544979 assert (finder.type .size () >= 1 );
49554980 // The continuation is the final value/type there.
4956- auto cont = self ()->getCurrContinuation ();
4957- cont->type = finder.type [finder.type .size () - 1 ].getHeapType ();
4981+ auto newCont = self ()->getCurrContinuation ();
4982+ newCont->type = finder.type [finder.type .size () - 1 ].getHeapType ();
4983+ // And we can set the function to be called, to resume it from here
4984+ // (the same function we called, that led to a suspension).
4985+ newCont->func = contData->func ;
49584986 // Add the continuation as the final value being sent.
4959- ret.values .push_back (Literal (cont ));
4960- // We are not longer processing that continuation.
4987+ ret.values .push_back (Literal (newCont ));
4988+ // We are no longer processing that continuation.
49614989 self ()->popCurrContinuation ();
49624990 return ret;
49634991 }
@@ -5067,9 +5095,17 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
50675095 for (Index i = 0 ; i < scope.locals .size (); i++) {
50685096 auto l = scope.locals .size () - 1 - i;
50695097 scope.locals [l] = self ()->popResumeEntry (" function" );
5070- // Must have restored valid data.
5071- assert (Type::isSubType (scope.locals [l].getType (),
5072- function->getLocalType (l)));
5098+ #ifndef NDEBUG
5099+ // Must have restored valid data. The type must match the local's
5100+ // type, except for the case of a non-nullable local that has not yet
5101+ // been accessed: that will contain a null (but the wasm type system
5102+ // ensures it will not be read by code, until a non-null value is
5103+ // assigned).
5104+ auto value = scope.locals [l];
5105+ auto localType = function->getLocalType (l);
5106+ assert (Type::isSubType (value.getType (), localType) ||
5107+ value == Literal::makeZeros (localType));
5108+ #endif
50735109 }
50745110 }
50755111
0 commit comments