Don't compile any part of scripts containing uncompileable opcodes, bug 728342. r=dvander
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 22 Feb 2012 10:57:00 -0800
changeset 87467 0457004daa8ca2803011ca00c0506039b194cdfe
parent 87466 aef22bc75f1f8a60e8f3d68968f1454acdb0a027
child 87468 b0faa32d35d8fea7640db75e03eec94de6c5bed1
push id22122
push userbmo@edmorley.co.uk
push dateThu, 23 Feb 2012 13:58:56 +0000
treeherdermozilla-central@15d7708672c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdvander
bugs728342
milestone13.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
Don't compile any part of scripts containing uncompileable opcodes, bug 728342. r=dvander
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsinfer.cpp
js/src/methodjit/Compiler.cpp
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -192,16 +192,18 @@ ScriptAnalysis::analyzeBytecode(JSContex
      * If the script is in debug mode, JS_SetFrameReturnValue can be called at
      * any safe point.
      */
     if (cx->compartment->debugMode())
         usesReturnValue_ = true;
 
     bool heavyweight = script->function() && script->function()->isHeavyweight();
 
+    isCompileable = true;
+
     isInlineable = true;
     if (script->nClosedArgs || script->nClosedVars || heavyweight ||
         script->usesEval || script->usesArguments || cx->compartment->debugMode()) {
         isInlineable = false;
     }
 
     modifiesArguments_ = false;
     if (script->nClosedArgs || heavyweight)
@@ -325,23 +327,24 @@ ScriptAnalysis::analyzeBytecode(JSContex
             break;
 
           case JSOP_SETRVAL:
           case JSOP_POPV:
             usesReturnValue_ = true;
             isInlineable = false;
             break;
 
+          case JSOP_QNAMEPART:
+          case JSOP_QNAMECONST:
+            isCompileable = false;
           case JSOP_NAME:
           case JSOP_CALLNAME:
           case JSOP_BINDNAME:
           case JSOP_SETNAME:
           case JSOP_DELNAME:
-          case JSOP_QNAMEPART:
-          case JSOP_QNAMECONST:
             checkAliasedName(cx, pc);
             usesScopeChain_ = true;
             isInlineable = false;
             break;
 
           case JSOP_DEFFUN:
           case JSOP_DEFVAR:
           case JSOP_DEFCONST:
@@ -353,17 +356,17 @@ ScriptAnalysis::analyzeBytecode(JSContex
 
           case JSOP_EVAL:
             extendsScope_ = true;
             isInlineable = canTrackVars = false;
             break;
 
           case JSOP_ENTERWITH:
             addsScopeObjects_ = true;
-            isInlineable = canTrackVars = false;
+            isCompileable = isInlineable = canTrackVars = false;
             break;
 
           case JSOP_ENTERLET0:
           case JSOP_ENTERLET1:
           case JSOP_ENTERBLOCK:
           case JSOP_LEAVEBLOCK:
             addsScopeObjects_ = true;
             isInlineable = false;
@@ -478,17 +481,18 @@ ScriptAnalysis::analyzeBytecode(JSContex
             break;
           }
 
           case JSOP_CALLLOCAL:
           case JSOP_INCLOCAL:
           case JSOP_DECLOCAL:
           case JSOP_LOCALINC:
           case JSOP_LOCALDEC:
-          case JSOP_SETLOCAL: {
+          case JSOP_SETLOCAL:
+          case JSOP_SETLOCALPOP: {
             uint32_t local = GET_SLOTNO(pc);
             if (local >= script->nfixed) {
                 localsAliasStack_ = true;
                 break;
             }
             break;
           }
 
@@ -512,17 +516,114 @@ ScriptAnalysis::analyzeBytecode(JSContex
           case JSOP_GETFCSLOT:
           case JSOP_CALLFCSLOT:
           case JSOP_DEBUGGER:
           case JSOP_FUNCALL:
           case JSOP_FUNAPPLY:
             isInlineable = false;
             break;
 
+          /* Additional opcodes which can be both compiled both normally and inline. */
+          case JSOP_NOP:
+          case JSOP_UNDEFINED:
+          case JSOP_GOTO:
+          case JSOP_DEFAULT:
+          case JSOP_IFEQ:
+          case JSOP_IFNE:
+          case JSOP_ITERNEXT:
+          case JSOP_DUP:
+          case JSOP_DUP2:
+          case JSOP_SWAP:
+          case JSOP_PICK:
+          case JSOP_BITOR:
+          case JSOP_BITXOR:
+          case JSOP_BITAND:
+          case JSOP_LT:
+          case JSOP_LE:
+          case JSOP_GT:
+          case JSOP_GE:
+          case JSOP_EQ:
+          case JSOP_NE:
+          case JSOP_LSH:
+          case JSOP_RSH:
+          case JSOP_URSH:
+          case JSOP_ADD:
+          case JSOP_SUB:
+          case JSOP_MUL:
+          case JSOP_DIV:
+          case JSOP_MOD:
+          case JSOP_NOT:
+          case JSOP_BITNOT:
+          case JSOP_NEG:
+          case JSOP_POS:
+          case JSOP_DELPROP:
+          case JSOP_DELELEM:
+          case JSOP_TYPEOF:
+          case JSOP_TYPEOFEXPR:
+          case JSOP_VOID:
+          case JSOP_GETPROP:
+          case JSOP_CALLPROP:
+          case JSOP_LENGTH:
+          case JSOP_GETELEM:
+          case JSOP_CALLELEM:
+          case JSOP_TOID:
+          case JSOP_SETELEM:
+          case JSOP_IMPLICITTHIS:
+          case JSOP_DOUBLE:
+          case JSOP_STRING:
+          case JSOP_ZERO:
+          case JSOP_ONE:
+          case JSOP_NULL:
+          case JSOP_FALSE:
+          case JSOP_TRUE:
+          case JSOP_OR:
+          case JSOP_AND:
+          case JSOP_CASE:
+          case JSOP_STRICTEQ:
+          case JSOP_STRICTNE:
+          case JSOP_ITER:
+          case JSOP_MOREITER:
+          case JSOP_ENDITER:
+          case JSOP_POP:
+          case JSOP_GETARG:
+          case JSOP_CALLARG:
+          case JSOP_BINDGNAME:
+          case JSOP_UINT16:
+          case JSOP_NEWINIT:
+          case JSOP_NEWARRAY:
+          case JSOP_NEWOBJECT:
+          case JSOP_ENDINIT:
+          case JSOP_INITMETHOD:
+          case JSOP_INITPROP:
+          case JSOP_INITELEM:
+          case JSOP_SETPROP:
+          case JSOP_SETMETHOD:
+          case JSOP_IN:
+          case JSOP_INSTANCEOF:
+          case JSOP_LINENO:
+          case JSOP_ENUMELEM:
+          case JSOP_CONDSWITCH:
+          case JSOP_LABEL:
+          case JSOP_RETRVAL:
+          case JSOP_GETGNAME:
+          case JSOP_CALLGNAME:
+          case JSOP_SETGNAME:
+          case JSOP_REGEXP:
+          case JSOP_OBJECT:
+          case JSOP_UINT24:
+          case JSOP_GETXPROP:
+          case JSOP_INT8:
+          case JSOP_INT32:
+          case JSOP_HOLE:
+          case JSOP_LOOPHEAD:
+          case JSOP_LOOPENTRY:
+            break;
+
           default:
+            isCompileable = isInlineable = false;
             break;
         }
 
         uint32_t type = JOF_TYPE(js_CodeSpec[op].format);
 
         /* Check basic jump opcodes, which may or may not have a fallthrough. */
         if (type == JOF_JUMP) {
             /* Some opcodes behave differently on their branching path. */
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -866,16 +866,17 @@ class ScriptAnalysis
     bool usesScopeChain_:1;
     bool usesThisValue_:1;
     bool hasFunctionCalls_:1;
     bool modifiesArguments_:1;
     bool extendsScope_:1;
     bool addsScopeObjects_:1;
     bool localsAliasStack_:1;
     bool isInlineable:1;
+    bool isCompileable:1;
     bool canTrackVars:1;
 
     uint32_t numReturnSites_;
 
     /* --------- Lifetime analysis --------- */
 
     LifetimeVariable *lifetimes;
 
@@ -900,16 +901,17 @@ class ScriptAnalysis
     void analyzeTypes(JSContext *cx);
 
     /* Analyze the effect of invoking 'new' on script. */
     void analyzeTypesNew(JSContext *cx);
 
     bool OOM() { return outOfMemory; }
     bool failed() { return hadFailure; }
     bool inlineable(uint32_t argc) { return isInlineable && argc == script->function()->nargs; }
+    bool compileable() { return isCompileable; }
 
     /* Whether there are POPV/SETRVAL bytecodes which can write to the frame's rval. */
     bool usesReturnValue() const { return usesReturnValue_; }
 
     /* Whether there are NAME bytecodes which can access the frame's scope chain. */
     bool usesScopeChain() const { return usesScopeChain_; }
 
     bool usesThisValue() const { return usesThisValue_; }
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -3319,16 +3319,19 @@ ScriptAnalysis::resolveNameAccess(JSCont
                 /*
                  * Record the dependency which compiled code has on the outer
                  * function being non-reentrant.
                  */
                 if (TypeSet::HasObjectFlags(cx, obj, OBJECT_FLAG_REENTRANT_FUNCTION))
                     return access;
             }
 
+            if (!script->isOuterFunction)
+                return access;
+
             access.script = script;
             access.nesting = script->nesting();
             access.slot = (kind == ARGUMENT) ? ArgSlot(index) : LocalSlot(script, index);
             access.arg = (kind == ARGUMENT);
             access.index = index;
             return access;
         } else if (kind != NONE) {
             return access;
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -172,23 +172,24 @@ mjit::Compiler::compile()
 CompileStatus
 mjit::Compiler::checkAnalysis(JSScript *script)
 {
     if (script->hasClearedGlobal()) {
         JaegerSpew(JSpew_Abort, "script has a cleared global\n");
         return Compile_Abort;
     }
 
-    if (JSOp(*script->code) == JSOP_GENERATOR) {
-        JaegerSpew(JSpew_Abort, "script is a generator\n");
-        return Compile_Abort;
-    }
-
     if (!script->ensureRanAnalysis(cx, NULL))
         return Compile_Error;
+
+    if (!script->analysis()->compileable()) {
+        JaegerSpew(JSpew_Abort, "script has uncompileable opcodes\n");
+        return Compile_Abort;
+    }
+
     if (cx->typeInferenceEnabled() && !script->ensureRanInference(cx))
         return Compile_Error;
 
     ScriptAnalysis *analysis = script->analysis();
     analysis->assertMatchingDebugMode();
     if (analysis->failed()) {
         JaegerSpew(JSpew_Abort, "couldn't analyze bytecode; probably switchX or OOM\n");
         return Compile_Abort;
@@ -3253,22 +3254,17 @@ mjit::Compiler::generateMethod()
           {
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(PC), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::DebuggerStatement, REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEBUGGER)
 
           default:
-           /* Sorry, this opcode isn't implemented yet. */
-#ifdef JS_METHODJIT_SPEW
-            JaegerSpew(JSpew_Abort, "opcode %s not handled yet (%s line %d)\n", OpcodeNames[op],
-                       script->filename, js_PCToLineNumber(cx, script, PC));
-#endif
-            return Compile_Abort;
+            JS_NOT_REACHED("Opcode not implemented");
         }
 
     /**********************
      *  END COMPILER OPS  *
      **********************/
 
         if (cx->typeInferenceEnabled() && PC == lastPC + GetBytecodeLength(lastPC)) {
             /*