@@ -123,19 +123,19 @@ def update_settings_glue(metadata, DEBUG):
123123 # -s DECLARE_ASM_MODULE_EXPORTS=0 builds.
124124 settings .WASM_FUNCTION_EXPORTS = metadata ['exports' ]
125125
126- # start with the MVP features, and add any detected features.
127- settings .BINARYEN_FEATURES = ['--mvp-features' ] + metadata ['features' ]
128- if settings .USE_PTHREADS :
129- assert '--enable-threads' in settings .BINARYEN_FEATURES
130- if settings .MEMORY64 :
131- assert '--enable-memory64' in settings .BINARYEN_FEATURES
132-
133- if settings .RELOCATABLE :
126+ if 'features' in metadata :
127+ # start with the MVP features, and add any detected features.
128+ settings .BINARYEN_FEATURES = ['--mvp-features' ] + metadata ['features' ]
129+ if settings .USE_PTHREADS :
130+ assert '--enable-threads' in settings .BINARYEN_FEATURES
131+ if settings .MEMORY64 :
132+ assert '--enable-memory64' in settings .BINARYEN_FEATURES
133+
134+ if settings .RELOCATABLE and settings .INITIAL_TABLE == - 1 :
134135 # When building relocatable output (e.g. MAIN_MODULE) the reported table
135136 # size does not include the reserved slot at zero for the null pointer.
136137 # Instead we use __table_base to offset the elements by 1.
137- if settings .INITIAL_TABLE == - 1 :
138- settings .INITIAL_TABLE = metadata ['tableSize' ] + 1
138+ settings .INITIAL_TABLE = metadata ['tableSize' ] + 1
139139
140140 settings .HAS_MAIN = settings .MAIN_MODULE or settings .STANDALONE_WASM or 'main' in settings .WASM_EXPORTS
141141
@@ -380,6 +380,99 @@ def remove_trailing_zeros(memfile):
380380 f .write (mem_data [:end ])
381381
382382
383+ def read_metadata (wasm_file ):
384+ module = webassembly .Module (wasm_file )
385+ imports = module .imports ()
386+ exports = module .exports ()
387+ globals_ = module .globals ()
388+ num_global_imports = len ([i for i in imports if i .kind == webassembly .ExternType .GLOBAL ])
389+
390+ metadata = {
391+ 'exports' : [],
392+ 'declares' : [],
393+ 'invokeFuncs' : [],
394+ 'namedGlobals' : {},
395+ 'emJsFuncs' : {},
396+ 'asmConsts' : {},
397+ }
398+
399+ em_asm_start = None
400+ em_asm_stop = None
401+
402+ for export in exports :
403+ if export .kind == webassembly .ExternType .FUNC :
404+ metadata ['exports' ].append (export .name )
405+ elif export .kind == webassembly .ExternType .GLOBAL :
406+ assert export .index >= num_global_imports
407+ glob = globals_ [export .index - num_global_imports ]
408+ if export .name == '__start_em_asm' :
409+ em_asm_start = glob
410+ elif export .name == '__stop_em_asm' :
411+ em_asm_stop = glob
412+ else :
413+ metadata ['namedGlobals' ][export .name ] = glob .init [1 ]
414+
415+ if em_asm_start and em_asm_stop :
416+ asm_start = em_asm_start .init [1 ]
417+ asm_stop = em_asm_stop .init [1 ]
418+
419+ def read_asm_strings (seg_data ):
420+ str_start = 0
421+ while str_start < len (seg_data ):
422+ str_end = seg_data .find (b'\0 ' , str_start )
423+ string = seg_data [str_start :str_end ].decode ('utf-8' )
424+ address = asm_start + str_start
425+ metadata ['asmConsts' ][address ] = string
426+ str_start = str_end + 1
427+
428+ asm_len = asm_stop - asm_start
429+ total_offset = 1024
430+ for seg in module .data_segments ():
431+ if seg .init and seg .init [1 ] == asm_start and seg .init [1 ] + len (seg .data ) == asm_stop :
432+ read_asm_strings (seg .data )
433+ break
434+ elif total_offset == asm_start and len (seg .data ) == asm_len :
435+ print ("FOUND" )
436+ read_asm_strings (seg .data )
437+ break
438+ total_offset += len (seg .data )
439+ if not metadata ['asmConsts' ]:
440+ exit_with_error ('em_asm section not found (%s - %s) %d' % (asm_start , asm_stop , asm_len ))
441+
442+ for imp in imports :
443+ if imp .kind == webassembly .ExternType .FUNC :
444+ if imp .field .startswith ('invoke_' ):
445+ metadata ['invokeFuncs' ].append (imp .field )
446+ else :
447+ metadata ['declares' ].append (imp .field )
448+
449+ for sec in module .sections ():
450+ if sec .type == webassembly .SecType .CUSTOM :
451+ sec_name = module .readString ()
452+ if sec_name == 'target_features' :
453+ metadata ['features' ] = []
454+ while module .tell () < sec .offset + sec .size :
455+ state = module .readString ()
456+ name = module .readString ()
457+ if state == '+' :
458+ metadata ['features' ].append ('--enable-' + name )
459+ else :
460+ assert False
461+ break
462+
463+ metadata ['globalImports' ] = [i .field for i in imports if i .kind == webassembly .ExternType .GLOBAL ]
464+ metadata ['mainReadsParams' ] = 1
465+
466+ tables = [i for i in imports if i .kind == webassembly .ExternType .TABLE ]
467+ if tables :
468+ assert len (tables ) == 1
469+ metadata ['tableSize' ] = tables [0 ].info [1 ].initial
470+ else :
471+ metadata ['tableSize' ] = 0
472+
473+ return metadata
474+
475+
383476def finalize_wasm (infile , outfile , memfile , DEBUG ):
384477 building .save_intermediate (infile , 'base.wasm' )
385478 # tell binaryen to look at the features section, and if there isn't one, to use MVP
@@ -435,26 +528,33 @@ def finalize_wasm(infile, outfile, memfile, DEBUG):
435528
436529 if settings .DEBUG_LEVEL >= 3 :
437530 args .append ('--dwarf' )
438- stdout = building .run_binaryen_command ('wasm-emscripten-finalize' ,
439- infile = infile ,
440- outfile = outfile if modify_wasm else None ,
441- args = args ,
442- stdout = subprocess .PIPE )
443- if modify_wasm :
444- building .save_intermediate (infile , 'post_finalize.wasm' )
445- elif infile != outfile :
446- shutil .copy (infile , outfile )
447- if settings .GENERATE_SOURCE_MAP :
448- building .save_intermediate (infile + '.map' , 'post_finalize.map' )
449531
450- if memfile :
451- # we have a separate .mem file. binaryen did not strip any trailing zeros,
452- # because it's an ABI question as to whether it is valid to do so or not.
453- # we can do so here, since we make sure to zero out that memory (even in
454- # the dynamic linking case, our loader zeros it out)
455- remove_trailing_zeros (memfile )
532+ if modify_wasm or settings .GENERATE_SOURCE_MAP or memfile :
533+ stdout = building .run_binaryen_command ('wasm-emscripten-finalize' ,
534+ infile = infile ,
535+ outfile = outfile if modify_wasm else None ,
536+ args = args ,
537+ stdout = subprocess .PIPE )
538+ if modify_wasm :
539+ building .save_intermediate (infile , 'post_finalize.wasm' )
540+ elif infile != outfile :
541+ shutil .copy (infile , outfile )
542+ if settings .GENERATE_SOURCE_MAP :
543+ building .save_intermediate (infile + '.map' , 'post_finalize.map' )
544+
545+ if memfile :
546+ # we have a separate .mem file. binaryen did not strip any trailing zeros,
547+ # because it's an ABI question as to whether it is valid to do so or not.
548+ # we can do so here, since we make sure to zero out that memory (even in
549+ # the dynamic linking case, our loader zeros it out)
550+ remove_trailing_zeros (memfile )
551+
552+ metadata = load_metadata_wasm (stdout , DEBUG )
553+ else :
554+ metadata = read_metadata (infile )
456555
457- return load_metadata_wasm (stdout , DEBUG )
556+ logger .debug ("Metadata parsed: " + pprint .pformat (metadata ))
557+ return metadata
458558
459559
460560def create_asm_consts (metadata ):
@@ -758,7 +858,6 @@ def load_metadata_wasm(metadata_raw, DEBUG):
758858 metadata = {
759859 'declares' : [],
760860 'globalImports' : [],
761- 'staticBump' : 0 ,
762861 'tableSize' : 0 ,
763862 'exports' : [],
764863 'namedGlobals' : {},
@@ -783,9 +882,6 @@ def load_metadata_wasm(metadata_raw, DEBUG):
783882 # TODO(sbc): remove this once binaryen has been changed to only emit the single element
784883 metadata ['asmConsts' ] = {k : v [0 ] if type (v ) is list else v for k , v in metadata ['asmConsts' ].items ()}
785884
786- if DEBUG :
787- logger .debug ("Metadata parsed: " + pprint .pformat (metadata ))
788-
789885 # Calculate the subset of exports that were explicitly marked with llvm.used.
790886 # These are any exports that were not requested on the command line and are
791887 # not known auto-generated system functions.
0 commit comments