예제 #1
0
def emscript(in_wasm, out_wasm, outfile_js, memfile, DEBUG):
    # Overview:
    #   * Run wasm-emscripten-finalize to extract metadata and modify the binary
    #     to use emscripten's wasm<->JS ABI
    #   * Use the metadata to generate the JS glue that goes with the wasm

    if settings.SINGLE_FILE:
        # placeholder strings for JS glue, to be replaced with subresource locations in do_binaryen
        settings.WASM_BINARY_FILE = '<<< WASM_BINARY_FILE >>>'
    else:
        # set file locations, so that JS glue can find what it needs
        settings.WASM_BINARY_FILE = js_manipulation.escape_for_js_string(
            os.path.basename(out_wasm))

    metadata = finalize_wasm(in_wasm, out_wasm, memfile, DEBUG)

    update_settings_glue(metadata, DEBUG)

    if settings.SIDE_MODULE:
        if metadata['asmConsts']:
            exit_with_error('EM_ASM is not supported in side modules')
        if metadata['emJsFuncs']:
            exit_with_error('EM_JS is not supported in side modules')
        logger.debug('emscript: skipping remaining js glue generation')
        return

    if DEBUG:
        logger.debug('emscript: js compiler glue')
        t = time.time()

    # memory and global initializers

    if settings.RELOCATABLE:
        dylink_sec = webassembly.parse_dylink_section(in_wasm)
        static_bump = align_memory(dylink_sec.mem_size)
        set_memory(static_bump)
        logger.debug('stack_base: %d, stack_max: %d, heap_base: %d',
                     settings.STACK_BASE, settings.STACK_MAX,
                     settings.HEAP_BASE)

        # When building relocatable output (e.g. MAIN_MODULE) the reported table
        # size does not include the reserved slot at zero for the null pointer.
        # So we need to offset the elements by 1.
        if settings.INITIAL_TABLE == -1:
            settings.INITIAL_TABLE = dylink_sec.table_size + 1

    glue, forwarded_data = compile_settings()
    if DEBUG:
        logger.debug('  emscript: glue took %s seconds' % (time.time() - t))
        t = time.time()

    forwarded_json = json.loads(forwarded_data)

    pre, post = glue.split('// EMSCRIPTEN_END_FUNCS')

    exports = metadata['exports']

    if settings.ASYNCIFY:
        exports += [
            'asyncify_start_unwind', 'asyncify_stop_unwind',
            'asyncify_start_rewind', 'asyncify_stop_rewind'
        ]

    report_missing_symbols(forwarded_json['libraryFunctions'])

    if not outfile_js:
        logger.debug('emscript: skipping remaining js glue generation')
        return

    if settings.MINIMAL_RUNTIME:
        # In MINIMAL_RUNTIME, atinit exists in the postamble part
        post = apply_static_code_hooks(forwarded_json, post)
    else:
        # In regular runtime, atinits etc. exist in the preamble part
        pre = apply_static_code_hooks(forwarded_json, pre)

    asm_consts = create_asm_consts(metadata)
    em_js_funcs = create_em_js(metadata)
    asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts]
    asm_const_map = 'var ASM_CONSTS = {\n  ' + ',  \n '.join(
        asm_const_pairs) + '\n};\n'
    pre = pre.replace('// === Body ===',
                      ('// === Body ===\n\n' + asm_const_map +
                       '\n'.join(em_js_funcs) + '\n'))

    with open(outfile_js, 'w') as out:
        out.write(normalize_line_endings(pre))
        pre = None

        invoke_funcs = metadata['invokeFuncs']
        sending = create_sending(invoke_funcs, metadata)
        receiving = create_receiving(exports)

        if settings.MINIMAL_RUNTIME:
            if settings.DECLARE_ASM_MODULE_EXPORTS:
                post = compute_minimal_runtime_initializer_and_exports(
                    post, exports, receiving)
            receiving = ''

        module = create_module(sending, receiving, invoke_funcs, metadata)

        write_output_file(out, module)

        out.write(normalize_line_endings(post))
        module = None
