aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-05-08 16:21:14 -0700
committerAlon Zakai <alonzakai@gmail.com>2014-05-08 16:21:14 -0700
commit2ad7b1037ceb2d5ec5457df8c1365694469dcab2 (patch)
tree20a1a927d277d2114be374c7a02d043fe02a2e54
parent9c613ffaac19bcc718c0c25e85fde7a3ec11f27c (diff)
parentdeb49776cf90ceb1033c741b568423d6a3bb5d46 (diff)
Merge pull request #2311 from fadams/fix-64bit-long-return-issue
Fix 64bit long return issue
-rwxr-xr-xemscripten.py34
-rw-r--r--src/runtime.js9
-rw-r--r--tests/return64bit/test.c6
-rw-r--r--tests/return64bit/testbind.js18
-rw-r--r--tests/return64bit/testbindend.js2
-rw-r--r--tests/return64bit/testbindstart.js3
-rw-r--r--tests/test_core.py22
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):