2525from tools import gen_struct_info
2626from tools import jsrun
2727from tools .response_file import substitute_response_files
28- from tools .shared import WINDOWS , asstr , path_from_root , exit_with_error
28+ from tools .shared import WINDOWS , asstr , path_from_root , exit_with_error , asmjs_mangle , treat_as_user_function
2929from tools .toolchain_profiler import ToolchainProfiler
3030from tools .minified_js_name_generator import MinifiedJsNameGenerator
3131
@@ -270,6 +270,26 @@ def get_asm_extern_primitives(pre):
270270 return []
271271
272272
273+ def compute_minimal_runtime_initializer_and_exports (post , initializers , exports , receiving ):
274+ # Generate invocations for all global initializers directly off the asm export object, e.g. asm['__GLOBAL__INIT']();
275+ post = post .replace ('/*** RUN_GLOBAL_INITIALIZERS(); ***/' , '\n ' .join (["asm['" + x + "']();" for x in global_initializer_funcs (initializers )]))
276+
277+ if shared .Settings .WASM :
278+ # Declare all exports out to global JS scope so that JS library functions can access them in a way that minifies well with Closure
279+ # e.g. var a,b,c,d,e,f;
280+ exports_that_are_not_initializers = [x for x in exports if x not in initializers ]
281+ if shared .Settings .WASM_BACKEND :
282+ # In Wasm backend the exports are still unmangled at this point, so mangle the names here
283+ exports_that_are_not_initializers = [asmjs_mangle (x ) for x in exports_that_are_not_initializers ]
284+ post = post .replace ('/*** ASM_MODULE_EXPORTS_DECLARES ***/' , 'var ' + ',' .join (exports_that_are_not_initializers ) + ';' )
285+
286+ # Generate assignments from all asm.js/wasm exports out to the JS variables above: e.g. a = asm['a']; b = asm['b'];
287+ post = post .replace ('/*** ASM_MODULE_EXPORTS ***/' , receiving )
288+ receiving = ''
289+
290+ return post , receiving
291+
292+
273293def function_tables_and_exports (funcs , metadata , mem_init , glue , forwarded_data , outfile , DEBUG ):
274294 if DEBUG :
275295 logger .debug ('emscript: python processing: function tables and exports' )
@@ -397,17 +417,7 @@ def define_asmjs_import_names(imports):
397417 post = apply_static_code_hooks (post )
398418
399419 if shared .Settings .MINIMAL_RUNTIME :
400- # Generate invocations for all global initializers directly off the asm export object, e.g. asm['__GLOBAL__INIT']();
401- post = post .replace ('/*** RUN_GLOBAL_INITIALIZERS(); ***/' , '\n ' .join (["asm['" + x + "']();" for x in global_initializer_funcs (metadata ['initializers' ])]))
402-
403- if shared .Settings .WASM :
404- # Declare all exports out to global JS scope so that JS library functions can access them in a way that minifies well with Closure
405- # e.g. var a,b,c,d,e,f;
406- post = post .replace ('/*** ASM_MODULE_EXPORTS_DECLARES ***/' , 'var ' + ',' .join (shared .Settings .MODULE_EXPORTS ) + ';' )
407-
408- # Generate assignments from all asm.js/wasm exports out to the JS variables above: e.g. a = asm['a']; b = asm['b'];
409- post = post .replace ('/*** ASM_MODULE_EXPORTS ***/' , receiving )
410- receiving = ''
420+ post , receiving = compute_minimal_runtime_initializer_and_exports (post , metadata ['initializers' ], [mangled for mangled , unmangled in shared .Settings .MODULE_EXPORTS ], receiving )
411421
412422 function_tables_impls = make_function_tables_impls (function_table_data )
413423 final_function_tables = '\n ' .join (function_tables_impls ) + '\n ' + function_tables_defs
@@ -1710,7 +1720,8 @@ def create_receiving(function_table_data, function_tables_defs, exported_impleme
17101720''' % {'name' : name , 'runtime_assertions' : runtime_assertions })
17111721 receiving = '\n ' .join (wrappers )
17121722
1713- shared .Settings .MODULE_EXPORTS = module_exports = exported_implemented_functions + function_tables (function_table_data )
1723+ module_exports = exported_implemented_functions + function_tables (function_table_data )
1724+ shared .Settings .MODULE_EXPORTS = [(f , f ) for f in module_exports ]
17141725
17151726 if not shared .Settings .SWAPPABLE_ASM_MODULE :
17161727 if shared .Settings .DECLARE_ASM_MODULE_EXPORTS :
@@ -2208,14 +2219,22 @@ def emscript_wasm_backend(infile, outfile, memfile, compiler_engine,
22082219
22092220 staticbump = shared .Settings .STATIC_BUMP
22102221
2222+ if shared .Settings .MINIMAL_RUNTIME :
2223+ # In minimal runtime, global initializers are run after the Wasm Module instantiation has finished.
2224+ global_initializers = ''
2225+ else :
2226+ # In regular runtime, global initializers are recorded in an __ATINIT__ array.
2227+ global_initializers = '''/* global initializers */ %s __ATINIT__.push(%s);
2228+ ''' % ('if (!ENVIRONMENT_IS_PTHREAD)' if shared .Settings .USE_PTHREADS else '' ,
2229+ global_initializers )
2230+
22112231 pre = pre .replace ('STATICTOP = STATIC_BASE + 0;' , '''STATICTOP = STATIC_BASE + %d;
2212- /* global initializers */ %s __ATINIT__.push(%s);
2213- ''' % (staticbump ,
2214- 'if (!ENVIRONMENT_IS_PTHREAD)' if shared .Settings .USE_PTHREADS else '' ,
2215- global_initializers ))
2232+ %s
2233+ ''' % (staticbump , global_initializers ))
22162234
22172235 pre = apply_memory (pre )
2218- pre = apply_static_code_hooks (pre )
2236+ pre = apply_static_code_hooks (pre ) # In regular runtime, atinits etc. exist in the preamble part
2237+ post = apply_static_code_hooks (post ) # In MINIMAL_RUNTIME, atinit exists in the postamble part
22192238
22202239 if shared .Settings .RELOCATABLE and not shared .Settings .SIDE_MODULE :
22212240 pre += 'var gb = GLOBAL_BASE, fb = 0;\n '
@@ -2225,6 +2244,10 @@ def emscript_wasm_backend(infile, outfile, memfile, compiler_engine,
22252244
22262245 exports = metadata ['exports' ]
22272246
2247+ # Store exports for Closure compiler to be able to track these as globals in
2248+ # -s DECLARE_ASM_MODULE_EXPORTS=0 builds.
2249+ shared .Settings .MODULE_EXPORTS = [(asmjs_mangle (f ), f ) for f in exports ]
2250+
22282251 if shared .Settings .ASYNCIFY :
22292252 exports += ['asyncify_start_unwind' , 'asyncify_stop_unwind' , 'asyncify_start_rewind' , 'asyncify_stop_rewind' ]
22302253
@@ -2255,6 +2278,9 @@ def emscript_wasm_backend(infile, outfile, memfile, compiler_engine,
22552278 sending = create_sending_wasm (invoke_funcs , forwarded_json , metadata )
22562279 receiving = create_receiving_wasm (exports )
22572280
2281+ if shared .Settings .MINIMAL_RUNTIME :
2282+ post , receiving = compute_minimal_runtime_initializer_and_exports (post , metadata ['initializers' ], exports , receiving )
2283+
22582284 module = create_module_wasm (sending , receiving , invoke_funcs , metadata )
22592285
22602286 write_output_file (outfile , post , module )
@@ -2608,7 +2634,7 @@ def fix_import_name(g):
26082634
26092635def create_receiving_wasm (exports ):
26102636 receiving = []
2611- if not shared .Settings .ASSERTIONS :
2637+ if shared . Settings . MINIMAL_RUNTIME or not shared .Settings .ASSERTIONS :
26122638 runtime_assertions = ''
26132639 else :
26142640 runtime_assertions = RUNTIME_ASSERTIONS
@@ -2623,8 +2649,42 @@ def create_receiving_wasm(exports):
26232649''' % {'mangled' : asmjs_mangle (e ), 'e' : e , 'assertions' : runtime_assertions })
26242650
26252651 if not shared .Settings .SWAPPABLE_ASM_MODULE :
2626- for e in exports :
2627- receiving .append ('var %(mangled)s = Module["%(mangled)s"] = asm["%(e)s"];' % {'mangled' : asmjs_mangle (e ), 'e' : e })
2652+ if shared .Settings .DECLARE_ASM_MODULE_EXPORTS :
2653+ if shared .Settings .WASM and shared .Settings .MINIMAL_RUNTIME :
2654+ # In Wasm exports are assigned inside a function to variables existing in top level JS scope, i.e.
2655+ # var _main;
2656+ # WebAssembly.instantiate(Module["wasm"], imports).then((function(output) {
2657+ # var asm = output.instance.exports;
2658+ # _main = asm["_main"];
2659+ receiving += [asmjs_mangle (s ) + ' = asm["' + s + '"];' for s in exports ]
2660+ else :
2661+ if shared .Settings .MINIMAL_RUNTIME :
2662+ # In wasm2js exports can be directly processed at top level, i.e.
2663+ # var asm = Module["asm"](asmGlobalArg, asmLibraryArg, buffer);
2664+ # var _main = asm["_main"];
2665+ receiving += ['var ' + asmjs_mangle (s ) + ' = asm["' + asmjs_mangle (s ) + '"];' for s in exports ]
2666+ else :
2667+ receiving += ['var ' + asmjs_mangle (s ) + ' = Module["' + asmjs_mangle (s ) + '"] = asm["' + s + '"];' for s in exports ]
2668+ else :
2669+ if shared .Settings .target_environment_may_be ('node' ) and shared .Settings .target_environment_may_be ('web' ):
2670+ global_object = '(typeof process !== "undefined" ? global : this)'
2671+ elif shared .Settings .target_environment_may_be ('node' ):
2672+ global_object = 'global'
2673+ else :
2674+ global_object = 'this'
2675+
2676+ if shared .Settings .MINIMAL_RUNTIME :
2677+ module_assign = ''
2678+ else :
2679+ module_assign = 'Module[asmjs_mangle(__exportedFunc)] = '
2680+
2681+ receiving .append ('''
2682+ function asmjs_mangle(x) {
2683+ var unmangledSymbols = %s;
2684+ return x.indexOf('dynCall_') == 0 || unmangledSymbols.indexOf(x) != -1 ? x : '_' + x;
2685+ }
2686+ ''' % shared .Settings .WASM_FUNCTIONS_THAT_ARE_NOT_NAME_MANGLED )
2687+ receiving .append ('for(var __exportedFunc in asm) ' + global_object + '[asmjs_mangle(__exportedFunc)] = ' + module_assign + 'asm[__exportedFunc];' )
26282688 else :
26292689 receiving .append ('Module["asm"] = asm;' )
26302690 for e in exports :
@@ -2650,7 +2710,8 @@ def create_module_wasm(sending, receiving, invoke_funcs, metadata):
26502710 if shared .Settings .ASYNCIFY and shared .Settings .ASSERTIONS :
26512711 module .append ('Asyncify.instrumentWasmImports(asmLibraryArg);\n ' )
26522712
2653- module .append ("var asm = createWasm();\n " )
2713+ if not shared .Settings .MINIMAL_RUNTIME :
2714+ module .append ("var asm = createWasm();\n " )
26542715
26552716 module .append (receiving )
26562717 module .append (invoke_wrappers )
@@ -2697,8 +2758,10 @@ def load_metadata_wasm(metadata_raw, DEBUG):
26972758 exit_with_error ('unexpected metadata key received from wasm-emscripten-finalize: %s' , key )
26982759 metadata [key ] = value
26992760
2700- # Initializers call the global var version of the export, so they get the mangled name.
2701- metadata ['initializers' ] = [asmjs_mangle (i ) for i in metadata ['initializers' ]]
2761+ if not shared .Settings .MINIMAL_RUNTIME :
2762+ # In regular runtime initializers call the global var version of the export, so they get the mangled name.
2763+ # In MINIMAL_RUNTIME, the initializers are called directly off the export object for minimal code size.
2764+ metadata ['initializers' ] = [asmjs_mangle (i ) for i in metadata ['initializers' ]]
27022765
27032766 if DEBUG :
27042767 logger .debug ("Metadata parsed: " + pprint .pformat (metadata ))
@@ -2723,30 +2786,6 @@ def create_invoke_wrappers(invoke_funcs):
27232786 return invoke_wrappers
27242787
27252788
2726- def treat_as_user_function (name ):
2727- library_functions_in_module = ('setTempRet0' , 'getTempRet0' , 'stackAlloc' ,
2728- 'stackSave' , 'stackRestore' ,
2729- 'establishStackSpace' , '__growWasmMemory' ,
2730- '__heap_base' , '__data_end' )
2731- if name .startswith ('dynCall_' ):
2732- return False
2733- if name in library_functions_in_module :
2734- return False
2735- return True
2736-
2737-
2738- def asmjs_mangle (name ):
2739- """Mangle a name the way asm.js/JSBackend globals are mangled.
2740-
2741- Prepends '_' and replaces non-alphanumerics with '_'.
2742- Used by wasm backend for JS library consistency with asm.js.
2743- """
2744- if treat_as_user_function (name ):
2745- return '_' + name
2746- else :
2747- return name
2748-
2749-
27502789def normalize_line_endings (text ):
27512790 """Normalize to UNIX line endings.
27522791
0 commit comments