From 8c188686b35b26cd215ddca2b78076810fea4b2d Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 15:33:26 -0700 Subject: [PATCH 01/31] wip move code behind CUSTOM_CORE_JS --- src/preamble.js | 314 ++++++++++++++++++++++++------------------------ src/settings.js | 11 ++ src/shell.js | 3 + 3 files changed, 173 insertions(+), 155 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index afb3658035774..2e59c68dc817e 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -88,13 +88,6 @@ function ftfault() { } #endif -//======================================== -// Runtime essentials -//======================================== - -var ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort() -var EXITSTATUS = 0; - /** @type {function(*, string=)} */ function assert(condition, text) { if (!condition) { @@ -843,13 +836,6 @@ function stackTrace() { return demangleAll(js); } -// Memory management - -var PAGE_SIZE = 16384; -var WASM_PAGE_SIZE = 65536; -var ASMJS_PAGE_SIZE = 16777216; -var MIN_TOTAL_MEMORY = 16777216; - function alignUp(x, multiple) { if (x % multiple > 0) { x += multiple - (x % multiple); @@ -857,7 +843,7 @@ function alignUp(x, multiple) { return x; } -var HEAP, +var /** @type {ArrayBuffer} */ buffer, /** @type {Int8Array} */ @@ -896,24 +882,6 @@ var STATIC_BASE, STATICTOP, staticSealed; // static area var STACK_BASE, STACKTOP, STACK_MAX; // stack area var DYNAMIC_BASE, DYNAMICTOP_PTR; // dynamic area handled by sbrk -#if USE_PTHREADS -if (!ENVIRONMENT_IS_PTHREAD) { // Pthreads have already initialized these variables in src/pthread-main.js, where they were passed to the thread worker at startup time -#endif - STATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0; - staticSealed = false; -#if USE_PTHREADS -} -#endif - -#if USE_PTHREADS -if (ENVIRONMENT_IS_PTHREAD) { - staticSealed = true; // The static memory area has been initialized already in the main thread, pthreads skip this. -#if SEPARATE_ASM != 0 - importScripts('{{{ SEPARATE_ASM }}}'); // load the separated-out asm.js -#endif -} -#endif - #if STACK_OVERFLOW_CHECK // Initializes the stack cookie. Called at the startup of main and at the startup of each thread in pthreads mode. function writeStackCookie() { @@ -1055,6 +1023,7 @@ function enlargeMemory() { #endif // USE_PTHREADS } +#if WASM == 0 #if ALLOW_MEMORY_GROWTH var byteLength; try { @@ -1063,11 +1032,8 @@ try { } catch(e) { // can fail on older node/v8 byteLength = function(buffer) { return buffer.byteLength; }; } -#endif - -var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}}; -var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; -if (TOTAL_MEMORY < TOTAL_STACK) err('TOTAL_MEMORY should be larger than TOTAL_STACK, was ' + TOTAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')'); +#endif // ALLOW_MEMORY_GROWTH +#endif // WASM == 0 // Initialize the runtime's memory #if ASSERTIONS @@ -1094,9 +1060,161 @@ if (typeof SharedArrayBuffer === 'undefined' || typeof Atomics === 'undefined') xhr.send(); setTimeout(function() { window.close() }, 2000); } +#endif // USE_PTHREADS == 1 +#endif // IN_TEST_HARNESS + +function getTotalMemory() { + return TOTAL_MEMORY; +} + +// Deprecated: This function should not be called because it is unsafe and does not provide +// a maximum length limit of how many bytes it is allowed to write. Prefer calling the +// function stringToUTF8Array() instead, which takes in a maximum length that can be used +// to be secure from out of bounds writes. +/** @deprecated */ +function writeStringToMemory(string, buffer, dontAddNull) { + warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); + + var /** @type {number} */ lastChar, /** @type {number} */ end; + if (dontAddNull) { + // stringToUTF8Array always appends null. If we don't want to do that, remember the + // character that existed at the location where the null will be placed, and restore + // that after the write (below). + end = buffer + lengthBytesUTF8(string); + lastChar = HEAP8[end]; + } + stringToUTF8(string, buffer, Infinity); + if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. +} + +function writeArrayToMemory(array, buffer) { +#if ASSERTIONS + assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') +#endif + HEAP8.set(array, buffer); +} + +function writeAsciiToMemory(str, buffer, dontAddNull) { + for (var i = 0; i < str.length; ++i) { +#if ASSERTIONS + assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff); +#endif + {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; + } + // Null-terminate the pointer to the HEAP. + if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; +} + +{{{ unSign }}} +{{{ reSign }}} + +#if LEGACY_VM_SUPPORT +// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 ) +if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) { + var ah = a >>> 16; + var al = a & 0xffff; + var bh = b >>> 16; + var bl = b & 0xffff; + return (al*bl + ((ah*bl + al*bh) << 16))|0; +}; +Math.imul = Math['imul']; + +#if PRECISE_F32 +#if PRECISE_F32 == 1 +if (!Math['fround']) { + var froundBuffer = new Float32Array(1); + Math['fround'] = function(x) { froundBuffer[0] = x; return froundBuffer[0] }; +} +#else // 2 +if (!Math['fround']) Math['fround'] = function(x) { return x }; +#endif +Math.fround = Math['fround']; +#else +#if SIMD +if (!Math['fround']) Math['fround'] = function(x) { return x }; +#endif +#endif + +if (!Math['clz32']) Math['clz32'] = function(x) { + x = x >>> 0; + for (var i = 0; i < 32; i++) { + if (x & (1 << (31 - i))) return i; + } + return 32; +}; +Math.clz32 = Math['clz32'] + +if (!Math['trunc']) Math['trunc'] = function(x) { + return x < 0 ? Math.ceil(x) : Math.floor(x); +}; +Math.trunc = Math['trunc']; +#else // LEGACY_VM_SUPPORT +#if ASSERTIONS +assert(Math['imul'] && Math['fround'] && Math['clz32'] && Math['trunc'], 'this is a legacy browser, build with LEGACY_VM_SUPPORT'); +#endif +#endif // LEGACY_VM_SUPPORT + +var Math_abs = Math.abs; +var Math_cos = Math.cos; +var Math_sin = Math.sin; +var Math_tan = Math.tan; +var Math_acos = Math.acos; +var Math_asin = Math.asin; +var Math_atan = Math.atan; +var Math_atan2 = Math.atan2; +var Math_exp = Math.exp; +var Math_log = Math.log; +var Math_sqrt = Math.sqrt; +var Math_ceil = Math.ceil; +var Math_floor = Math.floor; +var Math_pow = Math.pow; +var Math_imul = Math.imul; +var Math_fround = Math.fround; +var Math_round = Math.round; +var Math_min = Math.min; +var Math_max = Math.max; +var Math_clz32 = Math.clz32; +var Math_trunc = Math.trunc; + +#include "URIUtils.js" + +#if CUSTOM_CORE_JS +setup(); +#else // CUSTOM_CORE_JS + + +var ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort() +var EXITSTATUS = 0; + +// Memory management + +var PAGE_SIZE = 16384; +var WASM_PAGE_SIZE = 65536; +var ASMJS_PAGE_SIZE = 16777216; +var MIN_TOTAL_MEMORY = 16777216; + +#if USE_PTHREADS +if (!ENVIRONMENT_IS_PTHREAD) { // Pthreads have already initialized these variables in src/pthread-main.js, where they were passed to the thread worker at startup time +#endif + STATIC_BASE = STATICTOP = STACK_BASE = STACKTOP = STACK_MAX = DYNAMIC_BASE = DYNAMICTOP_PTR = 0; + staticSealed = false; +#if USE_PTHREADS +} +#endif + +#if USE_PTHREADS +if (ENVIRONMENT_IS_PTHREAD) { + staticSealed = true; // The static memory area has been initialized already in the main thread, pthreads skip this. +#if SEPARATE_ASM != 0 + importScripts('{{{ SEPARATE_ASM }}}'); // load the separated-out asm.js #endif +} #endif +var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}}; +var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}}; +if (TOTAL_MEMORY < TOTAL_STACK) err('TOTAL_MEMORY should be larger than TOTAL_STACK, was ' + TOTAL_MEMORY + '! (TOTAL_STACK=' + TOTAL_STACK + ')'); + #if USE_PTHREADS #if !WASM if (typeof SharedArrayBuffer !== 'undefined') { @@ -1485,10 +1603,6 @@ function setF64(ptr, value) { #endif // USE_PTHREADS -function getTotalMemory() { - return TOTAL_MEMORY; -} - // Endianness check (note: assumes compiler arch was little-endian) #if SAFE_SPLIT_MEMORY == 0 #if STACK_OVERFLOW_CHECK @@ -1629,115 +1743,6 @@ function addOnPostRun(cb) { __ATPOSTRUN__.unshift(cb); } -// Deprecated: This function should not be called because it is unsafe and does not provide -// a maximum length limit of how many bytes it is allowed to write. Prefer calling the -// function stringToUTF8Array() instead, which takes in a maximum length that can be used -// to be secure from out of bounds writes. -/** @deprecated */ -function writeStringToMemory(string, buffer, dontAddNull) { - warnOnce('writeStringToMemory is deprecated and should not be called! Use stringToUTF8() instead!'); - - var /** @type {number} */ lastChar, /** @type {number} */ end; - if (dontAddNull) { - // stringToUTF8Array always appends null. If we don't want to do that, remember the - // character that existed at the location where the null will be placed, and restore - // that after the write (below). - end = buffer + lengthBytesUTF8(string); - lastChar = HEAP8[end]; - } - stringToUTF8(string, buffer, Infinity); - if (dontAddNull) HEAP8[end] = lastChar; // Restore the value under the null character. -} - -function writeArrayToMemory(array, buffer) { -#if ASSERTIONS - assert(array.length >= 0, 'writeArrayToMemory array must have a length (should be an array or typed array)') -#endif - HEAP8.set(array, buffer); -} - -function writeAsciiToMemory(str, buffer, dontAddNull) { - for (var i = 0; i < str.length; ++i) { -#if ASSERTIONS - assert(str.charCodeAt(i) === str.charCodeAt(i)&0xff); -#endif - {{{ makeSetValue('buffer++', 0, 'str.charCodeAt(i)', 'i8') }}}; - } - // Null-terminate the pointer to the HEAP. - if (!dontAddNull) {{{ makeSetValue('buffer', 0, 0, 'i8') }}}; -} - -{{{ unSign }}} -{{{ reSign }}} - -#if LEGACY_VM_SUPPORT -// check for imul support, and also for correctness ( https://bugs.webkit.org/show_bug.cgi?id=126345 ) -if (!Math['imul'] || Math['imul'](0xffffffff, 5) !== -5) Math['imul'] = function imul(a, b) { - var ah = a >>> 16; - var al = a & 0xffff; - var bh = b >>> 16; - var bl = b & 0xffff; - return (al*bl + ((ah*bl + al*bh) << 16))|0; -}; -Math.imul = Math['imul']; - -#if PRECISE_F32 -#if PRECISE_F32 == 1 -if (!Math['fround']) { - var froundBuffer = new Float32Array(1); - Math['fround'] = function(x) { froundBuffer[0] = x; return froundBuffer[0] }; -} -#else // 2 -if (!Math['fround']) Math['fround'] = function(x) { return x }; -#endif -Math.fround = Math['fround']; -#else -#if SIMD -if (!Math['fround']) Math['fround'] = function(x) { return x }; -#endif -#endif - -if (!Math['clz32']) Math['clz32'] = function(x) { - x = x >>> 0; - for (var i = 0; i < 32; i++) { - if (x & (1 << (31 - i))) return i; - } - return 32; -}; -Math.clz32 = Math['clz32'] - -if (!Math['trunc']) Math['trunc'] = function(x) { - return x < 0 ? Math.ceil(x) : Math.floor(x); -}; -Math.trunc = Math['trunc']; -#else // LEGACY_VM_SUPPORT -#if ASSERTIONS -assert(Math['imul'] && Math['fround'] && Math['clz32'] && Math['trunc'], 'this is a legacy browser, build with LEGACY_VM_SUPPORT'); -#endif -#endif // LEGACY_VM_SUPPORT - -var Math_abs = Math.abs; -var Math_cos = Math.cos; -var Math_sin = Math.sin; -var Math_tan = Math.tan; -var Math_acos = Math.acos; -var Math_asin = Math.asin; -var Math_atan = Math.atan; -var Math_atan2 = Math.atan2; -var Math_exp = Math.exp; -var Math_log = Math.log; -var Math_sqrt = Math.sqrt; -var Math_ceil = Math.ceil; -var Math_floor = Math.floor; -var Math_pow = Math.pow; -var Math_imul = Math.imul; -var Math_fround = Math.fround; -var Math_round = Math.round; -var Math_min = Math.min; -var Math_max = Math.max; -var Math_clz32 = Math.clz32; -var Math_trunc = Math.trunc; - // A counter of dependencies for calling run(). If we need to // do asynchronous work before running, increment this and // decrement it. Incrementing must happen in a place like @@ -1985,8 +1990,6 @@ Module['FS_createPreloadedFile'] = FS.createPreloadedFile; var cyberDWARFFile = '{{{ BUNDLED_CD_DEBUG_FILE }}}'; #endif -#include "URIUtils.js" - #if WASM function integrateWasmJS() { // wasm.js has several methods for creating the compiled code module here: @@ -2485,6 +2488,7 @@ function integrateWasmJS() { } integrateWasmJS(); -#endif +#endif // WASM + +#endif // CUSTOM_CORE_JS -// === Body === diff --git a/src/settings.js b/src/settings.js index 84dfe03432c6b..4ae6a905232e8 100644 --- a/src/settings.js +++ b/src/settings.js @@ -483,6 +483,17 @@ var INCLUDE_FULL_LIBRARY = 0; // Include all JS library functions instead of the // need to use those in the main file too to pull in malloc // for use by the module. +var CUSTOM_CORE_JS = ''; // Setting this will include the contents of that .js file instead + // of shell.js, and will prevent emitting the setup/startup code + // in preamble.js and postamble.js. The custom core JS should + // instead set up the environment itself, and implement the + // functionality you want, which should include + // setup() - called early, to set up memory etc. + // startup(env) - called after the JS library is set up, with + // the wasm imports as a parameter. This + // function should handle creating and running + // the wasm. + var SHELL_FILE = 0; // set this to a string to override the shell file used var RELOCATABLE = 0; // If set to 1, we emit relocatable code from the LLVM backend; both diff --git a/src/shell.js b/src/shell.js index 66bd75be99fad..e72b3f0d971eb 100644 --- a/src/shell.js +++ b/src/shell.js @@ -21,6 +21,7 @@ var Module = typeof {{{ EXPORT_NAME }}} !== 'undefined' ? {{{ EXPORT_NAME }}} : #endif // USE_CLOSURE_COMPILER #endif // SIDE_MODULE +#if !CUSTOM_CORE_JS // --pre-jses are emitted after the Module integration code, so that they can // refer to Module (if they choose; they can also define Module) // {{PRE_JSES}} @@ -312,6 +313,8 @@ for (key in moduleOverrides) { // reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. moduleOverrides = undefined; +#endif //!CUSTOM_CORE_JS + {{BODY}} // {{MODULE_ADDITIONS}} From 16e41354fd86c17a56623719d91326ed19ff46ef Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 15:36:10 -0700 Subject: [PATCH 02/31] wip more custom-core-js --- src/jsifier.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 8c69971df13c2..9892ed5a559e0 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -70,6 +70,7 @@ function JSify(data, functionsOnly) { var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[0], shellFile))); + if (CUSTOM_CORE_JS) print(read(CUSTOM_CORE_JS)); var pre; if (BUILD_AS_SHARED_LIB || SIDE_MODULE) { pre = processMacros(preprocess(read('preamble_sharedlib.js'), 'preamble_sharedlib.js')); @@ -589,12 +590,12 @@ function JSify(data, functionsOnly) { print(read('deterministic.js')); } - var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js'; - var postParts = processMacros(preprocess(read(postFile), postFile)).split('{{GLOBAL_VARS}}'); - print(postParts[0]); - - print(postParts[1]); - + if (!CUSTOM_CORE_JS) { + var postFile = BUILD_AS_SHARED_LIB || SIDE_MODULE ? 'postamble_sharedlib.js' : 'postamble.js'; + var postParts = processMacros(preprocess(read(postFile), postFile)).split('{{GLOBAL_VARS}}'); + print(postParts[0]); + print(postParts[1]); + } var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[1], shellFile))); // Print out some useful metadata From 2095b19e001ebbe5051ded9ceae7bb01b20ce936 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 15:54:39 -0700 Subject: [PATCH 03/31] wip [ci skip] --- emscripten.py | 4 ++-- src/jsifier.js | 2 +- src/modules.js | 1 + src/postamble.js | 36 ------------------------------------ src/preamble.js | 35 +++++++++++++++++++++++++++++++++++ src/settings.js | 2 +- 6 files changed, 40 insertions(+), 40 deletions(-) diff --git a/emscripten.py b/emscripten.py index 4ab212550d9d8..0b56dac01ee0d 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1251,7 +1251,7 @@ def create_basic_funcs(function_table_sigs, settings): def create_basic_vars(exported_implemented_functions, forwarded_json, metadata, settings): - basic_vars = ['DYNAMICTOP_PTR', 'tempDoublePtr', 'ABORT'] + basic_vars = ['DYNAMICTOP_PTR', 'tempDoublePtr'] if not (settings['WASM'] and settings['SIDE_MODULE']): basic_vars += ['STACKTOP', 'STACK_MAX'] if settings['RELOCATABLE']: @@ -1982,7 +1982,7 @@ def create_sending_wasm(invoke_funcs, jscall_sigs, forwarded_json, metadata, if settings['SAFE_HEAP']: basic_funcs += ['segfault', 'alignfault'] - basic_vars = ['STACKTOP', 'STACK_MAX', 'DYNAMICTOP_PTR', 'ABORT'] + basic_vars = ['STACKTOP', 'STACK_MAX', 'DYNAMICTOP_PTR'] if not settings['RELOCATABLE']: global_vars = metadata['externs'] diff --git a/src/jsifier.js b/src/jsifier.js index 9892ed5a559e0..01d69125584b9 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -527,7 +527,7 @@ function JSify(data, functionsOnly) { legalizedI64s = legalizedI64sDefault; - if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE) { + if (!BUILD_AS_SHARED_LIB && !SIDE_MODULE && !CUSTOM_CORE_JS) { if (USE_PTHREADS) { print('\n // proxiedFunctionTable specifies the list of functions that can be called either synchronously or asynchronously from other threads in postMessage()d or internally queued events. This way a pthread in a Worker can synchronously access e.g. the DOM on the main thread.') print('\nvar proxiedFunctionTable = [' + proxiedFunctionTable.join() + '];\n'); diff --git a/src/modules.js b/src/modules.js index 407172bc000f1..b6430443bae00 100644 --- a/src/modules.js +++ b/src/modules.js @@ -408,6 +408,7 @@ function exportRuntime() { 'establishStackSpace', 'print', 'printErr', + 'abort', ]; if (SUPPORT_BASE64_EMBEDDING) { runtimeElements.push('intArrayFromBase64'); diff --git a/src/postamble.js b/src/postamble.js index f81ef5fc67098..016adfbdfdcb6 100644 --- a/src/postamble.js +++ b/src/postamble.js @@ -403,42 +403,6 @@ function exit(status, implicit) { Module['quit'](status, new ExitStatus(status)); } -var abortDecorators = []; - -function abort(what) { - if (Module['onAbort']) { - Module['onAbort'](what); - } - -#if USE_PTHREADS - if (ENVIRONMENT_IS_PTHREAD) console.error('Pthread aborting at ' + new Error().stack); -#endif - if (what !== undefined) { - out(what); - err(what); - what = JSON.stringify(what) - } else { - what = ''; - } - - ABORT = true; - EXITSTATUS = 1; - -#if ASSERTIONS == 0 - throw 'abort(' + what + '). Build with -s ASSERTIONS=1 for more info.'; -#else - var extra = ''; - var output = 'abort(' + what + ') at ' + stackTrace() + extra; - if (abortDecorators) { - abortDecorators.forEach(function(decorator) { - output = decorator(output, what); - }); - } - throw output; -#endif // ASSERTIONS -} -Module['abort'] = abort; - // {{PRE_RUN_ADDITIONS}} if (Module['preInit']) { diff --git a/src/preamble.js b/src/preamble.js index 2e59c68dc817e..04ba6f0278d62 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -1176,6 +1176,41 @@ var Math_max = Math.max; var Math_clz32 = Math.clz32; var Math_trunc = Math.trunc; +var abortDecorators = []; + +function abort(what) { + if (Module['onAbort']) { + Module['onAbort'](what); + } + +#if USE_PTHREADS + if (ENVIRONMENT_IS_PTHREAD) console.error('Pthread aborting at ' + new Error().stack); +#endif + if (what !== undefined) { + out(what); + err(what); + what = JSON.stringify(what) + } else { + what = ''; + } + + ABORT = true; + EXITSTATUS = 1; + +#if ASSERTIONS == 0 + throw 'abort(' + what + '). Build with -s ASSERTIONS=1 for more info.'; +#else + var extra = ''; + var output = 'abort(' + what + ') at ' + stackTrace() + extra; + if (abortDecorators) { + abortDecorators.forEach(function(decorator) { + output = decorator(output, what); + }); + } + throw output; +#endif // ASSERTIONS +} + #include "URIUtils.js" #if CUSTOM_CORE_JS diff --git a/src/settings.js b/src/settings.js index 4ae6a905232e8..5d5f03f4517e8 100644 --- a/src/settings.js +++ b/src/settings.js @@ -492,7 +492,7 @@ var CUSTOM_CORE_JS = ''; // Setting this will include the contents of that .js f // startup(env) - called after the JS library is set up, with // the wasm imports as a parameter. This // function should handle creating and running - // the wasm. + // the wasm. XXX or define Module['asm'] var SHELL_FILE = 0; // set this to a string to override the shell file used From fd335a522b818ffa5d1a6d8bb424b834c82a1fe3 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 19:02:53 -0700 Subject: [PATCH 04/31] more [ci skip] --- emscripten.py | 19 ++++++++++++++++++- src/preamble.js | 8 +++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/emscripten.py b/emscripten.py index 0b56dac01ee0d..d12e2da24e860 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1157,7 +1157,20 @@ def table_size(table): return table_contents.count(',') + 1 table_total_size = sum(map(table_size, list(function_table_data.values()))) - asm_setup += "\nModule['wasmTableSize'] = %d;\n" % table_total_size + if not settings['CUSTOM_CORE_JS']: + asm_setup += "\nModule['wasmTableSize'] = %d;\n" % table_total_size + else: + asm_setup += ''' +var setupInfo = setup({ + memorySize: %d / WASM_PAGE_SIZE, + tableSize: %d, +}); +var DYNAMICTOP_PTR = setupInfo.sbrkPtr; +var DYNAMICTOP = setupInfo.sbrkStart; +var STACKTOP = setupInfo.stackStart; +var STACK_MAX = setupInfo.stackMax; + +''' % (settings['TOTAL_MEMORY'], table_total_size) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size if settings['RELOCATABLE']: @@ -1327,6 +1340,8 @@ def create_the_global(metadata, settings): def create_receiving(function_table_data, function_tables_defs, exported_implemented_functions, settings): + if settings['CUSTOM_CORE_JS']: + return '' receiving = '' if not settings['ASSERTIONS']: runtime_assertions = '' @@ -2002,6 +2017,8 @@ def math_fix(g): def create_receiving_wasm(exported_implemented_functions, settings): + if settings['CUSTOM_CORE_JS']: + return '' receiving = '' if settings['ASSERTIONS']: # assert on the runtime being in a valid state when calling into compiled code. The only exceptions are diff --git a/src/preamble.js b/src/preamble.js index 04ba6f0278d62..15d43eaa53735 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -1211,12 +1211,11 @@ function abort(what) { #endif // ASSERTIONS } -#include "URIUtils.js" +var WASM_PAGE_SIZE = 65536; -#if CUSTOM_CORE_JS -setup(); -#else // CUSTOM_CORE_JS +#include "URIUtils.js" +#if !CUSTOM_CORE_JS var ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort() var EXITSTATUS = 0; @@ -1224,7 +1223,6 @@ var EXITSTATUS = 0; // Memory management var PAGE_SIZE = 16384; -var WASM_PAGE_SIZE = 65536; var ASMJS_PAGE_SIZE = 16777216; var MIN_TOTAL_MEMORY = 16777216; From d106d56ff7354334748252a55500a236edf74325 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 19:07:59 -0700 Subject: [PATCH 05/31] almost prints hello world [ci skip] --- emscripten.py | 10 ++++++- waka.js | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 waka.js diff --git a/emscripten.py b/emscripten.py index d12e2da24e860..fd11ec8e2f32b 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1169,7 +1169,15 @@ def table_size(table): var DYNAMICTOP = setupInfo.sbrkStart; var STACKTOP = setupInfo.stackStart; var STACK_MAX = setupInfo.stackMax; - +var buffer = memory.buffer; +var HEAP8 = new Int8Array(buffer); +var HEAP16 = new Int16Array(buffer); +var HEAP32 = new Int32Array(buffer); +var HEAPU8 = new Uint8Array(buffer); +var HEAPU16 = new Uint16Array(buffer); +var HEAPU32 = new Uint32Array(buffer); +var HEAPF32 = new Float32Array(buffer); +var HEAPF64 = new Float64Array(buffer); ''' % (settings['TOTAL_MEMORY'], table_total_size) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size diff --git a/waka.js b/waka.js new file mode 100644 index 0000000000000..9d7f87fe4d238 --- /dev/null +++ b/waka.js @@ -0,0 +1,73 @@ + +// Environment setup + +function out(x) { + console.log(x); +} + +function err(x) { + console.warn(x); +} + +// Set up memory and table + +var memory, table; + +function setup(info) { + memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); + table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); + var sbrkStart = 2048; + var sbrkPtr = 16; + (new Int32Array(memory.buffer))[sbrkPtr >> 2] = sbrkStart; + return { + memory: memory, + table: table, + stackStart: 1024, + stackMax: 2048, + sbrkStart: sbrkStart, + sbrkPtr: sbrkPtr, + }; +} + +// Compile and run + +Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but various parsing codes... + console.log('asm1'); + env.memory = memory; + env.table = table; + env.memoryBase = 0; + env.tableBase = 0; + var info = { + 'env': env, + 'global': { // XXX + 'NaN': NaN, + 'Infinity': Infinity + } + }; + fetch('b.wasm', { credentials: 'same-origin' }) + .then(function(response) { + console.log('asm2'); + return response.arrayBuffer(); + }) + .then(function(arrayBuffer) { + console.log('asm3'); + return new Uint8Array(arrayBuffer); + }) + .then(function(binary) { + console.log('asm4'); + console.log(info); + return WebAssembly.instantiate(binary, info); + }) + .then(function(pair) { + console.log('asm5'); + var instance = pair.instance; + var exports = instance.exports; + console.log(exports); + console.log(exports._main()); + }); +} + +// XXX fix these + +var __ATINIT__ = []; + From d8089ed5929919d405fc410f1f2b632bd0f133d0 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Fri, 29 Jun 2018 20:30:19 -0700 Subject: [PATCH 06/31] hello world works hurrah [ci skip] --- emscripten.py | 6 ++++-- waka.js | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/emscripten.py b/emscripten.py index fd11ec8e2f32b..8a94cd2a55c61 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1164,11 +1164,13 @@ def table_size(table): var setupInfo = setup({ memorySize: %d / WASM_PAGE_SIZE, tableSize: %d, + staticStart: %d, + staticSize: STATIC_BUMP, }); var DYNAMICTOP_PTR = setupInfo.sbrkPtr; var DYNAMICTOP = setupInfo.sbrkStart; var STACKTOP = setupInfo.stackStart; -var STACK_MAX = setupInfo.stackMax; +var STACK_MAX = STACKTOP + %d; var buffer = memory.buffer; var HEAP8 = new Int8Array(buffer); var HEAP16 = new Int16Array(buffer); @@ -1178,7 +1180,7 @@ def table_size(table): var HEAPU32 = new Uint32Array(buffer); var HEAPF32 = new Float32Array(buffer); var HEAPF64 = new Float64Array(buffer); -''' % (settings['TOTAL_MEMORY'], table_total_size) +''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size if settings['RELOCATABLE']: diff --git a/waka.js b/waka.js index 9d7f87fe4d238..f5cb980f7b8f8 100644 --- a/waka.js +++ b/waka.js @@ -16,14 +16,16 @@ var memory, table; function setup(info) { memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); - var sbrkStart = 2048; + var staticEnd = info.staticStart + info.staticSize; + var stackStart = staticEnd; + var stackMax = stackStart + info.stackSize; + var sbrkStart = stackMax; var sbrkPtr = 16; (new Int32Array(memory.buffer))[sbrkPtr >> 2] = sbrkStart; return { memory: memory, table: table, - stackStart: 1024, - stackMax: 2048, + stackStart: stackStart, sbrkStart: sbrkStart, sbrkPtr: sbrkPtr, }; From 207904d9d3b96aaf84ea2ae01b881163f6147bff Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 07:18:42 -0700 Subject: [PATCH 07/31] comment [ci skip] --- waka.js | 1 + 1 file changed, 1 insertion(+) diff --git a/waka.js b/waka.js index f5cb980f7b8f8..d8fdadbe70d0f 100644 --- a/waka.js +++ b/waka.js @@ -64,6 +64,7 @@ Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but v console.log('asm5'); var instance = pair.instance; var exports = instance.exports; +// need something for metadce here... console.log(exports); console.log(exports._main()); }); From f4a506850e8eb7a910a8537dfe1a90783ee03a3d Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 07:22:21 -0700 Subject: [PATCH 08/31] fix EM_ASMs [ci skip] --- src/preamble.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/preamble.js b/src/preamble.js index 15d43eaa53735..5bf15b91e553d 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -1215,6 +1215,8 @@ var WASM_PAGE_SIZE = 65536; #include "URIUtils.js" +// === Body === + #if !CUSTOM_CORE_JS var ABORT = 0; // whether we are quitting the application. no code should run after this. set in exit() and abort() From d125b179228c9cbc409d19c4ba80143c9f2081c7 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 08:01:21 -0700 Subject: [PATCH 09/31] hack for metadce [ci skip] --- tools/shared.py | 12 ++++++++++++ waka.js | 8 +++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tools/shared.py b/tools/shared.py index b2e9280e9b15a..12f125ea00b7e 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2322,14 +2322,26 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): txt = Building.js_optimizer_no_asmjs(js_file, ['emitDCEGraph', 'noEmitAst'], return_output=True) graph = json.loads(txt) # ensure that functions expected to be exported to the outside are roots + exports = set() for item in graph: if 'export' in item: export = item['export'] + exports.add(item['name']) # wasm backend's exports are prefixed differently inside the wasm if Settings.WASM_BACKEND: export = '_' + export if export in Building.user_requested_exports or Settings.EXPORT_ALL: item['root'] = True + # XXX + for export in Building.user_requested_exports: + if export not in exports: + graph.append({ + 'export': export, + 'name': 'emcc$export$' + export, + 'root': True, + 'reaches': [] + }) + logging.error(json.dumps(graph)) if Settings.WASM_BACKEND: # wasm backend's imports are prefixed differently inside the wasm for item in graph: diff --git a/waka.js b/waka.js index d8fdadbe70d0f..c2ca8bebe4cdc 100644 --- a/waka.js +++ b/waka.js @@ -33,6 +33,8 @@ function setup(info) { // Compile and run +//function processExports(asm) { +// Module['main'] = asm['_main'] Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but various parsing codes... console.log('asm1'); env.memory = memory; @@ -64,9 +66,9 @@ Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but v console.log('asm5'); var instance = pair.instance; var exports = instance.exports; -// need something for metadce here... - console.log(exports); - console.log(exports._main()); + console.log('exports', exports); + var main = exports['_main']; + main(); }); } From 13f745935bc65c75114808ba2828b7ca02e9184c Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 08:06:40 -0700 Subject: [PATCH 10/31] updates [ci skip] --- tests/test_other.py | 14 +++++++------- tools/shared.py | 1 - 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index d9a012242d400..a6e0e76828bfd 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -8017,9 +8017,9 @@ def test(filename, expectations): print('test on hello world') test(path_from_root('tests', 'hello_world.cpp'), [ - ([], 24, ['abort', 'tempDoublePtr'], ['waka'], 46505, 25, 19), - (['-O1'], 19, ['abort', 'tempDoublePtr'], ['waka'], 12630, 16, 17), - (['-O2'], 19, ['abort', 'tempDoublePtr'], ['waka'], 12616, 16, 17), + ([], 23, ['abort', 'tempDoublePtr'], ['waka'], 46505, 24, 19), + (['-O1'], 18, ['abort', 'tempDoublePtr'], ['waka'], 12630, 16, 17), + (['-O2'], 18, ['abort', 'tempDoublePtr'], ['waka'], 12616, 16, 17), (['-O3'], 7, ['abort'], ['tempDoublePtr', 'waka'], 2818, 10, 2), # in -O3, -Os and -Oz we metadce (['-Os'], 7, ['abort'], ['tempDoublePtr', 'waka'], 2771, 10, 2), (['-Oz'], 7, ['abort'], ['tempDoublePtr', 'waka'], 2765, 10, 2), @@ -8028,7 +8028,7 @@ def test(filename, expectations): 0, [], ['tempDoublePtr', 'waka'], 8, 0, 0), # totally empty! # but we don't metadce with linkable code! other modules may want it (['-O3', '-s', 'MAIN_MODULE=1'], - 1534, ['invoke_i'], ['waka'], 496958, 163, 2560), + 1533, ['invoke_i'], ['waka'], 496958, 163, 2560), ]) print('test on a minimal pure computational thing') @@ -8041,9 +8041,9 @@ def test(filename, expectations): } ''') test('minimal.c', [ - ([], 24, ['abort', 'tempDoublePtr'], ['waka'], 22712, 25, 18), - (['-O1'], 12, ['abort', 'tempDoublePtr'], ['waka'], 10450, 9, 15), - (['-O2'], 12, ['abort', 'tempDoublePtr'], ['waka'], 10440, 9, 15), + ([], 23, ['abort', 'tempDoublePtr'], ['waka'], 22712, 24, 18), + (['-O1'], 11, ['abort', 'tempDoublePtr'], ['waka'], 10450, 9, 15), + (['-O2'], 11, ['abort', 'tempDoublePtr'], ['waka'], 10440, 9, 15), # in -O3, -Os and -Oz we metadce, and they shrink it down to the minimal output we want (['-O3'], 0, [], ['tempDoublePtr', 'waka'], 58, 0, 1), (['-Os'], 0, [], ['tempDoublePtr', 'waka'], 58, 0, 1), diff --git a/tools/shared.py b/tools/shared.py index 12f125ea00b7e..6d5c281cb7301 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2341,7 +2341,6 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): 'root': True, 'reaches': [] }) - logging.error(json.dumps(graph)) if Settings.WASM_BACKEND: # wasm backend's imports are prefixed differently inside the wasm for item in graph: From 3c7eeac1d118c61b45c8adc0b512934ef49fc355 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 09:01:49 -0700 Subject: [PATCH 11/31] work with closure [ci skip] --- emscripten.py | 25 +++++++++++++------------ waka.js | 12 ++++++------ 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/emscripten.py b/emscripten.py index 8a94cd2a55c61..8453279389a73 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1167,19 +1167,20 @@ def table_size(table): staticStart: %d, staticSize: STATIC_BUMP, }); -var DYNAMICTOP_PTR = setupInfo.sbrkPtr; +var ABORT, EXITSTATUS; // XXX +DYNAMICTOP_PTR = setupInfo.sbrkPtr; var DYNAMICTOP = setupInfo.sbrkStart; -var STACKTOP = setupInfo.stackStart; -var STACK_MAX = STACKTOP + %d; -var buffer = memory.buffer; -var HEAP8 = new Int8Array(buffer); -var HEAP16 = new Int16Array(buffer); -var HEAP32 = new Int32Array(buffer); -var HEAPU8 = new Uint8Array(buffer); -var HEAPU16 = new Uint16Array(buffer); -var HEAPU32 = new Uint32Array(buffer); -var HEAPF32 = new Float32Array(buffer); -var HEAPF64 = new Float64Array(buffer); +STACKTOP = setupInfo.stackStart; +STACK_MAX = STACKTOP + %d; +buffer = memory.buffer; +HEAP8 = new Int8Array(buffer); +HEAP16 = new Int16Array(buffer); +HEAP32 = new Int32Array(buffer); +HEAPU8 = new Uint8Array(buffer); +HEAPU16 = new Uint16Array(buffer); +HEAPU32 = new Uint32Array(buffer); +HEAPF32 = new Float32Array(buffer); +HEAPF64 = new Float64Array(buffer); ''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size diff --git a/waka.js b/waka.js index c2ca8bebe4cdc..eb69a9244ee9d 100644 --- a/waka.js +++ b/waka.js @@ -37,10 +37,10 @@ function setup(info) { // Module['main'] = asm['_main'] Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but various parsing codes... console.log('asm1'); - env.memory = memory; - env.table = table; - env.memoryBase = 0; - env.tableBase = 0; + env['memory'] = memory; + env['table'] = table; + env['memoryBase'] = 0; + env['tableBase'] = 0; var info = { 'env': env, 'global': { // XXX @@ -64,8 +64,8 @@ Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but v }) .then(function(pair) { console.log('asm5'); - var instance = pair.instance; - var exports = instance.exports; + var instance = pair['instance']; + var exports = instance['exports']; console.log('exports', exports); var main = exports['_main']; main(); From a61918c5fcfd04096f74d146c5112ad101e00b0d Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 09:10:58 -0700 Subject: [PATCH 12/31] refactor --- emscripten.py | 15 +++++++++++++++ waka.js | 24 ++---------------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/emscripten.py b/emscripten.py index 8453279389a73..cc818d59ca733 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1181,6 +1181,21 @@ def table_size(table): HEAPU32 = new Uint32Array(buffer); HEAPF32 = new Float32Array(buffer); HEAPF64 = new Float64Array(buffer); + +Module['asm'] = function(global, env, buffer) { + env['memory'] = memory; + env['table'] = table; + env['memoryBase'] = 0; + env['tableBase'] = 0; + var info = { + 'env': env, + 'global': { // XXX + 'NaN': NaN, + 'Infinity': Infinity + } + }; + start(info); +}; ''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size diff --git a/waka.js b/waka.js index eb69a9244ee9d..6f64bcee543dd 100644 --- a/waka.js +++ b/waka.js @@ -33,40 +33,20 @@ function setup(info) { // Compile and run -//function processExports(asm) { -// Module['main'] = asm['_main'] -Module['asm'] = function(global, env, buffer) { // XXX rename "startup()"? but various parsing codes... - console.log('asm1'); - env['memory'] = memory; - env['table'] = table; - env['memoryBase'] = 0; - env['tableBase'] = 0; - var info = { - 'env': env, - 'global': { // XXX - 'NaN': NaN, - 'Infinity': Infinity - } - }; +function start(imports) { fetch('b.wasm', { credentials: 'same-origin' }) .then(function(response) { - console.log('asm2'); return response.arrayBuffer(); }) .then(function(arrayBuffer) { - console.log('asm3'); return new Uint8Array(arrayBuffer); }) .then(function(binary) { - console.log('asm4'); - console.log(info); - return WebAssembly.instantiate(binary, info); + return WebAssembly.instantiate(binary, imports); }) .then(function(pair) { - console.log('asm5'); var instance = pair['instance']; var exports = instance['exports']; - console.log('exports', exports); var main = exports['_main']; main(); }); From 92a55745c687a4a022cb14949512be171373fefc Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 09:11:33 -0700 Subject: [PATCH 13/31] comment [ci skip] --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index cc818d59ca733..83137a1916ae7 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1194,7 +1194,7 @@ def table_size(table): 'Infinity': Infinity } }; - start(info); + start(info); // XXX need to tell it about global ctors }; ''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) if not settings['EMULATED_FUNCTION_POINTERS']: From b569bbf8aef7fd612b05ed27ee1333bc0ead856f Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 09:15:54 -0700 Subject: [PATCH 14/31] more comments [ci skip] --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index 83137a1916ae7..94d04e29fa2b8 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1194,7 +1194,7 @@ def table_size(table): 'Infinity': Infinity } }; - start(info); // XXX need to tell it about global ctors + start(info); // XXX need to tell it about global ctors, and need those to be kept alive }; ''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) if not settings['EMULATED_FUNCTION_POINTERS']: From 5c94ee9342b484002ca5f26ee272f2adf27f2005 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 12:42:14 -0700 Subject: [PATCH 15/31] progress towards libc++ hello world [ci skip] --- emscripten.py | 10 ++++++++-- tools/shared.py | 31 ++++++++++++++++++++++--------- waka.js | 19 ++++++++++++++++++- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/emscripten.py b/emscripten.py index 94d04e29fa2b8..e942ab60be8b5 100755 --- a/emscripten.py +++ b/emscripten.py @@ -522,6 +522,8 @@ def update_settings_glue(settings, metadata): settings['JSCALL_START_INDEX'] = start_index settings['JSCALL_SIG_ORDER'] = sig2order + shared.Building.global_ctors = metadata['initializers'] + def compile_settings(compiler_engine, settings, libraries, temp_files): # Save settings to a file to work around v8 issue 1579 @@ -1194,9 +1196,13 @@ def table_size(table): 'Infinity': Infinity } }; - start(info); // XXX need to tell it about global ctors, and need those to be kept alive + start(info, [%s], __ATMAIN__); }; -''' % (settings['TOTAL_MEMORY'], table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK']) +''' % (settings['TOTAL_MEMORY'], + table_total_size, + settings['GLOBAL_BASE'], + settings['TOTAL_STACK'], + ', '.join(['"' + name + '"' for name in metadata['initializers']])) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size if settings['RELOCATABLE']: diff --git a/tools/shared.py b/tools/shared.py index 6d5c281cb7301..dfb2229d7bba3 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2332,15 +2332,25 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): export = '_' + export if export in Building.user_requested_exports or Settings.EXPORT_ALL: item['root'] = True - # XXX - for export in Building.user_requested_exports: - if export not in exports: - graph.append({ - 'export': export, - 'name': 'emcc$export$' + export, - 'root': True, - 'reaches': [] - }) + if Settings.CUSTOM_CORE_JS: + # In custom core JS we must handle things more manually, as we can't + # assume the JS contains the standard JS to receive wasm exports + # (the custom code might write it differently). + # Specifically, we need to have rooted exports for all user-requested + # exports, plus global ctors, as all those are absolutely mandatory + # to be kept alive through dce. (If users want more, they can add + # to EXPORTED_FUNCTIONS.) + needed = Building.user_requested_exports + Building.global_ctors + print(needed) + 1/0 + for export in needed: + if export not in exports: + graph.append({ + 'export': export, + 'name': 'emcc$export$' + export, + 'root': True, + 'reaches': [] + }) if Settings.WASM_BACKEND: # wasm backend's imports are prefixed differently inside the wasm for item in graph: @@ -2372,6 +2382,9 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): # the exports the user requested user_requested_exports = [] + # the global constructor functions (to be called before main) + global_ctors = [] + _is_ar_cache = {} @staticmethod def is_ar(filename): diff --git a/waka.js b/waka.js index 6f64bcee543dd..790d410f531e4 100644 --- a/waka.js +++ b/waka.js @@ -33,21 +33,35 @@ function setup(info) { // Compile and run -function start(imports) { +function start(imports, ctors, jsCtors) { + console.log('start1'); fetch('b.wasm', { credentials: 'same-origin' }) .then(function(response) { + console.log('start2'); return response.arrayBuffer(); }) .then(function(arrayBuffer) { + console.log('start3'); return new Uint8Array(arrayBuffer); }) .then(function(binary) { + console.log('start4'); return WebAssembly.instantiate(binary, imports); }) .then(function(pair) { + console.log('start5'); var instance = pair['instance']; var exports = instance['exports']; + ctors.forEach(function(ctor) { + console.log('ctor ' + ctor); + exports[ctor](); + }); + jsCtors.forEach(function(ctor) { + console.log('js ctor'); + ctor(); + }); var main = exports['_main']; + console.log('maintime'); main(); }); } @@ -55,4 +69,7 @@ function start(imports) { // XXX fix these var __ATINIT__ = []; +var __ATMAIN__ = []; +var __ATEXIT__ = []; +var ENVIRONMENT_IS_NODE = 0; From e5af7110cd75ed7c73f3466b20e3b6a0a35f982c Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 13:46:16 -0700 Subject: [PATCH 16/31] mozjs support [ci skip] --- waka.js | 74 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/waka.js b/waka.js index 790d410f531e4..b851729aa3538 100644 --- a/waka.js +++ b/waka.js @@ -1,13 +1,10 @@ // Environment setup -function out(x) { +var out, err; +out = err = function(x) { console.log(x); -} - -function err(x) { - console.warn(x); -} +}; // Set up memory and table @@ -35,35 +32,44 @@ function setup(info) { function start(imports, ctors, jsCtors) { console.log('start1'); - fetch('b.wasm', { credentials: 'same-origin' }) - .then(function(response) { - console.log('start2'); - return response.arrayBuffer(); - }) - .then(function(arrayBuffer) { - console.log('start3'); - return new Uint8Array(arrayBuffer); - }) - .then(function(binary) { - console.log('start4'); - return WebAssembly.instantiate(binary, imports); - }) - .then(function(pair) { - console.log('start5'); - var instance = pair['instance']; - var exports = instance['exports']; - ctors.forEach(function(ctor) { - console.log('ctor ' + ctor); - exports[ctor](); - }); - jsCtors.forEach(function(ctor) { - console.log('js ctor'); - ctor(); - }); - var main = exports['_main']; - console.log('maintime'); - main(); + function postInstantiate(instance) { + console.log('start5'); + var exports = instance['exports']; + ctors.forEach(function(ctor) { + console.log('ctor ' + ctor); + exports[ctor](); + }); + jsCtors.forEach(function(ctor) { + console.log('js ctor'); + ctor(); }); + var main = exports['_main']; + console.log('maintime'); + main(); + } + var where = 'mozjs'; + if (where === 'web') { + fetch('b.wasm', { credentials: 'same-origin' }) + .then(function(response) { + console.log('start2'); + return response.arrayBuffer(); + }) + .then(function(arrayBuffer) { + console.log('start3'); + return new Uint8Array(arrayBuffer); + }) + .then(function(binary) { + console.log('start4'); + return WebAssembly.instantiate(binary, imports); + }) + .then(function(pair) { + postInstantiate(pair['instance']); + }); + } else if (where === 'mozjs') { + var data = read('b.wasm', 'binary'); + var instance = new WebAssembly.Instance(new WebAssembly.Module(data), imports); + postInstantiate(instance); + } } // XXX fix these From 42d57d8b21014f60119d05626cd218e1c9bd44fc Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 14:00:47 -0700 Subject: [PATCH 17/31] fixes, now libc++ hello world works too [ci skip] --- emscripten.py | 2 +- waka.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/emscripten.py b/emscripten.py index e942ab60be8b5..bde34ee187a23 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1196,7 +1196,7 @@ def table_size(table): 'Infinity': Infinity } }; - start(info, [%s], __ATMAIN__); + start(info, [%s], __ATINIT__.concat(__ATMAIN__)); }; ''' % (settings['TOTAL_MEMORY'], table_total_size, diff --git a/waka.js b/waka.js index b851729aa3538..3aa55535e72d8 100644 --- a/waka.js +++ b/waka.js @@ -41,7 +41,9 @@ function start(imports, ctors, jsCtors) { }); jsCtors.forEach(function(ctor) { console.log('js ctor'); - ctor(); + if (typeof ctor === 'function') { // XXX FIXME + ctor(); + } }); var main = exports['_main']; console.log('maintime'); From 7498c0eba5426f50b89303ecb13ccd0afd9dd80a Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sat, 30 Jun 2018 15:36:16 -0700 Subject: [PATCH 18/31] closure -Os working on libc++ hello world [ci skip] --- emscripten.py | 8 ++++++-- src/shell.js | 19 +++++++++++++++++++ tools/shared.py | 2 -- waka.js | 15 --------------- 4 files changed, 25 insertions(+), 19 deletions(-) diff --git a/emscripten.py b/emscripten.py index bde34ee187a23..9b641d22051ef 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1169,9 +1169,8 @@ def table_size(table): staticStart: %d, staticSize: STATIC_BUMP, }); -var ABORT, EXITSTATUS; // XXX DYNAMICTOP_PTR = setupInfo.sbrkPtr; -var DYNAMICTOP = setupInfo.sbrkStart; +DYNAMICTOP = setupInfo.sbrkStart; STACKTOP = setupInfo.stackStart; STACK_MAX = STACKTOP + %d; buffer = memory.buffer; @@ -1184,6 +1183,11 @@ def table_size(table): HEAPF32 = new Float32Array(buffer); HEAPF64 = new Float64Array(buffer); +// XXX fix these +var ABORT, EXITSTATUS; +var DYNAMICTOP; +// XXX fix all the above + Module['asm'] = function(global, env, buffer) { env['memory'] = memory; env['table'] = table; diff --git a/src/shell.js b/src/shell.js index e72b3f0d971eb..67016e09deafe 100644 --- a/src/shell.js +++ b/src/shell.js @@ -313,6 +313,25 @@ for (key in moduleOverrides) { // reclaim data used e.g. in memoryInitializerRequest, which is a large typed array. moduleOverrides = undefined; +#else // !CUSTOM_CORE_JS +// XXX FIXME all these +var __ATINIT__ = []; +var __ATMAIN__ = []; +var __ATEXIT__ = []; +var ENVIRONMENT_IS_NODE = 0; +var ENVIRONMENT_IS_WORKER = 0; +var TOTAL_MEMORY = 0; +var __GLOBAL__I_000101 = 0; +var __GLOBAL__sub_I_iostream_cpp = 0; +var __ZSt18uncaught_exceptionv = 0; +var _free = 0; +var _malloc = 0; +var addRunDependency = 0; +var getUniqueRunDependency = 0; +var removeRunDependency = 0; +var stackRestore = 0; +var stackSave = 0; +// XXX FIXME all the above #endif //!CUSTOM_CORE_JS {{BODY}} diff --git a/tools/shared.py b/tools/shared.py index dfb2229d7bba3..908fe1763eef8 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -2341,8 +2341,6 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info): # to be kept alive through dce. (If users want more, they can add # to EXPORTED_FUNCTIONS.) needed = Building.user_requested_exports + Building.global_ctors - print(needed) - 1/0 for export in needed: if export not in exports: graph.append({ diff --git a/waka.js b/waka.js index 3aa55535e72d8..9eb68e47c75af 100644 --- a/waka.js +++ b/waka.js @@ -31,37 +31,29 @@ function setup(info) { // Compile and run function start(imports, ctors, jsCtors) { - console.log('start1'); function postInstantiate(instance) { - console.log('start5'); var exports = instance['exports']; ctors.forEach(function(ctor) { - console.log('ctor ' + ctor); exports[ctor](); }); jsCtors.forEach(function(ctor) { - console.log('js ctor'); if (typeof ctor === 'function') { // XXX FIXME ctor(); } }); var main = exports['_main']; - console.log('maintime'); main(); } var where = 'mozjs'; if (where === 'web') { fetch('b.wasm', { credentials: 'same-origin' }) .then(function(response) { - console.log('start2'); return response.arrayBuffer(); }) .then(function(arrayBuffer) { - console.log('start3'); return new Uint8Array(arrayBuffer); }) .then(function(binary) { - console.log('start4'); return WebAssembly.instantiate(binary, imports); }) .then(function(pair) { @@ -74,10 +66,3 @@ function start(imports, ctors, jsCtors) { } } -// XXX fix these - -var __ATINIT__ = []; -var __ATMAIN__ = []; -var __ATEXIT__ = []; -var ENVIRONMENT_IS_NODE = 0; - From bc7b79a64c192a5cd2ccb930f79547b19ce9327f Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 07:51:32 -0700 Subject: [PATCH 19/31] work towards ammo.js [ci skip] --- emscripten.py | 15 +++++++++--- waka2.js | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 waka2.js diff --git a/emscripten.py b/emscripten.py index 9b641d22051ef..636455ad7740f 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1194,11 +1194,20 @@ def table_size(table): env['memoryBase'] = 0; env['tableBase'] = 0; var info = { + 'asm2wasm': { + "f64-rem": function(x, y) { + return x % y; + }, + "debugger": function() { + debugger; + } + }, 'env': env, 'global': { // XXX - 'NaN': NaN, - 'Infinity': Infinity - } + 'Infinity': Infinity, + 'NaN': NaN + }, + 'global.Math': Math }; start(info, [%s], __ATINIT__.concat(__ATMAIN__)); }; diff --git a/waka2.js b/waka2.js new file mode 100644 index 0000000000000..810d382430748 --- /dev/null +++ b/waka2.js @@ -0,0 +1,67 @@ + +// Environment setup + +var out, err; +out = err = function(x) { + console.log(x); +}; + +// Set up memory and table + +var memory, table; + +function setup(info) { + memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); + table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); + var staticEnd = info.staticStart + info.staticSize; + var stackStart = staticEnd; + var stackMax = stackStart + info.stackSize; + var sbrkStart = stackMax; + var sbrkPtr = 16; + (new Int32Array(memory.buffer))[sbrkPtr >> 2] = sbrkStart; + return { + memory: memory, + table: table, + stackStart: stackStart, + sbrkStart: sbrkStart, + sbrkPtr: sbrkPtr, + }; +} + +// Compile and run + +function start(imports, ctors, jsCtors) { + function postInstantiate(instance) { + var exports = instance['exports']; + ctors.forEach(function(ctor) { + exports[ctor](); + }); + jsCtors.forEach(function(ctor) { + if (typeof ctor === 'function') { // XXX FIXME + ctor(); + } + }); + var main = exports['_main']; + main(); + } + if (typeof fetch === 'function') { + fetch('ammo.wasm.wasm', { credentials: 'same-origin' }) + .then(function(response) { + return response.arrayBuffer(); + }) + .then(function(arrayBuffer) { + return new Uint8Array(arrayBuffer); + }) + .then(function(binary) { + return WebAssembly.instantiate(binary, imports); + }) + .then(function(pair) { + postInstantiate(pair['instance']); + }); + } else { + var data = read('ammo.wasm.wasm', 'binary'); + var instance = new WebAssembly.Instance(new WebAssembly.Module(data), imports); + postInstantiate(instance); + } +} + From 8ff271f913ebf614aa5cb8a07495bfc7bd920af9 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 08:17:24 -0700 Subject: [PATCH 20/31] fix [ci skip] --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index 636455ad7740f..13258e9c3d036 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1196,7 +1196,7 @@ def table_size(table): var info = { 'asm2wasm': { "f64-rem": function(x, y) { - return x % y; + return x %% y; }, "debugger": function() { debugger; From dfb4243533b1ed4d39d3059c33fbdebedab29582 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 09:49:32 -0700 Subject: [PATCH 21/31] prep testing [ci skip] --- src/jsifier.js | 2 +- tests/test_core.py | 2 ++ waka2.js | 15 +++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/jsifier.js b/src/jsifier.js index 01d69125584b9..ae1917a9492e0 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -70,7 +70,7 @@ function JSify(data, functionsOnly) { var shellParts = read(shellFile).split('{{BODY}}'); print(processMacros(preprocess(shellParts[0], shellFile))); - if (CUSTOM_CORE_JS) print(read(CUSTOM_CORE_JS)); + if (CUSTOM_CORE_JS) print(processMacros(preprocess(read(CUSTOM_CORE_JS)))); var pre; if (BUILD_AS_SHARED_LIB || SIDE_MODULE) { pre = processMacros(preprocess(read('preamble_sharedlib.js'), 'preamble_sharedlib.js')); diff --git a/tests/test_core.py b/tests/test_core.py index ecc4002663e21..c6f20cc617e4a 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7803,4 +7803,6 @@ def setUp(self): asmi = make_run('asmi', compiler=CLANG, emcc_args=['-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) asm2i = make_run('asm2i', compiler=CLANG, emcc_args=['-O2', '-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) +cjs = make_run('cjs', compiler=CLANG, emcc_args=['-s', 'CUSTOM_CORE_JS="/home/alon/Dev/emscripten/waka2.js"']) + del T # T is just a shape for the specific subclasses, we don't test it itself diff --git a/waka2.js b/waka2.js index 810d382430748..27cf484250d83 100644 --- a/waka2.js +++ b/waka2.js @@ -44,8 +44,10 @@ function start(imports, ctors, jsCtors) { var main = exports['_main']; main(); } + var filename = '{{{ WASM_BINARY_FILE }}}'; if (typeof fetch === 'function') { - fetch('ammo.wasm.wasm', { credentials: 'same-origin' }) + // Web + fetch(filename, { credentials: 'same-origin' }) .then(function(response) { return response.arrayBuffer(); }) @@ -59,7 +61,16 @@ function start(imports, ctors, jsCtors) { postInstantiate(pair['instance']); }); } else { - var data = read('ammo.wasm.wasm', 'binary'); + var data; + if (typeof require === 'function') { + // node.js + data = require('fs')['readFileSync'](filename); + } else if (typeof read === 'function') { + // SpiderMonkey shell + data = read(filename, 'binary'); + } else { + throw Error('where am i'); + } var instance = new WebAssembly.Instance(new WebAssembly.Module(data), imports); postInstantiate(instance); } From dde724cb0ccff6dc8e6f7de16da8038de93308be Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 09:53:58 -0700 Subject: [PATCH 22/31] more test prep [ci skip] --- tests/runner.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/runner.py b/tests/runner.py index 04cfc7088ee6a..8711e33ebd695 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -150,6 +150,7 @@ def get_browser(): 'binaryenz', 'asmi', 'asm2i', + 'cjs', ] test_index = 0 From 197f76492b923b144c7c3e2d7565399db8e39481 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 14:11:53 -0700 Subject: [PATCH 23/31] add src/codejs/ [ci skip] --- emscripten.py | 3 ++ waka2.js => src/corejs/minimal-multi.js | 1 + src/corejs/minimal-web.js | 59 +++++++++++++++++++++ tests/test_core.py | 2 +- waka.js | 68 ------------------------- 5 files changed, 64 insertions(+), 69 deletions(-) rename waka2.js => src/corejs/minimal-multi.js (98%) create mode 100644 src/corejs/minimal-web.js delete mode 100644 waka.js diff --git a/emscripten.py b/emscripten.py index 13258e9c3d036..1e222b199ae19 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1188,6 +1188,9 @@ def table_size(table): var DYNAMICTOP; // XXX fix all the above +// XXX - should we disallow --post-js'es? checked late, +// so would error on things that emcc adds a post for. + Module['asm'] = function(global, env, buffer) { env['memory'] = memory; env['table'] = table; diff --git a/waka2.js b/src/corejs/minimal-multi.js similarity index 98% rename from waka2.js rename to src/corejs/minimal-multi.js index 27cf484250d83..0b2c9e4c7fea4 100644 --- a/waka2.js +++ b/src/corejs/minimal-multi.js @@ -31,6 +31,7 @@ function setup(info) { // Compile and run function start(imports, ctors, jsCtors) { + // todo main's argc/argv function postInstantiate(instance) { var exports = instance['exports']; ctors.forEach(function(ctor) { diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js new file mode 100644 index 0000000000000..218604aeb9427 --- /dev/null +++ b/src/corejs/minimal-web.js @@ -0,0 +1,59 @@ + +// Environment setup + +var out, err; +out = err = function(x) { + console.log(x); +}; + +// Set up memory and table + +var memory, table; + +function setup(info) { + memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); + table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); + var staticEnd = info.staticStart + info.staticSize; + var stackStart = staticEnd; + var stackMax = stackStart + info.stackSize; + var sbrkStart = stackMax; + var sbrkPtr = 16; + (new Int32Array(memory.buffer))[sbrkPtr >> 2] = sbrkStart; + return { + memory: memory, + table: table, + stackStart: stackStart, + sbrkStart: sbrkStart, + sbrkPtr: sbrkPtr, + }; +} + +// Compile and run + +function start(imports, ctors, jsCtors) { + fetch('b.wasm', { credentials: 'same-origin' }) + .then(function(response) { + return response.arrayBuffer(); + }) + .then(function(arrayBuffer) { + return new Uint8Array(arrayBuffer); + }) + .then(function(binary) { + return WebAssembly.instantiate(binary, imports); + }) + .then(function(pair) { + var instance = pair['instance']; + var exports = instance['exports']; + ctors.forEach(function(ctor) { + exports[ctor](); + }); + jsCtors.forEach(function(ctor) { + if (typeof ctor === 'function') { // XXX FIXME + ctor(); + } + }); + var main = exports['_main']; + main(); + }); +} + diff --git a/tests/test_core.py b/tests/test_core.py index c6f20cc617e4a..90bb13f576c85 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7803,6 +7803,6 @@ def setUp(self): asmi = make_run('asmi', compiler=CLANG, emcc_args=['-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) asm2i = make_run('asm2i', compiler=CLANG, emcc_args=['-O2', '-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) -cjs = make_run('cjs', compiler=CLANG, emcc_args=['-s', 'CUSTOM_CORE_JS="/home/alon/Dev/emscripten/waka2.js"']) +cjs = make_run('cjs', compiler=CLANG, emcc_args=['-s', 'CUSTOM_CORE_JS="%s"' % path_from_root('src', 'corejs', 'minimal-multi.js')]) del T # T is just a shape for the specific subclasses, we don't test it itself diff --git a/waka.js b/waka.js deleted file mode 100644 index 9eb68e47c75af..0000000000000 --- a/waka.js +++ /dev/null @@ -1,68 +0,0 @@ - -// Environment setup - -var out, err; -out = err = function(x) { - console.log(x); -}; - -// Set up memory and table - -var memory, table; - -function setup(info) { - memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); - table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); - var staticEnd = info.staticStart + info.staticSize; - var stackStart = staticEnd; - var stackMax = stackStart + info.stackSize; - var sbrkStart = stackMax; - var sbrkPtr = 16; - (new Int32Array(memory.buffer))[sbrkPtr >> 2] = sbrkStart; - return { - memory: memory, - table: table, - stackStart: stackStart, - sbrkStart: sbrkStart, - sbrkPtr: sbrkPtr, - }; -} - -// Compile and run - -function start(imports, ctors, jsCtors) { - function postInstantiate(instance) { - var exports = instance['exports']; - ctors.forEach(function(ctor) { - exports[ctor](); - }); - jsCtors.forEach(function(ctor) { - if (typeof ctor === 'function') { // XXX FIXME - ctor(); - } - }); - var main = exports['_main']; - main(); - } - var where = 'mozjs'; - if (where === 'web') { - fetch('b.wasm', { credentials: 'same-origin' }) - .then(function(response) { - return response.arrayBuffer(); - }) - .then(function(arrayBuffer) { - return new Uint8Array(arrayBuffer); - }) - .then(function(binary) { - return WebAssembly.instantiate(binary, imports); - }) - .then(function(pair) { - postInstantiate(pair['instance']); - }); - } else if (where === 'mozjs') { - var data = read('b.wasm', 'binary'); - var instance = new WebAssembly.Instance(new WebAssembly.Module(data), imports); - postInstantiate(instance); - } -} - From 563bbef041fe337e1c7998f2559f1a718dc1a274 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 17:03:58 -0700 Subject: [PATCH 24/31] wip arguments to main [ci skip] --- src/corejs/minimal-multi.js | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/corejs/minimal-multi.js b/src/corejs/minimal-multi.js index 0b2c9e4c7fea4..e6897b7760ac4 100644 --- a/src/corejs/minimal-multi.js +++ b/src/corejs/minimal-multi.js @@ -32,7 +32,7 @@ function setup(info) { function start(imports, ctors, jsCtors) { // todo main's argc/argv - function postInstantiate(instance) { + function postInstantiate(instance, args) { var exports = instance['exports']; ctors.forEach(function(ctor) { exports[ctor](); @@ -43,7 +43,22 @@ function start(imports, ctors, jsCtors) { } }); var main = exports['_main']; - main(); + var argc = 1, argv; + if (args && args.length) { // TODO + argc = args.length + 1; + argv = stackAlloc(argc * 4); + HEAP32[argv >> 2] = 0; // no program name XXX + for (var i = 0; i < args.length; i++) { + var arg = args[i]; + var ptr = stackAlloc(arg.length + 1); + HEAP32[(argv >> 2) + 1 + i] = ptr; + for (var j = 0; j < arg.length; j++) { + HEAPU8[ptr + j] = arg.charCodeAt(j); + } + HEAPU8[ptr + arg.length] = 0; + } + } + main(argc, argv); } var filename = '{{{ WASM_BINARY_FILE }}}'; if (typeof fetch === 'function') { @@ -62,18 +77,20 @@ function start(imports, ctors, jsCtors) { postInstantiate(pair['instance']); }); } else { - var data; + var data, args; if (typeof require === 'function') { // node.js data = require('fs')['readFileSync'](filename); + args = process['argv'].slice(2); } else if (typeof read === 'function') { // SpiderMonkey shell data = read(filename, 'binary'); + args = scriptArgs; } else { throw Error('where am i'); } var instance = new WebAssembly.Instance(new WebAssembly.Module(data), imports); - postInstantiate(instance); + postInstantiate(instance, args); } } From 7c93e90142324e3dfaf2535a61f57fd40ac98bbe Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Sun, 1 Jul 2018 19:09:29 -0700 Subject: [PATCH 25/31] fix total memory [ci skip] --- src/settings.js | 6 ++++++ src/shell.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/settings.js b/src/settings.js index 5d5f03f4517e8..89425bb1ab5f5 100644 --- a/src/settings.js +++ b/src/settings.js @@ -493,6 +493,12 @@ var CUSTOM_CORE_JS = ''; // Setting this will include the contents of that .js f // the wasm imports as a parameter. This // function should handle creating and running // the wasm. XXX or define Module['asm'] + // ISSUES: + // * test_llvm_intrinsics etc. - calling from a JS library into + // asm library function does not work, as the asm library export + // / receiving code is not emitted. + // * EMSCRIPTEN_KEEPALIVE auto exported is not emitted, the user + // must receive it from the wasm module. var SHELL_FILE = 0; // set this to a string to override the shell file used diff --git a/src/shell.js b/src/shell.js index 67016e09deafe..a4e0427d27eb9 100644 --- a/src/shell.js +++ b/src/shell.js @@ -320,7 +320,7 @@ var __ATMAIN__ = []; var __ATEXIT__ = []; var ENVIRONMENT_IS_NODE = 0; var ENVIRONMENT_IS_WORKER = 0; -var TOTAL_MEMORY = 0; +var TOTAL_MEMORY = {{{ TOTAL_MEMORY }}}; var __GLOBAL__I_000101 = 0; var __GLOBAL__sub_I_iostream_cpp = 0; var __ZSt18uncaught_exceptionv = 0; From b69d89b624058aa421e2e7b7bd29ca96af615045 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Mon, 2 Jul 2018 14:39:51 -0700 Subject: [PATCH 26/31] better api [ci skip] --- emscripten.py | 11 ++++++++++- src/corejs/minimal-multi.js | 11 ++--------- src/corejs/minimal-web.js | 12 ++---------- src/settings.js | 2 ++ 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/emscripten.py b/emscripten.py index 1e222b199ae19..bfa3ed4accecd 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1212,7 +1212,16 @@ def table_size(table): }, 'global.Math': Math }; - start(info, [%s], __ATINIT__.concat(__ATMAIN__)); + start(info, function(exports) { + [%s].forEach(function(ctor) { + exports[ctor](); + }); + __ATINIT__.concat(__ATMAIN__).forEach(function(ctor) { + if (typeof ctor === 'function') { // XXX FIXME + ctor(); + } + }); + }); }; ''' % (settings['TOTAL_MEMORY'], table_total_size, diff --git a/src/corejs/minimal-multi.js b/src/corejs/minimal-multi.js index e6897b7760ac4..2949f778b9be2 100644 --- a/src/corejs/minimal-multi.js +++ b/src/corejs/minimal-multi.js @@ -30,18 +30,11 @@ function setup(info) { // Compile and run -function start(imports, ctors, jsCtors) { +function start(imports, onload) { // todo main's argc/argv function postInstantiate(instance, args) { var exports = instance['exports']; - ctors.forEach(function(ctor) { - exports[ctor](); - }); - jsCtors.forEach(function(ctor) { - if (typeof ctor === 'function') { // XXX FIXME - ctor(); - } - }); + onload(exports); var main = exports['_main']; var argc = 1, argv; if (args && args.length) { // TODO diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js index 218604aeb9427..9478721e36e45 100644 --- a/src/corejs/minimal-web.js +++ b/src/corejs/minimal-web.js @@ -30,7 +30,7 @@ function setup(info) { // Compile and run -function start(imports, ctors, jsCtors) { +function start(imports, onload) { fetch('b.wasm', { credentials: 'same-origin' }) .then(function(response) { return response.arrayBuffer(); @@ -44,15 +44,7 @@ function start(imports, ctors, jsCtors) { .then(function(pair) { var instance = pair['instance']; var exports = instance['exports']; - ctors.forEach(function(ctor) { - exports[ctor](); - }); - jsCtors.forEach(function(ctor) { - if (typeof ctor === 'function') { // XXX FIXME - ctor(); - } - }); - var main = exports['_main']; + onload(exports); main(); }); } diff --git a/src/settings.js b/src/settings.js index 89425bb1ab5f5..469af250805a1 100644 --- a/src/settings.js +++ b/src/settings.js @@ -499,6 +499,8 @@ var CUSTOM_CORE_JS = ''; // Setting this will include the contents of that .js f // / receiving code is not emitted. // * EMSCRIPTEN_KEEPALIVE auto exported is not emitted, the user // must receive it from the wasm module. + // TODO: add a JS ctor that the start() receives which receives + // the necessary exports for internal use. simplifies metadce also. var SHELL_FILE = 0; // set this to a string to override the shell file used From a364659ffea7665f459c8bbeb6840dbe50b849c8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Jul 2018 09:37:31 -0700 Subject: [PATCH 27/31] wip [ci skip] --- src/corejs/minimal-multi.js | 45 +++++++++++++++++++++++-------------- src/corejs/minimal-web.js | 4 +--- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/corejs/minimal-multi.js b/src/corejs/minimal-multi.js index 2949f778b9be2..33f6016367c61 100644 --- a/src/corejs/minimal-multi.js +++ b/src/corejs/minimal-multi.js @@ -8,13 +8,15 @@ out = err = function(x) { // Set up memory and table -var memory, table; +// Some extra static memory for main() argv strings +var extraStatic, extraStaticSize = 1024; function setup(info) { memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); var staticEnd = info.staticStart + info.staticSize; - var stackStart = staticEnd; + extraStatic = staticEnd; + var stackStart = extraStatic + extraStaticSize; var stackMax = stackStart + info.stackSize; var sbrkStart = stackMax; var sbrkPtr = 16; @@ -35,23 +37,32 @@ function start(imports, onload) { function postInstantiate(instance, args) { var exports = instance['exports']; onload(exports); - var main = exports['_main']; - var argc = 1, argv; - if (args && args.length) { // TODO - argc = args.length + 1; - argv = stackAlloc(argc * 4); - HEAP32[argv >> 2] = 0; // no program name XXX - for (var i = 0; i < args.length; i++) { - var arg = args[i]; - var ptr = stackAlloc(arg.length + 1); - HEAP32[(argv >> 2) + 1 + i] = ptr; - for (var j = 0; j < arg.length; j++) { - HEAPU8[ptr + j] = arg.charCodeAt(j); - } - HEAPU8[ptr + arg.length] = 0; + // allocate main() argc/argv + var extraStaticMax = extraStatic + extraStaticSize; + function extraAlloc(size) { + var ret = extraStatic; + extraStatic += size; + assert(extraStatic <= extraStaticMax); + return ret; + } + function writeCString(ptr, string) { + for (var j = 0; j < string.length; j++) { + HEAPU8[ptr + j] = string.charCodeAt(j); } + HEAPU8[ptr + string.length] = 0; + } + function allocCString(string) { + var ptr = extraAlloc(string.length + 1); + writeCString(ptr, string); + return ptr; + } + var argc = args.length + 1; + var argv = extraAlloc(argc * 4); + HEAP32[argv >> 2] = allocCString('program'); + for (var i = 0; i < args.length; i++) { + HEAP32[(argv >> 2) + 1 + i] = allocCString(args[i]); } - main(argc, argv); + exports['_main'](argc, argv); } var filename = '{{{ WASM_BINARY_FILE }}}'; if (typeof fetch === 'function') { diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js index 9478721e36e45..346809ca7e359 100644 --- a/src/corejs/minimal-web.js +++ b/src/corejs/minimal-web.js @@ -8,8 +8,6 @@ out = err = function(x) { // Set up memory and table -var memory, table; - function setup(info) { memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); @@ -45,7 +43,7 @@ function start(imports, onload) { var instance = pair['instance']; var exports = instance['exports']; onload(exports); - main(); + exports['_main'](); }); } From a042bc06b52c037d738427991c0468548b8ca4b0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Jul 2018 12:57:33 -0700 Subject: [PATCH 28/31] fix [ci skip] --- src/corejs/minimal-multi.js | 4 ++-- src/corejs/minimal-web.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corejs/minimal-multi.js b/src/corejs/minimal-multi.js index 33f6016367c61..af1fbdeddda2d 100644 --- a/src/corejs/minimal-multi.js +++ b/src/corejs/minimal-multi.js @@ -12,8 +12,8 @@ out = err = function(x) { var extraStatic, extraStaticSize = 1024; function setup(info) { - memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); - table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); + var memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); + var table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); var staticEnd = info.staticStart + info.staticSize; extraStatic = staticEnd; var stackStart = extraStatic + extraStaticSize; diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js index 346809ca7e359..2cffcaa000cc9 100644 --- a/src/corejs/minimal-web.js +++ b/src/corejs/minimal-web.js @@ -9,8 +9,8 @@ out = err = function(x) { // Set up memory and table function setup(info) { - memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); - table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); + var memory = new WebAssembly.Memory({ initial: info.memorySize, maximum: info.memorySize }); + var table = new WebAssembly.Table({ initial: info.tableSize, maximum: info.tableSize, element: 'anyfunc' }); var staticEnd = info.staticStart + info.staticSize; var stackStart = staticEnd; var stackMax = stackStart + info.stackSize; From b47af169be5f04db853c9c67009e94bbc428fbb9 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Jul 2018 13:00:12 -0700 Subject: [PATCH 29/31] fix [ci skip] --- emscripten.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/emscripten.py b/emscripten.py index bfa3ed4accecd..d769557513d70 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1173,7 +1173,7 @@ def table_size(table): DYNAMICTOP = setupInfo.sbrkStart; STACKTOP = setupInfo.stackStart; STACK_MAX = STACKTOP + %d; -buffer = memory.buffer; +buffer = setupInfo.memory.buffer; HEAP8 = new Int8Array(buffer); HEAP16 = new Int16Array(buffer); HEAP32 = new Int32Array(buffer); @@ -1192,8 +1192,8 @@ def table_size(table): // so would error on things that emcc adds a post for. Module['asm'] = function(global, env, buffer) { - env['memory'] = memory; - env['table'] = table; + env['memory'] = setupInfo.memory; + env['table'] = setupInfo.table; env['memoryBase'] = 0; env['tableBase'] = 0; var info = { From 1ebc3ab9cc7d0565f45d787ada59bdeb53cf97d4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 3 Jul 2018 13:12:24 -0700 Subject: [PATCH 30/31] fix [ci skip] --- src/corejs/minimal-web.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js index 2cffcaa000cc9..e1f921858d74b 100644 --- a/src/corejs/minimal-web.js +++ b/src/corejs/minimal-web.js @@ -29,7 +29,7 @@ function setup(info) { // Compile and run function start(imports, onload) { - fetch('b.wasm', { credentials: 'same-origin' }) + fetch('{{{ WASM_BINARY_FILE }}}', { credentials: 'same-origin' }) .then(function(response) { return response.arrayBuffer(); }) From 668e8ae96b1ba5c0b10cb351c49d3d425a3b7d53 Mon Sep 17 00:00:00 2001 From: "Alon Zakai (kripken)" Date: Tue, 3 Jul 2018 15:32:17 -0700 Subject: [PATCH 31/31] fixes [ci skip] --- emscripten.py | 2 ++ src/corejs/minimal-multi.js | 5 +++++ src/corejs/minimal-web.js | 2 ++ tests/test_core.py | 2 +- 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index d769557513d70..f407789936834 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1168,6 +1168,7 @@ def table_size(table): tableSize: %d, staticStart: %d, staticSize: STATIC_BUMP, + stackSize: %d }); DYNAMICTOP_PTR = setupInfo.sbrkPtr; DYNAMICTOP = setupInfo.sbrkStart; @@ -1227,6 +1228,7 @@ def table_size(table): table_total_size, settings['GLOBAL_BASE'], settings['TOTAL_STACK'], + settings['TOTAL_STACK'], ', '.join(['"' + name + '"' for name in metadata['initializers']])) if not settings['EMULATED_FUNCTION_POINTERS']: asm_setup += "\nModule['wasmMaxTableSize'] = %d;\n" % table_total_size diff --git a/src/corejs/minimal-multi.js b/src/corejs/minimal-multi.js index af1fbdeddda2d..870ea7b19b0fd 100644 --- a/src/corejs/minimal-multi.js +++ b/src/corejs/minimal-multi.js @@ -1,4 +1,9 @@ +// Minimal core with +// * Web, Node.js, SpiderMonkey support for loading wasm +// * console.log for all output +// * Support for main()'s argc/argv + // Environment setup var out, err; diff --git a/src/corejs/minimal-web.js b/src/corejs/minimal-web.js index e1f921858d74b..5ff43f04f62f7 100644 --- a/src/corejs/minimal-web.js +++ b/src/corejs/minimal-web.js @@ -1,4 +1,6 @@ +// Minimal web-only core + // Environment setup var out, err; diff --git a/tests/test_core.py b/tests/test_core.py index 90bb13f576c85..e1ff9d288eaf9 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -7803,6 +7803,6 @@ def setUp(self): asmi = make_run('asmi', compiler=CLANG, emcc_args=['-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) asm2i = make_run('asm2i', compiler=CLANG, emcc_args=['-O2', '-s', 'EMTERPRETIFY=1', '-s', 'WASM=0']) -cjs = make_run('cjs', compiler=CLANG, emcc_args=['-s', 'CUSTOM_CORE_JS="%s"' % path_from_root('src', 'corejs', 'minimal-multi.js')]) +cjs = make_run('cjs', compiler=CLANG, emcc_args=['-g', '-s', 'CUSTOM_CORE_JS="%s"' % path_from_root('src', 'corejs', 'minimal-multi.js')]) del T # T is just a shape for the specific subclasses, we don't test it itself