Skip to content

Feedback wanted: Allow custom "core JS" replacements, to *really* shrink minimal JS sizes #6803

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
8c18868
wip move code behind CUSTOM_CORE_JS
kripken Jun 29, 2018
16e4135
wip more custom-core-js
kripken Jun 29, 2018
2095b19
wip [ci skip]
kripken Jun 29, 2018
fd335a5
more [ci skip]
kripken Jun 30, 2018
d106d56
almost prints hello world [ci skip]
kripken Jun 30, 2018
d8089ed
hello world works hurrah [ci skip]
kripken Jun 30, 2018
207904d
comment [ci skip]
kripken Jun 30, 2018
f4a5068
fix EM_ASMs [ci skip]
kripken Jun 30, 2018
d125b17
hack for metadce [ci skip]
kripken Jun 30, 2018
13f7459
updates [ci skip]
kripken Jun 30, 2018
3c7eeac
work with closure [ci skip]
kripken Jun 30, 2018
a61918c
refactor
kripken Jun 30, 2018
92a5574
comment [ci skip]
kripken Jun 30, 2018
b569bbf
more comments [ci skip]
kripken Jun 30, 2018
5c94ee9
progress towards libc++ hello world [ci skip]
kripken Jun 30, 2018
e5af711
mozjs support [ci skip]
kripken Jun 30, 2018
42d57d8
fixes, now libc++ hello world works too [ci skip]
kripken Jun 30, 2018
7498c0e
closure -Os working on libc++ hello world [ci skip]
kripken Jun 30, 2018
bc7b79a
work towards ammo.js [ci skip]
kripken Jul 1, 2018
8ff271f
fix [ci skip]
kripken Jul 1, 2018
dfb4243
prep testing [ci skip]
kripken Jul 1, 2018
dde724c
more test prep [ci skip]
kripken Jul 1, 2018
197f764
add src/codejs/ [ci skip]
kripken Jul 1, 2018
563bbef
wip arguments to main [ci skip]
kripken Jul 2, 2018
7c93e90
fix total memory [ci skip]
kripken Jul 2, 2018
b69d89b
better api [ci skip]
kripken Jul 2, 2018
a364659
wip [ci skip]
kripken Jul 3, 2018
a042bc0
fix [ci skip]
kripken Jul 3, 2018
b47af16
fix [ci skip]
kripken Jul 3, 2018
1ebc3ab
fix [ci skip]
kripken Jul 3, 2018
668e8ae
fixes [ci skip]
kripken Jul 3, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 79 additions & 3 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -1157,7 +1159,77 @@ 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,
staticStart: %d,
staticSize: STATIC_BUMP,
stackSize: %d
});
DYNAMICTOP_PTR = setupInfo.sbrkPtr;
DYNAMICTOP = setupInfo.sbrkStart;
STACKTOP = setupInfo.stackStart;
STACK_MAX = STACKTOP + %d;
buffer = setupInfo.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);

// XXX fix these
var ABORT, EXITSTATUS;
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'] = setupInfo.memory;
env['table'] = setupInfo.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
'Infinity': Infinity,
'NaN': NaN
},
'global.Math': Math
};
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,
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
if settings['RELOCATABLE']:
Expand Down Expand Up @@ -1251,7 +1323,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']:
Expand Down Expand Up @@ -1327,6 +1399,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 = ''
Expand Down Expand Up @@ -1982,7 +2056,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']
Expand All @@ -2002,6 +2076,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
Expand Down
105 changes: 105 additions & 0 deletions src/corejs/minimal-multi.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@

// 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;
out = err = function(x) {
console.log(x);
};

// Set up memory and table

// Some extra static memory for main() argv strings
var extraStatic, extraStaticSize = 1024;

function setup(info) {
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;
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, onload) {
// todo main's argc/argv
function postInstantiate(instance, args) {
var exports = instance['exports'];
onload(exports);
// 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]);
}
exports['_main'](argc, argv);
}
var filename = '{{{ WASM_BINARY_FILE }}}';
if (typeof fetch === 'function') {
// Web
fetch(filename, { 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, 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, args);
}
}

51 changes: 51 additions & 0 deletions src/corejs/minimal-web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

// Minimal web-only core

// Environment setup

var out, err;
out = err = function(x) {
console.log(x);
};

// Set up memory and table

function setup(info) {
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;
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, onload) {
fetch('{{{ WASM_BINARY_FILE }}}', { 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'];
onload(exports);
exports['_main']();
});
}

15 changes: 8 additions & 7 deletions src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(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'));
Expand Down Expand Up @@ -526,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');
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ function exportRuntime() {
'establishStackSpace',
'print',
'printErr',
'abort',
];
if (SUPPORT_BASE64_EMBEDDING) {
runtimeElements.push('intArrayFromBase64');
Expand Down
36 changes: 0 additions & 36 deletions src/postamble.js
Original file line number Diff line number Diff line change
Expand Up @@ -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']) {
Expand Down
Loading