예제 #2
0
def emscript(in_wasm, out_wasm, outfile_js, memfile, temp_files, DEBUG):
    # Overview:
    #   * Run wasm-emscripten-finalize to extract metadata and modify the binary
    #     to use emscripten's wasm<->JS ABI
    #   * Use the metadata to generate the JS glue that goes with the wasm

    if shared.Settings.SINGLE_FILE:
        # placeholder strings for JS glue, to be replaced with subresource locations in do_binaryen
        shared.Settings.WASM_BINARY_FILE = '<<< WASM_BINARY_FILE >>>'
    else:
        # set file locations, so that JS glue can find what it needs
        shared.Settings.WASM_BINARY_FILE = shared.JS.escape_for_js_string(
            os.path.basename(out_wasm))

    metadata = finalize_wasm(in_wasm, out_wasm, memfile, DEBUG)

    update_settings_glue(metadata, DEBUG)

    if shared.Settings.SIDE_MODULE:
        logger.debug('emscript: skipping remaining js glue generation')
        return

    if DEBUG:
        logger.debug('emscript: js compiler glue')
        t = time.time()

    glue, forwarded_data = compile_settings(temp_files)
    if DEBUG:
        logger.debug('  emscript: glue took %s seconds' % (time.time() - t))
        t = time.time()

    forwarded_json = json.loads(forwarded_data)
    # For the wasm backend the implementedFunctions from compiler.js should
    # always be empty. This only gets populated for __asm function when using
    # the JS backend.
    assert not forwarded_json['Functions']['implementedFunctions']

    pre, post = glue.split('// EMSCRIPTEN_END_FUNCS')

    exports = metadata['exports']

    if shared.Settings.ASYNCIFY:
        exports += [
            'asyncify_start_unwind', 'asyncify_stop_unwind',
            'asyncify_start_rewind', 'asyncify_stop_rewind'
        ]

    all_exports = exports + list(metadata['namedGlobals'].keys())
    all_exports = set([asmjs_mangle(e) for e in all_exports])
    report_missing_symbols(all_exports, pre)

    if not outfile_js:
        logger.debug('emscript: skipping remaining js glue generation')
        return

    # memory and global initializers

    if shared.Settings.RELOCATABLE:
        static_bump = align_memory(
            webassembly.parse_dylink_section(in_wasm)[0])
        memory = Memory(static_bump)
        logger.debug('stack_base: %d, stack_max: %d, dynamic_base: %d',
                     memory.stack_base, memory.stack_max, memory.dynamic_base)

        pre = apply_memory(pre, memory)
        post = apply_memory(post, memory)

    pre = apply_static_code_hooks(
        pre)  # In regular runtime, atinits etc. exist in the preamble part
    post = apply_static_code_hooks(
        post)  # In MINIMAL_RUNTIME, atinit exists in the postamble part

    # merge forwarded data
    shared.Settings.EXPORTED_FUNCTIONS = forwarded_json['EXPORTED_FUNCTIONS']

    asm_consts = create_asm_consts(metadata)
    em_js_funcs = create_em_js(forwarded_json, metadata)
    asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts]
    asm_const_map = 'var ASM_CONSTS = {\n  ' + ',  \n '.join(
        asm_const_pairs) + '\n};\n'
    pre = pre.replace('// === Body ===',
                      ('// === Body ===\n\n' + asm_const_map +
                       '\n'.join(em_js_funcs) + '\n'))

    with open(outfile_js, 'w') as out:
        out.write(pre)
        pre = None

        invoke_funcs = metadata['invokeFuncs']
        sending = create_sending(invoke_funcs, metadata)
        receiving = create_receiving(exports)

        if shared.Settings.MINIMAL_RUNTIME:
            post = compute_minimal_runtime_initializer_and_exports(
                post, exports, receiving)
            receiving = ''

        module = create_module(sending, receiving, invoke_funcs, metadata)

        write_output_file(out, post, module)
        module = None
