3131
3232namespace wasm {
3333
34- cashew::IString EMSCRIPTEN_ASM_CONST (" emscripten_asm_const" );
34+ cashew::IString EM_ASM_PREFIX (" emscripten_asm_const" );
3535cashew::IString EM_JS_PREFIX (" __em_js__" );
3636
3737static Name STACK_SAVE (" stackSave" );
@@ -664,13 +664,36 @@ std::string codeForConstAddr(Module& wasm,
664664 return escape (str);
665665}
666666
667+ enum class Proxying {
668+ None,
669+ Sync,
670+ Async,
671+ };
672+
673+ std::string proxyingSuffix (Proxying proxy) {
674+ switch (proxy) {
675+ case Proxying::None:
676+ return " " ;
677+ case Proxying::Sync:
678+ return " sync_on_main_thread_" ;
679+ case Proxying::Async:
680+ return " async_on_main_thread_" ;
681+ }
682+ WASM_UNREACHABLE ();
683+ }
684+
667685struct AsmConstWalker : public LinearExecutionWalker <AsmConstWalker> {
668686 Module& wasm;
669687 std::vector<Address> segmentOffsets; // segment index => address offset
670688
671- std::map<std::string, std::set<std::string>> sigsForCode;
672- std::map<std::string, Address> ids;
673- std::set<std::string> allSigs;
689+ struct AsmConst {
690+ std::set<std::string> sigs;
691+ Address id;
692+ Proxying proxy;
693+ };
694+
695+ std::map<std::string, AsmConst> asmConsts;
696+ std::set<std::pair<std::string, Proxying>> allSigs;
674697 // last sets in the current basic block, per index
675698 std::map<Index, LocalSet*> sets;
676699
@@ -686,12 +709,13 @@ struct AsmConstWalker : public LinearExecutionWalker<AsmConstWalker> {
686709 void process ();
687710
688711private:
689- std::string fixupNameWithSig (Name& name, std::string baseSig);
690- Literal idLiteralForCode (std::string code);
712+ std::string fixupName (Name& name, std::string baseSig, Proxying proxy );
713+ AsmConst& createAsmConst (std::string code, std::string sig, Name name );
691714 std::string asmConstSig (std::string baseSig);
692- Name nameForImportWithSig (std::string sig);
715+ Name nameForImportWithSig (std::string sig, Proxying proxy );
693716 void queueImport (Name importName, std::string baseSig);
694717 void addImports ();
718+ Proxying proxyType (Name name);
695719
696720 std::vector<std::unique_ptr<Function>> queuedImports;
697721};
@@ -707,57 +731,74 @@ void AsmConstWalker::visitCall(Call* curr) {
707731 auto * import = wasm.getFunction (curr->target );
708732 // Find calls to emscripten_asm_const* functions whose first argument is
709733 // is always a string constant.
710- if (import ->imported () && import ->base .hasSubstring (EMSCRIPTEN_ASM_CONST)) {
711- auto baseSig = getSig (curr);
712- auto sig = fixupNameWithSig (curr->target , baseSig);
713- auto * arg = curr->operands [0 ];
714- while (!arg->dynCast <Const>()) {
715- if (auto * get = arg->dynCast <LocalGet>()) {
716- // The argument may be a local.get, in which case, the last set in this
717- // basic block has the value.
718- auto * set = sets[get->index ];
719- if (set) {
720- assert (set->index == get->index );
721- arg = set->value ;
722- } else {
723- Fatal () << " local.get of unknown in arg0 of call to " << import ->base
724- << " (used by EM_ASM* macros) in function "
725- << getFunction ()->name
726- << " .\n This might be caused by aggressive compiler "
727- " transformations. Consider using EM_JS instead." ;
728- }
729- } else if (auto * value = arg->dynCast <Binary>()) {
730- // In the dynamic linking case the address of the string constant
731- // is the result of adding its offset to __memory_base.
732- // In this case are only looking for the offset with the data segment so
733- // the RHS of the addition is just what we want.
734- assert (value->op == AddInt32);
735- arg = value->right ;
734+ if (!import ->imported ()) {
735+ return ;
736+ }
737+ auto importName = import ->base ;
738+ if (!importName.hasSubstring (EM_ASM_PREFIX)) {
739+ return ;
740+ }
741+
742+ auto baseSig = getSig (curr);
743+ auto sig = asmConstSig (baseSig);
744+ auto * arg = curr->operands [0 ];
745+ while (!arg->dynCast <Const>()) {
746+ if (auto * get = arg->dynCast <LocalGet>()) {
747+ // The argument may be a local.get, in which case, the last set in this
748+ // basic block has the value.
749+ auto * set = sets[get->index ];
750+ if (set) {
751+ assert (set->index == get->index );
752+ arg = set->value ;
736753 } else {
737- if (!value) {
738- Fatal () << " Unexpected arg0 type (" << getExpressionName (arg)
739- << " ) in call to: " << import ->base ;
740- }
754+ Fatal () << " local.get of unknown in arg0 of call to " << importName
755+ << " (used by EM_ASM* macros) in function "
756+ << getFunction ()->name
757+ << " .\n This might be caused by aggressive compiler "
758+ " transformations. Consider using EM_JS instead." ;
759+ }
760+ } else if (auto * value = arg->dynCast <Binary>()) {
761+ // In the dynamic linking case the address of the string constant
762+ // is the result of adding its offset to __memory_base.
763+ // In this case are only looking for the offset with the data segment so
764+ // the RHS of the addition is just what we want.
765+ assert (value->op == AddInt32);
766+ arg = value->right ;
767+ } else {
768+ if (!value) {
769+ Fatal () << " Unexpected arg0 type (" << getExpressionName (arg)
770+ << " ) in call to: " << importName;
741771 }
742772 }
773+ }
743774
744- auto * value = arg->cast <Const>();
745- auto code = codeForConstAddr (wasm, segmentOffsets, value);
746- sigsForCode[code].insert (sig);
775+ auto * value = arg->cast <Const>();
776+ auto code = codeForConstAddr (wasm, segmentOffsets, value);
777+ auto & asmConst = createAsmConst (code, sig, importName);
778+ fixupName (curr->target , baseSig, asmConst.proxy );
747779
748- // Replace the first argument to the call with a Const index
749- Builder builder (wasm);
750- curr->operands [0 ] = builder.makeConst (idLiteralForCode (code));
780+ // Replace the first argument to the call with a Const index
781+ Builder builder (wasm);
782+ curr->operands [0 ] = builder.makeConst (Literal (asmConst.id ));
783+ }
784+
785+ Proxying AsmConstWalker::proxyType (Name name) {
786+ if (name.hasSubstring (" _sync_on_main_thread" )) {
787+ return Proxying::Sync;
788+ } else if (name.hasSubstring (" _async_on_main_thread" )) {
789+ return Proxying::Async;
751790 }
791+ return Proxying::None;
752792}
753793
754794void AsmConstWalker::visitTable (Table* curr) {
755795 for (auto & segment : curr->segments ) {
756796 for (auto & name : segment.data ) {
757797 auto * func = wasm.getFunction (name);
758- if (func->imported () && func->base .hasSubstring (EMSCRIPTEN_ASM_CONST )) {
798+ if (func->imported () && func->base .hasSubstring (EM_ASM_PREFIX )) {
759799 std::string baseSig = getSig (func);
760- fixupNameWithSig (name, baseSig);
800+ auto proxy = proxyType (func->base );
801+ fixupName (name, baseSig, proxy);
761802 }
762803 }
763804 }
@@ -771,27 +812,31 @@ void AsmConstWalker::process() {
771812 addImports ();
772813}
773814
774- std::string AsmConstWalker::fixupNameWithSig (Name& name, std::string baseSig) {
815+ std::string
816+ AsmConstWalker::fixupName (Name& name, std::string baseSig, Proxying proxy) {
775817 auto sig = asmConstSig (baseSig);
776- auto importName = nameForImportWithSig (sig);
818+ auto importName = nameForImportWithSig (sig, proxy );
777819 name = importName;
778820
779- if (allSigs.count (sig) == 0 ) {
780- allSigs.insert (sig);
821+ auto pair = std::make_pair (sig, proxy);
822+ if (allSigs.count (pair) == 0 ) {
823+ allSigs.insert (pair);
781824 queueImport (importName, baseSig);
782825 }
783826 return sig;
784827}
785828
786- Literal AsmConstWalker::idLiteralForCode (std::string code) {
787- int32_t id;
788- if (ids.count (code) == 0 ) {
789- id = ids.size ();
790- ids[code] = id;
791- } else {
792- id = ids[code];
829+ AsmConstWalker::AsmConst&
830+ AsmConstWalker::createAsmConst (std::string code, std::string sig, Name name) {
831+ if (asmConsts.count (code) == 0 ) {
832+ AsmConst asmConst;
833+ asmConst.id = asmConsts.size ();
834+ asmConst.sigs .insert (sig);
835+ asmConst.proxy = proxyType (name);
836+
837+ asmConsts[code] = asmConst;
793838 }
794- return Literal (id) ;
839+ return asmConsts[code] ;
795840}
796841
797842std::string AsmConstWalker::asmConstSig (std::string baseSig) {
@@ -806,8 +851,9 @@ std::string AsmConstWalker::asmConstSig(std::string baseSig) {
806851 return sig;
807852}
808853
809- Name AsmConstWalker::nameForImportWithSig (std::string sig) {
810- std::string fixedTarget = EMSCRIPTEN_ASM_CONST.str + std::string (" _" ) + sig;
854+ Name AsmConstWalker::nameForImportWithSig (std::string sig, Proxying proxy) {
855+ std::string fixedTarget =
856+ EM_ASM_PREFIX.str + std::string (" _" ) + proxyingSuffix (proxy) + sig;
811857 return Name (fixedTarget.c_str ());
812858}
813859
@@ -830,7 +876,7 @@ AsmConstWalker fixEmAsmConstsAndReturnWalker(Module& wasm) {
830876 // This would find our generated functions if we ran it later
831877 std::vector<Name> toRemove;
832878 for (auto & import : wasm.functions ) {
833- if (import ->imported () && import ->base .hasSubstring (EMSCRIPTEN_ASM_CONST )) {
879+ if (import ->imported () && import ->base .hasSubstring (EM_ASM_PREFIX )) {
834880 toRemove.push_back (import ->name );
835881 }
836882 }
@@ -1039,19 +1085,15 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
10391085
10401086 // print
10411087 commaFirst = true ;
1042- if (!emAsmWalker.sigsForCode .empty ()) {
1088+ if (!emAsmWalker.asmConsts .empty ()) {
10431089 meta << " \" asmConsts\" : {" ;
1044- for (auto & pair : emAsmWalker.sigsForCode ) {
1090+ for (auto & pair : emAsmWalker.asmConsts ) {
10451091 auto & code = pair.first ;
1046- auto & sigs = pair.second ;
1092+ auto & asmConst = pair.second ;
10471093 meta << nextElement ();
1048- meta << ' "' << emAsmWalker.ids [code] << " \" : [\" " << code << " \" , " ;
1049- printSet (meta, sigs);
1050- meta << " , " ;
1051-
1052- // TODO: proxying to main thread. Currently this is unsupported, so proxy
1053- // mode is "none", represented by an empty string.
1054- meta << " [\"\" ]" ;
1094+ meta << ' "' << asmConst.id << " \" : [\" " << code << " \" , " ;
1095+ printSet (meta, asmConst.sigs );
1096+ meta << " , [\" " << proxyingSuffix (asmConst.proxy ) << " \" ]" ;
10551097
10561098 meta << " ]" ;
10571099 }
@@ -1097,7 +1139,7 @@ std::string EmscriptenGlueGenerator::generateEmscriptenMetadata(
10971139 commaFirst = true ;
10981140 ModuleUtils::iterImportedFunctions (wasm, [&](Function* import ) {
10991141 if (emJsWalker.codeByName .count (import ->base .str ) == 0 &&
1100- !import ->base .startsWith (EMSCRIPTEN_ASM_CONST .str ) &&
1142+ !import ->base .startsWith (EM_ASM_PREFIX .str ) &&
11011143 !import ->base .startsWith (" invoke_" )) {
11021144 if (declares.insert (import ->base .str ).second ) {
11031145 meta << nextElement () << ' "' << import ->base .str << ' "' ;
0 commit comments