@@ -489,27 +489,36 @@ struct CtorEvalExternalInterface : EvallingModuleInstance::ExternalInterface {
489489 }
490490};
491491
492+ struct EvalCtorOutcome {
493+ // Whether we completely evalled the function (that is, we did not fail, and
494+ // we did not only partially eval it).
495+ bool evalledCompletely;
496+
497+ // If the function was evalled completely, and it returns something, that
498+ // value is given here.
499+ Literals results;
500+
501+ static EvalCtorOutcome incomplete () { return {false , Literals ()}; }
502+
503+ static EvalCtorOutcome complete (Literals results) { return {true , results}; }
504+ };
505+
492506// Eval a single ctor function. Returns whether we succeeded to completely
493- // evaluate the ctor, which means that the caller can proceed to try to eval
494- // further ctors if there are any.
495- bool evalCtor (EvallingModuleInstance& instance,
496- CtorEvalExternalInterface& interface,
497- Name funcName,
498- Name exportName) {
507+ // evaluate the ctor (which means that the caller can proceed to try to eval
508+ // further ctors if there are any), and if we did, the results if the function
509+ // returns any.
510+ EvalCtorOutcome evalCtor (EvallingModuleInstance& instance,
511+ CtorEvalExternalInterface& interface,
512+ Name funcName,
513+ Name exportName) {
499514 auto & wasm = instance.wasm ;
500515 auto * func = wasm.getFunction (funcName);
501516
502517 // We don't know the values of parameters, so give up if there are any.
503518 // TODO: Maybe use ignoreExternalInput?
504519 if (func->getNumParams () > 0 ) {
505520 std::cout << " ...stopping due to params\n " ;
506- return false ;
507- }
508-
509- // TODO: Handle a return value by emitting a proper constant.
510- if (func->getResults () != Type::none) {
511- std::cout << " ...stopping due to results\n " ;
512- return false ;
521+ return EvalCtorOutcome::incomplete ();
513522 }
514523
515524 // We want to handle the form of the global constructor function in LLVM. That
@@ -523,10 +532,10 @@ bool evalCtor(EvallingModuleInstance& instance,
523532 //
524533 // Some of those ctors may be inlined, however, which would mean that the
525534 // function could have locals, control flow, etc. However, we assume for now
526- // that it does not have parameters at least (whose values we can't tell),
527- // or results. And for now we look for a toplevel block and process its
528- // children one at a time. This allows us to eval some of the $ctor.*
529- // functions (or their inlined contents) even if not all.
535+ // that it does not have parameters at least (whose values we can't tell).
536+ // And for now we look for a toplevel block and process its children one at a
537+ // time. This allows us to eval some of the $ctor.* functions (or their
538+ // inlined contents) even if not all.
530539 //
531540 // TODO: Support complete partial evalling, that is, evaluate parts of an
532541 // arbitrary function, and not just a sequence in a single toplevel
@@ -546,6 +555,7 @@ bool evalCtor(EvallingModuleInstance& instance,
546555 // an item in the block that we only partially evalled.
547556 EvallingModuleInstance::FunctionScope appliedScope (func, LiteralList ());
548557
558+ Literals results;
549559 Index successes = 0 ;
550560 for (auto * curr : block->list ) {
551561 Flow flow;
@@ -568,6 +578,10 @@ bool evalCtor(EvallingModuleInstance& instance,
568578 appliedScope = scope;
569579 successes++;
570580
581+ // Note the values here, if any. If we are exiting the function now then
582+ // these will be returned.
583+ results = flow.values ;
584+
571585 if (flow.breaking ()) {
572586 // We are returning out of the function (either via a return, or via a
573587 // break to |block|, which has the same outcome. That means we don't
@@ -627,22 +641,27 @@ bool evalCtor(EvallingModuleInstance& instance,
627641
628642 // Return true if we evalled the entire block. Otherwise, even if we evalled
629643 // some of it, the caller must stop trying to eval further things.
630- return successes == block->list .size ();
644+ if (successes == block->list .size ()) {
645+ return EvalCtorOutcome::complete (results);
646+ } else {
647+ return EvalCtorOutcome::incomplete ();
648+ }
631649 }
632650
633651 // Otherwise, we don't recognize a pattern that allows us to do partial
634652 // evalling. So simply call the entire function at once and see if we can
635653 // optimize that.
654+ Literals results;
636655 try {
637- instance.callFunction (funcName, LiteralList ());
656+ results = instance.callFunction (funcName, LiteralList ());
638657 } catch (FailToEvalException& fail) {
639658 std::cout << " ...stopping since could not eval: " << fail.why << " \n " ;
640- return false ;
659+ return EvalCtorOutcome::incomplete () ;
641660 }
642661
643662 // Success! Apply the results.
644663 interface.applyToModule ();
645- return true ;
664+ return EvalCtorOutcome::complete (results) ;
646665}
647666
648667// Eval all ctors in a module.
@@ -677,12 +696,13 @@ void evalCtors(Module& wasm,
677696 Fatal () << " export not found: " << ctor;
678697 }
679698 auto funcName = ex->value ;
680- if (!evalCtor (instance, interface, funcName, ctor)) {
699+ auto outcome = evalCtor (instance, interface, funcName, ctor);
700+ if (!outcome.evalledCompletely ) {
681701 std::cout << " ...stopping\n " ;
682702 return ;
683703 }
684704
685- // Success! Remove the export, and continue.
705+ // Success! And we can continue to try more .
686706 std::cout << " ...success on " << ctor << " .\n " ;
687707
688708 // Remove the export if we should.
@@ -695,7 +715,12 @@ void evalCtors(Module& wasm,
695715 auto * func = wasm.getFunction (exp->value );
696716 auto copyName = Names::getValidFunctionName (wasm, func->name );
697717 auto * copyFunc = ModuleUtils::copyFunction (func, wasm, copyName);
698- copyFunc->body = Builder (wasm).makeNop ();
718+ if (func->getResults () == Type::none) {
719+ copyFunc->body = Builder (wasm).makeNop ();
720+ } else {
721+ copyFunc->body =
722+ Builder (wasm).makeConstantExpression (outcome.results );
723+ }
699724 wasm.getExport (exp->name )->value = copyName;
700725 }
701726 }
0 commit comments