예제 #3
0
def emscript(in_wasm, out_wasm, outfile_js, memfile):
    # Overview:
    #   * Run wasm-emscripten-finalize to extract metadata and modify the binary
    #     to use emscripten's wasm<->JS ABI
    #   * Use the metadata to generate the JS glue that goes with the wasm

    if settings.SINGLE_FILE:
        # placeholder strings for JS glue, to be replaced with subresource locations in do_binaryen
        settings.WASM_BINARY_FILE = '<<< WASM_BINARY_FILE >>>'
    else:
        # set file locations, so that JS glue can find what it needs
        settings.WASM_BINARY_FILE = js_manipulation.escape_for_js_string(
            os.path.basename(out_wasm))

    metadata = finalize_wasm(in_wasm, out_wasm, memfile)

    update_settings_glue(out_wasm, metadata)

    if not settings.WASM_BIGINT and metadata['emJsFuncs']:
        module = webassembly.Module(in_wasm)
        types = module.get_types()
        import_map = {}
        for imp in module.get_imports():
            import_map[imp.field] = imp
        for em_js_func, raw in metadata.get('emJsFuncs', {}).items():
            c_sig = raw.split('<::>')[0].strip('()')
            if not c_sig or c_sig == 'void':
                c_sig = []
            else:
                c_sig = c_sig.split(',')
            if em_js_func in import_map:
                imp = import_map[em_js_func]
                assert (imp.kind == webassembly.ExternType.FUNC)
                signature = types[imp.type]
                if len(signature.params) != len(c_sig):
                    diagnostics.warning(
                        'em-js-i64',
                        'using 64-bit arguments in EM_JS function without WASM_BIGINT is not yet fully supported: `%s` (%s, %s)',
                        em_js_func, c_sig, signature.params)

    if settings.SIDE_MODULE:
        if metadata['asmConsts']:
            exit_with_error('EM_ASM is not supported in side modules')
        if metadata['emJsFuncs']:
            exit_with_error('EM_JS is not supported in side modules')
        logger.debug('emscript: skipping remaining js glue generation')
        return

    if DEBUG:
        logger.debug('emscript: js compiler glue')
        t = time.time()

    # memory and global initializers

    if settings.RELOCATABLE:
        dylink_sec = webassembly.parse_dylink_section(in_wasm)
        static_bump = align_memory(dylink_sec.mem_size)
        set_memory(static_bump)
        logger.debug('stack_base: %d, stack_max: %d, heap_base: %d',
                     settings.STACK_BASE, settings.STACK_MAX,
                     settings.HEAP_BASE)

        # When building relocatable output (e.g. MAIN_MODULE) the reported table
        # size does not include the reserved slot at zero for the null pointer.
        # So we need to offset the elements by 1.
        if settings.INITIAL_TABLE == -1:
            settings.INITIAL_TABLE = dylink_sec.table_size + 1

        if settings.ASYNCIFY:
            metadata['globalImports'] += [
                '__asyncify_state', '__asyncify_data'
            ]

    invoke_funcs = metadata['invokeFuncs']
    if invoke_funcs:
        settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['$getWasmTableEntry']

    glue, forwarded_data = compile_settings()
    if DEBUG:
        logger.debug('  emscript: glue took %s seconds' % (time.time() - t))
        t = time.time()

    forwarded_json = json.loads(forwarded_data)

    if forwarded_json['warnings']:
        diagnostics.warning('js-compiler',
                            'warnings in JS library compilation')

    pre, post = glue.split('// EMSCRIPTEN_END_FUNCS')

    if settings.ASSERTIONS:
        pre += "function checkIncomingModuleAPI() {\n"
        for sym in settings.ALL_INCOMING_MODULE_JS_API:
            if sym not in settings.INCOMING_MODULE_JS_API:
                pre += f"  ignoredModuleProp('{sym}');\n"
        pre += "}\n"

    exports = metadata['exports']

    if settings.ASYNCIFY:
        exports += [
            'asyncify_start_unwind', 'asyncify_stop_unwind',
            'asyncify_start_rewind', 'asyncify_stop_rewind'
        ]

    report_missing_symbols(forwarded_json['librarySymbols'])

    if not outfile_js:
        logger.debug('emscript: skipping remaining js glue generation')
        return

    if settings.MINIMAL_RUNTIME:
        # In MINIMAL_RUNTIME, atinit exists in the postamble part
        post = apply_static_code_hooks(forwarded_json, post)
    else:
        # In regular runtime, atinits etc. exist in the preamble part
        pre = apply_static_code_hooks(forwarded_json, pre)

    asm_consts = create_asm_consts(metadata)
    em_js_funcs = create_em_js(metadata)
    asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts]
    asm_const_map = 'var ASM_CONSTS = {\n  ' + ',  \n '.join(
        asm_const_pairs) + '\n};\n'
    pre = pre.replace('// === Body ===',
                      ('// === Body ===\n\n' + asm_const_map +
                       '\n'.join(em_js_funcs) + '\n'))

    with open(outfile_js, 'w', encoding='utf-8') as out:
        out.write(normalize_line_endings(pre))
        pre = None

        sending = create_sending(invoke_funcs, metadata)
        receiving = create_receiving(exports)

        if settings.MINIMAL_RUNTIME:
            if settings.DECLARE_ASM_MODULE_EXPORTS:
                post = compute_minimal_runtime_initializer_and_exports(
                    post, exports, receiving)
            receiving = ''

        module = create_module(sending, receiving, invoke_funcs, metadata)

        write_output_file(out, module)

        out.write(normalize_line_endings(post))
        module = None
