Skip to content

Commit

Permalink
JS_FFI option to disable JS FFI mangling. (#5168)
Browse files Browse the repository at this point in the history
* LEGALIZE_JS_FFI option to disable JS FFI mangling.

For JS/Web platform, calls to JS imports are normally wrapped to
convert i64 to i32 and f32 to f64. Likewise calls from JS into exports
do the inverse wrapping. This change provides an option to disable
that wrapping and use the original types for the call. This is useful
for non-web embeddings.

The following fastcomp options get enabled by this option:
    -emscripten-legalize-javascript-ffi=0
    -emscripten-only-wasm

The following binaryen options get enabled by this option:
    --no-legalize-javascript-ffi
    --wasm-only

* Add test for LEGALIZE_JS_FFI.

The test other.test_legalize_js_ffi compiles tests/core/ffi.c several
different ways: LEGALIZE_JS_FFI={0,1}, SIDE_MODULE={0,1}, -O{2,0}.
After each build the test scans the results a.out.wast file to make
sure that type wrapping/conversions happen (LEGALIZE_JS_FFI=1) or
don't happen (LEGALIZE_JS_FFI=0).
  • Loading branch information
kanaka authored and kripken committed May 5, 2017
1 parent 909e396 commit ccaf4e7
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 1 deletion.
5 changes: 5 additions & 0 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1368,6 +1368,9 @@ def check(input_file):
newargs.append('-mllvm')
newargs.append('-disable-llvm-optzns')

if not shared.Settings.LEGALIZE_JS_FFI:
assert shared.Building.is_wasm_only(), 'LEGALIZE_JS_FFI incompatible with RUNNING_JS_OPTS and non-wasm BINARYEN_METHOD.'

shared.Settings.EMSCRIPTEN_VERSION = shared.EMSCRIPTEN_VERSION
shared.Settings.OPT_LEVEL = opt_level
shared.Settings.DEBUG_LEVEL = debug_level
Expand Down Expand Up @@ -2145,6 +2148,8 @@ def do_minify(): # minifies the code. this is also when we do certain optimizati
cmd += ['--mem-max=-1']
elif shared.Settings.BINARYEN_MEM_MAX >= 0:
cmd += ['--mem-max=' + str(shared.Settings.BINARYEN_MEM_MAX)]
if shared.Settings.LEGALIZE_JS_FFI != 1:
cmd += ['--no-legalize-javascript-ffi']
if shared.Building.is_wasm_only():
cmd += ['--wasm-only'] # this asm.js is code not intended to run as asm.js, it is only ever going to be wasm, an can contain special fastcomp-wasm support
if debug_level >= 2 or profiling_funcs:
Expand Down
2 changes: 2 additions & 0 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ def create_backend_args(infile, temp_js, settings):
args += ['-emscripten-global-base=%d' % settings['GLOBAL_BASE']]
if settings['SIDE_MODULE']:
args += ['-emscripten-side-module']
if settings['LEGALIZE_JS_FFI'] != 1:
args += ['-emscripten-legalize-javascript-ffi=0']
if settings['DISABLE_EXCEPTION_CATCHING'] != 1:
args += ['-enable-emscripten-cpp-exceptions']
if settings['DISABLE_EXCEPTION_CATCHING'] == 2:
Expand Down
7 changes: 7 additions & 0 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,13 @@ var BINARYEN_ASYNC_COMPILATION = 1; // Whether to compile the wasm asynchronousl
var BINARYEN_ROOT = ""; // Directory where we can find Binaryen. Will be automatically set for you,
// but you can set it to override if you are a Binaryen developer.

var LEGALIZE_JS_FFI = 1; // Whether to legalize the JS FFI interfaces (imports/exports) by wrapping
// them to automatically demote i64 to i32 and promote f32 to f64. This is
// necessary in order to interface with JavaScript, both for asm.js and wasm.
// For non-web/non-JS embeddings, setting this to 0 may be desirable.
// LEGALIZE_JS_FFI=0 is incompatible with RUNNING_JS_OPTS and using
// non-wasm BINARYEN_METHOD settings.

var WASM = 0; // Alias for BINARYEN, the two are identical. Both make us compile code to WebAssembly.

var WASM_BACKEND = 0; // Whether to use the WebAssembly backend that is in development in LLVM.
Expand Down
26 changes: 26 additions & 0 deletions tests/other/ffi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <stdio.h>
#include <math.h>

float add_f (float a, float b) {
return a + b;
}

long long add_ll (long long a, long long b) {
return a + b;
}

extern float import_f(float x);

extern long long import_ll(long long x);

int main () {
float a = 1.2,
b = import_f((float)3.4),
c;
c = add_f(a, b);

long long d = 1,
e = import_ll((long long)2),
f;
f = add_ll(d, e);
}
46 changes: 46 additions & 0 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -7508,6 +7508,52 @@ def test_binaryen_ignore_implicit_traps(self):
print 'sizes:', sizes
assert sizes[1] < sizes[0], 'ignoring implicit traps must reduce code size'

# test disabling of JS FFI legalization
def test_legalize_js_ffi(self):
with clean_write_access_to_canonical_temp_dir():
for (args,js_ffi) in [
(['-s', 'LEGALIZE_JS_FFI=1', '-s', 'SIDE_MODULE=1', '-O2', ], True),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O2', ], False),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=1', '-O0', ], False),
(['-s', 'LEGALIZE_JS_FFI=0', '-s', 'SIDE_MODULE=0', '-O0'], False),
]:
print args
try_delete('a.out.wasm')
try_delete('a.out.wast')
cmd = [PYTHON, EMCC, path_from_root('tests', 'other', 'ffi.c'), '-s', 'WASM=1', '-g', '-o', 'a.out.js'] + args
print ' '.join(cmd)
proc = Popen(cmd, stdout=PIPE, stderr=PIPE)
output, err = proc.communicate()
assert proc.returncode == 0
text = open('a.out.wast').read()
#print "text: %s" % text
e_add_f32 = re.search('func \$_add_f \(param \$*. f32\) \(param \$*. f32\) \(result f32\)', text)
i_i64_i32 = re.search('import .*"_import_ll" .*\(param i32 i32\) \(result i32\)', text)
i_f32_f64 = re.search('import .*"_import_f" .*\(param f64\) \(result f64\)', text)
i_i64_i64 = re.search('import .*"_import_ll" .*\(param i64\) \(result i64\)', text)
i_f32_f32 = re.search('import .*"_import_f" .*\(param f32\) \(result f32\)', text)
e_i64_i32 = re.search('func \$_add_ll \(param \$*. i32\) \(param \$*. i32\) \(param \$*. i32\) \(param \$*. i32\) \(result i32\)', text)
e_f32_f64 = re.search('func \$legalstub\$_add_f \(param \$*. f64\) \(param \$*. f64\) \(result f64\)', text)
e_i64_i64 = re.search('func \$_add_ll \(param \$*. i64\) \(param \$*. i64\) \(result i64\)', text)
#print e_add_f32, i_i64_i32, i_f32_f64, i_i64_i64, i_f32_f32, e_i64_i32, e_f32_f64, e_i64_i64
assert e_add_f32, 'add_f export missing'
if js_ffi:
assert i_i64_i32, 'i64 not converted to i32 in imports'
assert i_f32_f64, 'f32 not converted to f64 in imports'
assert not i_i64_i64, 'i64 not converted to i32 in imports'
assert not i_f32_f32, 'f32 not converted to f64 in imports'
assert e_i64_i32, 'i64 not converted to i32 in exports'
assert e_f32_f64, 'f32 not converted to f64 in exports'
assert not e_i64_i64, 'i64 not converted to i32 in exports'
else:
assert not i_i64_i32, 'i64 converted to i32 in imports'
assert not i_f32_f64, 'f32 converted to f64 in imports'
assert i_i64_i64, 'i64 converted to i32 in imports'
assert i_f32_f32, 'f32 converted to f64 in imports'
assert not e_i64_i32, 'i64 converted to i32 in exports'
assert not e_f32_f64, 'f32 converted to f64 in exports'
assert e_i64_i64, 'i64 converted to i32 in exports'

def test_sysconf_phys_pages(self):
for args, expected in [
([], 1024),
Expand Down
2 changes: 1 addition & 1 deletion tools/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -1981,7 +1981,7 @@ def is_wasm_only():
# fastcomp can emit wasm-only code.
# also disable this mode if it depends on special optimizations that are not yet
# compatible with it.
return 'asmjs' not in Settings.BINARYEN_METHOD and 'interpret-asm2wasm' not in Settings.BINARYEN_METHOD and not Settings.RUNNING_JS_OPTS and not Settings.EMULATED_FUNCTION_POINTERS and not Settings.EMULATE_FUNCTION_POINTER_CASTS
return ('asmjs' not in Settings.BINARYEN_METHOD and 'interpret-asm2wasm' not in Settings.BINARYEN_METHOD and not Settings.RUNNING_JS_OPTS and not Settings.EMULATED_FUNCTION_POINTERS and not Settings.EMULATE_FUNCTION_POINTER_CASTS) or not Settings.LEGALIZE_JS_FFI

@staticmethod
def get_safe_internalize():
Expand Down

0 comments on commit ccaf4e7

Please sign in to comment.