do not evaluate constants in asm.js, fix IIFE mode detection

fixes #10283
This commit is contained in:
Gergely Nagy 2020-01-21 18:25:26 +01:00
parent 04a613c8bd
commit aea4fd97b5
4 changed files with 64 additions and 9 deletions

View File

@ -131,6 +131,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") {
@ -201,6 +202,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") {
@ -236,6 +238,7 @@ class ConstPlugin {
parser.hooks.expressionLogicalOperator.tap(
"ConstPlugin",
expression => {
if (parser.scope.isAsmJs) return;
if (
expression.operator === "&&" ||
expression.operator === "||"
@ -321,6 +324,7 @@ class ConstPlugin {
parser.hooks.evaluateIdentifier
.for("__resourceQuery")
.tap("ConstPlugin", expr => {
if (parser.scope.isAsmJs) return;
if (!parser.state.module) return;
return evaluateToString(getQuery(parser.state.module.resource))(
expr
@ -329,6 +333,7 @@ class ConstPlugin {
parser.hooks.expression
.for("__resourceQuery")
.tap("ConstPlugin", expr => {
if (parser.scope.isAsmJs) return;
if (!parser.state.module) return;
const dep = new CachedConstDependency(
JSON.stringify(getQuery(parser.state.module.resource)),

View File

@ -78,6 +78,7 @@ class VariableInfo {
* @property {boolean | "arrow"} topLevelScope
* @property {boolean} inShorthand
* @property {boolean} isStrict
* @property {boolean} isAsmJs
* @property {boolean} inTry
*/
@ -1455,7 +1456,7 @@ class JavascriptParser extends Parser {
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 {
@ -1935,7 +1936,7 @@ class JavascriptParser extends Parser {
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 {
@ -1953,7 +1954,7 @@ class JavascriptParser extends Parser {
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 {
@ -2172,6 +2173,7 @@ class JavascriptParser extends Parser {
this.setVariable(params[i].name, varInfo);
}
if (functionExpression.body.type === "BlockStatement") {
this.detectMode(functionExpression.body.body);
this.prewalkStatement(functionExpression.body);
this.walkStatement(functionExpression.body);
} else {
@ -2495,6 +2497,7 @@ class JavascriptParser extends Parser {
inTry: false,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
};
@ -2516,6 +2519,7 @@ class JavascriptParser extends Parser {
inTry: false,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
};
@ -2539,6 +2543,7 @@ class JavascriptParser extends Parser {
inTry: oldScope.inTry,
inShorthand: false,
isStrict: oldScope.isStrict,
isAsmJs: oldScope.isAsmJs,
definitions: oldScope.definitions.createChild()
};
@ -2547,15 +2552,17 @@ class JavascriptParser extends Parser {
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) {
@ -2790,6 +2797,7 @@ class JavascriptParser extends Parser {
inTry: false,
inShorthand: false,
isStrict: false,
isAsmJs: false,
definitions: new StackedMap()
};
/** @type {ParserState} */
@ -2800,7 +2808,7 @@ class JavascriptParser extends Parser {
this.lastStatementEndPos = NaN;
this.statementStartPos = NaN;
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);

View File

@ -170,6 +170,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(() => {

22
test/fixtures/asmjs.js vendored Normal file
View File

@ -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;
};