Bug 1088328 - OdinMonkey: accept (and ignore) non-semantic processing directives (r=bbouvier)
authorLuke Wagner <luke@mozilla.com>
Fri, 24 Oct 2014 12:32:10 -0500
changeset 212298 fcd719ea99902352255b7f18188b2853fb6716d9
parent 212297 1090f3645eb3c17beeddfc22ee2a441ba781c93b
child 212299 7d515b995286c76af531e62ee20fae7274afa5a0
push id27704
push userkwierso@gmail.com
push dateSat, 25 Oct 2014 01:25:30 +0000
treeherdermozilla-central@e37231060eb4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbbouvier
bugs1088328
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1088328 - OdinMonkey: accept (and ignore) non-semantic processing directives (r=bbouvier)
js/src/asmjs/AsmJSValidate.cpp
js/src/jit-test/tests/asm.js/testBasic.js
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -324,16 +324,31 @@ MaybeDefinitionInitializer(ParseNode *pn
 
 static inline bool
 IsUseOfName(ParseNode *pn, PropertyName *name)
 {
     return pn->isKind(PNK_NAME) && pn->name() == name;
 }
 
 static inline bool
+IsIgnoredDirectiveName(ExclusiveContext *cx, JSAtom *atom)
+{
+    return atom != cx->names().useStrict;
+}
+
+static inline bool
+IsIgnoredDirective(ExclusiveContext *cx, ParseNode *pn)
+{
+    return pn->isKind(PNK_SEMI) &&
+           UnaryKid(pn) &&
+           UnaryKid(pn)->isKind(PNK_STRING) &&
+           IsIgnoredDirectiveName(cx, UnaryKid(pn)->pn_atom);
+}
+
+static inline bool
 IsEmptyStatement(ParseNode *pn)
 {
     return pn->isKind(PNK_SEMI) && !UnaryKid(pn);
 }
 
 static inline ParseNode *
 SkipEmptyStatements(ParseNode *pn)
 {
@@ -3507,18 +3522,21 @@ CheckModuleArguments(ModuleCompiler &m, 
     return true;
 }
 
 static bool
 CheckPrecedingStatements(ModuleCompiler &m, ParseNode *stmtList)
 {
     MOZ_ASSERT(stmtList->isKind(PNK_STATEMENTLIST));
 
-    if (ListLength(stmtList) != 0)
-        return m.fail(ListHead(stmtList), "invalid asm.js statement");
+    ParseNode *stmt = ListHead(stmtList);
+    for (unsigned i = 0, n = ListLength(stmtList); i < n; i++) {
+        if (!IsIgnoredDirective(m.cx(), stmt))
+            return m.fail(stmt, "invalid asm.js statement");
+    }
 
     return true;
 }
 
 static bool
 CheckGlobalVariableInitConstant(ModuleCompiler &m, PropertyName *varName, ParseNode *initNode,
                                 bool isConst)
 {
@@ -3836,16 +3854,32 @@ CheckModuleGlobal(ModuleCompiler &m, Par
 
     if (initNode->isKind(PNK_DOT))
         return CheckGlobalDotImport(m, var->name(), initNode);
 
     return m.fail(initNode, "unsupported import expression");
 }
 
 static bool
+CheckModuleProcessingDirectives(ModuleCompiler &m)
+{
+    TokenStream &ts = m.parser().tokenStream;
+    while (true) {
+        if (!ts.matchToken(TOK_STRING))
+            return true;
+
+        if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
+            return m.fail(nullptr, "unsupported processing directive");
+
+        if (!ts.matchToken(TOK_SEMI))
+            return m.fail(nullptr, "expected semicolon after string literal");
+    }
+}
+
+static bool
 CheckModuleGlobals(ModuleCompiler &m)
 {
     while (true) {
         ParseNode *varStmt;
         if (!ParseVarOrConstStatement(m.parser(), &varStmt))
             return false;
         if (!varStmt)
             break;
@@ -3889,16 +3923,28 @@ CheckArgumentType(FunctionCompiler &f, P
     if (!IsUseOfName(coercedExpr, name))
         return ArgFail(f, name, stmt);
 
     *type = VarType(coercion);
     return true;
 }
 
 static bool
+CheckProcessingDirectives(ModuleCompiler &m, ParseNode **stmtIter)
+{
+    ParseNode *stmt = *stmtIter;
+
+    while (stmt && IsIgnoredDirective(m.cx(), stmt))
+        stmt = NextNode(stmt);
+
+    *stmtIter = stmt;
+    return true;
+}
+
+static bool
 CheckArguments(FunctionCompiler &f, ParseNode **stmtIter, VarTypeVector *argTypes)
 {
     ParseNode *stmt = *stmtIter;
 
     unsigned numFormals;
     ParseNode *argpn = FunctionArgsList(f.fn(), &numFormals);
 
     for (unsigned i = 0; i < numFormals; i++, argpn = NextNode(argpn), stmt = NextNode(stmt)) {
@@ -6897,16 +6943,19 @@ CheckFunction(ModuleCompiler &m, LifoAll
     }
 
     FunctionCompiler f(m, fn, lifo);
     if (!f.init())
         return false;
 
     ParseNode *stmtIter = ListHead(FunctionStatementList(fn));
 
+    if (!CheckProcessingDirectives(m, &stmtIter))
+        return false;
+
     VarTypeVector argTypes(m.lifo());
     if (!CheckArguments(f, &stmtIter, &argTypes))
         return false;
 
     if (!CheckVariables(f, &stmtIter))
         return false;
 
     if (!f.prepareToEmitMIR(argTypes))
@@ -8500,16 +8549,19 @@ CheckModule(ExclusiveContext *cx, AsmJSP
         return false;
 
     if (!CheckModuleArguments(m, m.moduleFunctionNode()))
         return false;
 
     if (!CheckPrecedingStatements(m, stmtList))
         return false;
 
+    if (!CheckModuleProcessingDirectives(m))
+        return false;
+
     if (!CheckModuleGlobals(m))
         return false;
 
     m.startFunctionBodies();
 
     if (!CheckFunctions(m))
         return false;
 
--- a/js/src/jit-test/tests/asm.js/testBasic.js
+++ b/js/src/jit-test/tests/asm.js/testBasic.js
@@ -14,17 +14,28 @@ assertAsmTypeFail(USE_ASM + 'var f = f;'
 assertAsmTypeFail(USE_ASM + 'var f=0; function f(){} return f');
 assertAsmTypeFail(USE_ASM + 'var f=glob.Math.imul; return {}');
 assertAsmTypeFail('glob', USE_ASM + 'var f=glob.Math.imul; function f(){} return f');
 assertAsmTypeFail('glob','foreign', USE_ASM + 'var f=foreign.foo; function f(){} return f');
 assertAsmTypeFail(USE_ASM + 'function f(){} var f=[f,f]; return f');
 assertAsmTypeFail(USE_ASM + 'function f() 0; return f');
 assertAsmTypeFail('"use strict";' + USE_ASM + 'function f() {} return f');
 assertAsmTypeFail(USE_ASM + '"use strict"; function f() {} return f');
+assertAsmTypeFail(USE_ASM + '"use foopy" + 1; function f() {} return f');
 assertAsmTypeFail(USE_ASM + 'function f() { "use strict"; } return f');
+assertEq(asmLink(asmCompile(USE_ASM + '"use asm"; function f() {} return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + '"use foopy"; function f() {} return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + '"use foopy"; "use blarg"; function f() {} return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + 'function f() { "use asm"; } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + 'function f() { "use foopy"; } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + 'function f() { "use foopy"; "use blarg"; } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { "use foopy"; i=i|0; } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + 'function f(i) { "use foopy"; "use asm"; i=i|0; } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + '"use warm"; function f(i) { "use cold"; i=i|0 } function g() { "use hot"; return 0 } return f'))(), undefined);
+assertEq(asmLink(asmCompile(USE_ASM + '"use warm"; function f(i) { "use cold"; i=i|0 } function g() { "use asm"; return 0 } return f'))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(){} return f'))(), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(){;} return f'))(), undefined);
 assertAsmTypeFail(USE_ASM + 'function f(i,j){;} return f');
 assertEq(asmLink(asmCompile('"use asm";; function f(){};;; return f;;'))(), undefined);
 assertAsmTypeFail(USE_ASM + 'function f(x){} return f');
 assertAsmTypeFail(USE_ASM + 'function f(){return; return 1} return f');
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0} return f'))(42), undefined);
 assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0} return f'))(42), 42);