[INFER] Audit uses of PC in analysis and inference for UntrapOpcode, bug 657975, bug 657979, bug 657984.
authorBrian Hackett <bhackett1024@gmail.com>
Thu, 19 May 2011 10:09:17 -0700
changeset 75079 176ee6b37ad0de72cb84125ea0b8eb3538b0b8c2
parent 75078 00a1518d640a25d505c27dc121e341345394415f
child 75080 47e5a6ca466ed21caef377da15b49c6bf31bbec2
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs657975, 657979, 657984
milestone6.0a1
[INFER] Audit uses of PC in analysis and inference for UntrapOpcode, bug 657975, bug 657979, bug 657984.
js/src/jit-test/tests/basic/bug657975.js
js/src/jsanalyze.cpp
js/src/jsanalyze.h
js/src/jsinfer.cpp
js/src/jsinferinlines.h
js/src/jsscript.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug657975.js
@@ -0,0 +1,24 @@
+// |jit-test| debug
+setDebug(true);
+
+// bug 657975
+function f1(){ "use strict"; options('strict'); }
+trap(f1, 0, '')
+f1()
+
+// bug 657979
+function f2(){ with({a:0}){}; }
+trap(f2, 0, '')
+f2()
+
+x = 0;
+
+// bug 657984 #1
+function f3(){ for(y in x); }
+trap(f3, 5, '')
+f3()
+
+// bug 657984 #2
+function f4(){ for(y in x); }
+trap(f4, 10, '')
+f4()
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -171,18 +171,20 @@ ScriptAnalysis::addJump(JSContext *cx, u
         }
     }
 
     if (!code->mergeDefines(cx, this, initial, stackDepth, defineArray, defineCount))
         return false;
     code->jumpTarget = true;
 
     if (offset < *currentOffset) {
-        JSOp op = JSOp(script->code[offset]);
-        if (op == JSOP_TRACE || op == JSOP_NOTRACE)
+        jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
+        if (JSOp(*pc) == JSOP_TRACE || JSOp(*pc) == JSOP_NOTRACE)
             code->loopHead = true;
 
         /* Scripts containing loops are never inlined. */
         isInlineable = false;
 
         /* Don't follow back edges to bytecode which has already been analyzed. */
         if (!code->analyzed) {
             if (*forwardJump == 0)
@@ -785,17 +787,20 @@ ScriptAnalysis::analyzeLifetimes(JSConte
         if (!code) {
             offset--;
             continue;
         }
 
         if (loop && code->safePoint)
             loop->hasSafePoints = true;
 
-        UntrapOpcode untrap(cx, script, script->code + offset);
+        jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
+        JSOp op = (JSOp) *pc;
 
         if (code->loop) {
             /*
              * This is the head of a loop, we need to go and make sure that any
              * variables live at the head are live at the backedge and points prior.
              * For each such variable, look for the last lifetime segment in the body
              * and extend it to the end of the loop.
              */
@@ -809,19 +814,16 @@ ScriptAnalysis::analyzeLifetimes(JSConte
             loop = loop->parent;
             JS_ASSERT_IF(loop, loop->head < offset);
         }
 
         /* Find the last jump target in the loop, other than the initial entry point. */
         if (loop && code->jumpTarget && offset != loop->entry && offset > loop->lastBlock)
             loop->lastBlock = offset;
 
-        jsbytecode *pc = script->code + offset;
-        JSOp op = (JSOp) *pc;
-
         switch (op) {
           case JSOP_GETARG:
           case JSOP_CALLARG:
           case JSOP_GETLOCAL:
           case JSOP_CALLLOCAL:
           case JSOP_THIS: {
             uint32 slot = GetBytecodeSlot(script, pc);
             if (!slotEscapes(slot))
@@ -906,17 +908,17 @@ ScriptAnalysis::analyzeLifetimes(JSConte
             if (loop && loop->entry == targetOffset && loop->entry > loop->lastBlock)
                 loop->lastBlock = loop->entry;
 
             if (targetOffset < offset) {
                 /* This is a loop back edge, no lifetime to pull in yet. */
 
 #ifdef DEBUG
                 JSOp nop = JSOp(script->code[targetOffset]);
-                JS_ASSERT(nop == JSOP_TRACE || nop == JSOP_NOTRACE);
+                JS_ASSERT(nop == JSOP_TRACE || nop == JSOP_NOTRACE || nop == JSOP_TRAP);
 #endif
 
                 /*
                  * If we already have a loop, it is an outer loop and we
                  * need to prune the last block in the loop --- we do not
                  * track 'continue' statements for outer loops.
                  */
                 if (loop && loop->entry > loop->lastBlock)
@@ -947,16 +949,18 @@ ScriptAnalysis::analyzeLifetimes(JSConte
                  */
                 uint32 entry = targetOffset;
                 if (entry) {
                     do {
                         entry--;
                     } while (!maybeCode(entry));
 
                     jsbytecode *entrypc = script->code + entry;
+                    UntrapOpcode untrap(cx, script, entrypc);
+
                     if (JSOp(*entrypc) == JSOP_GOTO || JSOp(*entrypc) == JSOP_GOTOX)
                         loop->entry = entry + GetJumpOffset(entrypc, entrypc);
                     else
                         loop->entry = targetOffset;
                 } else {
                     /* Do-while loop at the start of the script. */
                     loop->entry = targetOffset;
                 }
@@ -1790,16 +1794,18 @@ CrossScriptSSA::foldValue(const CrossSSA
             uint32 argc = GET_ARGC(frame.parentpc);
             SSAValue argv = parentAnalysis->poppedValue(frame.parentpc, argc - 1 - (slot - ArgSlot(0)));
             return foldValue(CrossSSAValue(frame.parent, argv));
         }
     }
 
     if (v.kind() == SSAValue::PUSHED) {
         jsbytecode *pc = frame.script->code + v.pushedOffset();
+        UntrapOpcode untrap(cx, frame.script, pc);
+
         switch (JSOp(*pc)) {
           case JSOP_THIS:
             if (parentScript) {
                 uint32 argc = GET_ARGC(frame.parentpc);
                 SSAValue thisv = parentAnalysis->poppedValue(frame.parentpc, argc);
                 return foldValue(CrossSSAValue(frame.parent, thisv));
             }
             break;
@@ -1819,16 +1825,17 @@ CrossScriptSSA::foldValue(const CrossSSA
                     calleeFrame = iterFrame(i).index;
                 }
             }
             if (callee && callee->analysis(cx)->numReturnSites() == 1) {
                 ScriptAnalysis *analysis = callee->analysis(cx);
                 uint32 offset = 0;
                 while (offset < callee->length) {
                     jsbytecode *pc = callee->code + offset;
+                    UntrapOpcode untrap(cx, callee, pc);
                     if (analysis->maybeCode(pc) && JSOp(*pc) == JSOP_RETURN)
                         return foldValue(CrossSSAValue(calleeFrame, analysis->poppedValue(pc, 0)));
                     offset += GetBytecodeLength(pc);
                 }
             }
             break;
           }
 
@@ -1862,16 +1869,18 @@ ScriptAnalysis::printSSA(JSContext *cx)
     printf("\n");
 
     for (unsigned offset = 0; offset < script->length; offset++) {
         Bytecode *code = maybeCode(offset);
         if (!code)
             continue;
 
         jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
         PrintBytecode(cx, script, pc);
 
         SlotValue *newv = code->newValues;
         if (newv) {
             while (newv->slot) {
                 if (newv->value.kind() != SSAValue::PHI || newv->value.phiOffset() != offset) {
                     newv++;
                     continue;
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -221,16 +221,18 @@ GetBytecodeLength(jsbytecode *pc)
     return js_GetVariableBytecodeLength(pc);
 }
 
 static inline unsigned
 GetDefCount(JSScript *script, unsigned offset)
 {
     JS_ASSERT(offset < script->length);
     jsbytecode *pc = script->code + offset;
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     if (js_CodeSpec[*pc].ndefs == -1)
         return js_GetEnterBlockStackDefs(NULL, script, pc);
 
     /*
      * Add an extra pushed value for OR/AND opcodes, so that they are included
      * in the pushed array of stack values for type inference.
      */
     switch (JSOp(*pc)) {
@@ -246,28 +248,32 @@ GetDefCount(JSScript *script, unsigned o
     }
 }
 
 static inline unsigned
 GetUseCount(JSScript *script, unsigned offset)
 {
     JS_ASSERT(offset < script->length);
     jsbytecode *pc = script->code + offset;
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     if (js_CodeSpec[*pc].nuses == -1)
         return js_GetVariableStackUses(JSOp(*pc), pc);
     return js_CodeSpec[*pc].nuses;
 }
 
 /*
  * For opcodes which assign to a local variable or argument, track an extra def
  * during SSA analysis for the value's use chain and assigned type.
  */
 static inline bool
 ExtendedDef(jsbytecode *pc)
 {
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     switch ((JSOp)*pc) {
       case JSOP_SETARG:
       case JSOP_INCARG:
       case JSOP_DECARG:
       case JSOP_ARGINC:
       case JSOP_ARGDEC:
       case JSOP_FORARG:
       case JSOP_SETLOCAL:
@@ -303,16 +309,18 @@ ExtendedUse(jsbytecode *pc)
       default:
         return false;
     }
 }
 
 static inline ptrdiff_t
 GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
 {
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     uint32 type = JOF_OPTYPE(*pc);
     if (JOF_TYPE_IS_EXTENDED_JUMP(type))
         return GET_JUMPX_OFFSET(pc2);
     return GET_JUMP_OFFSET(pc2);
 }
 
 static inline unsigned
 FollowBranch(JSScript *script, unsigned offset)
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1674,23 +1674,26 @@ TypeCompartment::newInitializerTypeObjec
         return NULL;
 
     if (isArray)
         res->initializerArray = true;
     else
         res->initializerObject = true;
     res->initializerOffset = offset;
 
-    if (JSOp(script->code[offset]) == JSOP_NEWOBJECT) {
+    jsbytecode *pc = script->code + offset;
+    UntrapOpcode untrap(cx, script, pc);
+
+    if (JSOp(*pc) == JSOP_NEWOBJECT) {
         /*
          * This object is always constructed the same way and will not be
          * observed by other code before all properties have been added. Mark
          * all the properties as definite properties of the object.
          */
-        JSObject *baseobj = script->getObject(GET_SLOTNO(script->code + offset));
+        JSObject *baseobj = script->getObject(GET_SLOTNO(pc));
 
         if (!res->addDefiniteProperties(cx, baseobj))
             return NULL;
     }
 
     return res;
 }
 
@@ -1722,16 +1725,18 @@ GetScriptConst(JSContext *cx, JSScript *
     return script->getConst(index);
 }
 
 bool
 types::UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
 
+    UntrapOpcode untrap(cx, script, pc);
+
     /*
      * Make a heuristic guess at a use of JSOP_NEW that the constructed object
      * should have a fresh type object. We do this when the NEW is immediately
      * followed by a simple assignment to an object's .prototype field.
      * This is designed to catch common patterns for subclassing in JS:
      *
      * function Super() { ... }
      * function Sub1() { ... }
@@ -2104,22 +2109,25 @@ TypeCompartment::addPendingRecompile(JSC
 }
 
 void
 TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset)
 {
     if (script->analysis(cx)->getCode(offset).monitoredTypes)
         return;
 
+    jsbytecode *pc = script->code + offset;
+    UntrapOpcode untrap(cx, script, pc);
+
     /*
      * Make sure monitoring is limited to property sets and calls where the
      * target of the set/call could be statically unknown, and mark the bytecode
      * results as unknown.
      */
-    JSOp op = JSOp(script->code[offset]);
+    JSOp op = JSOp(*pc);
     switch (op) {
       case JSOP_SETNAME:
       case JSOP_SETGNAME:
       case JSOP_SETXMLNAME:
       case JSOP_SETCONST:
       case JSOP_SETELEM:
       case JSOP_SETHOLE:
       case JSOP_SETPROP:
@@ -2825,53 +2833,16 @@ TypeObject::print(JSContext *cx)
 
     printf("\n}\n");
 }
 
 /////////////////////////////////////////////////////////////////////
 // Type Analysis
 /////////////////////////////////////////////////////////////////////
 
-static inline ptrdiff_t
-GetJumpOffset(jsbytecode *pc, jsbytecode *pc2)
-{
-    uint32 type = JOF_OPTYPE(*pc);
-    if (JOF_TYPE_IS_EXTENDED_JUMP(type))
-        return GET_JUMPX_OFFSET(pc2);
-    return GET_JUMP_OFFSET(pc2);
-}
-
-/* Return whether op bytecodes do not fallthrough (they may do a jump). */
-static inline bool
-BytecodeNoFallThrough(JSOp op)
-{
-    switch (op) {
-      case JSOP_GOTO:
-      case JSOP_GOTOX:
-      case JSOP_DEFAULT:
-      case JSOP_DEFAULTX:
-      case JSOP_RETURN:
-      case JSOP_STOP:
-      case JSOP_RETRVAL:
-      case JSOP_THROW:
-      case JSOP_TABLESWITCH:
-      case JSOP_TABLESWITCHX:
-      case JSOP_LOOKUPSWITCH:
-      case JSOP_LOOKUPSWITCHX:
-      case JSOP_FILTER:
-        return true;
-      case JSOP_GOSUB:
-      case JSOP_GOSUBX:
-        /* These fall through indirectly, after executing a 'finally'. */
-        return false;
-      default:
-        return false;
-    }
-}
-
 /*
  * If the bytecode immediately following code/pc is a test of the value
  * pushed by code, that value should be marked as possibly void.
  */
 static inline bool
 CheckNextTest(jsbytecode *pc)
 {
     jsbytecode *next = pc + GetBytecodeLength(pc);
@@ -2882,40 +2853,43 @@ CheckNextTest(jsbytecode *pc)
       case JSOP_OR:
       case JSOP_ORX:
       case JSOP_AND:
       case JSOP_ANDX:
       case JSOP_TYPEOF:
       case JSOP_TYPEOFEXPR:
         return true;
       default:
+        /* TRAP ok here */
         return false;
     }
 }
 
 static inline TypeObject *
 GetInitializerType(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     if (!script->global)
         return NULL;
 
+    UntrapOpcode untrap(cx, script, pc);
+
     JSOp op = JSOp(*pc);
     JS_ASSERT(op == JSOP_NEWARRAY || op == JSOP_NEWOBJECT || op == JSOP_NEWINIT);
 
     bool isArray = (op == JSOP_NEWARRAY || (op == JSOP_NEWINIT && pc[1] == JSProto_Array));
     return script->getTypeInitObject(cx, pc, isArray);
 }
 
 inline void
 ScriptAnalysis::setForTypes(JSContext *cx, jsbytecode *pc, TypeSet *types)
 {
     /* Find the initial ITER opcode which constructed the active iterator. */
     const SSAValue &iterv = poppedValue(pc, 0);
     jsbytecode *iterpc = script->code + iterv.pushedOffset();
-    JS_ASSERT(JSOp(*iterpc) == JSOP_ITER);
+    JS_ASSERT(JSOp(*iterpc) == JSOP_ITER || JSOp(*iterpc) == JSOP_TRAP);
 
     uintN flags = iterpc[1];
     if (flags & JSITER_FOREACH) {
         types->addType(cx, TYPE_UNKNOWN);
         return;
     }
 
     /*
@@ -3962,16 +3936,18 @@ AnalyzeNewScriptProperties(JSContext *cx
      * a 'this' is pushed before the previous 'this' value was popped.
      */
     uint32 lastThisPopped = 0;
 
     unsigned nextOffset = 0;
     while (nextOffset < script->length) {
         unsigned offset = nextOffset;
         jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
         JSOp op = JSOp(*pc);
 
         nextOffset += GetBytecodeLength(pc);
 
         Bytecode *code = analysis->maybeCode(pc);
         if (!code)
             continue;
 
@@ -4018,16 +3994,18 @@ AnalyzeNewScriptProperties(JSContext *cx
         lastThisPopped = uses->offset;
 
         /* Only handle 'this' values popped in unconditional code. */
         Bytecode *poppedCode = analysis->maybeCode(uses->offset);
         if (!poppedCode || !poppedCode->unconditional)
             return false;
 
         pc = script->code + uses->offset;
+        UntrapOpcode untrapUse(cx, script, pc);
+
         op = JSOp(*pc);
 
         JSObject *obj = *pbaseobj;
 
         if (op == JSOP_SETPROP && uses->u.which == 1) {
             jsid id = GetAtomId(cx, script, pc, 0);
             if (MakeTypeId(cx, id) != id)
                 return false;
@@ -4083,24 +4061,25 @@ AnalyzeNewScriptProperties(JSContext *cx
              * script boundaries.
              *
              * Add constraints ensuring we are calling Function.call on a
              * particular script, removing definite properties from the result
              */
 
             /* Callee/this must have been pushed by a CALLPROP. */
             SSAValue calleev = analysis->poppedValue(pc, GET_ARGC(pc) + 1);
-            if (calleev.kind() != SSAValue::PUSHED ||
-                JSOp(script->code[calleev.pushedOffset()]) != JSOP_CALLPROP ||
-                calleev.pushedIndex() != 0) {
+            if (calleev.kind() != SSAValue::PUSHED)
                 return false;
-            }
-
-            TypeSet *funcallTypes = analysis->pushedTypes(calleev.pushedOffset(), 0);
-            TypeSet *scriptTypes = analysis->pushedTypes(calleev.pushedOffset(), 1);
+            jsbytecode *calleepc = script->code + calleev.pushedOffset();
+            UntrapOpcode untrapCallee(cx, script, calleepc);
+            if (JSOp(*calleepc) != JSOP_CALLPROP || calleev.pushedIndex() != 0)
+                return false;
+
+            TypeSet *funcallTypes = analysis->pushedTypes(calleepc, 0);
+            TypeSet *scriptTypes = analysis->pushedTypes(calleepc, 1);
 
             /* Need to definitely be calling Function.call on a specific script. */
             TypeObject *funcallObj = funcallTypes->getSingleObject();
             if (!funcallObj || !funcallObj->singleton ||
                 !funcallObj->singleton->isFunction() ||
                 funcallObj->singleton->getFunctionPrivate()->maybeNative() != js_fun_call) {
                 return false;
             }
@@ -4172,16 +4151,19 @@ ScriptAnalysis::printTypes(JSContext *cx
     /*
      * Check if there are warnings for used values with unknown types, and build
      * statistics about the size of type sets found for stack values.
      */
     for (unsigned offset = 0; offset < script->length; offset++) {
         if (!maybeCode(offset))
             continue;
 
+        jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
         unsigned defCount = GetDefCount(script, offset);
         if (!defCount)
             continue;
 
         for (unsigned i = 0; i < defCount; i++) {
             TypeSet *types = pushedTypes(offset, i);
 
             if (types->unknown()) {
@@ -4246,20 +4228,23 @@ ScriptAnalysis::printTypes(JSContext *cx
         script->upvarTypes(i)->print(cx);
     }
     printf("\n");
 
     for (unsigned offset = 0; offset < script->length; offset++) {
         if (!maybeCode(offset))
             continue;
 
-        PrintBytecode(cx, script, script->code + offset);
-
-        if (js_CodeSpec[script->code[offset]].format & JOF_TYPESET) {
-            TypeSet *types = script->bytecodeTypes(script->code + offset);
+        jsbytecode *pc = script->code + offset;
+        UntrapOpcode untrap(cx, script, pc);
+
+        PrintBytecode(cx, script, pc);
+
+        if (js_CodeSpec[*pc].format & JOF_TYPESET) {
+            TypeSet *types = script->bytecodeTypes(pc);
             printf("  typeset %d:", (int) (types - script->typeArray));
             types->print(cx);
             printf("\n");
         }
 
         unsigned defCount = GetDefCount(script, offset);
         for (unsigned i = 0; i < defCount; i++) {
             printf("  type %d:", i);
@@ -4293,16 +4278,18 @@ ScriptAnalysis::printTypes(JSContext *cx
 
 /*
  * Returns true if we don't expect to compute the correct types for some value
  * pushed by the specified bytecode.
  */
 static inline bool
 IgnorePushed(const jsbytecode *pc, unsigned index)
 {
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     switch (JSOp(*pc)) {
       /* We keep track of the scopes pushed by BINDNAME separately. */
       case JSOP_BINDNAME:
       case JSOP_BINDGNAME:
       case JSOP_BINDXMLNAME:
         return true;
 
       /* Stack not consistent in TRY_BRANCH_AFTER_COND. */
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -203,16 +203,18 @@ struct AutoEnterCompilation
 
 bool
 UseNewType(JSContext *cx, JSScript *script, jsbytecode *pc);
 
 /* Whether type barriers can be placed at pc for a property read. */
 static inline bool
 CanHaveReadBarrier(const jsbytecode *pc)
 {
+    JS_ASSERT(JSOp(*pc) != JSOP_TRAP);
+
     switch (JSOp(*pc)) {
       case JSOP_LENGTH:
       case JSOP_GETPROP:
       case JSOP_CALLPROP:
       case JSOP_GETXPROP:
       case JSOP_GETELEM:
       case JSOP_CALLELEM:
       case JSOP_NAME:
@@ -286,16 +288,18 @@ JSContext::markTypeCallerUnexpected(js::
      * This must have gone through a cross-compartment wrapper.
      */
     if (caller->script()->compartment != compartment)
         return;
 
     JSScript *script;
     jsbytecode *pc = caller->inlinepc(this, &script);
 
+    js::analyze::UntrapOpcode untrap(this, script, pc);
+
     switch ((JSOp)*pc) {
       case JSOP_CALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW:
         break;
       case JSOP_ITER:
@@ -510,16 +514,17 @@ JSScript::ensureTypeArray(JSContext *cx)
 }
 
 inline js::types::TypeSet *
 JSScript::bytecodeTypes(const jsbytecode *pc)
 {
     JS_ASSERT(typeArray);
 
     JSOp op = JSOp(*pc);
+    JS_ASSERT(op != JSOP_TRAP);
     JS_ASSERT(js_CodeSpec[op].format & JOF_TYPESET);
 
     /* All bytecodes with type sets are JOF_ATOM, except JSOP_{GET,CALL}ELEM */
     uint16 index = (op == JSOP_GETELEM || op == JSOP_CALLELEM) ? GET_UINT16(pc) : GET_UINT16(pc + 2);
     JS_ASSERT(index < nTypeSets);
 
     return &typeArray[index];
 }
@@ -617,18 +622,20 @@ JSScript::getTypeInitObject(JSContext *c
         prev = obj;
         obj = obj->next;
     }
 
     return cx->compartment->types.newInitializerTypeObject(cx, this, offset, isArray);
 }
 
 inline void
-JSScript::typeMonitor(JSContext *cx, const jsbytecode *pc, const js::Value &rval)
+JSScript::typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &rval)
 {
+    js::analyze::UntrapOpcode untrap(cx, this, pc);
+
     if (cx->typeInferenceEnabled() && (js_CodeSpec[*pc].format & JOF_TYPESET)) {
         /* Allow the non-TYPESET scenario to simplify stubs invonked by INC* ops. Yuck. */
 
         js::types::jstype type = js::types::GetValueType(cx, rval);
         js::types::TypeSet *types = bytecodeTypes(pc);
         if (types->hasType(type))
             return;
 
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -590,17 +590,17 @@ struct JSScript {
     getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray);
 
     /* Monitor a bytecode pushing an unexpected value. */
     inline void typeMonitorOverflow(JSContext *cx, const jsbytecode *pc);
     inline void typeMonitorString(JSContext *cx, const jsbytecode *pc);
     inline void typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
 
     /* Monitor a JOF_TYPESET bytecode pushing any value into its pushed type set. */
-    inline void typeMonitor(JSContext *cx, const jsbytecode *pc, const js::Value &val);
+    inline void typeMonitor(JSContext *cx, jsbytecode *pc, const js::Value &val);
 
     /* Monitor an assignment at a SETELEM on a non-integer identifier. */
     inline void typeMonitorAssign(JSContext *cx, const jsbytecode *pc,
                                   JSObject *obj, jsid id, const js::Value &val);
 
     /* Add a type for a variable in this script. */
     inline void typeSetThis(JSContext *cx, js::types::jstype type);
     inline void typeSetThis(JSContext *cx, const js::Value &value);