예제 #4
0
def emscript(infile, outfile_js, memfile, temp_files, DEBUG):
    # Overview:
    #   * Run wasm-emscripten-finalize to extract metadata and modify the binary
    #     to use emscripten's wasm<->JS ABI
    #   * Use the metadata to generate the JS glue that goes with the wasm

    metadata = finalize_wasm(infile, memfile, DEBUG)

    update_settings_glue(metadata, DEBUG)

    if not outfile_js:
        logger.debug('emscript: skipping js compiler glue')
        return

    if DEBUG:
        logger.debug('emscript: js compiler glue')

    if DEBUG:
        t = time.time()
    glue, forwarded_data = compile_settings(temp_files)
    if DEBUG:
        logger.debug('  emscript: glue took %s seconds' % (time.time() - t))
        t = time.time()

    forwarded_json = json.loads(forwarded_data)
    # For the wasm backend the implementedFunctions from compiler.js should
    # always be empty. This only gets populated for __asm function when using
    # the JS backend.
    assert not forwarded_json['Functions']['implementedFunctions']

    pre, post = glue.split('// EMSCRIPTEN_END_FUNCS')

    # memory and global initializers

    # In minimal runtime, global initializers are run after the Wasm Module instantiation has finished.
    if not shared.Settings.MINIMAL_RUNTIME:
        global_initializers = ', '.join('{ func: function() { %s() } }' % i
                                        for i in metadata['initializers'])
        # In regular runtime, global initializers are recorded in an __ATINIT__ array.
        global_initializers = '__ATINIT__.push(%s);' % global_initializers
        if shared.Settings.USE_PTHREADS:
            global_initializers = 'if (!ENVIRONMENT_IS_PTHREAD) ' + global_initializers

        pre += '\n' + global_initializers + '\n'

    if shared.Settings.RELOCATABLE:
        static_bump = align_memory(webassembly.parse_dylink_section(infile)[0])
        memory = Memory(static_bump)
        logger.debug('stack_base: %d, stack_max: %d, dynamic_base: %d',
                     memory.stack_base, memory.stack_max, memory.dynamic_base)

        pre = apply_memory(pre, memory)
        post = apply_memory(post, memory)

    pre = apply_static_code_hooks(
        pre)  # In regular runtime, atinits etc. exist in the preamble part
    post = apply_static_code_hooks(
        post)  # In MINIMAL_RUNTIME, atinit exists in the postamble part

    # merge forwarded data
    shared.Settings.EXPORTED_FUNCTIONS = forwarded_json['EXPORTED_FUNCTIONS']

    exports = metadata['exports']

    # Store exports for Closure compiler to be able to track these as globals in
    # -s DECLARE_ASM_MODULE_EXPORTS=0 builds.
    shared.Settings.MODULE_EXPORTS = [(asmjs_mangle(f), f) for f in exports]

    if shared.Settings.ASYNCIFY:
        exports += [
            'asyncify_start_unwind', 'asyncify_stop_unwind',
            'asyncify_start_rewind', 'asyncify_stop_rewind'
        ]

    all_exports = exports + list(metadata['namedGlobals'].keys())
    all_exports = set([asmjs_mangle(e) for e in all_exports])
    report_missing_symbols(all_exports, pre)

    asm_consts = create_asm_consts(metadata)
    em_js_funcs = create_em_js(forwarded_json, metadata)
    asm_const_pairs = ['%s: %s' % (key, value) for key, value in asm_consts]
    asm_const_map = 'var ASM_CONSTS = {\n  ' + ',  \n '.join(
        asm_const_pairs) + '\n};\n'
    pre = pre.replace('// === Body ===',
                      ('// === Body ===\n\n' + asm_const_map +
                       '\n'.join(em_js_funcs) + '\n'))

    with open(outfile_js, 'w') as out:
        out.write(pre)
        pre = None

        invoke_funcs = metadata['invokeFuncs']
        sending = create_sending(invoke_funcs, metadata)
        receiving = create_receiving(exports, metadata['initializers'])

        if shared.Settings.MINIMAL_RUNTIME:
            post = compute_minimal_runtime_initializer_and_exports(
                post, metadata['initializers'], exports, receiving)
            receiving = ''

        module = create_module(sending, receiving, invoke_funcs, metadata)

        write_output_file(out, post, module)
        module = None
예제 #5
0
def get_weak_imports(main_wasm):
    dylink_sec = webassembly.parse_dylink_section(main_wasm)
    for symbols in dylink_sec.import_info.values():
        for symbol, flags in symbols.items():
            if flags & webassembly.SYMBOL_BINDING_MASK == webassembly.SYMBOL_BINDING_WEAK:
                settings.WEAK_IMPORTS.append(symbol)