diff options
-rwxr-xr-x | emscripten.py | 34 | ||||
-rw-r--r-- | src/runtime.js | 9 | ||||
-rw-r--r-- | tests/return64bit/test.c | 6 | ||||
-rw-r--r-- | tests/return64bit/testbind.js | 18 | ||||
-rw-r--r-- | tests/return64bit/testbindend.js | 2 | ||||
-rw-r--r-- | tests/return64bit/testbindstart.js | 3 | ||||
-rw-r--r-- | tests/test_core.py | 22 |
7 files changed, 82 insertions, 12 deletions
diff --git a/emscripten.py b/emscripten.py index 939ddbe8..e2aef648 100755 --- a/emscripten.py +++ b/emscripten.py @@ -477,7 +477,7 @@ def emscript(infile, settings, outfile, libraries=[], compiler_engine=None, if '_rand' in exported_implemented_functions or '_srand' in exported_implemented_functions: basic_vars += ['___rand_seed'] - asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] + asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] + ['getTempRet%d' % i for i in range(10)] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] @@ -632,6 +632,10 @@ function setTempRet%d(value) { value = value|0; tempRet%d = value; } +''' % (i, i) for i in range(10)]) + ''.join([''' +function getTempRet%d() { + return tempRet%d|0; +} ''' % (i, i) for i in range(10)])] + [PostSets.js + '\n'] + funcs_js + [''' %s @@ -644,9 +648,11 @@ function setTempRet%d(value) { if not settings.get('SIDE_MODULE'): funcs_js.append(''' -Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) }; -Runtime.stackSave = function() { return asm['stackSave']() }; -Runtime.stackRestore = function(top) { asm['stackRestore'](top) }; +Runtime.stackAlloc = asm['stackAlloc']; +Runtime.stackSave = asm['stackSave']; +Runtime.stackRestore = asm['stackRestore']; +Runtime.setTempRet0 = asm['setTempRet0']; +Runtime.getTempRet0 = asm['getTempRet0']; ''') # Set function table masks @@ -1058,7 +1064,7 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None, if '_rand' in exported_implemented_functions or '_srand' in exported_implemented_functions: basic_vars += ['___rand_seed'] - asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] + asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew', 'setTempRet0', 'getTempRet0'] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] @@ -1208,12 +1214,14 @@ function copyTempDouble(ptr) { HEAP8[tempDoublePtr+6>>0] = HEAP8[ptr+6>>0]; HEAP8[tempDoublePtr+7>>0] = HEAP8[ptr+7>>0]; } -''' + ''.join([''' -function setTempRet%d(value) { +function setTempRet0(value) { value = value|0; - tempRet%d = value; + tempRet0 = value; +} +function getTempRet0() { + return tempRet0|0; } -''' % (i, i) for i in range(10)])] + funcs_js + [''' +'''] + funcs_js + [''' %s return %s; @@ -1225,9 +1233,11 @@ function setTempRet%d(value) { if not settings.get('SIDE_MODULE'): funcs_js.append(''' -Runtime.stackAlloc = function(size) { return asm['stackAlloc'](size) }; -Runtime.stackSave = function() { return asm['stackSave']() }; -Runtime.stackRestore = function(top) { asm['stackRestore'](top) }; +Runtime.stackAlloc = asm['stackAlloc']; +Runtime.stackSave = asm['stackSave']; +Runtime.stackRestore = asm['stackRestore']; +Runtime.setTempRet0 = asm['setTempRet0']; +Runtime.getTempRet0 = asm['getTempRet0']; ''') # Set function table masks diff --git a/src/runtime.js b/src/runtime.js index 63610d3b..4466a308 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -96,6 +96,15 @@ function unInline(name_, params) { } var Runtime = { + // When a 64 bit long is returned from a compiled function the least significant + // 32 bit word is passed in the return value, but the most significant 32 bit + // word is placed in tempRet0. This provides an accessor for that value. + setTempRet0: function(value) { + tempRet0 = value; + }, + getTempRet0: function() { + return tempRet0; + }, stackSave: function() { return STACKTOP; }, diff --git a/tests/return64bit/test.c b/tests/return64bit/test.c new file mode 100644 index 00000000..e75ee5c1 --- /dev/null +++ b/tests/return64bit/test.c @@ -0,0 +1,6 @@ + +// This is just a trivial test function, the key bit of interest is that it returns a 64 bit long. +long long test() { + long long x = ((long long)1234 << 32) + 5678; + return x; +} diff --git a/tests/return64bit/testbind.js b/tests/return64bit/testbind.js new file mode 100644 index 00000000..f2cc0e7b --- /dev/null +++ b/tests/return64bit/testbind.js @@ -0,0 +1,18 @@ +// This code represents a simple native JavaScript binding to a test C function +// that returns a 64 bit long. Notice that the least significant 32 bits are +// returned in the normal return value, but the most significant 32 bits are +// returned via the accessor method Runtime.getTempRet0() + +var Module = { + 'noExitRuntime' : true +}; + +Module['runtest'] = function() { + var low = _test(); + var high = Runtime.getTempRet0(); + + console.log("low = " + low); + console.log("high = " + high); +}; + + diff --git a/tests/return64bit/testbindend.js b/tests/return64bit/testbindend.js new file mode 100644 index 00000000..2218f14d --- /dev/null +++ b/tests/return64bit/testbindend.js @@ -0,0 +1,2 @@ + +})(); // End of self calling lambda used to wrap library. diff --git a/tests/return64bit/testbindstart.js b/tests/return64bit/testbindstart.js new file mode 100644 index 00000000..4956806b --- /dev/null +++ b/tests/return64bit/testbindstart.js @@ -0,0 +1,3 @@ + +(function() { // Start of self-calling lambda used to avoid polluting global namespace. + diff --git a/tests/test_core.py b/tests/test_core.py index fb53897a..04271192 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -6528,6 +6528,28 @@ def process(filename): if self.emcc_args is None: return self.skip('needs emcc') self.do_run_from_file(path_from_root('tests', 'test_locale.c'), path_from_root('tests', 'test_locale.out')) + def test_64bit_return_value(self): + # This test checks that the most significant 32 bits of a 64 bit long are correctly made available + # to native JavaScript applications that wish to interact with compiled code returning 64 bit longs. + # The MS 32 bits should be available in Runtime.getTempRet0() even when compiled with -O2 --closure 1 + # Run with ./runner.py test_64bit_return_value + + # Compile test.c and wrap it in a native JavaScript binding so we can call our compiled function from JS. + Popen([PYTHON, EMCC, path_from_root('tests', 'return64bit', 'test.c'), '--pre-js', path_from_root('tests', 'return64bit', 'testbindstart.js'), '--pre-js', path_from_root('tests', 'return64bit', 'testbind.js'), '--post-js', path_from_root('tests', 'return64bit', 'testbindend.js'), '-s', 'EXPORTED_FUNCTIONS=["_test"]', '-o', 'test.js', '-O2', '--closure', '1'], stdout=PIPE, stderr=PIPE).communicate() + + # Simple test program to load the test.js binding library and call the binding to the + # C function returning the 64 bit long. + open(os.path.join(self.get_dir(), 'testrun.js'), 'w').write(''' + var test = require("./test.js"); + test.runtest(); + ''') + + # Run the test and confirm the output is as expected. + if NODE_JS in JS_ENGINES: + out = run_js('testrun.js', engine=NODE_JS, full_output=True) + assert "low = 5678" in out + assert "high = 1234" in out + # Generate tests for everything def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0, typed_arrays=0, emcc_args=None, env=None): |