aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/intertyper.js20
-rw-r--r--tests/test_core.py14
-rw-r--r--tools/js-optimizer.js16
3 files changed, 39 insertions, 11 deletions
diff --git a/src/intertyper.js b/src/intertyper.js
index 5432b1ca..ddb93d71 100644
--- a/src/intertyper.js
+++ b/src/intertyper.js
@@ -707,18 +707,24 @@ function intertyper(data, sidePass, baseLineNums) {
var tokensLeft = item.tokens.slice(2);
item.ident = eatLLVMIdent(tokensLeft);
if (item.ident == 'asm') {
+ if (ASM_JS) {
+ warnOnce('inline JS in asm.js mode can cause the code to no longer fall in the asm.js subset of JavaScript');
+ }
+ assert(TARGET_LE32, 'inline js is only supported in le32');
// Inline assembly is just JavaScript that we paste into the code
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
var i = 0;
- if (tokensLeft[3].item) { // not present in x86 inline asm
- splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
- var ident = toNiceIdent(element[1].text);
- var type = element[0].text;
- item.ident = item.ident.replace(new RegExp('\\$' + i++, 'g'), ident);
- });
- }
+ var params = [], args = [];
+ splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
+ var ident = toNiceIdent(element[1].text);
+ var type = element[0].text;
+ params.push('$' + (i++));
+ args.push(ident);
+ });
+ if (item.assignTo) item.ident = 'return ' + item.ident;
+ item.ident = '(function(' + params + ') { ' + item.ident + ' })(' + args + ');';
return { forward: null, ret: [item], item: item };
}
if (item.ident.substr(-2) == '()') {
diff --git a/tests/test_core.py b/tests/test_core.py
index 3568efee..5d4f35e8 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -3743,6 +3743,7 @@ def process(filename):
def test_inlinejs(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = r'''
#include <stdio.h>
@@ -3763,6 +3764,7 @@ def process(filename):
def test_inlinejs2(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = r'''
#include <stdio.h>
@@ -3773,8 +3775,8 @@ def process(filename):
}
void mult() {
- asm("var $_$1 = Math.abs(-100); $_$1 *= 2;"); // multiline
- asm __volatile__("Module.print($_$1); Module.print('\n')");
+ asm("var $_$1 = Math.abs(-100); $_$1 *= 2; Module.print($_$1)"); // multiline
+ asm __volatile__("Module.print('done')");
}
int main(int argc, char **argv) {
@@ -3784,7 +3786,7 @@ def process(filename):
}
'''
- self.do_run(src, '4\n200\n')
+ self.do_run(src, '4\n200\ndone\n')
def test_inlinejs3(self):
if Settings.ASM_JS: return self.skip('asm does not support random code, TODO: something that works in asm')
@@ -7614,12 +7616,14 @@ def process(filename):
def test_unistd_access(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = open(path_from_root('tests', 'unistd', 'access.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'access.out'), 'r').read()
self.do_run(src, expected)
def test_unistd_curdir(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = open(path_from_root('tests', 'unistd', 'curdir.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'curdir.out'), 'r').read()
self.do_run(src, expected)
@@ -7650,6 +7654,7 @@ def process(filename):
def test_unistd_truncate(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = open(path_from_root('tests', 'unistd', 'truncate.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'truncate.out'), 'r').read()
self.do_run(src, expected)
@@ -7679,6 +7684,7 @@ def process(filename):
def test_unistd_links(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
src = open(path_from_root('tests', 'unistd', 'links.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'links.out'), 'r').read()
self.do_run(src, expected)
@@ -7690,6 +7696,8 @@ def process(filename):
def test_unistd_io(self):
if Settings.ASM_JS: Settings.ASM_JS = 2 # skip validation, asm does not support random code
+ if not self.is_le32(): return self.skip('le32 needed for inline js')
+ if self.run_name == 'o2': return self.skip('non-asm optimized builds can fail with inline js')
src = open(path_from_root('tests', 'unistd', 'io.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'io.out'), 'r').read()
self.do_run(src, expected)
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 21b19fd3..7358e1df 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -1564,6 +1564,7 @@ function normalizeAsm(func) {
var data = {
params: {}, // ident => ASM_* type
vars: {}, // ident => ASM_* type
+ inlines: [], // list of inline assembly copies
};
// process initial params
var stats = func[3];
@@ -1588,7 +1589,7 @@ function normalizeAsm(func) {
var name = v[0];
var value = v[1];
if (!(name in data.vars)) {
- if (!(value[0] === 'num' || (value[0] === 'unary-prefix' && value[2][0] === 'num'))) break outer; // must be valid coercion no-op
+ assert(value[0] === 'num' || (value[0] === 'unary-prefix' && value[2][0] === 'num')); // must be valid coercion no-op
data.vars[name] = detectAsmCoercion(value);
v.length = 1; // make an un-assigning var
} else {
@@ -1621,6 +1622,10 @@ function normalizeAsm(func) {
node[0] = 'name';
node[1] = 'Math_' + node[2];
}
+ } else if (type === 'call' && node[1][0] === 'function') {
+ assert(!node[1][1]); // anonymous functions only
+ data.inlines.push(node[1]);
+ node[1] = ['name', 'inlinejs']; // empty out body, leave arguments, so they are eliminated/minified properly
}
});
i++;
@@ -1669,6 +1674,14 @@ function denormalizeAsm(func, data) {
} else {
stats[next] = emptyNode();
}
+ if (data.inlines.length > 0) {
+ var i = 0;
+ traverse(func, function(node, type) {
+ if (type === 'call' && node[1][0] === 'name' && node[1][1] === 'inlinejs') {
+ node[1] = data.inlines[i++]; // swap back in the body
+ }
+ });
+ }
//printErr('denormalized \n\n' + astToSrc(func) + '\n\n');
}
@@ -2019,6 +2032,7 @@ function registerize(ast) {
var finalAsmData = {
params: {},
vars: {},
+ inlines: asmData.inlines,
};
for (var i = 1; i < nextReg; i++) {
var reg = fullNames[i];