diff --git a/lib/ConstPlugin.js b/lib/ConstPlugin.js index 164b840dab2..6b05720fdf1 100644 --- a/lib/ConstPlugin.js +++ b/lib/ConstPlugin.js @@ -119,6 +119,7 @@ class ConstPlugin { const handler = parser => { parser.hooks.statementIf.tap("ConstPlugin", statement => { + if (parser.scope.isAsmJs) return; const param = parser.evaluateExpression(statement.test); const bool = param.asBool(); if (typeof bool === "boolean") { @@ -189,6 +190,7 @@ class ConstPlugin { parser.hooks.expressionConditionalOperator.tap( "ConstPlugin", expression => { + if (parser.scope.isAsmJs) return; const param = parser.evaluateExpression(expression.test); const bool = param.asBool(); if (typeof bool === "boolean") { @@ -224,6 +226,7 @@ class ConstPlugin { parser.hooks.expressionLogicalOperator.tap( "ConstPlugin", expression => { + if (parser.scope.isAsmJs) return; if ( expression.operator === "&&" || expression.operator === "||" @@ -309,6 +312,7 @@ class ConstPlugin { parser.hooks.evaluateIdentifier .for("__resourceQuery") .tap("ConstPlugin", expr => { + if (parser.scope.isAsmJs) return; if (!parser.state.module) return; return ParserHelpers.evaluateToString( getQuery(parser.state.module.resource) @@ -317,6 +321,7 @@ class ConstPlugin { parser.hooks.expression .for("__resourceQuery") .tap("ConstPlugin", () => { + if (parser.scope.isAsmJs) return; if (!parser.state.module) return; parser.state.current.addVariable( "__resourceQuery", diff --git a/lib/Parser.js b/lib/Parser.js index e29a12d98e7..721bf3db192 100644 --- a/lib/Parser.js +++ b/lib/Parser.js @@ -1229,7 +1229,7 @@ class Parser extends Tapable { this.walkPattern(param); } if (statement.body.type === "BlockStatement") { - this.detectStrictMode(statement.body.body); + this.detectMode(statement.body.body); this.prewalkStatement(statement.body); this.walkStatement(statement.body); } else { @@ -1697,7 +1697,7 @@ class Parser extends Tapable { this.walkPattern(param); } if (expression.body.type === "BlockStatement") { - this.detectStrictMode(expression.body.body); + this.detectMode(expression.body.body); this.prewalkStatement(expression.body); this.walkStatement(expression.body); } else { @@ -1713,7 +1713,7 @@ class Parser extends Tapable { this.walkPattern(param); } if (expression.body.type === "BlockStatement") { - this.detectStrictMode(expression.body.body); + this.detectMode(expression.body.body); this.prewalkStatement(expression.body); this.walkStatement(expression.body); } else { @@ -1894,6 +1894,7 @@ class Parser extends Tapable { this.scope.renames.set(params[i].name, param); } if (functionExpression.body.type === "BlockStatement") { + this.detectMode(functionExpression.body.body); this.prewalkStatement(functionExpression.body); this.walkStatement(functionExpression.body); } else { @@ -2001,6 +2002,7 @@ class Parser extends Tapable { inTry: false, inShorthand: false, isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, definitions: oldScope.definitions.createChild(), renames: oldScope.renames.createChild() }; @@ -2024,6 +2026,7 @@ class Parser extends Tapable { inTry: false, inShorthand: false, isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, definitions: oldScope.definitions.createChild(), renames: oldScope.renames.createChild() }; @@ -2049,6 +2052,7 @@ class Parser extends Tapable { inTry: oldScope.inTry, inShorthand: false, isStrict: oldScope.isStrict, + isAsmJs: oldScope.isAsmJs, definitions: oldScope.definitions.createChild(), renames: oldScope.renames.createChild() }; @@ -2058,15 +2062,17 @@ class Parser extends Tapable { this.scope = oldScope; } - detectStrictMode(statements) { - const isStrict = + detectMode(statements) { + const isLiteral = statements.length >= 1 && statements[0].type === "ExpressionStatement" && - statements[0].expression.type === "Literal" && - statements[0].expression.value === "use strict"; - if (isStrict) { + statements[0].expression.type === "Literal"; + if (isLiteral && statements[0].expression.value === "use strict") { this.scope.isStrict = true; } + if (isLiteral && statements[0].expression.value === "use asm") { + this.scope.isAsmJs = true; + } } enterPatterns(patterns, onIdent) { @@ -2272,13 +2278,14 @@ class Parser extends Tapable { inTry: false, inShorthand: false, isStrict: false, + isAsmJs: false, definitions: new StackedSetMap(), renames: new StackedSetMap() }; const state = (this.state = initialState || {}); this.comments = comments; if (this.hooks.program.call(ast, comments) === undefined) { - this.detectStrictMode(ast.body); + this.detectMode(ast.body); this.prewalkStatements(ast.body); this.blockPrewalkStatements(ast.body); this.walkStatements(ast.body); diff --git a/test/Compiler.test.js b/test/Compiler.test.js index 8507090edac..3da9a269de2 100644 --- a/test/Compiler.test.js +++ b/test/Compiler.test.js @@ -168,6 +168,26 @@ describe("Compiler", () => { done(); }); }); + + it("should not evaluate constants in asm.js", done => { + compile("./asmjs", {}, (stats, files) => { + expect(Object.keys(files)).toEqual(["/main.js"]); + const bundle = files["/main.js"]; + expect(bundle).toMatch('"use asm";'); + expect(bundle).toMatch("101"); + expect(bundle).toMatch("102"); + expect(bundle).toMatch("103"); + expect(bundle).toMatch("104"); + expect(bundle).toMatch("105"); + expect(bundle).not.toMatch("106"); + expect(bundle).not.toMatch("107"); + expect(bundle).not.toMatch("108"); + expect(bundle).toMatch("109"); + expect(bundle).toMatch("110"); + done(); + }); + }); + describe("methods", () => { let compiler; beforeEach(() => { diff --git a/test/fixtures/asmjs.js b/test/fixtures/asmjs.js new file mode 100644 index 00000000000..59d2101f7ed --- /dev/null +++ b/test/fixtures/asmjs.js @@ -0,0 +1,22 @@ +module.exports = function a() { + function b() { + "use asm"; + if (0 == 0) { + return 1 == 1 ? 101 : 102; + } else { + return 0 == 1 ? 103 : 104; + } + } + function c() { + if (0 == 0) { + return 1 == 1 ? 105 : 106; + } else { + return 0 == 1 ? 107 : 108; + } + } + var d = (function() { + "use asm"; + return 1 == 1 ? 109 : 110; + })(); + return b() + c() + d; +};