[INFER] Remove on stack recompilation, allow removed on stack JIT frames to rejoin into the interpreter, bug 650163.
authorBrian Hackett <bhackett1024@gmail.com>
Mon, 09 May 2011 07:12:47 -0700
changeset 75004 c963b24694cd723f423c8024c8e3adfc96476a3c
parent 75003 e5d548c514276ca21245459b431a1c499a9dfe96
child 75005 24a2e5740ab8b1a018af6bee5fbc734bc5955f1a
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs650163
milestone6.0a1
[INFER] Remove on stack recompilation, allow removed on stack JIT frames to rejoin into the interpreter, bug 650163.
js/src/GlobalObject.cpp
js/src/assembler/assembler/X86Assembler.h
js/src/jit-test/tests/jaeger/recompile/exotic.js
js/src/jit-test/tests/jaeger/testForOps.js
js/src/jsanalyze.h
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsarray.cpp
js/src/jsarray.h
js/src/jscntxt.h
js/src/jsdate.cpp
js/src/jsdbgapi.cpp
js/src/jsemit.cpp
js/src/jsfun.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsinterp.cpp
js/src/jsinterp.h
js/src/jsiter.cpp
js/src/jsmath.cpp
js/src/jsnum.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/json.cpp
js/src/jsparse.cpp
js/src/jsproxy.cpp
js/src/jsregexp.cpp
js/src/jsscript.h
js/src/jsstr.cpp
js/src/jstracer.cpp
js/src/jstypedarray.cpp
js/src/jsvalue.h
js/src/jswrapper.cpp
js/src/jsxml.cpp
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastArithmetic.cpp
js/src/methodjit/FastBuiltins.cpp
js/src/methodjit/FastOps.cpp
js/src/methodjit/FrameEntry.h
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.cpp
js/src/methodjit/FrameState.h
js/src/methodjit/InvokeHelpers.cpp
js/src/methodjit/LoopState.cpp
js/src/methodjit/LoopState.h
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/MethodJIT.h
js/src/methodjit/MonoIC.cpp
js/src/methodjit/MonoIC.h
js/src/methodjit/PolyIC.cpp
js/src/methodjit/PunboxAssembler.h
js/src/methodjit/Retcon.cpp
js/src/methodjit/Retcon.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
js/src/methodjit/StubCompiler.cpp
js/src/methodjit/StubCompiler.h
js/src/vm/Stack-inl.h
js/src/vm/Stack.h
--- a/js/src/GlobalObject.cpp
+++ b/js/src/GlobalObject.cpp
@@ -112,34 +112,32 @@ GlobalObject::create(JSContext *cx, Clas
 
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, NULL, NULL);
     if (!obj)
         return NULL;
 
     types::TypeObject *type = cx->newTypeObject("Global", NULL);
     if (!type || !obj->setTypeAndUniqueShape(cx, type))
         return NULL;
-    if (clasp->ext.equality && !cx->markTypeObjectHasSpecialEquality(type))
-        return NULL;
+    if (clasp->ext.equality)
+        cx->markTypeObjectHasSpecialEquality(type);
     type->singleton = obj;
 
     GlobalObject *globalObj = obj->asGlobal();
 
     globalObj->syncSpecialEquality();
 
     /* Construct a regexp statics object for this global object. */
     JSObject *res = regexp_statics_construct(cx, globalObj);
     if (!res)
         return NULL;
     globalObj->setSlot(REGEXP_STATICS, ObjectValue(*res));
     globalObj->setFlags(0);
 
-    if (!cx->addTypeProperty(type, js_undefined_str, UndefinedValue()))
-        return NULL;
-
+    cx->addTypeProperty(type, js_undefined_str, UndefinedValue());
     return globalObj;
 }
 
 bool
 GlobalObject::initStandardClasses(JSContext *cx)
 {
     /* Native objects get their reserved slots from birth. */
     JS_ASSERT(numSlots() >= JSSLOT_FREE(getClass()));
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -1559,18 +1559,18 @@ public:
     {
         FIXME_INSN_PRINTING;
         m_formatter.oneByteOp64_disp32(OP_MOV_GvEv, dst, base, offset);
     }
 
     void movq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
     {
         js::JaegerSpew(js::JSpew_Insns,
-                       IPFX "movq       %s0x%x(%s), %s\n", MAYBE_PAD,
-                       PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(8,dst));
+                       IPFX "movq       %d(%s,%s,%d), %s\n", MAYBE_PAD,
+                       offset, nameIReg(base), nameIReg(index), scale, nameIReg(8,dst));
         m_formatter.oneByteOp64(OP_MOV_GvEv, dst, base, index, scale, offset);
     }
 
     void leaq_mr(int offset, RegisterID base, RegisterID index, int scale, RegisterID dst)
     {
         js::JaegerSpew(js::JSpew_Insns,
                        IPFX "leaq       %d(%s,%s,%d), %s\n", MAYBE_PAD,
                        offset, nameIReg(base), nameIReg(index), scale, nameIReg(8,dst)),
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/jaeger/recompile/exotic.js
@@ -0,0 +1,74 @@
+
+// Test exotic ways of triggering recompilation.
+
+// Lowered native call.
+
+var x = 0;
+var y = true;
+for (var i = 0; i < 20; i++) {
+  x += Array.map.apply(undefined, [[0], function(x) { if (i == 10) eval("y = 20"); return 1; }])[0];
+}
+assertEq(x, 20);
+assertEq(y, 20);
+
+// Recompilation triggered by local function.
+
+var o = {};
+function what(q) {
+  function inner() { return q; }
+  o.f = inner;
+  var a = o.f();
+  return a;
+}
+for (var i = 0; i < 10; i++) {
+  var a = what(i);
+  assertEq(a, i);
+}
+
+// Lowered scripted call to apply returning code pointer.
+
+var global = 3;
+function foo(x, y) {
+  var q = x.apply(null, y);
+  if (q != 10)
+    assertEq(global, true);
+}
+foo(function(a) { global = a; return 10; }, [1]);
+foo(function(a) { global = a; return 10; }, [1]);
+foo(function(a) { global = a; return 10; }, [1]);
+assertEq(global, 1);
+foo(function(a) { global = a; return 3; }, [true]);
+assertEq(global, true);
+
+// Lowered scripted call returning NULL.
+
+var oglobal = 3;
+function xfoo(x, y) {
+  var q = x.apply(null, y);
+  if (q != 10)
+    assertEq(oglobal, true);
+}
+xfoo(function(a) { oglobal = a; return 10; }, [1]);
+xfoo(function(a) { oglobal = a; return 10; }, [1]);
+xfoo(function(a) { oglobal = a; return 10; }, [1]);
+assertEq(oglobal, 1);
+xfoo(function(a) { <x></x>; oglobal = a; return 3; }, [true]);
+assertEq(oglobal, true);
+
+// Recompilation out of SplatApplyArgs.
+
+weirdarray = [,,1,2,3];
+Object.defineProperty(weirdarray, 0, {get: function() { vglobal = 'true'; }});
+
+var vglobal = 3;
+function yfoo(x, y) {
+  var q = x.apply(null, y);
+  if (q != 10)
+    assertEq(vglobal, 'true');
+  else
+    assertEq(vglobal, 3);
+}
+yfoo(function(a) { return 10; }, [1]);
+yfoo(function(a) { return 10; }, [1]);
+yfoo(function(a) { return 10; }, [1]);
+yfoo(function() { return 0; }, weirdarray);
--- a/js/src/jit-test/tests/jaeger/testForOps.js
+++ b/js/src/jit-test/tests/jaeger/testForOps.js
@@ -8,17 +8,17 @@ function assertObjectsEqual(obj1, obj2) 
     assertEq(obj1.d, obj2.d);
     assertEq(obj2.a, 1);
     assertEq(obj2.b, "bee");
     assertEq(obj2.c, "crab");
     assertEq(obj2.d, 12);
 }
 
 function forName(obj) {
-    assertJit();
+    // assertJit();  // :XXX: assertJit is a CALLNAME here which can cause a recompilation.
     eval('');
     var r = { };
     for (x in obj)
         r[x] = obj[x];
     return r;
 }
 
 function forGlobalName(obj) {
--- a/js/src/jsanalyze.h
+++ b/js/src/jsanalyze.h
@@ -206,16 +206,41 @@ GetBytecodeLength(jsbytecode *pc)
     JS_ASSERT(op != JSOP_TRAP);
 
     if (js_CodeSpec[op].length != -1)
         return js_CodeSpec[op].length;
     return js_GetVariableBytecodeLength(pc);
 }
 
 static inline unsigned
+GetDefCount(JSScript *script, unsigned offset)
+{
+    JS_ASSERT(offset < script->length);
+    jsbytecode *pc = script->code + offset;
+    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)) {
+      case JSOP_OR:
+      case JSOP_ORX:
+      case JSOP_AND:
+      case JSOP_ANDX:
+        return 1;
+      case JSOP_FILTER:
+        return 2;
+      default:
+        return js_CodeSpec[*pc].ndefs;
+    }
+}
+
+static inline unsigned
 GetUseCount(JSScript *script, unsigned offset)
 {
     JS_ASSERT(offset < script->length);
     jsbytecode *pc = script->code + offset;
     if (js_CodeSpec[*pc].nuses == -1)
         return js_GetVariableStackUses(JSOp(*pc), pc);
     return js_CodeSpec[*pc].nuses;
 }
@@ -264,41 +289,16 @@ ExtendedUse(jsbytecode *pc)
       case JSOP_GETLOCAL:
       case JSOP_CALLLOCAL:
         return true;
       default:
         return false;
     }
 }
 
-static inline unsigned
-GetDefCount(JSScript *script, unsigned offset)
-{
-    JS_ASSERT(offset < script->length);
-    jsbytecode *pc = script->code + offset;
-    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)) {
-      case JSOP_OR:
-      case JSOP_ORX:
-      case JSOP_AND:
-      case JSOP_ANDX:
-        return 1;
-      case JSOP_FILTER:
-        return 2;
-      default:
-        return js_CodeSpec[*pc].ndefs;
-    }
-}
-
 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);
 }
@@ -349,16 +349,24 @@ struct UntrapOpcode
 
     UntrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
         : pc(pc), trap(JSOp(*pc) == JSOP_TRAP)
     {
         if (trap)
             *pc = JS_GetTrapOpcode(cx, script, pc);
     }
 
+    void retrap()
+    {
+        if (trap) {
+            *pc = JSOP_TRAP;
+            trap = false;
+        }
+    }
+
     ~UntrapOpcode()
     {
         if (trap)
             *pc = JSOP_TRAP;
     }
 };
 
 /* Common representation of slots throughout analyses and the compiler. */
@@ -896,16 +904,26 @@ class ScriptAnalysis
     Bytecode* maybeCode(const jsbytecode *pc) { return maybeCode(pc - script->code); }
 
     bool jumpTarget(uint32 offset) {
         JS_ASSERT(offset < script->length);
         return codeArray[offset] && codeArray[offset]->jumpTarget;
     }
     bool jumpTarget(const jsbytecode *pc) { return jumpTarget(pc - script->code); }
 
+    bool popGuaranteed(jsbytecode *pc) {
+        jsbytecode *next = pc + GetBytecodeLength(pc);
+        return JSOp(*next) == JSOP_POP && !jumpTarget(next);
+    }
+
+    bool incrementInitialValueObserved(jsbytecode *pc) {
+        const JSCodeSpec *cs = &js_CodeSpec[*pc];
+        return (cs->format & JOF_POST) && !popGuaranteed(pc);
+    }
+
     const SSAValue &poppedValue(uint32 offset, uint32 which) {
         JS_ASSERT(offset < script->length);
         JS_ASSERT_IF(script->code[offset] != JSOP_TRAP,
                      which < GetUseCount(script, offset) +
                      (ExtendedUse(script->code + offset) ? 1 : 0));
         return getCode(offset).poppedValues[which];
     }
     const SSAValue &poppedValue(const jsbytecode *pc, uint32 which) {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3065,38 +3065,39 @@ JS_NewObject(JSContext *cx, JSClass *jsc
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     JSObject *obj = NewNonFunction<WithProto::Class>(cx, clasp, proto, parent);
     if (obj) {
-        if (clasp->ext.equality && !cx->markTypeObjectHasSpecialEquality(obj->getType()))
-            return NULL;
+        if (clasp->ext.equality)
+            cx->markTypeObjectHasSpecialEquality(obj->getType());
         obj->syncSpecialEquality();
-        if (!cx->markTypeObjectUnknownProperties(obj->getType()))
-            return NULL;
+        cx->markTypeObjectUnknownProperties(obj->getType());
     }
 
     JS_ASSERT_IF(obj, obj->getParent());
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent)
 {
     JSObject *obj = JS_NewObject(cx, clasp, proto, parent);
     if (!obj)
         return NULL;
 
     types::TypeObject *type = cx->newTypeObject("Unique", proto);
-    if (obj->hasSpecialEquality() && !cx->markTypeObjectHasSpecialEquality(type))
+    if (!type)
         return NULL;
-    if (!type || !obj->setTypeAndUniqueShape(cx, type))
+    if (obj->hasSpecialEquality())
+        cx->markTypeObjectHasSpecialEquality(type);
+    if (!obj->setTypeAndUniqueShape(cx, type))
         return NULL;
     type->singleton = obj;
 
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectWithGivenProto(JSContext *cx, JSClass *jsclasp, JSObject *proto, JSObject *parent)
@@ -3110,18 +3111,17 @@ JS_NewObjectWithGivenProto(JSContext *cx
         clasp = &js_ObjectClass;    /* default class is Object */
 
     JS_ASSERT(clasp != &js_FunctionClass);
     JS_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL));
 
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent);
     if (obj) {
         obj->syncSpecialEquality();
-        if (!cx->markTypeObjectUnknownProperties(obj->getType()))
-            return NULL;
+        cx->markTypeObjectUnknownProperties(obj->getType());
     }
     return obj;
 }
 
 JS_PUBLIC_API(JSObject *)
 JS_NewObjectForConstructor(JSContext *cx, const jsval *vp)
 {
     CHECK_REQUEST(cx);
@@ -3194,26 +3194,26 @@ JS_ConstructObjectWithArguments(JSContex
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto, parent, JSValueArray(argv, argc));
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
     return js_ConstructObject(cx, clasp, proto, parent, argc, Valueify(argv));
 }
 
-JS_PUBLIC_API(JSBool)
+JS_PUBLIC_API(void)
 JS_AddTypeProperty(JSContext *cx, JSObject *obj, const char *name, jsval value)
 {
-    return cx->addTypeProperty(obj->getType(), name, Valueify(value));
-}
-
-JS_PUBLIC_API(JSBool)
+    cx->addTypeProperty(obj->getType(), name, Valueify(value));
+}
+
+JS_PUBLIC_API(void)
 JS_AddTypePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value)
 {
-    return cx->addTypePropertyId(obj->getType(), id, Valueify(value));
+    cx->addTypePropertyId(obj->getType(), id, Valueify(value));
 }
 
 static JSBool
 LookupPropertyById(JSContext *cx, JSObject *obj, jsid id, uintN flags,
                    JSObject **objp, JSProperty **propp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
@@ -3474,18 +3474,19 @@ JS_DefinePropertyWithTinyId(JSContext *c
 }
 
 static JSBool
 DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                  const Value &value, PropertyOp getter, StrictPropertyOp setter, uintN attrs,
                  uintN flags, intN tinyid)
 {
     JSAtom *atom = js_AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen), 0);
-    if (!atom || !cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), value))
+    if (!atom)
         return false;
+    cx->addTypePropertyId(obj->getType(), ATOM_TO_JSID(atom), value);
     return DefinePropertyById(cx, obj, ATOM_TO_JSID(atom), value, getter, setter, attrs,
                               flags, tinyid);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineUCProperty(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
                     jsval value, JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs)
 {
@@ -3520,36 +3521,34 @@ JS_DefineObject(JSContext *cx, JSObject 
     Class *clasp = Valueify(jsclasp);
     if (!clasp)
         clasp = &js_ObjectClass;    /* default class is Object */
 
     JSObject *nobj = NewObject<WithProto::Class>(cx, clasp, proto, obj);
     if (!nobj)
         return NULL;
 
-    if (!cx->addTypeProperty(obj->getType(), name, ObjectValue(*nobj)))
-        return NULL;
+    cx->addTypeProperty(obj->getType(), name, ObjectValue(*nobj));
     nobj->syncSpecialEquality();
 
     if (!DefineProperty(cx, obj, name, ObjectValue(*nobj), NULL, NULL, attrs, 0, 0))
         return NULL;
 
     return nobj;
 }
 
 JS_PUBLIC_API(JSBool)
 JS_DefineConstDoubles(JSContext *cx, JSObject *obj, JSConstDoubleSpec *cds)
 {
     JSBool ok;
     uintN attrs;
 
     CHECK_REQUEST(cx);
     for (ok = JS_TRUE; cds->name; cds++) {
-        if (!cx->addTypeProperty(obj->getType(), cds->name, TYPE_DOUBLE))
-            return false;
+        cx->addTypeProperty(obj->getType(), cds->name, TYPE_DOUBLE);
         Value value = DoubleValue(cds->dval);
         attrs = cds->flags;
         if (!attrs)
             attrs = JSPROP_READONLY | JSPROP_PERMANENT;
         ok = DefineProperty(cx, obj, cds->name, value, NULL, NULL, attrs, 0, 0);
         if (!ok)
             break;
     }
@@ -3569,19 +3568,17 @@ JS_DefineProperties(JSContext *cx, JSObj
             else if (ps->handler == JS_TypeHandlerInt)
                 type = TYPE_INT32;
             else if (ps->handler == JS_TypeHandlerFloat)
                 type = TYPE_DOUBLE;
             else if (ps->handler == JS_TypeHandlerString)
                 type = TYPE_STRING;
             JS_ASSERT(type);
 
-            ok = cx->addTypeProperty(obj->getType(), ps->name, type);
-            if (!ok)
-                break;
+            cx->addTypeProperty(obj->getType(), ps->name, type);
         }
 
         ok = DefineProperty(cx, obj, ps->name, UndefinedValue(),
                             Valueify(ps->getter), Valueify(ps->setter),
                             ps->flags, Shape::HAS_SHORTID, ps->tinyid);
         if (!ok)
             break;
     }
@@ -3614,18 +3611,17 @@ JS_AliasProperty(JSContext *cx, JSObject
                              alias, name, obj2->getClass()->name);
         return JS_FALSE;
     }
     JSAtom *aliasAtom = js_Atomize(cx, alias, strlen(alias), 0);
     if (!aliasAtom) {
         ok = JS_FALSE;
     } else {
         /* Alias the properties within the type information for the object. */
-        if (!cx->aliasTypeProperties(obj->getType(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom)))
-            return JS_FALSE;
+        cx->aliasTypeProperties(obj->getType(), ATOM_TO_JSID(nameAtom), ATOM_TO_JSID(aliasAtom));
 
         shape = (Shape *)prop;
         ok = (js_AddNativeProperty(cx, obj, ATOM_TO_JSID(aliasAtom),
                                    shape->getter(), shape->setter(), shape->slot,
                                    shape->attributes(), shape->getFlags() | Shape::ALIAS,
                                    shape->shortid)
               != NULL);
     }
@@ -3889,18 +3885,17 @@ JS_GetMethod(JSContext *cx, JSObject *ob
 
 JS_PUBLIC_API(JSBool)
 JS_SetPropertyById(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj, id);
     JSAutoResolveFlags rf(cx, JSRESOLVE_QUALIFIED | JSRESOLVE_ASSIGNING);
 
-    if (!cx->addTypePropertyId(obj->getType(), id, Valueify(*vp)))
-        return false;
+    cx->addTypePropertyId(obj->getType(), id, Valueify(*vp));
     return obj->setProperty(cx, id, Valueify(vp), false);
 }
 
 JS_PUBLIC_API(JSBool)
 JS_SetElement(JSContext *cx, JSObject *obj, jsint index, jsval *vp)
 {
     return JS_SetPropertyById(cx, obj, INT_TO_JSID(index), vp);
 }
@@ -4374,18 +4369,17 @@ JS_CloneFunctionObject(JSContext *cx, JS
                                      JSMSG_BAD_CLONE_FUNOBJ_SCOPE);
                 return NULL;
             }
             obj = obj->getParent();
         }
         Value v;
         if (!obj->getProperty(cx, r.front().id, &v))
             return NULL;
-        if (!fun->script()->typeSetUpvar(cx, i, v))
-            return NULL;
+        fun->script()->typeSetUpvar(cx, i, v);
         clone->getFlatClosureUpvars()[i] = v;
     }
 
     return clone;
 }
 
 JS_PUBLIC_API(void)
 JS_TypeHandlerDynamic(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2282,20 +2282,20 @@ extern JS_PUBLIC_API(JSBool)
 JS_DefinePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value,
                       JSPropertyOp getter, JSStrictPropertyOp setter, uintN attrs);
 
 extern JS_PUBLIC_API(JSBool)
 JS_DefineOwnProperty(JSContext *cx, JSObject *obj, jsid id, jsval descriptor, JSBool *bp);
 
 /* Add properties to the type information for obj. */
 
-extern JS_PUBLIC_API(JSBool)
+extern JS_PUBLIC_API(void)
 JS_AddTypeProperty(JSContext *cx, JSObject *obj, const char *name, jsval value);
 
-extern JS_PUBLIC_API(JSBool)
+extern JS_PUBLIC_API(void)
 JS_AddTypePropertyById(JSContext *cx, JSObject *obj, jsid id, jsval value);
 
 /*
  * Determine the attributes (JSPROP_* flags) of a property on a given object.
  *
  * If the object does not have a property by that name, *foundp will be
  * JS_FALSE and the value of *attrsp is undefined.
  */
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -550,18 +550,17 @@ JS_DEFINE_CALLINFO_3(extern, BOOL, js_En
 static int
 DeleteArrayElement(JSContext *cx, JSObject *obj, jsdouble index, bool strict)
 {
     JS_ASSERT(index >= 0);
     if (obj->isDenseArray()) {
         if (index <= jsuint(-1)) {
             jsuint idx = jsuint(index);
             if (idx < obj->getDenseArrayInitializedLength()) {
-                if (!obj->setDenseArrayNotPacked(cx))
-                    return -1;
+                obj->setDenseArrayNotPacked(cx);
                 obj->setDenseArrayElement(idx, MagicValue(JS_ARRAY_HOLE));
                 if (!js_SuppressDeletedIndexProperties(cx, obj, idx, idx+1))
                     return -1;
             }
         }
         return 1;
     }
 
@@ -601,18 +600,18 @@ js_SetLengthProperty(JSContext *cx, JSOb
 
     v.setNumber(length);
     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
 
     /*
      * Arrays are already known to have lengths (if the length overflows, it will
      * be caught by setArrayLength).
      */
-    if (!obj->isArray() && !cx->addTypePropertyId(obj->getType(), id, v))
-        return false;
+    if (!obj->isArray())
+        cx->addTypePropertyId(obj->getType(), id, v);
 
     /* We don't support read-only array length yet. */
     return obj->setProperty(cx, id, &v, false);
 }
 
 JSBool
 js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
@@ -969,18 +968,17 @@ array_deleteProperty(JSContext *cx, JSOb
         return js_DeleteProperty(cx, obj, id, rval, strict);
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         rval->setBoolean(false);
         return JS_TRUE;
     }
 
     if (js_IdIsIndex(id, &i) && i < obj->getDenseArrayInitializedLength()) {
-        if (!obj->setDenseArrayNotPacked(cx))
-            return false;
+        obj->setDenseArrayNotPacked(cx);
         obj->setDenseArrayElement(i, MagicValue(JS_ARRAY_HOLE));
     }
 
     if (!js_SuppressDeletedProperty(cx, obj, id))
         return false;
 
     rval->setBoolean(true);
     return JS_TRUE;
@@ -1075,19 +1073,18 @@ AddLengthProperty(JSContext *cx, JSObjec
 /*
  * Convert an array object from fast-and-dense to slow-and-flexible.
  */
 JSBool
 JSObject::makeDenseArraySlow(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
 
-    if (!cx->markTypeArrayNotPacked(getType(), true))
-        return false;
-    JS_ALWAYS_TRUE(setDenseArrayNotPacked(cx));
+    cx->markTypeArrayNotPacked(getType(), true);
+    setDenseArrayNotPacked(cx);
 
     /*
      * Save old map now, before calling InitScopeForObject. We'll have to undo
      * on error. This is gross, but a better way is not obvious. Note: the
      * exact contents of the array are not preserved on error.
      */
     js::Shape *oldMap = lastProp;
 
@@ -1606,18 +1603,18 @@ InitArrayObject(JSContext *cx, JSObject 
     else
         obj->backfillDenseArrayHoles();
 
     bool hole = false;
     for (jsuint i = 0; i < length; i++) {
         obj->setDenseArrayElement(i, vector[i]);
         hole |= vector[i].isMagic(JS_ARRAY_HOLE);
     }
-    if (hole && !obj->setDenseArrayNotPacked(cx))
-        return false;
+    if (hole)
+        obj->setDenseArrayNotPacked(cx);
 
     return true;
 }
 
 /*
  * Perl-inspired join, reverse, and sort.
  */
 static JSBool
@@ -1678,19 +1675,18 @@ array_reverse(JSContext *cx, uintN argc,
             JS_ASSERT(result == JSObject::ED_SPARSE);
             break;
         }
 
         /* Fill out the array's initialized length to its proper length. */
         jsuint initlen = obj->getDenseArrayInitializedLength();
         if (len > initlen) {
             JS_ASSERT(cx->typeInferenceEnabled());
-            if (!obj->setDenseArrayNotPacked(cx))
-                return false;
             ClearValueRange(obj->getDenseArrayElements() + initlen, len - initlen, true);
+            obj->setDenseArrayNotPacked(cx);
             obj->setDenseArrayInitializedLength(len);
         }
 
         uint32 lo = 0, hi = len - 1;
         for (; lo < hi; lo++, hi--) {
             Value origlo = obj->getDenseArrayElement(lo);
             Value orighi = obj->getDenseArrayElement(hi);
             obj->setDenseArrayElement(lo, orighi);
@@ -2203,18 +2199,18 @@ array_push_slowly(JSContext *cx, JSObjec
     if (!InitArrayElements(cx, obj, length, argc, argv, true))
         return JS_FALSE;
 
     /* Per ECMA-262, return the new array length. */
     jsdouble newlength = length + jsdouble(argc);
     rval->setNumber(newlength);
 
     /* watch for length overflowing to a double. */
-    if (!rval->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!rval->isInt32())
+        cx->markTypeCallerOverflow();
 
     return js_SetLengthProperty(cx, obj, newlength);
 }
 
 static JSBool
 array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
 {
     uint32 length = obj->getArrayLength();
@@ -2222,18 +2218,17 @@ array_push1_dense(JSContext* cx, JSObjec
         JSObject::EnsureDenseResult result = obj->ensureDenseArrayElements(cx, length, 1);
         if (result != JSObject::ED_OK) {
             if (result == JSObject::ED_FAILED)
                 return false;
             JS_ASSERT(result == JSObject::ED_SPARSE);
             break;
         }
 
-        if (cx->typeInferenceEnabled() && !cx->addTypePropertyId(obj->getType(), JSID_VOID, v))
-            return false;
+        cx->addTypePropertyId(obj->getType(), JSID_VOID, v);
 
         obj->setDenseArrayLength(length + 1);
         obj->setDenseArrayElement(length, v);
         rval->setNumber(obj->getArrayLength());
         return true;
     } while (false);
 
     if (!obj->makeDenseArraySlow(cx))
@@ -2322,50 +2317,48 @@ array_pop_slowly(JSContext *cx, JSObject
 {
     jsuint index;
     JSBool hole;
 
     if (!js_GetLengthProperty(cx, obj, &index))
         return JS_FALSE;
     if (index == 0) {
         vp->setUndefined();
-        if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-            return JS_FALSE;
+        cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
     } else {
         index--;
 
         /* Get the to-be-deleted property's value into vp. */
         if (!GetElement(cx, obj, index, &hole, vp))
             return JS_FALSE;
-        if (hole && !cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-            return JS_FALSE;
+        if (hole)
+            cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
         if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
             return JS_FALSE;
     }
     return js_SetLengthProperty(cx, obj, index);
 }
 
 static JSBool
 array_pop_dense(JSContext *cx, JSObject* obj, Value *vp)
 {
     jsuint index;
     JSBool hole;
 
     index = obj->getArrayLength();
     if (index == 0) {
         vp->setUndefined();
-        if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-            return JS_FALSE;
+        cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
         return JS_TRUE;
     }
     index--;
     if (!GetElement(cx, obj, index, &hole, vp))
         return JS_FALSE;
-    if (hole && !cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-        return JS_FALSE;
+    if (hole)
+        cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
     if (!hole && DeleteArrayElement(cx, obj, index, true) < 0)
         return JS_FALSE;
 
     if (cx->typeInferenceEnabled() && obj->getDenseArrayInitializedLength() > index)
         obj->setDenseArrayInitializedLength(index);
     obj->setDenseArrayLength(index);
     return JS_TRUE;
 }
@@ -2389,29 +2382,27 @@ array_shift(JSContext *cx, uintN argc, V
         return JS_FALSE;
 
     jsuint length;
     if (!js_GetLengthProperty(cx, obj, &length))
         return JS_FALSE;
 
     if (length == 0) {
         vp->setUndefined();
-        if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-            return JS_FALSE;
+        cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
     } else {
         length--;
 
         if (obj->isDenseArray() && !js_PrototypeHasIndexedProperties(cx, obj) &&
             length < obj->getDenseArrayCapacity() &&
             0 < obj->getDenseArrayInitializedLength()) {
             *vp = obj->getDenseArrayElement(0);
             if (vp->isMagic(JS_ARRAY_HOLE)) {
                 vp->setUndefined();
-                if (!cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-                    return JS_FALSE;
+                cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
             }
             Value *elems = obj->getDenseArrayElements();
             memmove(elems, elems + 1, length * sizeof(jsval));
             if (cx->typeInferenceEnabled())
                 obj->setDenseArrayInitializedLength(obj->getDenseArrayInitializedLength() - 1);
             else
                 obj->setDenseArrayElement(length, MagicValue(JS_ARRAY_HOLE));
             JS_ALWAYS_TRUE(obj->setArrayLength(cx, length));
@@ -2420,18 +2411,18 @@ array_shift(JSContext *cx, uintN argc, V
             return JS_TRUE;
         }
 
         /* Get the to-be-deleted property's value into vp ASAP. */
         JSBool hole;
         if (!GetElement(cx, obj, 0, &hole, vp))
             return JS_FALSE;
 
-        if (hole && !cx->markTypeCallerUnexpected(TYPE_UNDEFINED))
-            return JS_FALSE;
+        if (hole)
+            cx->markTypeCallerUnexpected(TYPE_UNDEFINED);
 
         /* Slide down the array above the first element. */
         AutoValueRooter tvr(cx);
         for (jsuint i = 0; i < length; i++) {
             if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                 !GetElement(cx, obj, i + 1, &hole, tvr.addr()) ||
                 !SetOrDeleteArrayElement(cx, obj, i, hole, tvr.value())) {
                 return JS_FALSE;
@@ -2507,18 +2498,18 @@ array_unshift(JSContext *cx, uintN argc,
     }
     if (!js_SetLengthProperty(cx, obj, newlen))
         return JS_FALSE;
 
     /* Follow Perl by returning the new array length. */
     vp->setNumber(newlen);
 
     /* watch for length overflowing to a double. */
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
 
     return JS_TRUE;
 }
 
 static JSBool
 array_splice(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
@@ -2538,18 +2529,19 @@ array_splice(JSContext *cx, uintN argc, 
          */
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
         type = cx->getTypeNewObject(JSProto_Array);
-        if (!type || !cx->markTypeCallerUnexpected((jstype) type))
+        if (!type)
             return false;
+        cx->markTypeCallerUnexpected((jstype) type);
     }
 
     /* Create a new array value to return. */
     JSObject *obj2 = NewDenseEmptyArray(cx);
     if (!obj2)
         return JS_FALSE;
     obj2->setType(type);
     vp->setObject(*obj2);
@@ -2605,20 +2597,18 @@ array_splice(JSContext *cx, uintN argc, 
                 return JS_FALSE;
         } else {
             for (last = begin; last < end; last++) {
                 if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                     !GetElement(cx, obj, last, &hole, tvr.addr())) {
                     return JS_FALSE;
                 }
 
-                if (!cx->addTypePropertyId(obj2->getType(), JSID_VOID, tvr.value()))
-                    return JS_FALSE;
-
                 /* Copy tvr.value() to the new array unless it's a hole. */
+                cx->addTypePropertyId(obj2->getType(), JSID_VOID, tvr.value());
                 if (!hole && !SetArrayElement(cx, obj2, last - begin, tvr.value()))
                     return JS_FALSE;
             }
 
             if (!js_SetLengthProperty(cx, obj2, count))
                 return JS_FALSE;
         }
     }
@@ -2721,34 +2711,33 @@ array_concat(JSContext *cx, uintN argc, 
         length = aobj->getArrayLength();
         Value *vector = aobj->getDenseArrayElements();
         jsuint initlen = aobj->getDenseArrayInitializedLength();
         nobj = NewDenseCopiedArray(cx, initlen, vector);
         if (!nobj)
             return JS_FALSE;
         if (nobj->getProto() == aobj->getProto())
             nobj->setType(aobj->getType());
-        else if (!cx->markTypeCallerUnexpected(TYPE_UNKNOWN))
-            return JS_FALSE;
+        else
+            cx->markTypeCallerUnexpected(TYPE_UNKNOWN);
         nobj->setType(aobj->getType());
         if (!nobj->setArrayLength(cx, length))
             return JS_FALSE;
-        if (!aobj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
-            return JS_FALSE;
+        if (!aobj->isPackedDenseArray())
+            nobj->setDenseArrayNotPacked(cx);
         vp->setObject(*nobj);
         if (argc == 0)
             return JS_TRUE;
         argc--;
         p++;
     } else {
         nobj = NewDenseEmptyArray(cx);
         if (!nobj)
             return JS_FALSE;
-        if (!cx->markTypeCallerUnexpected(TYPE_UNKNOWN))
-            return JS_FALSE;
+        cx->markTypeCallerUnexpected(TYPE_UNKNOWN);
         vp->setObject(*nobj);
         length = 0;
     }
 
     AutoValueRooter tvr(cx);
 
     /* Loop over [0, argc] to concat args into nobj, expanding all Arrays. */
     for (uintN i = 0; i <= argc; i++) {
@@ -2767,36 +2756,34 @@ array_concat(JSContext *cx, uintN argc, 
                     return false;
                 for (jsuint slot = 0; slot < alength; slot++) {
                     JSBool hole;
                     if (!JS_CHECK_OPERATION_LIMIT(cx) ||
                         !GetElement(cx, aobj, slot, &hole, tvr.addr())) {
                         return false;
                     }
 
-                    if (!hole && !cx->addTypePropertyId(nobj->getType(), JSID_VOID, tvr.value()))
-                        return false;
+                    if (!hole)
+                        cx->addTypePropertyId(nobj->getType(), JSID_VOID, tvr.value());
 
                     /*
                      * Per ECMA 262, 15.4.4.4, step 9, ignore nonexistent
                      * properties.
                      */
                     if (!hole &&
                         !SetArrayElement(cx, nobj, length+slot, tvr.value())) {
                         return false;
                     }
                 }
                 length += alength;
                 continue;
             }
         }
 
-        if (!cx->addTypePropertyId(nobj->getType(), JSID_VOID, v))
-            return false;
-
+        cx->addTypePropertyId(nobj->getType(), JSID_VOID, v);
         if (!SetArrayElement(cx, nobj, length, v))
             return false;
         length++;
     }
 
     return js_SetLengthProperty(cx, nobj, length);
 }
 
@@ -2855,28 +2842,29 @@ array_slice(JSContext *cx, uintN argc, V
         /* :FIXME: Same issue as array_splice. */
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
         type = cx->getTypeNewObject(JSProto_Array);
-        if (!type || !cx->markTypeCallerUnexpected((jstype) type))
+        if (!type)
             return false;
+        cx->markTypeCallerUnexpected((jstype) type);
     }
 
     if (obj->isDenseArray() && end <= obj->getDenseArrayInitializedLength() &&
         !js_PrototypeHasIndexedProperties(cx, obj)) {
         nobj = NewDenseCopiedArray(cx, end - begin, obj->getDenseArrayElements() + begin);
         if (!nobj)
             return JS_FALSE;
         nobj->setType(type);
-        if (!obj->isPackedDenseArray() && !nobj->setDenseArrayNotPacked(cx))
-            return JS_FALSE;
+        if (!obj->isPackedDenseArray())
+            nobj->setDenseArrayNotPacked(cx);
         vp->setObject(*nobj);
         return JS_TRUE;
     }
 
     /* Create a new Array object and root it using *vp. */
     nobj = NewDenseAllocatedArray(cx, end - begin);
     if (!nobj)
         return JS_FALSE;
@@ -2955,18 +2943,18 @@ array_indexOfHelper(JSContext *cx, JSBoo
             return JS_FALSE;
         }
         if (!hole) {
             JSBool equal;
             if (!StrictlyEqual(cx, *vp, tosearch, &equal))
                 return JS_FALSE;
             if (equal) {
                 vp->setNumber(i);
-                if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-                    return false;
+                if (!vp->isInt32())
+                    cx->markTypeCallerOverflow();
                 return JS_TRUE;
             }
         }
         if (i == stop)
             goto not_found;
         i += direction;
     }
 
@@ -3145,28 +3133,28 @@ array_extra(JSContext *cx, ArrayExtraMod
         switch (mode) {
           case FOREACH:
             break;
           case REDUCE:
           case REDUCE_RIGHT:
             *vp = rval;
             break;
           case MAP:
-            ok = cx->addTypePropertyId(newarr->getType(), JSID_VOID, rval);
+            cx->addTypePropertyId(newarr->getType(), JSID_VOID, rval);
             if (!ok)
                 goto out;
             ok = SetArrayElement(cx, newarr, i, rval);
             if (!ok)
                 goto out;
             break;
           case FILTER:
             if (!cond)
                 break;
             /* The element passed the filter, so push it onto our result. */
-            ok = cx->addTypePropertyId(newarr->getType(), JSID_VOID, tvr.value());
+            cx->addTypePropertyId(newarr->getType(), JSID_VOID, tvr.value());
             if (!ok)
                 goto out;
             ok = SetArrayElement(cx, newarr, newlen++, tvr.value());
             if (!ok)
                 goto out;
             break;
           case SOME:
             if (cond) {
@@ -3488,18 +3476,17 @@ js_Array(JSContext *cx, uintN argc, Valu
 
     if (argc == 0) {
         obj = NewDenseEmptyArray(cx);
     } else if (argc > 1) {
         if (!InitArrayTypes(cx, type, vp + 2, argc))
             return false;
         obj = NewDenseCopiedArray(cx, argc, vp + 2);
     } else if (!vp[2].isNumber()) {
-        if (!cx->addTypeProperty(type, NULL, vp[2]))
-            return false;
+        cx->addTypeProperty(type, NULL, vp[2]);
         obj = NewDenseCopiedArray(cx, 1, vp + 2);
     } else {
         jsuint length;
         if (!ValueToLength(cx, vp + 2, &length))
             return JS_FALSE;
         obj = NewDenseUnallocatedArray(cx, length);
     }
 
@@ -3558,24 +3545,24 @@ array_TypeNew(JSContext *cx, JSTypeFunct
 JSObject *
 js_InitArrayClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_ArrayClass, js_Array, 1, array_TypeNew,
                                    NULL, array_methods, NULL, array_static_methods);
     if (!proto)
         return NULL;
 
-    if (!JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0)))
-        return NULL;
+    JS_AddTypeProperty(cx, proto, "length", INT_TO_JSVAL(0));
     JS_ALWAYS_TRUE(proto->setArrayLength(cx, 0));
 
     /* The default 'new' object for Array.prototype has unknown properties. */
     TypeObject *newType = proto->getNewType(cx);
-    if (!newType || !cx->markTypeObjectUnknownProperties(newType))
+    if (!newType)
         return NULL;
+    cx->markTypeObjectUnknownProperties(newType);
 
     return proto;
 }
 
 /*
  * Array allocation functions.
  */
 namespace js {
@@ -3839,14 +3826,14 @@ js_CloneDensePrimitiveArray(JSContext *c
 
         vector.infallibleAppend(val);
     }
 
     *clone = NewDenseCopiedArray(cx, initlen, vector.begin());
     if (!*clone)
         return JS_FALSE;
 
-    if (!obj->isPackedDenseArray() && !(*clone)->setDenseArrayNotPacked(cx))
-        return JS_FALSE;
+    if (!obj->isPackedDenseArray())
+        (*clone)->setDenseArrayNotPacked(cx);
 
     /* The length will be set to the initlen, above, but length might be larger. */
     return (*clone)->setArrayLength(cx, length);
 }
--- a/js/src/jsarray.h
+++ b/js/src/jsarray.h
@@ -69,25 +69,24 @@ JSObject::setDenseArrayInitializedLength
 
 inline bool
 JSObject::isPackedDenseArray()
 {
     JS_ASSERT(isDenseArray());
     return flags & PACKED_ARRAY;
 }
 
-inline bool
+inline void
 JSObject::setDenseArrayNotPacked(JSContext *cx)
 {
     JS_ASSERT(isDenseArray());
     if (flags & PACKED_ARRAY) {
         flags ^= PACKED_ARRAY;
-        return cx->markTypeArrayNotPacked(getType(), false);
+        cx->markTypeArrayNotPacked(getType(), false);
     }
-    return true;
 }
 
 inline JSObject::EnsureDenseResult
 JSObject::ensureDenseArrayElements(JSContext *cx, uintN index, uintN extra)
 {
     JS_ASSERT(isDenseArray());
 
     uintN currentCapacity = numSlots();
@@ -102,18 +101,17 @@ JSObject::ensureDenseArrayElements(JSCon
     uintN requiredCapacity;
     if (extra == 1) {
         /* Optimize for the common case. */
         if (index < initLength)
             return ED_OK;
         if (index < currentCapacity) {
             JS_ASSERT(cx->typeInferenceEnabled());
             if (index > initLength) {
-                if (!setDenseArrayNotPacked(cx))
-                    return ED_FAILED;
+                setDenseArrayNotPacked(cx);
                 ClearValueRange(getDenseArrayElements() + initLength,
                                 index - initLength, true);
             }
             setDenseArrayInitializedLength(index + 1);
             return ED_OK;
         }
         requiredCapacity = index + 1;
         if (requiredCapacity == 0) {
@@ -128,18 +126,17 @@ JSObject::ensureDenseArrayElements(JSCon
         }
         if (requiredCapacity <= initLength)
             return ED_OK;
         if (requiredCapacity <= currentCapacity) {
             JS_ASSERT(cx->typeInferenceEnabled());
             if (index > initLength) {
                 ClearValueRange(getDenseArrayElements() + initLength,
                                 index - initLength, true);
-                if (!setDenseArrayNotPacked(cx))
-                    return ED_FAILED;
+                setDenseArrayNotPacked(cx);
             }
             setDenseArrayInitializedLength(requiredCapacity);
             return ED_OK;
         }
     }
 
     /*
      * We use the extra argument also as a hint about number of non-hole
@@ -149,18 +146,17 @@ JSObject::ensureDenseArrayElements(JSCon
         willBeSparseDenseArray(requiredCapacity, extra)) {
         return ED_SPARSE;
     }
     if (!growSlots(cx, requiredCapacity))
         return ED_FAILED;
 
     if (cx->typeInferenceEnabled()) {
         if (index > initLength) {
-            if (!setDenseArrayNotPacked(cx))
-                return ED_FAILED;
+            setDenseArrayNotPacked(cx);
             ClearValueRange(getDenseArrayElements() + initLength,
                             index - initLength, true);
         }
         setDenseArrayInitializedLength(requiredCapacity);
     } else {
         backfillDenseArrayHoles();
     }
 
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -1372,70 +1372,70 @@ struct JSContext
      */
     inline js::types::TypeObject *getTypeNewObject(JSProtoKey key);
 
     /* Get a type object for the immediate allocation site in this context. */
     inline js::types::TypeObject *
     getTypeCallerInitObject(bool isArray);
 
     /* Mark the immediate allocation site as having produced an unexpected value. */
-    inline bool markTypeCallerUnexpected(js::types::jstype type);
-    inline bool markTypeCallerUnexpected(const js::Value &value);
-    inline bool markTypeCallerOverflow();
+    inline void markTypeCallerUnexpected(js::types::jstype type);
+    inline void markTypeCallerUnexpected(const js::Value &value);
+    inline void markTypeCallerOverflow();
 
     /*
      * Monitor a javascript call, either on entry to the interpreter or made
      * from within the interpreter.
      */
-    inline bool typeMonitorCall(const js::CallArgs &args, bool constructing);
+    inline void typeMonitorCall(const js::CallArgs &args, bool constructing);
 
     /* Monitor an assignment made to a property by a script. */
-    inline bool typeMonitorAssign(JSObject *obj, jsid id, const js::Value &value);
+    inline void typeMonitorAssign(JSObject *obj, jsid id, const js::Value &value);
 
     /* Add a possible value for the named property of obj. */
-    inline bool addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
-    inline bool addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
-    inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
-    inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
-    inline bool addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::ClonedTypeSet *types);
+    inline void addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type);
+    inline void addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value);
+    inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type);
+    inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value);
+    inline void addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::ClonedTypeSet *types);
 
     /* Get the type to use for objects with no prototype. */
     inline js::types::TypeObject *getTypeEmpty();
 
     /* Alias two properties in the type information for obj. */
-    inline bool aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
+    inline void aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second);
 
     /* Mark an array type as being not packed and, possibly, not dense. */
-    inline bool markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense);
+    inline void markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense);
 
     /* Mark a function as being uninlineable (its .arguments property has been accessed). */
-    inline bool markTypeFunctionUninlineable(js::types::TypeObject *obj);
+    inline void markTypeFunctionUninlineable(js::types::TypeObject *obj);
 
     /* Monitor all properties of a type object as unknown. */
-    inline bool markTypeObjectUnknownProperties(js::types::TypeObject *obj);
+    inline void markTypeObjectUnknownProperties(js::types::TypeObject *obj);
 
     /* Mark a type as possibly having special equality hooks. */
-    inline bool markTypeObjectHasSpecialEquality(js::types::TypeObject *obj);
+    inline void markTypeObjectHasSpecialEquality(js::types::TypeObject *obj);
 
     /* Mark any property which has been deleted or reconfigured. */
-    inline bool markTypePropertyConfigured(js::types::TypeObject *obj, jsid id);
+    inline void markTypePropertyConfigured(js::types::TypeObject *obj, jsid id);
 
     /* Mark a global object as having had its slots reallocated. */
-    inline bool markGlobalReallocation(JSObject *obj);
+    inline void markGlobalReallocation(JSObject *obj);
 
     /*
      * For an array or object which has not yet escaped and been referenced elsewhere,
      * pick a new type based on the object's current contents.
      */
-    inline bool fixArrayType(JSObject *obj);
-    inline bool fixObjectType(JSObject *obj);
+    inline void fixArrayType(JSObject *obj);
+    inline void fixObjectType(JSObject *obj);
 
   private:
 
-    inline bool addTypeFlags(js::types::TypeObject *obj, js::types::TypeObjectFlags flags);
+    inline void addTypeFlags(js::types::TypeObject *obj, js::types::TypeObjectFlags flags);
 
 }; /* struct JSContext */
 
 namespace js {
 
 #ifdef JS_THREADSAFE
 # define JS_THREAD_ID(cx)       ((cx)->thread() ? (cx)->thread()->id : 0)
 #endif
--- a/js/src/jsdate.cpp
+++ b/js/src/jsdate.cpp
@@ -1449,210 +1449,210 @@ date_getYear(JSContext *cx, uintN argc, 
 
     Value yearVal = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
     if (yearVal.isInt32()) {
         /* Follow ECMA-262 to the letter, contrary to IE JScript. */
         jsint year = yearVal.toInt32() - 1900;
         vp->setInt32(year);
     } else {
         *vp = yearVal;
-        if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-            return false;
+        if (!vp->isInt32())
+            cx->markTypeCallerOverflow();
     }
 
     return true;
 }
 
 static JSBool
 date_getFullYear(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return JS_FALSE;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_YEAR);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static JSBool
 date_getUTCFullYear(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = YearFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_getMonth(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MONTH);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 static JSBool
 date_getUTCMonth(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = MonthFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_getDate(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DATE);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 static JSBool
 date_getUTCDate(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = DateFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_getDay(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_DAY);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 static JSBool
 date_getUTCDay(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = WeekDay(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_getHours(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_HOURS);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 static JSBool
 date_getUTCHours(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = HourFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return JS_TRUE;
 }
 
 static JSBool
 date_getMinutes(JSContext *cx, uintN argc, Value *vp)
 {
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_MINUTES);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 static JSBool
 date_getUTCMinutes(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = MinFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 /* Date.getSeconds is mapped to getUTCSeconds */
 
 static JSBool
@@ -1661,34 +1661,34 @@ date_getUTCSeconds(JSContext *cx, uintN 
     JSObject *obj = ToObject(cx, &vp[1]);
     if (!obj)
         return false;
 
     if (!GetAndCacheLocalTime(cx, obj, vp))
         return false;
 
     *vp = obj->getSlot(JSObject::JSSLOT_DATE_LOCAL_SECONDS);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 /* Date.getMilliseconds is mapped to getUTCMilliseconds */
 
 static JSBool
 date_getUTCMilliseconds(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble result;
     if (!GetThisUTCTime(cx, vp, &result))
         return false;
 
     if (JSDOUBLE_IS_FINITE(result))
         result = msFromTime(result);
-    else if (!cx->markTypeCallerOverflow())
-        return false;
+    else
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_getTimezoneOffset(JSContext *cx, uintN argc, Value *vp)
 {
@@ -1705,18 +1705,18 @@ date_getTimezoneOffset(JSContext *cx, ui
         return false;
 
     /*
      * Return the time zone offset in minutes for the current locale that is
      * appropriate for this time. This value would be a constant except for
      * daylight savings time.
      */
     jsdouble result = (utctime - localtime) / msPerMinute;
-    if (!JSDOUBLE_IS_FINITE(result) && !cx->markTypeCallerOverflow())
-        return false;
+    if (!JSDOUBLE_IS_FINITE(result))
+        cx->markTypeCallerOverflow();
 
     vp->setNumber(result);
     return true;
 }
 
 static JSBool
 date_setTime(JSContext *cx, uintN argc, Value *vp)
 {
@@ -2653,19 +2653,20 @@ js_InitDateClass(JSContext *cx, JSObject
      *   The Function object that is the initial value of
      *   Date.prototype.toGMTString is the same Function
      *   object that is the initial value of
      *   Date.prototype.toUTCString.
      */
     AutoValueRooter toUTCStringFun(cx);
     jsid toUTCStringId = ATOM_TO_JSID(cx->runtime->atomState.toUTCStringAtom);
     jsid toGMTStringId = ATOM_TO_JSID(cx->runtime->atomState.toGMTStringAtom);
-    if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()) ||
-        !cx->addTypePropertyId(proto->getType(), toGMTStringId, toUTCStringFun.value()) ||
-        !js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(),
+    if (!js_GetProperty(cx, proto, toUTCStringId, toUTCStringFun.addr()))
+        return NULL;
+    cx->addTypePropertyId(proto->getType(), toGMTStringId, toUTCStringFun.value());
+    if (!js_DefineProperty(cx, proto, toGMTStringId, toUTCStringFun.addr(),
                            PropertyStub, StrictPropertyStub, 0)) {
         return NULL;
     }
 
     return proto;
 }
 
 JS_FRIEND_API(JSObject *)
--- a/js/src/jsdbgapi.cpp
+++ b/js/src/jsdbgapi.cpp
@@ -243,20 +243,17 @@ js_SetSingleStepMode(JSContext *cx, JSSc
 
 #ifdef JS_METHODJIT
     /* request the next recompile to inject single step interrupts */
     script->singleStepMode = !!singleStep;
 
     js::mjit::JITScript *jit = script->jitNormal ? script->jitNormal : script->jitCtor;
     if (jit && script->singleStepMode != jit->singleStepMode) {
         js::mjit::Recompiler recompiler(cx, script);
-        if (!recompiler.recompile()) {
-            script->singleStepMode = !singleStep;
-            return JS_FALSE;
-        }
+        recompiler.recompile();
     }
 #endif
     return JS_TRUE;
 }
 
 static JSBool
 CheckDebugMode(JSContext *cx)
 {
@@ -385,18 +382,17 @@ JS_SetTrap(JSContext *cx, JSScript *scri
     trap->closure = closure;
     DBG_UNLOCK(rt);
     if (junk)
         cx->free_(junk);
 
 #ifdef JS_METHODJIT
     if (script->hasJITCode()) {
         js::mjit::Recompiler recompiler(cx, script);
-        if (!recompiler.recompile())
-            return JS_FALSE;
+        recompiler.recompile();
     }
 #endif
 
     return JS_TRUE;
 }
 
 JS_PUBLIC_API(JSOp)
 JS_GetTrapOpcode(JSContext *cx, JSScript *script, jsbytecode *pc)
@@ -984,18 +980,17 @@ UpdateWatchpointShape(JSContext *cx, JSW
         return NULL;
 
     /*
      * Save the shape's setter; we don't know whether js_ChangeNativePropertyAttrs will
      * return a new shape, or mutate this one.
      */
     StrictPropertyOp originalSetter = newShape->setter();
 
-    if (!cx->addTypePropertyId(wp->object->getType(), newShape->id, types::TYPE_UNKNOWN))
-        return NULL;
+    cx->addTypePropertyId(wp->object->getType(), newShape->id, types::TYPE_UNKNOWN);
 
     /*
      * Drop the watching setter into the object, in place of newShape. Note that a single
      * watchpoint-wrapped shape may correspond to more than one non-watchpoint shape: we
      * wrap all (JSPropertyOp, not JSObject *) setters with js_watch_set, so shapes that
      * differ only in their setter may all get wrapped to the same shape.
      */
     const Shape *watchingShape = 
@@ -1092,18 +1087,17 @@ JS_SetWatchPoint(JSContext *cx, JSObject
         return false;
 
     if (!obj->isNative()) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_WATCH,
                              obj->getClass()->name);
         return false;
     }
 
-    if (!cx->markTypePropertyConfigured(obj->getType(), propid))
-        return false;
+    cx->markTypePropertyConfigured(obj->getType(), propid);
 
     JSObject *pobj;
     JSProperty *prop;
     if (!js_LookupProperty(cx, obj, propid, &pobj, &prop))
         return false;
     const Shape *shape = (Shape *) prop;
     JSRuntime *rt = cx->runtime;
     if (!shape) {
--- a/js/src/jsemit.cpp
+++ b/js/src/jsemit.cpp
@@ -4422,18 +4422,17 @@ JSParseNode::getConstantValue(JSContext 
             Value value;
             if (!pn->getConstantValue(cx, strictChecks, &value))
                 return false;
             if (!obj->defineProperty(cx, INT_TO_JSID(idx), value, NULL, NULL, JSPROP_ENUMERATE))
                 return false;
         }
         JS_ASSERT(idx == pn_count);
 
-        if (!cx->fixArrayType(obj))
-            return false;
+        cx->fixArrayType(obj);
         vp->setObject(*obj);
         return true;
       }
       case TOK_RC: {
         JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
 
         gc::FinalizeKind kind = GuessObjectGCKind(pn_count, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
@@ -4463,18 +4462,17 @@ JSParseNode::getConstantValue(JSContext 
                       ? js_SetPropertyHelper(cx, obj, id, 0, &value, strictChecks)
                       : js_DefineNativeProperty(cx, obj, id, value, NULL, NULL,
                                                 JSPROP_ENUMERATE, 0, 0, NULL, 0))) {
                     return false;
                 }
             }
         }
 
-        if (!cx->fixObjectType(obj))
-            return false;
+        cx->fixObjectType(obj);
         vp->setObject(*obj);
         return true;
       }
       default:
         JS_NOT_REACHED("Unexpected node");
     }
     return false;
 }
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -582,18 +582,18 @@ ArgSetter(JSContext *cx, JSObject *obj, 
 
     if (JSID_IS_INT(id)) {
         uintN arg = uintN(JSID_TO_INT(id));
         if (arg < obj->getArgsInitialLength()) {
             StackFrame *fp = (StackFrame *) obj->getPrivate();
             if (fp) {
                 JSScript *script = fp->functionScript();
                 if (script->usesArguments) {
-                    if (arg < fp->numFormalArgs() && !script->typeSetArgument(cx, arg, *vp))
-                        return false;
+                    if (arg < fp->numFormalArgs())
+                        script->typeSetArgument(cx, arg, *vp);
                     fp->canonicalActualArg(arg) = *vp;
                 }
                 return true;
             }
         }
     } else {
         JS_ASSERT(JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom) ||
                   JSID_IS_ATOM(id, cx->runtime->atomState.calleeAtom));
@@ -1233,18 +1233,17 @@ SetCallArg(JSContext *cx, JSObject *obj,
 
     Value *argp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         argp = &fp->formalArg(i);
     else
         argp = &obj->callObjArg(i);
 
     JSScript *script = obj->getCallObjCalleeFunction()->script();
-    if (!script->typeSetArgument(cx, i, *vp))
-        return false;
+    script->typeSetArgument(cx, i, *vp);
 
     GC_POKE(cx, *argp);
     *argp = *vp;
     return true;
 }
 
 JSBool
 GetCallUpvar(JSContext *cx, JSObject *obj, jsid id, Value *vp)
@@ -1317,18 +1316,17 @@ SetCallVar(JSContext *cx, JSObject *obj,
 
     Value *varp;
     if (StackFrame *fp = obj->maybeCallObjStackFrame())
         varp = &fp->varSlot(i);
     else
         varp = &obj->callObjVar(i);
 
     JSScript *script = obj->getCallObjCalleeFunction()->script();
-    if (!script->typeSetLocal(cx, i, *vp))
-        return false;
+    script->typeSetLocal(cx, i, *vp);
 
     GC_POKE(cx, *varp);
     *varp = *vp;
     return true;
 }
 
 } // namespace js
 
@@ -1601,18 +1599,18 @@ fun_getProperty(JSContext *cx, JSObject 
     }
     JSFunction *fun = obj->getFunctionPrivate();
 
     if (slot == FUN_ARGUMENTS || slot == FUN_CALLER) {
         /*
          * Mark the function's script as uninlineable, to expand any of its
          * frames on the stack before we go looking for them.
          */
-        if (fun->isInterpreted() && !cx->markTypeFunctionUninlineable(fun->getType()))
-            return false;
+        if (fun->isInterpreted())
+            cx->markTypeFunctionUninlineable(fun->getType());
     }
 
     /* Find fun's top-most activation record. */
     StackFrame *fp;
     for (fp = js_GetTopStackFrame(cx, FRAME_EXPAND_NONE);
          fp && (fp->maybeFun() != fun || fp->isEvalOrDebuggerFrame());
          fp = fp->prev()) {
         continue;
@@ -1620,18 +1618,17 @@ fun_getProperty(JSContext *cx, JSObject 
 
 #ifdef JS_METHODJIT
     if (slot == FUN_CALLER && fp && fp->prev()) {
         /* Also make sure the caller is uninlineable. */
         JSInlinedSite *inlined;
         fp->prev()->pc(cx, fp, &inlined);
         if (inlined) {
             JSFunction *fun = fp->prev()->jit()->inlineFrames()[inlined->inlineIndex].fun;
-            if (!cx->markTypeFunctionUninlineable(fun->getType()))
-                return false;
+            cx->markTypeFunctionUninlineable(fun->getType());
         }
     }
 #endif
 
     JSAtom *atom = NULL;
 
     switch (slot) {
       case FUN_ARGUMENTS:
@@ -1690,18 +1687,17 @@ fun_getProperty(JSContext *cx, JSObject 
         }
         atom = cx->runtime->atomState.callerAtom;
         break;
 
       default:
         JS_NOT_REACHED("fun_getProperty");
     }
 
-    jsid nameid = atom ? ATOM_TO_JSID(atom) : JSID_VOID;
-    return cx->addTypePropertyId(obj->getType(), nameid, *vp);
+    return true;
 }
 
 struct LazyFunctionDataProp {
     uint16      atomOffset;
     int8        tinyid;
     uint8       attrs;
 };
 
@@ -1835,18 +1831,18 @@ fun_resolve(JSContext *cx, JSObject *obj
             return false;
 
         *objp = obj;
         return true;
     }
 
     if (JSID_IS_ATOM(id, cx->runtime->atomState.lengthAtom)) {
         JS_ASSERT(!IsInternalFunctionObject(obj));
-        if (!cx->addTypePropertyId(obj->getType(), id, types::TYPE_INT32) ||
-            !js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
+        cx->addTypePropertyId(obj->getType(), id, types::TYPE_INT32);
+        if (!js_DefineNativeProperty(cx, obj, id, Int32Value(fun->nargs),
                                      PropertyStub, StrictPropertyStub,
                                      JSPROP_PERMANENT | JSPROP_READONLY, 0, 0, NULL)) {
             return false;
         }
         *objp = obj;
         return true;
     }
 
@@ -2751,18 +2747,19 @@ js_InitFunctionClass(JSContext *cx, JSOb
     if (!proto)
         return NULL;
 
     /*
      * The default 'new' object for Function.prototype has unknown properties.
      * This will be used for generic scripted functions, e.g. from non-compileAndGo code.
      */
     TypeObject *newType = proto->getNewType(cx);
-    if (!newType || !cx->markTypeObjectUnknownProperties(newType))
+    if (!newType)
         return NULL;
+    cx->markTypeObjectUnknownProperties(newType);
 
     JSFunction *fun = js_NewFunction(cx, proto, NULL, 0, JSFUN_INTERPRETED, obj, NULL, NULL, NULL);
     if (!fun)
         return NULL;
     fun->flags |= JSFUN_PROTOTYPE;
 
     JSScript *script = JSScript::NewScript(cx, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, JSVERSION_DEFAULT);
     if (!script)
@@ -2918,22 +2915,20 @@ js_CloneFunctionObject(JSContext *cx, JS
 #ifdef CHECK_SCRIPT_OWNER
             cfun->script()->owner = NULL;
 #endif
             js_CallNewScriptHook(cx, cfun->script(), cfun);
         } else {
             TypeFunction *type = cx->newTypeFunction("ClonedFunction", clone->getProto());
             if (!type || !clone->setTypeAndUniqueShape(cx, type))
                 return NULL;
-            if (fun->getType()->unknownProperties()) {
-                if (!cx->markTypeObjectUnknownProperties(type))
-                    return NULL;
-            } else {
+            if (fun->getType()->unknownProperties())
+                cx->markTypeObjectUnknownProperties(type);
+            else
                 type->handler = fun->getType()->asFunction()->handler;
-            }
         }
     }
     return clone;
 }
 
 #ifdef JS_TRACER
 JS_DEFINE_CALLINFO_4(extern, OBJECT, js_CloneFunctionObject, CONTEXT, FUNCTION, OBJECT, OBJECT, 0,
                      nanojit::ACCSET_STORE_ANY)
@@ -2990,23 +2985,20 @@ js_NewFlatClosure(JSContext *cx, JSFunct
     JSObject *closure = js_AllocFlatClosure(cx, fun, scopeChain);
     if (!closure || !fun->script()->bindings.hasUpvars())
         return closure;
 
     Value *upvars = closure->getFlatClosureUpvars();
     uintN level = fun->u.i.script->staticLevel;
     JSUpvarArray *uva = fun->script()->upvars();
 
-    bool ok = true;
     for (uint32 i = 0, n = uva->length; i < n; i++) {
         upvars[i] = GetUpvar(cx, level, uva->vector[i]);
-        ok &= fun->script()->typeSetUpvar(cx, i, upvars[i]);
+        fun->script()->typeSetUpvar(cx, i, upvars[i]);
     }
-    if (!ok)
-        return NULL;
 
     return closure;
 }
 
 JSObject *
 js_NewDebuggableFlatClosure(JSContext *cx, JSFunction *fun)
 {
     JS_ASSERT(cx->fp()->fun()->flags & JSFUN_HEAVYWEIGHT);
@@ -3095,19 +3087,17 @@ js_DefineFunction(JSContext *cx, JSObjec
                          JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL,
                          handler, fullName);
     if (!fun)
         return NULL;
 
     if (!wasDelegate && obj->isDelegate())
         obj->clearDelegate();
 
-    if (!cx->addTypePropertyId(obj->getType(), id, ObjectValue(*fun)))
-        return NULL;
-
+    cx->addTypePropertyId(obj->getType(), id, ObjectValue(*fun));
     if (!obj->defineProperty(cx, id, ObjectValue(*fun), gop, sop, attrs & ~JSFUN_FLAGS_MASK))
         return NULL;
 
     return fun;
 }
 
 JS_STATIC_ASSERT((JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK) == 0);
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1809,52 +1809,45 @@ TypeCompartment::growPendingArray(JSCont
 
     memcpy(newArray, pendingArray, pendingCount * sizeof(PendingWork));
     cx->free_(pendingArray);
 
     pendingArray = newArray;
     pendingCapacity = newCapacity;
 }
 
-bool
+void
 TypeCompartment::dynamicCall(JSContext *cx, JSObject *callee,
                              const js::CallArgs &args, bool constructing)
 {
     unsigned nargs = callee->getFunctionPrivate()->nargs;
     JSScript *script = callee->getFunctionPrivate()->script();
 
     if (constructing) {
         script->typeSetNewCalled(cx);
     } else {
         jstype type = GetValueType(cx, args.thisv());
-        if (!script->typeSetThis(cx, type))
-            return false;
+        script->typeSetThis(cx, type);
     }
 
     /*
      * Add constraints going up to the minimum of the actual and formal count.
      * If there are more actuals than formals the later values can only be
      * accessed through the arguments object, which is monitored.
      */
     unsigned arg = 0;
-    for (; arg < args.argc() && arg < nargs; arg++) {
-        if (!script->typeSetArgument(cx, arg, args[arg]))
-            return false;
-    }
+    for (; arg < args.argc() && arg < nargs; arg++)
+        script->typeSetArgument(cx, arg, args[arg]);
 
     /* Watch for fewer actuals than formals to the call. */
-    for (; arg < nargs; arg++) {
-        if (!script->typeSetArgument(cx, arg, UndefinedValue()))
-            return false;
-    }
-
-    return true;
+    for (; arg < nargs; arg++)
+        script->typeSetArgument(cx, arg, UndefinedValue());
 }
 
-bool
+void
 TypeCompartment::dynamicPush(JSContext *cx, JSScript *script, uint32 offset, jstype type)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     AutoEnterTypeInference enter(cx);
 
     /*
      * For inc/dec ops, we need to go back and reanalyze the affected opcode
      * taking the overflow into account. We won't see an explicit adjustment
@@ -1912,58 +1905,58 @@ TypeCompartment::dynamicPush(JSContext *
     if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
         /*
          * If the pushed set already has this type, we don't need to ensure
          * there is a TypeResult. Either there already is a TypeResult, or the
          * type could be determined from the script's other input type sets.
          */
         TypeSet *pushed = script->analysis(cx)->pushedTypes(offset, 0);
         if (pushed->hasType(type))
-            return true;
+            return;
     } else {
         /* Scan all TypeResults on the script to check for a duplicate. */
         TypeResult *result, **presult = &script->typeResults;
         while (*presult) {
             result = *presult;
             if (result->offset == offset && result->type == type) {
                 if (presult != &script->typeResults) {
                     /* Move this result to the head of the list, maintain LRU order. */
                     *presult = result->next;
                     result->next = script->typeResults;
                     script->typeResults = result;
                 }
-                return true;
+                return;
             }
             presult = &result->next;
         }
     }
 
     InferSpew(ISpewOps, "externalType: monitorResult #%u:%05u: %s",
                script->id(), offset, TypeString(type));
 
     TypeResult *result = (TypeResult *) cx->calloc_(sizeof(TypeResult));
     if (!result) {
         setPendingNukeTypes(cx);
-        return false;
+        return;
     }
 
     result->offset = offset;
     result->type = type;
     result->next = script->typeResults;
     script->typeResults = result;
 
     if (script->hasAnalysis() && script->analysis(cx)->ranInference()) {
         TypeSet *pushed = script->analysis(cx)->pushedTypes(offset, 0);
         pushed->addType(cx, type);
     } else if (script->analyzed) {
         /* Any new dynamic result triggers reanalysis and recompilation. */
         analyze::ScriptAnalysis *analysis = script->analysis(cx);
         if (!analysis) {
             setPendingNukeTypes(cx);
-            return false;
+            return;
         }
         analysis->analyzeTypes(cx);
     }
 
     /*
      * If this script was inlined into a parent, we need to make sure the
      * parent has constraints listening to type changes in this one (it won't
      * necessarily, if we have condensed the constraints but not reanalyzed the
@@ -1985,70 +1978,64 @@ TypeCompartment::dynamicPush(JSContext *
         while (offset < script->length) {
             if (JSOp(script->code[offset]) == JSOP_GETELEM && analysis->maybeCode(offset)) {
                 TypeSet *pushed = analysis->pushedTypes(offset, 0);
                 if (!pushed->hasType(TYPE_UNDEFINED)) {
                     pushed->addType(cx, TYPE_UNDEFINED);
                     TypeResult *result = (TypeResult *) cx->calloc_(sizeof(TypeResult));
                     if (!result) {
                         setPendingNukeTypes(cx);
-                        return false;
+                        return;
                     }
                     result->offset = offset;
                     result->type = TYPE_UNDEFINED;
                     result->next = script->typeResults;
                     script->typeResults = result;
                 }
             }
             offset += analyze::GetBytecodeLength(pc);
         }
     }
-
-    return true;
 }
 
-bool
+void
 TypeCompartment::processPendingRecompiles(JSContext *cx)
 {
     /* Steal the list of scripts to recompile, else we will try to recursively recompile them. */
     Vector<JSScript*> *pending = pendingRecompiles;
     pendingRecompiles = NULL;
 
     JS_ASSERT(!pending->empty());
 
 #ifdef JS_METHODJIT
 
     mjit::ExpandInlineFrames(cx, true);
 
     for (unsigned i = 0; i < pending->length(); i++) {
         JSScript *script = (*pending)[i];
         mjit::Recompiler recompiler(cx, script);
-        if (script->hasJITCode() && !recompiler.recompile()) {
-            pendingNukeTypes = true;
-            cx->delete_(pending);
-            return nukeTypes(cx);
-        }
+        if (script->hasJITCode())
+            recompiler.recompile();
     }
 
 #endif /* JS_METHODJIT */
 
     cx->delete_(pending);
-    return true;
 }
 
 void
 TypeCompartment::setPendingNukeTypes(JSContext *cx)
 {
     if (!pendingNukeTypes) {
         js_ReportOutOfMemory(cx);
         pendingNukeTypes = true;
     }
 }
 
-bool
+void
 TypeCompartment::nukeTypes(JSContext *cx)
 {
     /*
      * This is the usual response if we encounter an OOM while adding a type
      * or resolving type constraints. Release all memory used for type information,
      * reset the compartment to not use type inference, and recompile all scripts.
      *
      * Because of the nature of constraint-based analysis (add constraints, and
@@ -2060,18 +2047,16 @@ TypeCompartment::nukeTypes(JSContext *cx
     JS_ASSERT(pendingNukeTypes);
     if (pendingRecompiles) {
         cx->free_(pendingRecompiles);
         pendingRecompiles = NULL;
     }
 
     /* :FIXME: Implement this function. */
     *((int*)0) = 0;
-
-    return true;
 }
 
 void
 TypeCompartment::addPendingRecompile(JSContext *cx, JSScript *script)
 {
     if (!script->jitNormal && !script->jitCtor) {
         /* Scripts which haven't been compiled yet don't need to be recompiled. */
         return;
@@ -2091,51 +2076,51 @@ TypeCompartment::addPendingRecompile(JSC
     }
 
     if (!pendingRecompiles->append(script)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return;
     }
 }
 
-bool
+void
 TypeCompartment::dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval)
 {
     if (obj->isWith())
         obj = js_UnwrapWithObject(cx, obj);
 
     jstype rvtype = GetValueType(cx, rval);
     TypeObject *object = obj->getType();
 
     if (object->unknownProperties())
-        return true;
+        return;
 
     id = MakeTypeId(cx, id);
 
     /*
      * Mark as unknown any object which has had dynamic assignments to __proto__,
      * and any object which has had dynamic assignments to string properties through SETELEM.
      * The latter avoids making large numbers of type properties for hashmap-style objects.
      * :FIXME: this is too aggressive for things like prototype library initialization.
      */
     JSOp op = JSOp(*cx->regs().pc);
-    if (id == id___proto__(cx) || (op == JSOP_SETELEM && !JSID_IS_VOID(id)))
-        return cx->markTypeObjectUnknownProperties(object);
+    if (id == id___proto__(cx) || (op == JSOP_SETELEM && !JSID_IS_VOID(id))) {
+        cx->markTypeObjectUnknownProperties(object);
+        return;
+    }
 
     AutoEnterTypeInference enter(cx);
 
     TypeSet *assignTypes = object->getProperty(cx, id, true);
     if (!assignTypes || assignTypes->hasType(rvtype))
-        return true;
+        return;
 
     InferSpew(ISpewOps, "externalType: monitorAssign %s %s: %s",
               object->name(), TypeIdString(id), TypeString(rvtype));
     assignTypes->addType(cx, rvtype);
-
-    return true;
 }
 
 void
 TypeCompartment::monitorBytecode(JSContext *cx, JSScript *script, uint32 offset)
 {
     if (script->analysis(cx)->monitoredTypes(offset))
         return;
 
@@ -2273,49 +2258,51 @@ struct types::ArrayTableKey
         return (uint32) (v.type ^ ((uint32)(size_t)v.proto >> 2));
     }
 
     static inline bool match(const ArrayTableKey &v1, const ArrayTableKey &v2) {
         return v1.type == v2.type && v1.proto == v2.proto;
     }
 };
 
-bool
+void
 TypeCompartment::fixArrayType(JSContext *cx, JSObject *obj)
 {
+    AutoEnterTypeInference enter(cx);
+
     if (!arrayTypeTable) {
         arrayTypeTable = cx->new_<ArrayTypeTable>();
         if (!arrayTypeTable || !arrayTypeTable->init()) {
             arrayTypeTable = NULL;
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
     }
 
     /*
      * If the array is of homogenous type, pick a type object which will be
      * shared with all other singleton/JSON arrays of the same type.
      * If the array is heterogenous, keep the existing type object, which has
      * unknown properties.
      */
     JS_ASSERT(obj->isPackedDenseArray());
 
     unsigned len = obj->getDenseArrayInitializedLength();
     if (len == 0)
-        return true;
+        return;
 
     jstype type = GetValueType(cx, obj->getDenseArrayElement(0));
 
     for (unsigned i = 1; i < len; i++) {
         jstype ntype = GetValueType(cx, obj->getDenseArrayElement(i));
         if (ntype != type) {
             if (NumberTypes(type, ntype))
                 type = TYPE_DOUBLE;
             else
-                return true;
+                return;
         }
     }
 
     ArrayTableKey key;
     key.type = type;
     key.proto = obj->getProto();
     ArrayTypeTable::AddPtr p = arrayTypeTable->lookupForAdd(key);
 
@@ -2323,31 +2310,28 @@ TypeCompartment::fixArrayType(JSContext 
         obj->setType(p->value);
     } else {
         static unsigned count = 0;
         char *name = (char *) alloca(20);
         JS_snprintf(name, 20, "TableArray:%u", ++count);
 
         TypeObject *objType = newTypeObject(cx, NULL, name, false, true, obj->getProto());
         if (!objType) {
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
         obj->setType(objType);
 
-        if (!cx->addTypePropertyId(objType, JSID_VOID, type))
-            return false;
+        cx->addTypePropertyId(objType, JSID_VOID, type);
 
         if (!arrayTypeTable->relookupOrAdd(p, key, objType)) {
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
     }
-
-    return true;
 }
 
 /*
  * N.B. We could also use the initial shape of the object (before its type is
  * fixed) as the key in the object table, but since all references in the table
  * are weak the hash entries would usually be collected on GC even if objects
  * with the new type/shape are still live.
  */
@@ -2384,145 +2368,148 @@ struct types::ObjectTableKey
 
 struct types::ObjectTableEntry
 {
     TypeObject *object;
     Shape *newShape;
     jstype *types;
 };
 
-bool
+void
 TypeCompartment::fixObjectType(JSContext *cx, JSObject *obj)
 {
+    AutoEnterTypeInference enter(cx);
+
     if (!objectTypeTable) {
         objectTypeTable = cx->new_<ObjectTypeTable>();
         if (!objectTypeTable || !objectTypeTable->init()) {
             objectTypeTable = NULL;
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
     }
 
     /*
      * Use the same type object for all singleton/JSON arrays with the same
      * base shape, i.e. the same fields written in the same order. If there
      * is a type mismatch with previous objects of the same shape, use the
      * generic unknown type.
      */
     JS_ASSERT(obj->isObject());
 
     if (obj->slotSpan() == 0 || obj->inDictionaryMode())
-        return true;
+        return;
 
     ObjectTypeTable::AddPtr p = objectTypeTable->lookupForAdd(obj);
     const Shape *baseShape = obj->lastProperty();
 
     if (p) {
         /* The lookup ensures the shape matches, now check that the types match. */
         jstype *types = p->value.types;
         for (unsigned i = 0; i < obj->slotSpan(); i++) {
             jstype ntype = GetValueType(cx, obj->getSlot(i));
             if (ntype != types[i]) {
                 if (NumberTypes(ntype, types[i])) {
                     if (types[i] == TYPE_INT32) {
                         types[i] = TYPE_DOUBLE;
                         const Shape *shape = baseShape;
                         while (!JSID_IS_EMPTY(shape->id)) {
                             if (shape->slot == i) {
-                                if (!cx->addTypePropertyId(p->value.object, shape->id, TYPE_DOUBLE))
-                                    return false;
+                                cx->addTypePropertyId(p->value.object, shape->id, TYPE_DOUBLE);
                                 break;
                             }
                             shape = shape->previous();
                         }
                     }
                 } else {
-                    return true;
+                    return;
                 }
             }
         }
 
         obj->setTypeAndShape(p->value.object, p->value.newShape);
     } else {
         /*
          * Make a new type to use, and regenerate a new shape to go with it.
          * Shapes are rooted at the empty shape for the object's type, so we
          * can't change the type without changing the shape.
          */
         JSObject *xobj = NewBuiltinClassInstance(cx, &js_ObjectClass,
                                                  (gc::FinalizeKind) obj->finalizeKind());
         if (!xobj) {
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
         AutoObjectRooter xvr(cx, xobj);
 
         static unsigned count = 0;
         char *name = (char *) alloca(20);
         JS_snprintf(name, 20, "TableObject:%u", ++count);
 
         TypeObject *objType = newTypeObject(cx, NULL, name, false, false, obj->getProto());
         if (!objType) {
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
         xobj->setType(objType);
 
         jsid *ids = (jsid *) cx->calloc_(obj->slotSpan() * sizeof(jsid));
-        if (!ids)
-            return false;
+        if (!ids) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
 
         jstype *types = (jstype *) cx->calloc_(obj->slotSpan() * sizeof(jstype));
-        if (!types)
-            return false;
+        if (!types) {
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
+        }
 
         const Shape *shape = baseShape;
         while (!JSID_IS_EMPTY(shape->id)) {
             ids[shape->slot] = shape->id;
             types[shape->slot] = GetValueType(cx, obj->getSlot(shape->slot));
-            if (!cx->addTypePropertyId(objType, shape->id, types[shape->slot]))
-                return false;
+            cx->addTypePropertyId(objType, shape->id, types[shape->slot]);
             shape = shape->previous();
         }
 
         /* Construct the new shape. */
         for (unsigned i = 0; i < obj->slotSpan(); i++) {
             if (!js_DefineNativeProperty(cx, xobj, ids[i], UndefinedValue(), NULL, NULL,
                                          JSPROP_ENUMERATE, 0, 0, NULL, 0)) {
-                return false;
+                cx->compartment->types.setPendingNukeTypes(cx);
+                return;
             }
         }
         JS_ASSERT(!xobj->inDictionaryMode());
         const Shape *newShape = xobj->lastProperty();
 
         if (!objType->addDefiniteProperties(cx, xobj, false))
-            return false;
+            return;
 
         ObjectTableKey key;
         key.ids = ids;
         key.nslots = obj->slotSpan();
         key.nfixed = obj->numFixedSlots();
         key.proto = obj->getProto();
         JS_ASSERT(ObjectTableKey::match(key, obj));
 
         ObjectTableEntry entry;
         entry.object = objType;
         entry.newShape = (Shape *) newShape;
         entry.types = types;
 
         p = objectTypeTable->lookupForAdd(obj);
         if (!objectTypeTable->add(p, key, entry)) {
-            js_ReportOutOfMemory(cx);
-            return false;
+            cx->compartment->types.setPendingNukeTypes(cx);
+            return;
         }
 
         obj->setTypeAndShape(objType, newShape);
     }
-
-    return true;
 }
 
 /////////////////////////////////////////////////////////////////////
 // TypeObject
 /////////////////////////////////////////////////////////////////////
 
 void
 TypeObject::storeToInstances(JSContext *cx, Property *base)
@@ -4093,19 +4080,19 @@ JSContext::newTypeObject(const char *bas
 // JSScript
 /////////////////////////////////////////////////////////////////////
 
 /*
  * Returns true if we don't expect to compute the correct types for some value
  * pushed by the specified bytecode.
  */
 static inline bool
-IgnorePushed(JSOp op, unsigned index)
+IgnorePushed(const jsbytecode *pc, unsigned index)
 {
-    switch (op) {
+    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. */
       case JSOP_IN:
@@ -4151,31 +4138,44 @@ IgnorePushed(JSOp op, unsigned index)
       case JSOP_DUP:
       case JSOP_DUP2:
         return true;
 
       /* We don't keep track of state indicating whether there is a pending exception. */
       case JSOP_FINALLY:
         return true;
 
+      /*
+       * We don't treat GETLOCAL immediately followed by a pop as a use-before-def,
+       * and while the type will have been inferred correctly the method JIT
+       * may not have written the local's initial undefined value to the stack,
+       * leaving a stale value.
+       */
+      case JSOP_GETLOCAL:
+        return JSOp(pc[JSOP_GETLOCAL_LENGTH]) == JSOP_POP;
+
       default:
         return false;
     }
 }
 
 bool
 JSScript::makeVarTypes(JSContext *cx)
 {
     JS_ASSERT(!varTypes);
 
+    AutoEnterTypeInference enter(cx);
+
     unsigned nargs = fun ? fun->nargs : 0;
     unsigned count = 2 + nargs + nfixed + bindings.countUpvars();
     varTypes = (TypeSet *) cx->calloc_(sizeof(TypeSet) * count);
-    if (!varTypes)
+    if (!varTypes) {
+        compartment->types.setPendingNukeTypes(cx);
         return false;
+    }
 
 #ifdef DEBUG
     InferSpew(ISpewOps, "typeSet: T%p return #%u", returnTypes(), id());
     InferSpew(ISpewOps, "typeSet: T%p this #%u", thisTypes(), id());
     for (unsigned i = 0; i < nargs; i++)
         InferSpew(ISpewOps, "typeSet: T%p arg%u #%u", argTypes(i), i, id());
     for (unsigned i = 0; i < nfixed; i++)
         InferSpew(ISpewOps, "typeSet: T%p local%u #%u", localTypes(i), i, id());
@@ -4221,17 +4221,17 @@ JSScript::typeCheckBytecode(JSContext *c
     if (!(analysis_ && analysis_->ranInference()))
         return;
 
     int defCount = js::analyze::GetDefCount(this, pc - code);
 
     for (int i = 0; i < defCount; i++) {
         const js::Value &val = sp[-defCount + i];
         TypeSet *types = analysis_->pushedTypes(pc, i);
-        if (IgnorePushed(JSOp(*pc), i))
+        if (IgnorePushed(pc, i))
             continue;
 
         jstype type = GetValueType(cx, val);
 
         if (!TypeSetMatches(cx, types, type)) {
             TypeFailure(cx, "Missing type at #%u:%05u pushed %u: %s",
                                    id(), pc - code, i, TypeString(type));
         }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -739,18 +739,18 @@ struct TypeCompartment
      */
     JSScript *compiledScript;
 
     /* Tables for determining types of singleton/JSON objects. */
 
     ArrayTypeTable *arrayTypeTable;
     ObjectTypeTable *objectTypeTable;
 
-    bool fixArrayType(JSContext *cx, JSObject *obj);
-    bool fixObjectType(JSContext *cx, JSObject *obj);
+    void fixArrayType(JSContext *cx, JSObject *obj);
+    void fixObjectType(JSContext *cx, JSObject *obj);
 
     /* Constraint solving worklist structures. */
 
     /*
      * Worklist of types which need to be propagated to constraints. We use a
      * worklist to avoid blowing the native stack.
      */
     struct PendingWork
@@ -793,22 +793,22 @@ struct TypeCompartment
     /* Make an initializer object. */
     TypeObject *newInitializerTypeObject(JSContext *cx, JSScript *script,
                                          uint32 offset, bool isArray);
 
     /*
      * Add the specified type to the specified set, do any necessary reanalysis
      * stemming from the change and recompile any affected scripts.
      */
-    bool dynamicPush(JSContext *cx, JSScript *script, uint32 offset, jstype type);
-    bool dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval);
-    bool dynamicCall(JSContext *cx, JSObject *callee, const CallArgs &args, bool constructing);
+    void dynamicPush(JSContext *cx, JSScript *script, uint32 offset, jstype type);
+    void dynamicAssign(JSContext *cx, JSObject *obj, jsid id, const Value &rval);
+    void dynamicCall(JSContext *cx, JSObject *callee, const CallArgs &args, bool constructing);
 
-    bool nukeTypes(JSContext *cx);
-    bool processPendingRecompiles(JSContext *cx);
+    void nukeTypes(JSContext *cx);
+    void processPendingRecompiles(JSContext *cx);
 
     /* Mark all types as needing destruction once inference has 'finished'. */
     void setPendingNukeTypes(JSContext *cx);
 
     /* Mark a script as needing recompilation once inference has finished. */
     void addPendingRecompile(JSContext *cx, JSScript *script);
 
     /* Monitor future effects on a bytecode. */
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -232,293 +232,275 @@ JSContext::getTypeCallerInitObject(bool 
             JSScript *script;
             jsbytecode *pc = caller->inlinepc(this, &script);
             return script->getTypeInitObject(this, pc, isArray);
         }
     }
     return getTypeNewObject(isArray ? JSProto_Array : JSProto_Object);
 }
 
-inline bool
+inline void
 JSContext::markTypeCallerUnexpected(js::types::jstype type)
 {
     if (!typeInferenceEnabled())
-        return true;
+        return;
 
     /*
      * Check that we are actually at a scripted callsite. This function is
      * called from JS natives which can be called anywhere a script can be
      * called, such as on property getters or setters. This filtering is not
      * perfect, but we only need to make sure the type result is added wherever
      * the native's type handler was used, i.e. at scripted callsites directly
      * calling the native.
      */
 
     js::StackFrame *caller = js_GetScriptedCaller(this, NULL);
     if (!caller)
-        return true;
+        return;
 
     /*
      * Watch out if the caller is in a different compartment from this one.
      * This must have gone through a cross-compartment wrapper.
      */
     if (caller->script()->compartment != compartment)
-        return true;
+        return;
 
     JSScript *script;
     jsbytecode *pc = caller->inlinepc(this, &script);
 
     switch ((JSOp)*pc) {
       case JSOP_CALL:
       case JSOP_EVAL:
       case JSOP_FUNCALL:
       case JSOP_FUNAPPLY:
       case JSOP_NEW:
         break;
       case JSOP_ITER:
         /* This is also used for handling custom iterators. */
         break;
       default:
-        return true;
+        return;
     }
 
-    return script->typeMonitorResult(this, pc, type);
+    script->typeMonitorResult(this, pc, type);
 }
 
-inline bool
+inline void
 JSContext::markTypeCallerUnexpected(const js::Value &value)
 {
-    if (!typeInferenceEnabled())
-        return true;
-    return markTypeCallerUnexpected(js::types::GetValueType(this, value));
+    if (typeInferenceEnabled())
+        markTypeCallerUnexpected(js::types::GetValueType(this, value));
 }
 
-inline bool
+inline void
 JSContext::markTypeCallerOverflow()
 {
-    return markTypeCallerUnexpected(js::types::TYPE_DOUBLE);
+    markTypeCallerUnexpected(js::types::TYPE_DOUBLE);
 }
 
-inline bool
+inline void
 JSContext::addTypeProperty(js::types::TypeObject *obj, const char *name, js::types::jstype type)
 {
     if (typeInferenceEnabled() && !obj->unknownProperties()) {
         jsid id = JSID_VOID;
         if (name) {
             JSAtom *atom = js_Atomize(this, name, strlen(name), 0);
-            if (!atom)
-                return false;
+            if (!atom) {
+                js::types::AutoEnterTypeInference enter(this);
+                compartment->types.setPendingNukeTypes(this);
+                return;
+            }
             id = ATOM_TO_JSID(atom);
         }
-        return addTypePropertyId(obj, id, type);
+        addTypePropertyId(obj, id, type);
     }
-    return true;
 }
 
-inline bool
+inline void
 JSContext::addTypeProperty(js::types::TypeObject *obj, const char *name, const js::Value &value)
 {
     if (typeInferenceEnabled() && !obj->unknownProperties())
-        return addTypeProperty(obj, name, js::types::GetValueType(this, value));
-    return true;
+        addTypeProperty(obj, name, js::types::GetValueType(this, value));
 }
 
-inline bool
+inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::jstype type)
 {
     if (!typeInferenceEnabled() || obj->unknownProperties())
-        return true;
+        return;
 
     /* Convert string index properties into the common index property. */
     id = js::types::MakeTypeId(this, id);
 
     js::types::AutoEnterTypeInference enter(this);
 
     js::types::TypeSet *types = obj->getProperty(this, id, true);
     if (!types || types->hasType(type))
-        return true;
+        return;
 
     js::types::InferSpew(js::types::ISpewOps, "externalType: property %s %s: %s",
                          obj->name(), js::types::TypeIdString(id),
                          js::types::TypeString(type));
     types->addType(this, type);
-
-    return true;
 }
 
-inline bool
+inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, const js::Value &value)
 {
     if (typeInferenceEnabled() && !obj->unknownProperties())
-        return addTypePropertyId(obj, id, js::types::GetValueType(this, value));
-    return true;
+        addTypePropertyId(obj, id, js::types::GetValueType(this, value));
 }
 
-inline bool
+inline void
 JSContext::addTypePropertyId(js::types::TypeObject *obj, jsid id, js::types::ClonedTypeSet *set)
 {
     if (obj->unknownProperties())
-        return true;
+        return;
     id = js::types::MakeTypeId(this, id);
 
     js::types::AutoEnterTypeInference enter(this);
 
     js::types::TypeSet *types = obj->getProperty(this, id, true);
     if (!types)
-        return true;
+        return;
 
     js::types::InferSpew(js::types::ISpewOps, "externalType: property %s %s",
                          obj->name(), js::types::TypeIdString(id));
     types->addTypeSet(this, set);
-
-    return true;
 }
 
 inline js::types::TypeObject *
 JSContext::getTypeEmpty()
 {
     return &compartment->types.typeEmpty;
 }
 
-inline bool
+inline void
 JSContext::aliasTypeProperties(js::types::TypeObject *obj, jsid first, jsid second)
 {
     if (!typeInferenceEnabled() || obj->unknownProperties())
-        return true;
+        return;
 
     js::types::AutoEnterTypeInference enter(this);
 
     first = js::types::MakeTypeId(this, first);
     second = js::types::MakeTypeId(this, second);
 
     js::types::TypeSet *firstTypes = obj->getProperty(this, first, true);
     js::types::TypeSet *secondTypes = obj->getProperty(this, second, true);
     if (!firstTypes || !secondTypes)
-        return false;
+        return;
 
     firstTypes->addBaseSubset(this, obj, secondTypes);
     secondTypes->addBaseSubset(this, obj, firstTypes);
-
-    return true;
 }
 
-inline bool
+inline void
 JSContext::addTypeFlags(js::types::TypeObject *obj, js::types::TypeObjectFlags flags)
 {
     if (!typeInferenceEnabled() || obj->hasFlags(flags))
-        return true;
+        return;
 
     js::types::AutoEnterTypeInference enter(this);
     obj->setFlags(this, flags);
-    return true;
 }
 
-inline bool
+inline void
 JSContext::markTypeArrayNotPacked(js::types::TypeObject *obj, bool notDense)
 {
-    return addTypeFlags(obj, js::types::OBJECT_FLAG_NON_PACKED_ARRAY |
-                        (notDense ? js::types::OBJECT_FLAG_NON_DENSE_ARRAY : 0));
+    addTypeFlags(obj, js::types::OBJECT_FLAG_NON_PACKED_ARRAY |
+                 (notDense ? js::types::OBJECT_FLAG_NON_DENSE_ARRAY : 0));
 }
 
-inline bool
+inline void
 JSContext::markTypeFunctionUninlineable(js::types::TypeObject *obj)
 {
-    return addTypeFlags(obj, js::types::OBJECT_FLAG_UNINLINEABLE);
-}
-
-inline bool
-JSContext::markTypeObjectHasSpecialEquality(js::types::TypeObject *obj)
-{
-    return addTypeFlags(obj, js::types::OBJECT_FLAG_SPECIAL_EQUALITY);
+    addTypeFlags(obj, js::types::OBJECT_FLAG_UNINLINEABLE);
 }
 
-inline bool
+inline void
+JSContext::markTypeObjectHasSpecialEquality(js::types::TypeObject *obj)
+{
+    addTypeFlags(obj, js::types::OBJECT_FLAG_SPECIAL_EQUALITY);
+}
+
+inline void
 JSContext::markTypePropertyConfigured(js::types::TypeObject *obj, jsid id)
 {
-    if (!typeInferenceEnabled())
-        return true;
-
-    if (obj->unknownProperties())
-        return true;
+    if (!typeInferenceEnabled() || obj->unknownProperties())
+        return;
     id = js::types::MakeTypeId(this, id);
 
     js::types::AutoEnterTypeInference enter(this);
     js::types::TypeSet *types = obj->getProperty(this, id, true);
     if (types)
         types->setOwnProperty(this, true);
-
-    return true;
 }
 
-inline bool
+inline void
 JSContext::markGlobalReallocation(JSObject *obj)
 {
     JS_ASSERT(obj->isGlobal());
 
-    if (!typeInferenceEnabled())
-        return true;
-
-    if (obj->getType()->unknownProperties())
-        return true;
+    if (!typeInferenceEnabled() || obj->getType()->unknownProperties())
+        return;
 
     js::types::AutoEnterTypeInference enter(this);
     js::types::TypeSet *types = obj->getType()->getProperty(this, JSID_VOID, false);
     if (types) {
         js::types::TypeConstraint *constraint = types->constraintList;
         while (constraint) {
             constraint->slotsReallocation(this);
             constraint = constraint->next;
         }
     }
-
-    return true;
 }
 
-inline bool
+inline void
 JSContext::markTypeObjectUnknownProperties(js::types::TypeObject *obj)
 {
     if (!typeInferenceEnabled() || obj->unknownProperties())
-        return true;
+        return;
 
     js::types::AutoEnterTypeInference enter(this);
     obj->markUnknown(this);
-    return true;
 }
 
-inline bool
+inline void
 JSContext::typeMonitorAssign(JSObject *obj, jsid id, const js::Value &rval)
 {
     if (typeInferenceEnabled())
-        return compartment->types.dynamicAssign(this, obj, id, rval);
-    return true;
+        compartment->types.dynamicAssign(this, obj, id, rval);
 }
 
-inline bool
+inline void
 JSContext::typeMonitorCall(const js::CallArgs &args, bool constructing)
 {
     if (!typeInferenceEnabled())
-        return true;
+        return;
 
     JSObject *callee = &args.callee();
     if (!callee->isFunction() || !callee->getFunctionPrivate()->isInterpreted())
-        return true;
+        return;
 
-    return compartment->types.dynamicCall(this, callee, args, constructing);
+    compartment->types.dynamicCall(this, callee, args, constructing);
 }
 
-inline bool
+inline void
 JSContext::fixArrayType(JSObject *obj)
 {
-    return !typeInferenceEnabled() || compartment->types.fixArrayType(this, obj);
+    if (typeInferenceEnabled())
+        compartment->types.fixArrayType(this, obj);
 }
 
-inline bool
+inline void
 JSContext::fixObjectType(JSObject *obj)
 {
-    return !typeInferenceEnabled() || compartment->types.fixObjectType(this, obj);
+    if (typeInferenceEnabled())
+        compartment->types.fixObjectType(this, obj);
 }
 
 /////////////////////////////////////////////////////////////////////
 // JSScript
 /////////////////////////////////////////////////////////////////////
 
 inline bool
 JSScript::ensureVarTypes(JSContext *cx)
@@ -620,236 +602,208 @@ JSScript::getTypeInitObject(JSContext *c
         }
         prev = obj;
         obj = obj->next;
     }
 
     return cx->compartment->types.newInitializerTypeObject(cx, this, offset, isArray);
 }
 
-inline bool
+inline void
 JSScript::typeMonitorResult(JSContext *cx, const jsbytecode *pc,
                             js::types::jstype type)
 {
     if (cx->typeInferenceEnabled())
-        return cx->compartment->types.dynamicPush(cx, this, pc - code, type);
-    return true;
+        cx->compartment->types.dynamicPush(cx, this, pc - code, type);
 }
 
-inline bool
+inline void
 JSScript::typeMonitorResult(JSContext *cx, const jsbytecode *pc, const js::Value &rval)
 {
     if (cx->typeInferenceEnabled())
-        return typeMonitorResult(cx, pc, js::types::GetValueType(cx, rval));
-    return true;
+        typeMonitorResult(cx, pc, js::types::GetValueType(cx, rval));
 }
 
-inline bool
+inline void
 JSScript::typeMonitorOverflow(JSContext *cx, const jsbytecode *pc)
 {
-    return typeMonitorResult(cx, pc, js::types::TYPE_DOUBLE);
+    typeMonitorResult(cx, pc, js::types::TYPE_DOUBLE);
 }
 
-inline bool
+inline void
 JSScript::typeMonitorUndefined(JSContext *cx, const jsbytecode *pc)
 {
-    return typeMonitorResult(cx, pc, js::types::TYPE_UNDEFINED);
+    typeMonitorResult(cx, pc, js::types::TYPE_UNDEFINED);
 }
 
-inline bool
+inline void
 JSScript::typeMonitorString(JSContext *cx, const jsbytecode *pc)
 {
-    return typeMonitorResult(cx, pc, js::types::TYPE_STRING);
+    typeMonitorResult(cx, pc, js::types::TYPE_STRING);
 }
 
-inline bool
+inline void
 JSScript::typeMonitorUnknown(JSContext *cx, const jsbytecode *pc)
 {
-    return typeMonitorResult(cx, pc, js::types::TYPE_UNKNOWN);
+    typeMonitorResult(cx, pc, js::types::TYPE_UNKNOWN);
 }
 
-inline bool
+inline void
 JSScript::typeSetThis(JSContext *cx, js::types::jstype type)
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     if (!ensureVarTypes(cx))
-        return false;
+        return;
 
     /* Analyze the script regardless if -a was used. */
     bool analyze = !(analysis_ && analysis_->ranInference()) &&
         cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS) && !isUncachedEval;
 
     if (!thisTypes()->hasType(type) || analyze) {
         js::types::AutoEnterTypeInference enter(cx);
 
         js::types::InferSpew(js::types::ISpewOps, "externalType: setThis #%u: %s",
                              id(), js::types::TypeString(type));
         thisTypes()->addType(cx, type);
 
         if (analyze && !(analysis_ && analysis_->ranInference())) {
             js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
             if (!analysis)
-                return false;
+                return;
             analysis->analyzeTypes(cx);
         }
-
-        return true;
     }
-
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetThis(JSContext *cx, const js::Value &value)
 {
     if (cx->typeInferenceEnabled())
-        return typeSetThis(cx, js::types::GetValueType(cx, value));
-    return true;
+        typeSetThis(cx, js::types::GetValueType(cx, value));
 }
 
-inline bool
+inline void
 JSScript::typeSetThis(JSContext *cx, js::types::ClonedTypeSet *set)
 {
+    JS_ASSERT(cx->typeInferenceEnabled());
     if (!ensureVarTypes(cx))
-        return false;
+        return;
     js::types::AutoEnterTypeInference enter(cx);
 
     js::types::InferSpew(js::types::ISpewOps, "externalType: setThis #%u", id());
     thisTypes()->addTypeSet(cx, set);
-
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetNewCalled(JSContext *cx)
 {
     if (!cx->typeInferenceEnabled() || calledWithNew)
-        return true;
+        return;
     calledWithNew = true;
 
     /*
      * Determining the 'this' type used when the script is invoked with 'new'
      * happens during the script's prologue, so we don't try to pick it up from
      * dynamic calls. Instead, generate constraints modeling the construction
      * of 'this' when the script is analyzed or reanalyzed after an invoke with 'new',
      * and if 'new' is first invoked after the script has already been analyzed.
      */
     if (analyzed) {
         /* Regenerate types for the function. */
         js::types::AutoEnterTypeInference enter(cx);
         js::analyze::ScriptAnalysis *analysis = this->analysis(cx);
         if (!analysis)
-            return false;
+            return;
         analysis->analyzeTypesNew(cx);
     }
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type)
 {
-    if (!cx->typeInferenceEnabled())
-        return true;
-    if (!ensureVarTypes(cx))
-        return false;
+    if (!cx->typeInferenceEnabled() || !ensureVarTypes(cx))
+        return;
     if (!localTypes(local)->hasType(type)) {
         js::types::AutoEnterTypeInference enter(cx);
 
         js::types::InferSpew(js::types::ISpewOps, "externalType: setLocal #%u %u: %s",
                              id(), local, js::types::TypeString(type));
         localTypes(local)->addType(cx, type);
-
-        return true;
     }
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetLocal(JSContext *cx, unsigned local, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         js::types::jstype type = js::types::GetValueType(cx, value);
-        return typeSetLocal(cx, local, type);
+        typeSetLocal(cx, local, type);
     }
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *set)
 {
+    JS_ASSERT(cx->typeInferenceEnabled());
     if (!ensureVarTypes(cx))
-        return false;
+        return;
     js::types::AutoEnterTypeInference enter(cx);
 
     js::types::InferSpew(js::types::ISpewOps, "externalType: setLocal #%u %u", id(), local);
     localTypes(local)->addTypeSet(cx, set);
-
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type)
 {
-    if (!cx->typeInferenceEnabled())
-        return true;
-    if (!ensureVarTypes(cx))
-        return false;
+    if (!cx->typeInferenceEnabled() || !ensureVarTypes(cx))
+        return;
     if (!argTypes(arg)->hasType(type)) {
         js::types::AutoEnterTypeInference enter(cx);
 
         js::types::InferSpew(js::types::ISpewOps, "externalType: setArg #%u %u: %s",
                              id(), arg, js::types::TypeString(type));
         argTypes(arg)->addType(cx, type);
-
-        return true;
     }
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value)
 {
     if (cx->typeInferenceEnabled()) {
         js::types::jstype type = js::types::GetValueType(cx, value);
-        return typeSetArgument(cx, arg, type);
+        typeSetArgument(cx, arg, type);
     }
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *set)
 {
+    JS_ASSERT(cx->typeInferenceEnabled());
     if (!ensureVarTypes(cx))
-        return false;
+        return;
     js::types::AutoEnterTypeInference enter(cx);
 
     js::types::InferSpew(js::types::ISpewOps, "externalType: setArg #%u %u", id(), arg);
     argTypes(arg)->addTypeSet(cx, set);
-
-    return true;
 }
 
-inline bool
+inline void
 JSScript::typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value)
 {
-    if (!cx->typeInferenceEnabled())
-        return true;
-    if (!ensureVarTypes(cx))
-        return false;
+    if (!cx->typeInferenceEnabled() || !ensureVarTypes(cx))
+        return;
     js::types::jstype type = js::types::GetValueType(cx, value);
     if (!upvarTypes(upvar)->hasType(type)) {
         js::types::AutoEnterTypeInference enter(cx);
 
         js::types::InferSpew(js::types::ISpewOps, "externalType: setUpvar #%u %u: %s",
                              id(), upvar, js::types::TypeString(type));
         upvarTypes(upvar)->addType(cx, type);
-
-        return true;
     }
-    return true;
 }
 
 namespace js {
 namespace types {
 
 /////////////////////////////////////////////////////////////////////
 // TypeCompartment
 /////////////////////////////////////////////////////////////////////
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -510,18 +510,17 @@ js_OnUnknownMethod(JSContext *cx, Value 
 {
     JS_ASSERT(!vp[1].isPrimitive());
 
     JSObject *obj = &vp[1].toObject();
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.noSuchMethodAtom);
     AutoValueRooter tvr(cx);
     if (!js_GetMethod(cx, obj, id, JSGET_NO_METHOD_BARRIER, tvr.addr()))
         return false;
-    if (!cx->fp()->script()->typeMonitorUnknown(cx, cx->regs().pc))
-        return false;
+    cx->fp()->script()->typeMonitorUnknown(cx, cx->regs().pc);
 
     if (tvr.value().isPrimitive()) {
         vp[0] = tvr.value();
     } else {
 #if JS_HAS_XML_SUPPORT
         /* Extract the function name from function::name qname. */
         if (vp[0].isObject()) {
             obj = &vp[0].toObject();
@@ -636,18 +635,17 @@ Invoke(JSContext *cx, const CallArgs &ar
         if (JS_UNLIKELY(clasp == &js_NoSuchMethodClass))
             return NoSuchMethod(cx, args.argc(), args.base());
 #endif
         JS_ASSERT_IF(option == INVOKE_CONSTRUCTOR, !clasp->construct);
         if (!clasp->call) {
             js_ReportIsNotFunction(cx, &args.calleev(), ToReportFlags(option));
             return false;
         }
-        if (!cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN))
-            return false;
+        cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN);
         return CallJSNative(cx, clasp->call, args.argc(), args.base());
     }
 
     /* Invoke native functions. */
     JSFunction *fun = callee.getFunctionPrivate();
     JS_ASSERT_IF(option == INVOKE_CONSTRUCTOR, !fun->isConstructor());
     if (fun->isNative())
         return CallJSNative(cx, fun->u.n.native, args.argc(), args.base());
@@ -663,18 +661,17 @@ Invoke(JSContext *cx, const CallArgs &ar
                 return false;
             args.rval().setObject(*obj);
         } else {
             args.rval().setUndefined();
         }
         return true;
     }
 
-    if (!cx->typeMonitorCall(args, option == INVOKE_CONSTRUCTOR))
-        return false;
+    cx->typeMonitorCall(args, option == INVOKE_CONSTRUCTOR);
 
     /* Get pointer to new frame/slots, prepare arguments. */
     uint32 flags = ToFrameFlags(option);
     InvokeFrameGuard frame;
     StackFrame *fp = cx->stack.getInvokeFrame(cx, args, fun, script, &flags, &frame);
     if (!fp)
         return false;
 
@@ -750,22 +747,19 @@ InvokeSessionGuard::start(JSContext *cx,
 
         if (cx->typeInferenceEnabled()) {
             /*
              * Set the 'this' type according to the value given, but mark the types
              * of all arguments as unknown. We don't want to keep track of the
              * possible values the InvokeSession's client could pass in.
              */
             jstype type = GetValueType(cx, thisv);
-            if (!script_->typeSetThis(cx, type))
-                return false;
-            for (unsigned i = 0; i < fun->nargs; i++) {
-                if (!script_->typeSetArgument(cx, i, TYPE_UNKNOWN))
-                    return false;
-            }
+            script_->typeSetThis(cx, type);
+            for (unsigned i = 0; i < fun->nargs; i++)
+                script_->typeSetArgument(cx, i, TYPE_UNKNOWN);
         }
 
 #ifdef JS_METHODJIT
         /* Hoist dynamic checks from RunScript. */
         mjit::CompileStatus status = mjit::CanMethodJIT(cx, script_, fp, mjit::CompileRequest_JIT);
         if (status == mjit::Compile_Error)
             return false;
         if (status != mjit::Compile_Okay)
@@ -983,18 +977,17 @@ Execute(JSContext *cx, JSObject &chain, 
     if (script->hasSharps && !InitSharpSlots(cx, frame.fp()))
         return false;
 #endif
 
     Probes::startExecution(cx, script);
 
     if (cx->typeInferenceEnabled()) {
         jstype type = GetValueType(cx, frame.fp()->thisValue());
-        if (!script->typeSetThis(cx, type))
-            return false;
+        script->typeSetThis(cx, type);
     }
 
     /* Run script until JSOP_STOP or error. */
     AutoPreserveEnumerators preserve(cx);
     JSBool ok = RunScript(cx, script, frame.fp());
     if (result)
         *result = frame.fp()->returnValue();
 
@@ -1270,18 +1263,17 @@ InvokeConstructor(JSContext *cx, const C
             if (!Invoke(cx, args, INVOKE_CONSTRUCTOR))
                 return false;
 
             JS_ASSERT(args.rval().isObject());
             JS_RUNTIME_METER(cx->runtime, constructs);
             return true;
         }
         if (clasp->construct) {
-            if (!cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN))
-                return false;
+            cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN);
             args.thisv().setMagicWithObjectOrNullPayload(NULL);
             return CallJSNativeConstructor(cx, clasp->construct, args.argc(), args.base());
         }
     }
 
 error:
     js_ReportIsNotFunction(cx, &args.calleev(), JSV2F_CONSTRUCT);
     return false;
@@ -2557,16 +2549,18 @@ Interpret(JSContext *cx, StackFrame *ent
         JS_ASSERT_IF(!fp->isGeneratorFrame(), regs.pc == script->code);
         bool newType = fp->isConstructing() && cx->typeInferenceEnabled() &&
             fp->prev() && fp->prev()->isScriptFrame() &&
             UseNewType(cx, fp->prev()->script(), fp->prev()->pc(cx));
         if (!ScriptPrologueOrGeneratorResume(cx, fp, newType))
             goto error;
     }
 
+    JS_ASSERT_IF(interpMode == JSINTERP_SKIP_TRAP, JSOp(*regs.pc) == JSOP_TRAP);
+
     CHECK_INTERRUPT_HANDLER();
 
     RESET_USE_METHODJIT();
 
     /* State communicated between non-local jumps: */
     JSBool interpReturnOK;
     JSAtom *atomNotDefined;
 
@@ -3147,18 +3141,17 @@ BEGIN_CASE(JSOP_FORGNAME)
     if (!js_FindProperty(cx, id, &obj, &obj2, &prop))
         goto error;
 
     {
         AutoValueRooter tvr(cx);
         JS_ASSERT(regs.sp[-1].isObject());
         if (!IteratorNext(cx, &regs.sp[-1].toObject(), tvr.addr()))
             goto error;
-        if (!cx->typeMonitorAssign(obj, id, tvr.value()))
-            goto error;
+        cx->typeMonitorAssign(obj, id, tvr.value());
         if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode))
             goto error;
     }
 }
 END_CASE(JSOP_FORNAME)
 
 BEGIN_CASE(JSOP_FORPROP)
 {
@@ -3168,18 +3161,17 @@ BEGIN_CASE(JSOP_FORPROP)
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj;
     FETCH_OBJECT(cx, -1, obj);
     {
         AutoValueRooter tvr(cx);
         JS_ASSERT(regs.sp[-2].isObject());
         if (!IteratorNext(cx, &regs.sp[-2].toObject(), tvr.addr()))
             goto error;
-        if (!cx->typeMonitorAssign(obj, id, tvr.value()))
-            goto error;
+        cx->typeMonitorAssign(obj, id, tvr.value());
         if (!obj->setProperty(cx, id, tvr.addr(), script->strictModeCode))
             goto error;
     }
     regs.sp--;
 }
 END_CASE(JSOP_FORPROP)
 
 BEGIN_CASE(JSOP_FORELEM)
@@ -3296,37 +3288,34 @@ END_CASE(JSOP_PICK)
 
 BEGIN_CASE(JSOP_SETCONST)
 {
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     JSObject &obj = cx->stack.currentVarObj();
     const Value &ref = regs.sp[-1];
 
-    if (!cx->typeMonitorAssign(&obj, ATOM_TO_JSID(atom), ref))
-        goto error;
-
+    cx->typeMonitorAssign(&obj, ATOM_TO_JSID(atom), ref);
     if (!obj.defineProperty(cx, ATOM_TO_JSID(atom), ref,
                             PropertyStub, StrictPropertyStub,
                             JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
         goto error;
     }
 }
 END_SET_CASE(JSOP_SETCONST);
 
 #if JS_HAS_DESTRUCTURING
 BEGIN_CASE(JSOP_ENUMCONSTELEM)
 {
     const Value &ref = regs.sp[-3];
     JSObject *obj;
     FETCH_OBJECT(cx, -2, obj);
     jsid id;
     FETCH_ELEMENT_ID(obj, -1, id);
-    if (!cx->typeMonitorAssign(obj, id, ref))
-        goto error;
+    cx->typeMonitorAssign(obj, id, ref);
     if (!obj->defineProperty(cx, id, ref,
                              PropertyStub, StrictPropertyStub,
                              JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY)) {
         goto error;
     }
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMCONSTELEM)
@@ -3565,46 +3554,44 @@ BEGIN_CASE(JSOP_URSH)
         goto error;
     int32_t j;
     if (!ValueToECMAInt32(cx, regs.sp[-1], &j))
         goto error;
 
     u >>= (j & 31);
 
     regs.sp--;
-    if (!regs.sp[-1].setNumber(uint32(u)) && !script->typeMonitorOverflow(cx, regs.pc))
-        goto error;
+    if (!regs.sp[-1].setNumber(uint32(u)))
+        script->typeMonitorOverflow(cx, regs.pc);
 }
 END_CASE(JSOP_URSH)
 
 BEGIN_CASE(JSOP_ADD)
 {
     Value rval = regs.sp[-1];
     Value lval = regs.sp[-2];
 
     if (lval.isInt32() && rval.isInt32()) {
         int32_t l = lval.toInt32(), r = rval.toInt32();
         int32_t sum = l + r;
         regs.sp--;
         if (JS_UNLIKELY(bool((l ^ sum) & (r ^ sum) & 0x80000000))) {
             regs.sp[-1].setDouble(double(l) + double(r));
-            if (!script->typeMonitorOverflow(cx, regs.pc))
-                goto error;
+            script->typeMonitorOverflow(cx, regs.pc);
         } else {
             regs.sp[-1].setInt32(sum);
         }
     } else
 #if JS_HAS_XML_SUPPORT
     if (IsXML(lval) && IsXML(rval)) {
         if (!js_ConcatenateXML(cx, &lval.toObject(), &rval.toObject(), &rval))
             goto error;
         regs.sp--;
         regs.sp[-1] = rval;
-        if (!script->typeMonitorUnknown(cx, regs.pc))
-            goto error;
+        script->typeMonitorUnknown(cx, regs.pc);
     } else
 #endif
     {
         bool lIsObject, rIsObject;
         if ((lIsObject = lval.isObject()))
             DEFAULT_VALUE(cx, -2, JSTYPE_VOID, lval);
         if ((rIsObject = rval.isObject()))
             DEFAULT_VALUE(cx, -1, JSTYPE_VOID, rval);
@@ -3625,30 +3612,29 @@ BEGIN_CASE(JSOP_ADD)
                 rstr = js_ValueToString(cx, rval);
                 if (!rstr)
                     goto error;
                 regs.sp[-1].setString(rstr);
             }
             JSString *str = js_ConcatStrings(cx, lstr, rstr);
             if (!str)
                 goto error;
-            if ((lIsObject || rIsObject) && !script->typeMonitorString(cx, regs.pc))
-                goto error;
+            if (lIsObject || rIsObject)
+                script->typeMonitorString(cx, regs.pc);
             regs.sp--;
             regs.sp[-1].setString(str);
         } else {
             double l, r;
             if (!ValueToNumber(cx, lval, &l) || !ValueToNumber(cx, rval, &r))
                 goto error;
             l += r;
             regs.sp--;
             if (!regs.sp[-1].setNumber(l) &&
-                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble())) &&
-                !script->typeMonitorOverflow(cx, regs.pc)) {
-                goto error;
+                (lIsObject || rIsObject || (!lval.isDouble() && !rval.isDouble()))) {
+                script->typeMonitorOverflow(cx, regs.pc);
             }
         }
     }
 }
 END_CASE(JSOP_ADD)
 
 #define BINARY_OP(OP)                                                         \
     JS_BEGIN_MACRO                                                            \
@@ -3657,19 +3643,18 @@ END_CASE(JSOP_ADD)
         double d1, d2;                                                        \
         if (!ValueToNumber(cx, lval, &d1) ||                                  \
             !ValueToNumber(cx, rval, &d2)) {                                  \
             goto error;                                                       \
         }                                                                     \
         double d = d1 OP d2;                                                  \
         regs.sp--;                                                            \
         if (!regs.sp[-1].setNumber(d) &&                                      \
-            !(lval.isDouble() || rval.isDouble()) &&                          \
-            !script->typeMonitorOverflow(cx, regs.pc)) {                      \
-            goto error;                                                       \
+            !(lval.isDouble() || rval.isDouble())) {                          \
+            script->typeMonitorOverflow(cx, regs.pc);                         \
         }                                                                     \
     JS_END_MACRO
 
 BEGIN_CASE(JSOP_SUB)
     BINARY_OP(-);
 END_CASE(JSOP_SUB)
 
 BEGIN_CASE(JSOP_MUL)
@@ -3698,24 +3683,22 @@ BEGIN_CASE(JSOP_DIV)
 #endif
         if (d1 == 0 || JSDOUBLE_IS_NaN(d1))
             vp = &rt->NaNValue;
         else if (JSDOUBLE_IS_NEG(d1) != JSDOUBLE_IS_NEG(d2))
             vp = &rt->negativeInfinityValue;
         else
             vp = &rt->positiveInfinityValue;
         regs.sp[-1] = *vp;
-        if (!script->typeMonitorOverflow(cx, regs.pc))
-            goto error;
+        script->typeMonitorOverflow(cx, regs.pc);
     } else {
         d1 /= d2;
         if (!regs.sp[-1].setNumber(d1) &&
-            !(lval.isDouble() || rval.isDouble()) &&
-            !script->typeMonitorOverflow(cx, regs.pc)) {
-            goto error;
+            !(lval.isDouble() || rval.isDouble())) {
+            script->typeMonitorOverflow(cx, regs.pc);
         }
     }
 }
 END_CASE(JSOP_DIV)
 
 BEGIN_CASE(JSOP_MOD)
 {
     Value &lref = regs.sp[-2];
@@ -3734,18 +3717,17 @@ BEGIN_CASE(JSOP_MOD)
         }
         regs.sp--;
         if (d2 == 0) {
             regs.sp[-1].setDouble(js_NaN);
         } else {
             d1 = js_fmod(d1, d2);
             regs.sp[-1].setDouble(d1);
         }
-        if (!script->typeMonitorOverflow(cx, regs.pc))
-            goto error;
+        script->typeMonitorOverflow(cx, regs.pc);
     }
 }
 END_CASE(JSOP_MOD)
 
 BEGIN_CASE(JSOP_NOT)
 {
     Value *_;
     bool cond;
@@ -3776,29 +3758,27 @@ BEGIN_CASE(JSOP_NEG)
     if (ref.isInt32() && (i = ref.toInt32()) != 0 && i != INT32_MIN) {
         i = -i;
         regs.sp[-1].setInt32(i);
     } else {
         double d;
         if (!ValueToNumber(cx, regs.sp[-1], &d))
             goto error;
         d = -d;
-        if (!regs.sp[-1].setNumber(d) && !ref.isDouble() &&
-            !script->typeMonitorOverflow(cx, regs.pc)) {
-            goto error;
-        }
+        if (!regs.sp[-1].setNumber(d) && !ref.isDouble())
+            script->typeMonitorOverflow(cx, regs.pc);
     }
 }
 END_CASE(JSOP_NEG)
 
 BEGIN_CASE(JSOP_POS)
     if (!ValueToNumber(cx, &regs.sp[-1]))
         goto error;
-    if (!regs.sp[-1].isInt32() && !script->typeMonitorOverflow(cx, regs.pc))
-        goto error;
+    if (!regs.sp[-1].isInt32())
+        script->typeMonitorOverflow(cx, regs.pc);
 END_CASE(JSOP_POS)
 
 BEGIN_CASE(JSOP_DELNAME)
 {
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     jsid id = ATOM_TO_JSID(atom);
     JSObject *obj, *obj2;
@@ -3893,18 +3873,18 @@ BEGIN_CASE(JSOP_PROPDEC)
     LOAD_ATOM(0, atom);
     id = ATOM_TO_JSID(atom);
     i = -1;
 
   fetch_incop_obj:
     FETCH_OBJECT(cx, i, obj);
     if (JSID_IS_VOID(id)) {
         FETCH_ELEMENT_ID(obj, -1, id);
-        if (!JSID_IS_INT(id) && !script->typeMonitorUnknown(cx, regs.pc))
-            goto error;
+        if (!JSID_IS_INT(id))
+            script->typeMonitorUnknown(cx, regs.pc);
     }
     goto do_incop;
 
 BEGIN_CASE(JSOP_INCNAME)
 BEGIN_CASE(JSOP_DECNAME)
 BEGIN_CASE(JSOP_NAMEINC)
 BEGIN_CASE(JSOP_NAMEDEC)
 BEGIN_CASE(JSOP_INCGNAME)
@@ -3958,20 +3938,18 @@ do_incop:
     if (!obj->getProperty(cx, id, &regs.sp[-1]))
         goto error;
 
     /*
      * Add undefined to the object itself when read out during an incop.
      * typeMonitorUndefined does not capture the value being pushed here
      * during compound operations in the method JIT.
      */
-    if (regs.sp[-1].isUndefined() &&
-        !cx->addTypePropertyId(obj->getType(), id, types::TYPE_UNDEFINED)) {
-        goto error;
-    }
+    if (regs.sp[-1].isUndefined())
+        cx->addTypePropertyId(obj->getType(), id, types::TYPE_UNDEFINED);
 
     const JSCodeSpec *cs = &js_CodeSpec[op];
     JS_ASSERT(cs->ndefs == 1);
     JS_ASSERT((cs->format & JOF_TMPSLOT_MASK) >= JOF_TMPSLOT2);
 
     uint32 format = cs->format;
     uint32 setPropFlags = (JOF_MODE(format) == JOF_NAME)
                           ? JSRESOLVE_ASSIGNING
@@ -3998,20 +3976,18 @@ do_incop:
          */
         ref.setInt32(tmp);
     } else {
         /* We need an extra root for the result. */
         PUSH_NULL();
         if (!js_DoIncDec(cx, cs, &regs.sp[-2], &regs.sp[-1]))
             goto error;
 
-        if (!cx->typeMonitorAssign(obj, id, regs.sp[-1]))
-            goto error;
-        if (!script->typeMonitorOverflow(cx, regs.pc))
-            goto error;
+        cx->typeMonitorAssign(obj, id, regs.sp[-1]);
+        script->typeMonitorOverflow(cx, regs.pc);
 
         {
             JSAutoResolveFlags rf(cx, setPropFlags);
             if (!obj->setProperty(cx, id, &regs.sp[-1], script->strictModeCode))
                 goto error;
         }
 
         regs.sp--;
@@ -4076,18 +4052,17 @@ BEGIN_CASE(JSOP_LOCALINC)
         vp->getInt32Ref() = tmp + incr;
         JS_ASSERT(JSOP_INCARG_LENGTH == js_CodeSpec[op].length);
         SKIP_POP_AFTER_SET(JSOP_INCARG_LENGTH, 0);
         PUSH_INT32(tmp + incr2);
     } else {
         PUSH_COPY(*vp);
         if (!js_DoIncDec(cx, &js_CodeSpec[op], &regs.sp[-1], vp))
             goto error;
-        if (!script->typeMonitorOverflow(cx, regs.pc))
-            goto error;
+        script->typeMonitorOverflow(cx, regs.pc);
     }
     len = JSOP_INCARG_LENGTH;
     JS_ASSERT(len == js_CodeSpec[op].length);
     DO_NEXT_OP(len);
 }
 
 BEGIN_CASE(JSOP_THIS)
     if (!ComputeThis(cx, regs.fp()))
@@ -4176,18 +4151,18 @@ BEGIN_CASE(JSOP_LENGTH)
                                     ? JSGET_CACHE_RESULT | JSGET_NO_METHOD_BARRIER
                                     : JSGET_CACHE_RESULT | JSGET_METHOD_BARRIER,
                                     &rval)
             : !obj->getProperty(cx, id, &rval)) {
             goto error;
         }
     } while (0);
 
-    if (rval.isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
-        goto error;
+    if (rval.isUndefined())
+        script->typeMonitorUndefined(cx, regs.pc);
 
     regs.sp[-1] = rval;
     assertSameCompartment(cx, regs.sp[-1]);
 }
 END_CASE(JSOP_GETPROP)
 
 BEGIN_CASE(JSOP_CALLPROP)
 {
@@ -4272,18 +4247,18 @@ BEGIN_CASE(JSOP_CALLPROP)
 #if JS_HAS_NO_SUCH_METHOD
     if (JS_UNLIKELY(rval.isPrimitive()) && regs.sp[-1].isObject()) {
         LOAD_ATOM(0, atom);
         regs.sp[-2].setString(atom);
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             goto error;
     }
 #endif
-    if (rval.isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
-        goto error;
+    if (rval.isUndefined())
+        script->typeMonitorUndefined(cx, regs.pc);
 }
 END_CASE(JSOP_CALLPROP)
 
 BEGIN_CASE(JSOP_UNBRAND)
     JS_ASSERT(regs.sp - regs.fp()->slots() >= 1);
     regs.sp[-1].toObject().unbrand(cx);
 END_CASE(JSOP_UNBRAND)
 
@@ -4297,18 +4272,17 @@ BEGIN_CASE(JSOP_SETMETHOD)
     Value &lref = regs.sp[-2];
     JS_ASSERT_IF(op == JSOP_SETNAME, lref.isObject());
     JSObject *obj;
     VALUE_TO_OBJECT(cx, &lref, obj);
 
     JS_ASSERT_IF(op == JSOP_SETGNAME, obj == regs.fp()->scopeChain().getGlobal());
 
     jsid id = ATOM_TO_JSID(atoms[GET_INDEX(regs.pc)]);
-    if (!cx->typeMonitorAssign(obj, id, rval))
-        goto error;
+    cx->typeMonitorAssign(obj, id, rval);
 
     do {
         PropertyCache *cache = &JS_PROPERTY_CACHE(cx);
 
         /*
          * Probe the property cache, specializing for two important
          * set-property cases. First:
          *
@@ -4506,27 +4480,25 @@ BEGIN_CASE(JSOP_GETELEM)
                 goto error;
         }
     }
 
     if (!obj->getProperty(cx, id, &rval))
         goto error;
     copyFrom = &rval;
 
-    if (!JSID_IS_INT(id) && !script->typeMonitorUnknown(cx, regs.pc))
-        goto error;
+    if (!JSID_IS_INT(id))
+        script->typeMonitorUnknown(cx, regs.pc);
 
   end_getelem:
     regs.sp--;
     regs.sp[-1] = *copyFrom;
     assertSameCompartment(cx, regs.sp[-1]);
-    if (copyFrom->isUndefined()) {
-        if (!script->typeMonitorUndefined(cx, regs.pc))
-            goto error;
-    }
+    if (copyFrom->isUndefined())
+        script->typeMonitorUndefined(cx, regs.pc);
 }
 END_CASE(JSOP_GETELEM)
 
 BEGIN_CASE(JSOP_CALLELEM)
 {
     /* Find the object on which to look for |this|'s properties. */
     Value thisv = regs.sp[-2];
     JSObject *thisObj = ValuePropertyBearer(cx, thisv, -2);
@@ -4549,33 +4521,30 @@ BEGIN_CASE(JSOP_CALLELEM)
         if (!js_OnUnknownMethod(cx, regs.sp - 2))
             goto error;
     } else
 #endif
     {
         regs.sp[-1] = thisv;
     }
 
-    if ((regs.sp[-2].isUndefined() || !JSID_IS_INT(id)) &&
-        !script->typeMonitorUnknown(cx, regs.pc)) {
-        goto error;
-    }
+    if (regs.sp[-2].isUndefined() || !JSID_IS_INT(id))
+        script->typeMonitorUnknown(cx, regs.pc);
 }
 END_CASE(JSOP_CALLELEM)
 
 BEGIN_CASE(JSOP_SETELEM)
 BEGIN_CASE(JSOP_SETHOLE)
 {
     JSObject *obj;
     FETCH_OBJECT(cx, -3, obj);
     jsid id;
     FETCH_ELEMENT_ID(obj, -2, id);
     Value rval;
-    if (!cx->typeMonitorAssign(obj, id, regs.sp[-1]))
-        goto error;
+    cx->typeMonitorAssign(obj, id, regs.sp[-1]);
     do {
         if (obj->isDenseArray() && JSID_IS_INT(id)) {
             jsuint length = obj->getDenseArrayInitializedLength();
             jsint i = JSID_TO_INT(id);
             if ((jsuint)i < length) {
                 if (obj->getDenseArrayElement(i).isMagic(JS_ARRAY_HOLE)) {
                     if (js_PrototypeHasIndexedProperties(cx, obj))
                         break;
@@ -4600,18 +4569,17 @@ END_SET_CASE_STORE_RVAL(JSOP_SETELEM, 3)
 BEGIN_CASE(JSOP_ENUMELEM)
 {
     /* Funky: the value to set is under the [obj, id] pair. */
     JSObject *obj;
     FETCH_OBJECT(cx, -2, obj);
     jsid id;
     FETCH_ELEMENT_ID(obj, -1, id);
     Value rval = regs.sp[-3];
-    if (!cx->typeMonitorAssign(obj, id, rval))
-        goto error;
+    cx->typeMonitorAssign(obj, id, rval);
     if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
         goto error;
     regs.sp -= 3;
 }
 END_CASE(JSOP_ENUMELEM)
 
 { // begin block around calling opcodes
     JSFunction *newfun;
@@ -4696,18 +4664,17 @@ BEGIN_CASE(JSOP_FUNCALL)
             }
 
             /* Restrict recursion of lightweight functions. */
             if (JS_UNLIKELY(inlineCallCount >= StackSpace::MAX_INLINE_CALLS)) {
                 js_ReportOverRecursed(cx);
                 goto error;
             }
 
-            if (!cx->typeMonitorCall(CallArgsFromVp(argc, vp), flags & StackFrame::CONSTRUCTING))
-                goto error;
+            cx->typeMonitorCall(CallArgsFromVp(argc, vp), flags & StackFrame::CONSTRUCTING);
 
             bool newType = (flags & StackFrame::CONSTRUCTING) &&
                 cx->typeInferenceEnabled() && UseNewType(cx, script, regs.pc);
 
             /* Get pointer to new frame/slots, prepare arguments. */
             ContextStack &stack = cx->stack;
             StackFrame *newfp = stack.getInlineFrame(cx, regs.sp, argc, newfun,
                                                      newscript, &flags);
@@ -4828,20 +4795,18 @@ BEGIN_CASE(JSOP_CALLNAME)
             PUSH_COPY(obj2->nativeGetSlot(slot));
         } else {
             JS_ASSERT(entry->vword.isShape());
             shape = entry->vword.toShape();
             NATIVE_GET(cx, obj, obj2, shape, JSGET_METHOD_BARRIER, &rval);
             PUSH_COPY(rval);
         }
 
-        if (op == JSOP_NAME || op == JSOP_CALLNAME) {
-            if (!script->typeMonitorResult(cx, regs.pc, regs.sp[-1]))
-                goto error;
-        }
+        if (op == JSOP_NAME || op == JSOP_CALLNAME)
+            script->typeMonitorResult(cx, regs.pc, regs.sp[-1]);
 
         JS_ASSERT(obj->isGlobal() || IsCacheableNonGlobalScope(obj));
         if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
             PUSH_IMPLICIT_THIS(cx, obj, regs.sp[-1]);
         len = JSOP_NAME_LENGTH;
         DO_NEXT_OP(len);
     }
 
@@ -4850,18 +4815,17 @@ BEGIN_CASE(JSOP_CALLNAME)
     JSProperty *prop;
     if (!js_FindPropertyHelper(cx, id, true, &obj, &obj2, &prop))
         goto error;
     if (!prop) {
         /* Kludge to allow (typeof foo == "undefined") tests. */
         JSOp op2 = js_GetOpcode(cx, script, regs.pc + JSOP_NAME_LENGTH);
         if (op2 == JSOP_TYPEOF) {
             PUSH_UNDEFINED();
-            if (!script->typeMonitorUndefined(cx, regs.pc))
-                goto error;
+            script->typeMonitorUndefined(cx, regs.pc);
             len = JSOP_NAME_LENGTH;
             DO_NEXT_OP(len);
         }
         atomNotDefined = atom;
         goto atom_not_defined;
     }
 
     /* Take the slow path if prop was not found in a native object. */
@@ -4872,23 +4836,20 @@ BEGIN_CASE(JSOP_CALLNAME)
         shape = (Shape *)prop;
         JSObject *normalized = obj;
         if (normalized->getClass() == &js_WithClass && !shape->hasDefaultGetter())
             normalized = js_UnwrapWithObject(cx, normalized);
         NATIVE_GET(cx, normalized, obj2, shape, JSGET_METHOD_BARRIER, &rval);
     }
 
     PUSH_COPY(rval);
-    if (op == JSOP_NAME || op == JSOP_CALLNAME) {
-        if (!script->typeMonitorResult(cx, regs.pc, rval))
-            goto error;
-    } else if (rval.isUndefined()) {
-        if (!script->typeMonitorUndefined(cx, regs.pc))
-            goto error;
-    }
+    if (op == JSOP_NAME || op == JSOP_CALLNAME)
+        script->typeMonitorResult(cx, regs.pc, rval);
+    else if (rval.isUndefined())
+        script->typeMonitorUndefined(cx, regs.pc);
 
     /* obj must be on the scope chain, thus not a function. */
     if (op == JSOP_CALLNAME || op == JSOP_CALLGNAME)
         PUSH_IMPLICIT_THIS(cx, obj, rval);
 }
 END_CASE(JSOP_NAME)
 
 BEGIN_CASE(JSOP_UINT16)
@@ -5142,16 +5103,22 @@ BEGIN_CASE(JSOP_LOOKUPSWITCH)
           ? GET_JUMP_OFFSET(pc2)
           : GET_JUMPX_OFFSET(pc2);
 }
 END_VARLEN_CASE
 }
 
 BEGIN_CASE(JSOP_TRAP)
 {
+    if (interpMode == JSINTERP_SKIP_TRAP) {
+        interpMode = JSINTERP_SAFEPOINT;
+        op = JS_GetTrapOpcode(cx, script, regs.pc);
+        DO_OP();
+    }
+
     Value rval;
     JSTrapStatus status = JS_HandleTrap(cx, script, regs.pc, Jsvalify(&rval));
     switch (status) {
       case JSTRAP_ERROR:
         goto error;
       case JSTRAP_RETURN:
         regs.fp()->setReturnValue(rval);
         interpReturnOK = JS_TRUE;
@@ -5303,18 +5270,18 @@ END_CASE(JSOP_GETFCSLOT)
 BEGIN_CASE(JSOP_GETGLOBAL)
 BEGIN_CASE(JSOP_CALLGLOBAL)
 {
     uint32 slot = GET_SLOTNO(regs.pc);
     slot = script->getGlobalSlot(slot);
     JSObject *obj = regs.fp()->scopeChain().getGlobal();
     JS_ASSERT(obj->containsSlot(slot));
     PUSH_COPY(obj->getSlot(slot));
-    if (regs.sp[-1].isUndefined() && !script->typeMonitorUndefined(cx, regs.pc))
-        goto error;
+    if (regs.sp[-1].isUndefined())
+        script->typeMonitorUndefined(cx, regs.pc);
     if (op == JSOP_CALLGLOBAL)
         PUSH_UNDEFINED();
 }
 END_CASE(JSOP_GETGLOBAL)
 
 BEGIN_CASE(JSOP_DEFCONST)
 BEGIN_CASE(JSOP_DEFVAR)
 {
@@ -5423,19 +5390,17 @@ BEGIN_CASE(JSOP_DEFFUN)
     /* ES5 10.5 (NB: with subsequent errata). */
     jsid id = ATOM_TO_JSID(fun->atom);
     JSProperty *prop = NULL;
     JSObject *pobj;
     if (!parent->lookupProperty(cx, id, &pobj, &prop))
         goto error;
 
     Value rval = ObjectValue(*obj);
-
-    if (!cx->typeMonitorAssign(parent, id, rval))
-        goto error;
+    cx->typeMonitorAssign(parent, id, rval);
 
     do {
         /* Steps 5d, 5f. */
         if (!prop || pobj != parent) {
             if (!parent->defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs))
                 goto error;
             break;
         }
@@ -5492,19 +5457,17 @@ BEGIN_CASE(JSOP_DEFFUN_DBGFC)
                   ? JSPROP_ENUMERATE
                   : JSPROP_ENUMERATE | JSPROP_PERMANENT;
 
     JSObject &parent = cx->stack.currentVarObj();
 
     jsid id = ATOM_TO_JSID(fun->atom);
     if (!CheckRedeclaration(cx, &parent, id, attrs))
         goto error;
-
-    if (!cx->typeMonitorAssign(&parent, id, rval))
-        goto error;
+    cx->typeMonitorAssign(&parent, id, rval);
 
     if ((attrs == JSPROP_ENUMERATE)
         ? !parent.setProperty(cx, id, &rval, script->strictModeCode)
         : !parent.defineProperty(cx, id, rval, PropertyStub, StrictPropertyStub, attrs)) {
         goto error;
     }
 }
 END_CASE(JSOP_DEFFUN_FC)
@@ -5831,19 +5794,17 @@ BEGIN_CASE(JSOP_SETTER)
         attrs = JSPROP_SETTER;
     }
     attrs |= JSPROP_ENUMERATE | JSPROP_SHARED;
 
     /* Check for a readonly or permanent property of the same name. */
     if (!CheckRedeclaration(cx, obj, id, attrs))
         goto error;
 
-    if (!cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN))
-        goto error;
-
+    cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN);
     if (!obj->defineProperty(cx, id, UndefinedValue(), getter, setter, attrs))
         goto error;
 
     regs.sp += i;
     if (js_CodeSpec[op2].ndefs > js_CodeSpec[op2].nuses) {
         JS_ASSERT(js_CodeSpec[op2].ndefs == js_CodeSpec[op2].nuses + 1);
         regs.sp[-1] = rval;
         assertSameCompartment(cx, regs.sp[-1]);
@@ -5963,18 +5924,17 @@ BEGIN_CASE(JSOP_INITMETHOD)
         if (slot < obj->numSlots()) {
             JS_ASSERT(obj->getSlot(slot).isUndefined());
         } else {
             if (!obj->allocSlot(cx, &slot))
                 goto error;
             JS_ASSERT(slot == shape->slot);
         }
 
-        if (!cx->typeMonitorAssign(obj, shape->id, rval))
-            goto error;
+        cx->typeMonitorAssign(obj, shape->id, rval);
 
         /* A new object, or one we just extended in a recent initprop op. */
         JS_ASSERT(!obj->lastProperty() ||
                   obj->shape() == obj->lastProperty()->shape);
         obj->extend(cx, shape);
 
         /*
          * No method change check here because here we are adding a new
@@ -5986,18 +5946,17 @@ BEGIN_CASE(JSOP_INITMETHOD)
     } else {
         PCMETER(JS_PROPERTY_CACHE(cx).inipcmisses++);
 
         /* Get the immediate property name into id. */
         JSAtom *atom;
         LOAD_ATOM(0, atom);
         jsid id = ATOM_TO_JSID(atom);
 
-        if (!cx->typeMonitorAssign(obj, id, rval))
-            goto error;
+        cx->typeMonitorAssign(obj, id, rval);
 
         uintN defineHow = (op == JSOP_INITMETHOD)
                           ? JSDNP_CACHE_RESULT | JSDNP_SET_METHOD
                           : JSDNP_CACHE_RESULT;
         if (!(JS_UNLIKELY(atom == cx->runtime->atomState.protoAtom)
               ? js_SetPropertyHelper(cx, obj, id, defineHow, &rval, script->strictModeCode)
               : js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
                                         JSPROP_ENUMERATE, 0, 0, NULL,
@@ -6035,18 +5994,17 @@ BEGIN_CASE(JSOP_INITELEM)
         JS_ASSERT(obj->isArray());
         JS_ASSERT(JSID_IS_INT(id));
         JS_ASSERT(jsuint(JSID_TO_INT(id)) < JS_ARGS_LENGTH_MAX);
         if (js_GetOpcode(cx, script, regs.pc + JSOP_INITELEM_LENGTH) == JSOP_ENDINIT &&
             !js_SetLengthProperty(cx, obj, (jsuint) (JSID_TO_INT(id) + 1))) {
             goto error;
         }
     } else {
-        if (!cx->typeMonitorAssign(obj, id, rref))
-            goto error;
+        cx->typeMonitorAssign(obj, id, rref);
         if (!obj->defineProperty(cx, id, rref, NULL, NULL, JSPROP_ENUMERATE))
             goto error;
     }
     regs.sp -= 2;
 }
 END_CASE(JSOP_INITELEM)
 
 #if JS_HAS_SHARP_VARS
@@ -6396,18 +6354,17 @@ BEGIN_CASE(JSOP_BINDXMLNAME)
 END_CASE(JSOP_BINDXMLNAME)
 
 BEGIN_CASE(JSOP_SETXMLNAME)
 {
     JSObject *obj = &regs.sp[-3].toObject();
     Value rval = regs.sp[-1];
     jsid id;
     FETCH_ELEMENT_ID(obj, -2, id);
-    if (!cx->typeMonitorAssign(obj, id, rval))
-        goto error;
+    cx->typeMonitorAssign(obj, id, rval);
     if (!obj->setProperty(cx, id, &rval, script->strictModeCode))
         goto error;
     rval = regs.sp[-1];
     regs.sp -= 2;
     regs.sp[-1] = rval;
 }
 END_CASE(JSOP_SETXMLNAME)
 
@@ -6686,18 +6643,17 @@ BEGIN_CASE(JSOP_YIELD)
     goto exit;
 
 BEGIN_CASE(JSOP_ARRAYPUSH)
 {
     uint32 slot = GET_UINT16(regs.pc);
     JS_ASSERT(script->nfixed <= slot);
     JS_ASSERT(slot < script->nslots);
     JSObject *obj = &regs.fp()->slots()[slot].toObject();
-    if (!cx->typeMonitorAssign(obj, JSID_VOID, regs.sp[-1]))
-        goto error;
+    cx->typeMonitorAssign(obj, JSID_VOID, regs.sp[-1]);
     if (!js_ArrayCompPush(cx, obj, regs.sp[-1]))
         goto error;
     regs.sp--;
 }
 END_CASE(JSOP_ARRAYPUSH)
 #endif /* JS_HAS_GENERATORS */
 
 #if JS_THREADED_INTERP
--- a/js/src/jsinterp.h
+++ b/js/src/jsinterp.h
@@ -244,17 +244,18 @@ Execute(JSContext *cx, JSObject &chain, 
         StackFrame *prev, uintN flags, Value *result);
 
 /* Flags to toggle js::Interpret() execution. */
 enum InterpMode
 {
     JSINTERP_NORMAL    = 0, /* interpreter is running normally */
     JSINTERP_RECORD    = 1, /* interpreter has been started to record/run traces */
     JSINTERP_SAFEPOINT = 2, /* interpreter should leave on a method JIT safe point */
-    JSINTERP_PROFILE   = 3  /* interpreter should profile a loop */
+    JSINTERP_PROFILE   = 3, /* interpreter should profile a loop */
+    JSINTERP_SKIP_TRAP = 4  /* as SAFEPOINT, but skip trap at first opcode */
 };
 
 /*
  * Execute the caller-initialized frame for a user-defined script or function
  * pointed to by cx->fp until completion or error.
  */
 extern JS_REQUIRES_STACK JS_NEVER_INLINE bool
 Interpret(JSContext *cx, StackFrame *stopFp, uintN inlineCallCount = 0, InterpMode mode = JSINTERP_NORMAL);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -377,18 +377,18 @@ GetCustomIterator(JSContext *cx, JSObjec
     }
 
     /*
      * Notify type inference of the custom iterator.  This only needs to be done
      * if this is coming from a 'for in' loop, not a call to Iterator itself.
      * If an Iterator object is used in a for loop then the values fetched in
      * that loop are unknown, whether there is a custom __iterator__ or not.
      */
-    if (!(flags & JSITER_OWNONLY) && !cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN))
-        return false;
+    if (!(flags & JSITER_OWNONLY))
+        cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN);
 
     /* Otherwise call it and return that object. */
     LeaveTrace(cx);
     Value arg = BooleanValue((flags & JSITER_FOREACH) == 0);
     if (!ExternalInvoke(cx, ObjectValue(*obj), *vp, 1, &arg, vp))
         return false;
     if (vp->isPrimitive()) {
         /*
@@ -1243,18 +1243,17 @@ SendToGenerator(JSContext *cx, JSGenerat
       case JSGENOP_NEXT:
       case JSGENOP_SEND:
         if (gen->state == JSGEN_OPEN) {
             JSScript *script = gen->floatingFrame()->script();
 
             jsbytecode *yieldpc = gen->regs.pc - JSOP_YIELD_LENGTH;
             JS_ASSERT(JSOp(*yieldpc) == JSOP_YIELD);
 
-            if (!script->typeMonitorUnknown(cx, yieldpc))
-                return JS_FALSE;
+            script->typeMonitorUnknown(cx, yieldpc);
 
             /*
              * Store the argument to send as the result of the yield
              * expression.
              */
             gen->regs.sp[-1] = arg;
         }
         gen->state = JSGEN_RUNNING;
@@ -1490,13 +1489,12 @@ js_InitIteratorClasses(JSContext *cx, JS
     }
 #endif
 
     proto = js_InitClass(cx, obj, NULL, &js_StopIterationClass, NULL, 0, NULL,
                          NULL, NULL, NULL, NULL);
     if (!proto)
         return NULL;
 
-    if (!cx->addTypeProperty(obj->getType(), js_StopIteration_str, ObjectValue(*proto)))
-        return NULL;
+    cx->addTypeProperty(obj->getType(), js_StopIteration_str, ObjectValue(*proto));
 
     return proto;
 }
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -121,24 +121,25 @@ Class js_MathClass = {
 
 JSBool
 js_math_abs(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = fabs(x);
     vp->setNumber(z);
-    if (!vp[2].isDouble() && vp->isDouble() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp[2].isDouble() && vp->isDouble())
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static JSBool
 math_acos(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
@@ -266,24 +267,25 @@ js_math_ceil_impl(jsdouble x)
 
 JSBool
 js_math_ceil(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = js_math_ceil_impl(x);
     vp->setNumber(z);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static JSBool
 math_cos(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
@@ -342,24 +344,25 @@ js_math_floor_impl(jsdouble x)
 
 JSBool
 js_math_floor(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = js_math_floor_impl(x);
     vp->setNumber(z);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static JSBool
 math_log(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
@@ -387,70 +390,74 @@ JSBool
 js_math_max(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z = js_NegativeInfinity;
     Value *argv;
     uintN i;
 
     if (argc == 0) {
         vp->setDouble(js_NegativeInfinity);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     argv = vp + 2;
     bool expectDouble = false;
     for (i = 0; i < argc; i++) {
         expectDouble |= argv[i].isDouble();
         if (!ValueToNumber(cx, argv[i], &x))
             return JS_FALSE;
         if (JSDOUBLE_IS_NaN(x)) {
             vp->setDouble(js_NaN);
-            return cx->markTypeCallerOverflow();
+            cx->markTypeCallerOverflow();
+            return JS_TRUE;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, z) == -1)
                 z = x;
         } else {
             z = (x > z) ? x : z;
         }
     }
     if (!vp->setNumber(z) && !expectDouble)
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 JSBool
 js_math_min(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z = js_PositiveInfinity;
     Value *argv;
     uintN i;
 
     if (argc == 0) {
         vp->setDouble(js_PositiveInfinity);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     argv = vp + 2;
     bool expectDouble = false;
     for (i = 0; i < argc; i++) {
         expectDouble |= argv[i].isDouble();
         if (!ValueToNumber(cx, argv[i], &x))
             return JS_FALSE;
         if (JSDOUBLE_IS_NaN(x)) {
             vp->setDouble(js_NaN);
-            return cx->markTypeCallerOverflow();
+            cx->markTypeCallerOverflow();
+            return JS_TRUE;
         }
         if (x == 0 && x == z) {
             if (js_copysign(1.0, x) == -1)
                 z = x;
         } else {
             z = (x < z) ? x : z;
         }
     }
     if (!vp->setNumber(z) && !expectDouble)
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static jsdouble
 powi(jsdouble x, jsint y)
 {
     jsuint n = (y < 0) ? -y : y;
     jsdouble m = x;
@@ -479,58 +486,65 @@ powi(jsdouble x, jsint y)
 
 JSBool
 js_math_pow(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, y, z;
 
     if (argc <= 1) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     bool expectDouble = vp[2].isDouble() || vp[3].isDouble();
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     if (!ValueToNumber(cx, vp[3], &y))
         return JS_FALSE;
     /*
      * Special case for square roots. Note that pow(x, 0.5) != sqrt(x)
      * when x = -0.0, so we have to guard for this.
      */
     if (JSDOUBLE_IS_FINITE(x) && x != 0.0) {
         if (y == 0.5) {
             vp->setNumber(sqrt(x));
-            return expectDouble || cx->markTypeCallerOverflow();
+            if (!expectDouble)
+                cx->markTypeCallerOverflow();
+            return JS_TRUE;
         }
         if (y == -0.5) {
             vp->setNumber(1.0/sqrt(x));
-            return expectDouble || cx->markTypeCallerOverflow();
+            if (!expectDouble)
+                cx->markTypeCallerOverflow();
+            return JS_TRUE;
         }
     }
     /*
      * Because C99 and ECMA specify different behavior for pow(),
      * we need to wrap the libm call to make it ECMA compliant.
      */
     if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
         vp->setDouble(js_NaN);
-        return expectDouble || cx->markTypeCallerOverflow();
+        if (!expectDouble)
+            cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     /* pow(x, +-0) is always 1, even for x = NaN. */
     if (y == 0) {
         vp->setInt32(1);
         return JS_TRUE;
     }
 
     if (vp[3].isInt32())
         z = powi(x, vp[3].toInt32());
     else
         z = pow(x, y);
 
     if (!vp->setNumber(z) && !expectDouble)
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static const int64 RNG_MULTIPLIER = 0x5DEECE66DLL;
 static const int64 RNG_ADDEND = 0xBLL;
 static const int64 RNG_MASK = (1LL << 48) - 1;
 static const jsdouble RNG_DSCALE = jsdouble(1LL << 53);
 
@@ -605,24 +619,25 @@ js_math_round_impl(jsdouble x)
 
 JSBool
 js_math_round(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
     if (argc == 0) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return JS_TRUE;
     }
     if (!ValueToNumber(cx, vp[2], &x))
         return JS_FALSE;
     z = js_copysign(floor(x + 0.5), x);
     vp->setNumber(z);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return JS_TRUE;
 }
 
 static JSBool
 math_sin(JSContext *cx, uintN argc, Value *vp)
 {
     jsdouble x, z;
 
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -419,28 +419,29 @@ ParseIntDoubleHelper(jsdouble d)
 
 /* See ECMA 15.1.2.2. */
 static JSBool
 num_parseInt(JSContext *cx, uintN argc, Value *vp)
 {
     /* Fast paths and exceptional cases. */
     if (argc == 0) {
         vp->setDouble(js_NaN);
-        return cx->markTypeCallerOverflow();
+        cx->markTypeCallerOverflow();
+        return true;
     }
 
     if (argc == 1 || (vp[3].isInt32() && (vp[3].toInt32() == 0 || vp[3].toInt32() == 10))) {
         if (vp[2].isInt32()) {
             *vp = vp[2];
             return true;
         }
         if (vp[2].isDouble()) {
             vp->setNumber(ParseIntDoubleHelper(vp[2].toDouble()));
-            if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-                return false;
+            if (!vp->isInt32())
+                cx->markTypeCallerOverflow();
             return true;
         }
     }
 
     /* Step 1. */
     JSString *inputString = js_ValueToString(cx, vp[2]);
     if (!inputString)
         return false;
@@ -450,17 +451,18 @@ num_parseInt(JSContext *cx, uintN argc, 
     bool stripPrefix = true;
     int32_t radix = 0;
     if (argc > 1) {
         if (!ValueToECMAInt32(cx, vp[3], &radix))
             return false;
         if (radix != 0) {
             if (radix < 2 || radix > 36) {
                 vp->setDouble(js_NaN);
-                return cx->markTypeCallerOverflow();
+                cx->markTypeCallerOverflow();
+                return true;
             }
             if (radix != 16)
                 stripPrefix = false;
         }
     }
 
     /* Steps 2-5, 9-14. */
     const jschar *ws = inputString->getChars(cx);
@@ -469,18 +471,18 @@ num_parseInt(JSContext *cx, uintN argc, 
     const jschar *end = ws + inputString->length();
 
     jsdouble number;
     if (!ParseIntStringHelper(cx, ws, end, radix, stripPrefix, &number))
         return false;
 
     /* Step 15. */
     vp->setNumber(number);
-    if (!vp->isInt32() && !cx->markTypeCallerOverflow())
-        return false;
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
     return true;
 }
 
 #ifdef JS_TRACER
 static jsdouble FASTCALL
 ParseInt(JSContext* cx, JSString* str)
 {
     TraceMonitor *tm = JS_TRACE_MONITOR_ON_TRACE(cx);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1643,20 +1643,18 @@ js_obj_defineGetter(JSContext *cx, uintN
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
 
-    if (!cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN))
-        return JS_FALSE;
-    if (!cx->markTypePropertyConfigured(obj->getType(), id))
-        return false;
+    cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN);
+    cx->markTypePropertyConfigured(obj->getType(), id);
 
     call.rval().setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), getter, StrictPropertyStub,
                                JSPROP_ENUMERATE | JSPROP_GETTER | JSPROP_SHARED);
 }
 
 JS_FRIEND_API(JSBool)
 js_obj_defineSetter(JSContext *cx, uintN argc, Value *vp)
@@ -1683,20 +1681,18 @@ js_obj_defineSetter(JSContext *cx, uintN
      * Getters and setters are just like watchpoints from an access
      * control point of view.
      */
     Value junk;
     uintN attrs;
     if (!CheckAccess(cx, obj, id, JSACC_WATCH, &junk, &attrs))
         return JS_FALSE;
 
-    if (!cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN))
-        return JS_FALSE;
-    if (!cx->markTypePropertyConfigured(obj->getType(), id))
-        return false;
+    cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN);
+    cx->markTypePropertyConfigured(obj->getType(), id);
 
     call.rval().setUndefined();
     return obj->defineProperty(cx, id, UndefinedValue(), PropertyStub, setter,
                                JSPROP_ENUMERATE | JSPROP_SETTER | JSPROP_SHARED);
 }
 
 static JSBool
 obj_lookupGetter(JSContext *cx, uintN argc, Value *vp)
@@ -2476,26 +2472,22 @@ DefinePropertyOnArray(JSContext *cx, JSO
 
     return DefinePropertyOnObject(cx, obj, id, desc, throwError, rval);
 }
 
 static JSBool
 DefineProperty(JSContext *cx, JSObject *obj, const jsid &id, const PropDesc &desc, bool throwError,
                bool *rval)
 {
-    if (!cx->addTypePropertyId(obj->getType(), id, desc.value))
-        return false;
+    cx->addTypePropertyId(obj->getType(), id, desc.value);
     if (!desc.get.isUndefined() || !desc.set.isUndefined()) {
-        if (!cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN))
-            return false;
-        if (!cx->markTypePropertyConfigured(obj->getType(), id))
-            return false;
+        cx->addTypePropertyId(obj->getType(), id, TYPE_UNKNOWN);
+        cx->markTypePropertyConfigured(obj->getType(), id);
     } else if (!desc.configurable() || !desc.enumerable() || !desc.writable()) {
-        if (!cx->markTypePropertyConfigured(obj->getType(), id))
-            return false;
+        cx->markTypePropertyConfigured(obj->getType(), id);
     }
 
     if (obj->isArray())
         return DefinePropertyOnArray(cx, obj, id, desc, throwError, rval);
 
     if (obj->getOps()->lookupProperty) {
         if (obj->isProxy())
             return JSProxy::defineProperty(cx, obj, id, desc.pd);
@@ -2629,18 +2621,17 @@ obj_create(JSContext *cx, uintN argc, Va
      */
     JSObject *obj = NewNonFunction<WithProto::Given>(cx, &js_ObjectClass, v.toObjectOrNull(),
                                                         vp->toObject().getGlobal());
     if (!obj)
         return JS_FALSE;
     vp->setObject(*obj); /* Root and prepare for eventual return. */
 
     /* Don't track types or array-ness for objects created here. */
-    if (!cx->markTypeObjectUnknownProperties(obj->getType()))
-        return false;
+    cx->markTypeObjectUnknownProperties(obj->getType());
 
     /* 15.2.3.5 step 4. */
     if (argc > 1 && !vp[3].isUndefined()) {
         if (vp[3].isPrimitive()) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_NOT_NONNULL_OBJECT);
             return JS_FALSE;
         }
 
@@ -3035,18 +3026,17 @@ js_CreateThisForFunction(JSContext *cx, 
 
         types::TypeObject *type = cx->newTypeObject(name, obj->getProto());
         types::AutoTypeRooter root(cx, type);
 
         obj = NewReshapedObject(cx, type, obj->getParent(), gc::FinalizeKind(obj->finalizeKind()),
                                 obj->lastProperty());
         if (!obj)
             return NULL;
-        if (!callee->getFunctionPrivate()->script()->typeSetThis(cx, (types::jstype) type))
-            return NULL;
+        callee->getFunctionPrivate()->script()->typeSetThis(cx, (types::jstype) type);
     }
 
     return obj;
 }
 
 #ifdef JS_TRACER
 
 static JS_ALWAYS_INLINE JSObject*
@@ -3967,18 +3957,19 @@ js_InitObjectClass(JSContext *cx, JSObje
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_ObjectClass, js_Object, 1,
                                    object_TypeNew,
                                    object_props, object_methods, NULL, object_static_methods);
     if (!proto)
         return NULL;
 
     /* The default 'new' object for Object.prototype has unknown properties. */
     TypeObject *newType = proto->getNewType(cx);
-    if (!newType || !cx->markTypeObjectUnknownProperties(newType))
+    if (!newType)
         return NULL;
+    cx->markTypeObjectUnknownProperties(newType);
 
     /* ECMA (15.1.2.1) says 'eval' is a property of the global object. */
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.evalAtom);
 
     JSObject *evalobj = js_DefineFunction(cx, obj, id, eval, 1, JSFUN_STUB_GSOPS,
                                           JS_TypeHandlerDynamic, js_eval_str);
     if (!evalobj)
         return NULL;
@@ -3989,18 +3980,17 @@ js_InitObjectClass(JSContext *cx, JSObje
 }
 
 static bool
 DefineStandardSlot(JSContext *cx, JSObject *obj, JSProtoKey key, JSAtom *atom,
                    const Value &v, uint32 attrs, bool &named)
 {
     jsid id = ATOM_TO_JSID(atom);
 
-    if (!cx->addTypePropertyId(obj->getType(), id, v))
-        return false;
+    cx->addTypePropertyId(obj->getType(), id, v);
 
     if (key != JSProto_Null) {
         /*
          * Initializing an actual standard class on a global object. If the
          * property is not yet present, force it into a new one bound to a
          * reserved slot. Otherwise, go through the normal property path.
          */
         JS_ASSERT(obj->isGlobal());
@@ -4092,20 +4082,19 @@ DefineConstructorAndPrototype(JSContext 
     if (clasp == &js_ArrayClass && !proto->makeDenseArraySlow(cx))
         return NULL;
 
     TypeObject *type = proto->getNewType(cx);
     if (!type)
         return NULL;
 
     /* Mark types with a special equality hook as having unknown properties. */
-    if (clasp->ext.equality &&
-        (!cx->markTypeObjectUnknownProperties(type) ||
-         !cx->markTypeObjectUnknownProperties(proto->getType()))) {
-        return NULL;
+    if (clasp->ext.equality) {
+        cx->markTypeObjectUnknownProperties(type);
+        cx->markTypeObjectUnknownProperties(proto->getType());
     }
 
     proto->syncSpecialEquality();
 
     /* After this point, control must exit via label bad or out. */
     AutoObjectRooter tvr(cx, proto);
 
     JSObject *ctor;
@@ -4580,20 +4569,18 @@ SetProto(JSContext *cx, JSObject *obj, J
 
     /*
      * Setting __proto__ on an object that has escaped and may be referenced by
      * other heap objects can only be done if the properties of both objects are unknown.
      * Type sets containing this object will contain the original type but not the
      * new type of the object, which is OK since we treat objects in type sets with
      * unknown properties as interchangeable.
      */
-    if (!cx->markTypeObjectUnknownProperties(obj->getType()) ||
-        !cx->markTypeObjectUnknownProperties(type)) {
-        return false;
-    }
+    cx->markTypeObjectUnknownProperties(obj->getType());
+    cx->markTypeObjectUnknownProperties(type);
 
     if (!proto || !checkForCycles) {
         obj->setType(type);
     } else if (!SetTypeCheckingForCycles(cx, obj, type)) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CYCLIC_VALUE, js_proto_str);
         return false;
     }
     return true;
@@ -4745,18 +4732,17 @@ js_ConstructObject(JSContext *cx, Class 
             proto = rval.toObjectOrNull();
     }
 
     JSObject *obj = NewObject<WithProto::Class>(cx, clasp, proto, parent);
     if (!obj)
         return NULL;
 
     obj->syncSpecialEquality();
-    if (!cx->markTypeObjectUnknownProperties(obj->getType()))
-        return NULL;
+    cx->markTypeObjectUnknownProperties(obj->getType());
 
     Value rval;
     if (!InvokeConstructorWithGivenThis(cx, obj, cval, argc, argv, &rval))
         return NULL;
 
     if (rval.isPrimitive())
         return obj;
 
@@ -5623,18 +5609,17 @@ js_NativeGetInline(JSContext *cx, JSObje
     if (pobj->containsSlot(slot) &&
         (JS_LIKELY(cx->runtime->propertyRemovals == sample) ||
          pobj->nativeContains(*shape))) {
         if (!pobj->methodWriteBarrier(cx, *shape, *vp))
             return false;
         pobj->nativeSetSlot(slot, *vp);
     }
 
-    if (!cx->addTypePropertyId(obj->getType(), shape->id, *vp))
-        return false;
+    cx->addTypePropertyId(obj->getType(), shape->id, *vp);
 
     return true;
 }
 
 JSBool
 js_NativeGet(JSContext *cx, JSObject *obj, JSObject *pobj, const Shape *shape, uintN getHow,
              Value *vp)
 {
@@ -6601,20 +6586,18 @@ js_GetClassPrototype(JSContext *cx, JSOb
     }
 
     return FindClassPrototype(cx, scopeobj, protoKey, protop, clasp);
 }
 
 JSBool
 js_SetClassPrototype(JSContext *cx, JSObject *ctor, JSObject *proto, uintN attrs)
 {
-    if (!cx->addTypePropertyId(ctor->getType(), ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
-                               ObjectOrNullValue(proto))) {
-        return JS_FALSE;
-    }
+    cx->addTypePropertyId(ctor->getType(), ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
+                          ObjectOrNullValue(proto));
 
     /*
      * Use the given attributes for the prototype property of the constructor,
      * as user-defined constructors have a DontDelete prototype (which may be
      * reset), while native or "system" constructors have DontEnum | ReadOnly |
      * DontDelete.
      */
     if (!ctor->defineProperty(cx, ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom),
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -861,17 +861,17 @@ struct JSObject : js::gc::Cell {
     inline js::Value* addressOfDenseArrayElement(uintN idx);
     inline void setDenseArrayElement(uintN idx, const js::Value &val);
     inline void shrinkDenseArrayElements(JSContext *cx, uintN cap);
     inline bool denseArrayHasInlineSlots() const;
     inline void backfillDenseArrayHoles();
 
     /* Packed information for this array. May be incorrect if !cx->typeInferenceEnabled(). */
     inline bool isPackedDenseArray();
-    inline bool setDenseArrayNotPacked(JSContext *cx);
+    inline void setDenseArrayNotPacked(JSContext *cx);
 
     /*
      * ensureDenseArrayElements ensures that the dense array can hold at least
      * index + extra elements. It returns ED_OK on success, ED_FAILED on
      * failure to grow the array, ED_SPARSE when the array is too sparse to
      * grow (this includes the case of index + extra overflow). In the last
      * two cases the array is kept intact.
      */
@@ -1772,18 +1772,18 @@ js_DefineNativeProperty(JSContext *cx, J
                         uintN defineHow = 0);
 
 static inline JSBool
 js_DefineNativePropertyWithType(JSContext *cx, JSObject *obj, jsid id, const js::Value &value,
                                 js::PropertyOp getter, js::StrictPropertyOp setter, uintN attrs,
                                 uintN flags, intN shortid, JSProperty **propp,
                                 uintN defineHow = 0)
 {
-    return JS_AddTypePropertyById(cx, obj, id, Jsvalify(value)) &&
-           js_DefineNativeProperty(cx, obj, id, value, getter, setter,
+    JS_AddTypePropertyById(cx, obj, id, Jsvalify(value));
+    return js_DefineNativeProperty(cx, obj, id, value, getter, setter,
                                    attrs, flags, shortid, propp, defineHow);
 }
 
 /*
  * Specialized subroutine that allows caller to preset JSRESOLVE_* flags and
  * returns the index along the prototype chain in which *propp was found, or
  * the last index if not found, or -1 on error.
  */
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -122,29 +122,26 @@ JSObject::unbrand(JSContext *cx)
     }
     setGeneric();
     return true;
 }
 
 inline JSBool
 JSObject::setAttributes(JSContext *cx, jsid id, uintN *attrsp)
 {
-    if (!cx->markTypePropertyConfigured(getType(), id))
-        return false;
+    cx->markTypePropertyConfigured(getType(), id);
     js::AttributesOp op = getOps()->setAttributes;
     return (op ? op : js_SetAttributes)(cx, this, id, attrsp);
 }
 
 inline JSBool
 JSObject::deleteProperty(JSContext *cx, jsid id, js::Value *rval, JSBool strict)
 {
-    if (!cx->addTypePropertyId(getType(), id, js::types::TYPE_UNDEFINED))
-        return false;
-    if (!cx->markTypePropertyConfigured(getType(), id))
-        return false;
+    cx->addTypePropertyId(getType(), id, js::types::TYPE_UNDEFINED);
+    cx->markTypePropertyConfigured(getType(), id);
     js::DeleteIdOp op = getOps()->deleteProperty;
     return (op ? op : js_DeleteProperty)(cx, this, id, rval, strict);
 }
 
 inline void
 JSObject::syncSpecialEquality()
 {
     if (clasp->ext.equality) {
@@ -430,21 +427,19 @@ JSObject::setArrayLength(JSContext *cx, 
 {
     JS_ASSERT(isArray());
 
     if (length > INT32_MAX) {
         /*
          * Mark the type of this object as possibly not a dense array, per the
          * requirements of OBJECT_FLAG_NON_DENSE_ARRAY.
          */
-        if (!cx->markTypeArrayNotPacked(getType(), true))
-            return false;
+        cx->markTypeArrayNotPacked(getType(), true);
         jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
-        if (!cx->addTypePropertyId(getType(), lengthId, js::types::TYPE_DOUBLE))
-            return false;
+        cx->addTypePropertyId(getType(), lengthId, js::types::TYPE_DOUBLE);
     }
 
     setPrivate((void*) length);
     return true;
 }
 
 inline void
 JSObject::setDenseArrayLength(uint32 length)
@@ -1696,18 +1691,18 @@ DefineConstructorAndPrototype(JSContext 
 
     jsid id = ATOM_TO_JSID(cx->runtime->atomState.classAtoms[key]);
     JS_ASSERT(!global->nativeLookup(id));
 
     /* Set these first in case addTypePropertyId looks for this class. */
     global->setSlot(key, ObjectValue(*ctor));
     global->setSlot(key + JSProto_LIMIT, ObjectValue(*proto));
 
-    if (!cx->addTypePropertyId(global->getType(), id, ObjectValue(*ctor)) ||
-        !global->addDataProperty(cx, id, key + JSProto_LIMIT * 2, 0)) {
+    cx->addTypePropertyId(global->getType(), id, ObjectValue(*ctor));
+    if (!global->addDataProperty(cx, id, key + JSProto_LIMIT * 2, 0)) {
         global->setSlot(key, UndefinedValue());
         global->setSlot(key + JSProto_LIMIT, UndefinedValue());
         return false;
     }
 
     global->setSlot(key + JSProto_LIMIT * 2, ObjectValue(*ctor));
     return true;
 }
--- a/js/src/json.cpp
+++ b/js/src/json.cpp
@@ -153,18 +153,17 @@ js_json_stringify(JSContext *cx, uintN a
     // needs to support returning undefined. So this is a little awkward
     // for the API, because we want to support streaming writers.
     if (!sb.empty()) {
         JSString *str = sb.finishString();
         if (!str)
             return JS_FALSE;
         vp->setString(str);
     } else {
-        if (!cx->markTypeCallerUnexpected(types::TYPE_UNDEFINED))
-            return JS_FALSE;
+        cx->markTypeCallerUnexpected(types::TYPE_UNDEFINED);
         vp->setUndefined();
     }
 
     return JS_TRUE;
 }
 
 JSBool
 js_TryJSON(JSContext *cx, Value *vp)
@@ -1025,18 +1024,20 @@ CloseObject(JSContext *cx, JSONParser *j
     if (!js_GetLengthProperty(cx, jp->objectStack, &len))
         return JS_FALSE;
 
     Value p;
     if (!jp->objectStack->getProperty(cx, INT_TO_JSID(len - 1), &p))
         return JS_FALSE;
 
     JSObject *obj = &p.toObject();
-    if (obj->isArray() ? !cx->fixArrayType(obj) : !cx->fixObjectType(obj))
-        return JS_FALSE;
+    if (obj->isArray())
+        cx->fixArrayType(obj);
+    else
+        cx->fixObjectType(obj);
 
     if (!js_SetLengthProperty(cx, jp->objectStack, len - 1))
         return JS_FALSE;
 
     return JS_TRUE;
 }
 
 static JSBool
--- a/js/src/jsparse.cpp
+++ b/js/src/jsparse.cpp
@@ -1176,18 +1176,17 @@ Compiler::defineGlobals(JSContext *cx, G
         if (def.funbox) {
             JSFunction *fun = def.funbox->function();
 
             /*
              * No need to check for redeclarations or anything, global
              * optimizations only take place if the property is not defined.
              */
             rval.setObject(*fun);
-            if (!cx->addTypePropertyId(globalObj->getType(), id, rval))
-                return false;
+            cx->addTypePropertyId(globalObj->getType(), id, rval);
         } else {
             rval.setUndefined();
         }
 
         JSProperty *prop;
 
         if (!js_DefineNativeProperty(cx, globalObj, id, rval, PropertyStub, StrictPropertyStub,
                                      JSPROP_ENUMERATE | JSPROP_PERMANENT, 0, 0, &prop)) {
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -1172,18 +1172,17 @@ NewProxyObject(JSContext *cx, JSProxyHan
     if (fun) {
         obj->setSlot(JSSLOT_PROXY_CALL, call ? ObjectValue(*call) : UndefinedValue());
         if (construct) {
             obj->setSlot(JSSLOT_PROXY_CONSTRUCT, ObjectValue(*construct));
         }
     }
 
     /* Don't track types of properties of proxies. */
-    if (!cx->markTypeObjectUnknownProperties(obj->getType()))
-        return NULL;
+    cx->markTypeObjectUnknownProperties(obj->getType());
 
     return obj;
 }
 
 static JSBool
 proxy_create(JSContext *cx, uintN argc, Value *vp)
 {
     if (argc < 1) {
--- a/js/src/jsregexp.cpp
+++ b/js/src/jsregexp.cpp
@@ -825,18 +825,17 @@ regexp_construct(JSContext *cx, uintN ar
         if (argc >= 1 && argv[0].isObject() && argv[0].toObject().isRegExp() &&
             (argc == 1 || argv[1].isUndefined())) {
             *vp = argv[0];
             /*
              * Note: the type handler for RegExp only accounts for a new
              * regexps for any associated compileAndGo RegExp global, not new
              * regexps with different prototypes or RegExp.prototype itself.
              */
-            if (!cx->markTypeCallerUnexpected(*vp))
-                return false;
+            cx->markTypeCallerUnexpected(*vp);
             return true;
         }
     }
 
     JSObject *obj = NewBuiltinClassInstance(cx, &js_RegExpClass);
     if (!obj)
         return false;
 
@@ -935,23 +934,21 @@ js_InitRegExpClass(JSContext *cx, JSObje
      * some other class could snap it up. (The risk is particularly great for
      * Object.prototype.)
      *
      * All callers of JSObject::initSharingEmptyShape depend on this.
      */
     if (!type->getEmptyShape(cx, &js_RegExpClass, FINALIZE_OBJECT0))
         return NULL;
 
-    if (!cx->addTypeProperty(protoType, "source", TYPE_STRING) ||
-        !cx->addTypeProperty(protoType, "global", TYPE_BOOLEAN) ||
-        !cx->addTypeProperty(protoType, "ignoreCase", TYPE_BOOLEAN) ||
-        !cx->addTypeProperty(protoType, "multiline", TYPE_BOOLEAN) ||
-        !cx->addTypeProperty(protoType, "sticky", TYPE_BOOLEAN) ||
-        !cx->addTypeProperty(protoType, "lastIndex", TYPE_INT32)) {
-        return NULL;
-    }
+    cx->addTypeProperty(protoType, "source", TYPE_STRING);
+    cx->addTypeProperty(protoType, "global", TYPE_BOOLEAN);
+    cx->addTypeProperty(protoType, "ignoreCase", TYPE_BOOLEAN);
+    cx->addTypeProperty(protoType, "multiline", TYPE_BOOLEAN);
+    cx->addTypeProperty(protoType, "sticky", TYPE_BOOLEAN);
+    cx->addTypeProperty(protoType, "lastIndex", TYPE_INT32);
 
     /* Install the fully-constructed RegExp and RegExp.prototype in global. */
     if (!DefineConstructorAndPrototype(cx, global, JSProto_RegExp, ctor, proto))
         return NULL;
 
     return proto;
 }
--- a/js/src/jsscript.h
+++ b/js/src/jsscript.h
@@ -459,17 +459,16 @@ struct JSScript {
     bool            isActiveEval:1;   /* script came from eval(), and is still active */
     bool            isCachedEval:1;   /* script came from eval(), and is in eval cache */
     bool            isUncachedEval:1; /* script came from EvaluateScript */
     bool            calledWithNew:1;  /* script has been called using 'new' */
     bool            analyzed:1;       /* script has been analyzed by type inference */
 #ifdef JS_METHODJIT
     bool            debugMode:1;      /* script was compiled in debug mode */
     bool            singleStepMode:1; /* compile script in single-step mode */
-    bool            inlineParents:1;  /* script may be inlined in other frames */
     bool            failedBoundsCheck:1; /* script has had hoisted bounds checks fail */
 #endif
 
     jsbytecode      *main;      /* main entry point, after predef'ing prolog */
     JSAtomMap       atomMap;    /* maps immediate index to literal struct */
     JSCompartment   *compartment; /* compartment the script was compiled for */
     const char      *filename;  /* source filename or null */
     uint32          lineno;     /* base line number of script */
@@ -579,35 +578,35 @@ struct JSScript {
     void condenseTypes(JSContext *cx);
     void sweepAnalysis(JSContext *cx);
 
     /* Get a type object for an allocation site in this script. */
     inline js::types::TypeObject *
     getTypeInitObject(JSContext *cx, const jsbytecode *pc, bool isArray);
 
     /* Monitor a bytecode pushing an unexpected value. */
-    inline bool typeMonitorResult(JSContext *cx, const jsbytecode *pc, js::types::jstype type);
-    inline bool typeMonitorResult(JSContext *cx, const jsbytecode *pc, const js::Value &val);
-    inline bool typeMonitorUndefined(JSContext *cx, const jsbytecode *pc);
-    inline bool typeMonitorOverflow(JSContext *cx, const jsbytecode *pc);
-    inline bool typeMonitorString(JSContext *cx, const jsbytecode *pc);
-    inline bool typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
+    inline void typeMonitorResult(JSContext *cx, const jsbytecode *pc, js::types::jstype type);
+    inline void typeMonitorResult(JSContext *cx, const jsbytecode *pc, const js::Value &val);
+    inline void typeMonitorUndefined(JSContext *cx, const jsbytecode *pc);
+    inline void typeMonitorOverflow(JSContext *cx, const jsbytecode *pc);
+    inline void typeMonitorString(JSContext *cx, const jsbytecode *pc);
+    inline void typeMonitorUnknown(JSContext *cx, const jsbytecode *pc);
 
     /* Add a type for a variable in this script. */
-    inline bool typeSetThis(JSContext *cx, js::types::jstype type);
-    inline bool typeSetThis(JSContext *cx, const js::Value &value);
-    inline bool typeSetThis(JSContext *cx, js::types::ClonedTypeSet *types);
-    inline bool typeSetNewCalled(JSContext *cx);
-    inline bool typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type);
-    inline bool typeSetLocal(JSContext *cx, unsigned local, const js::Value &value);
-    inline bool typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *types);
-    inline bool typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type);
-    inline bool typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
-    inline bool typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *types);
-    inline bool typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
+    inline void typeSetThis(JSContext *cx, js::types::jstype type);
+    inline void typeSetThis(JSContext *cx, const js::Value &value);
+    inline void typeSetThis(JSContext *cx, js::types::ClonedTypeSet *types);
+    inline void typeSetNewCalled(JSContext *cx);
+    inline void typeSetLocal(JSContext *cx, unsigned local, js::types::jstype type);
+    inline void typeSetLocal(JSContext *cx, unsigned local, const js::Value &value);
+    inline void typeSetLocal(JSContext *cx, unsigned local, js::types::ClonedTypeSet *types);
+    inline void typeSetArgument(JSContext *cx, unsigned arg, js::types::jstype type);
+    inline void typeSetArgument(JSContext *cx, unsigned arg, const js::Value &value);
+    inline void typeSetArgument(JSContext *cx, unsigned arg, js::types::ClonedTypeSet *types);
+    inline void typeSetUpvar(JSContext *cx, unsigned upvar, const js::Value &value);
 
     /*
      * Associates this script with a specific function, constructing a new type
      * object for the function.
      */
     bool typeSetFunction(JSContext *cx, JSFunction *fun);
 
 #ifdef JS_METHODJIT
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -1133,17 +1133,18 @@ js_str_charCodeAt(JSContext *cx, uintN a
     if (!chars)
         return false;
 
     vp->setInt32(chars[i]);
     return true;
 
 out_of_range:
     vp->setDouble(js_NaN);
-    return cx->markTypeCallerOverflow();
+    cx->markTypeCallerOverflow();
+    return true;
 }
 
 /*
  * Boyer-Moore-Horspool superlinear search for pat:patlen in text:textlen.
  * The patlen argument must be positive and no greater than sBMHPatLenMax.
  *
  * Return the index of pat in text, or -1 if not found.
  */
@@ -2706,18 +2707,17 @@ SplitHelper(JSContext *cx, JSLinearStrin
                 if (res->pairIsPresent(i + 1)) {
                     JSSubString parsub;
                     res->getParen(i + 1, &parsub);
                     sub = js_NewStringCopyN(cx, parsub.chars, parsub.length);
                     if (!sub || !splits.append(StringValue(sub)))
                         return NULL;
                 } else {
                     /* Only string entries have been accounted for so far. */
-                    if (!cx->addTypePropertyId(type, JSID_VOID, UndefinedValue()))
-                        return NULL;
+                    cx->addTypePropertyId(type, JSID_VOID, UndefinedValue());
                     if (!splits.append(UndefinedValue()))
                         return NULL;
                 }
 
                 /* Step 13(c)(iii)(7)(d). */
                 if (splits.length() == limit)
                     return NewDenseCopiedArray(cx, splits.length(), splits.begin());
             }
@@ -2802,18 +2802,19 @@ static JSBool
 str_split(JSContext *cx, uintN argc, Value *vp)
 {
     /* Steps 1-2. */
     JSString *str = ThisToStringForStringProto(cx, vp);
     if (!str)
         return false;
 
     TypeObject *type = cx->getTypeCallerInitObject(true);
-    if (!type || !cx->addTypeProperty(type, NULL, types::TYPE_STRING))
+    if (!type)
         return false;
+    cx->addTypeProperty(type, NULL, types::TYPE_STRING);
 
     /* Step 5: Use the second argument as the split limit, if given. */
     uint32 limit;
     if (argc > 1 && !vp[3].isUndefined()) {
         jsdouble d;
         if (!ValueToNumber(cx, vp[3], &d))
             return false;
         limit = js_DoubleToECMAUint32(d);
@@ -3619,22 +3620,22 @@ js_InitStringClass(JSContext *cx, JSObje
 
     /* Pre-brand String and String.prototype for trace-jitted code. */
     if (!cx->typeInferenceEnabled()) {
         proto->brand(cx);
         ctor->brand(cx);
     }
 
     jsid lengthId = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
-    if (!cx->addTypePropertyId(proto->getType(), lengthId, TYPE_INT32))
-        return NULL;
+    cx->addTypePropertyId(proto->getType(), lengthId, TYPE_INT32);
 
     TypeObject *type = proto->getNewType(cx);
-    if (!type || !cx->addTypePropertyId(type, JSID_VOID, TYPE_STRING))
+    if (!type)
         return NULL;
+    cx->addTypePropertyId(type, JSID_VOID, TYPE_STRING);
 
     /*
      * Make sure proto's emptyShape is available to be shared by String
      * objects. JSObject::emptyShape is a one-slot cache. If we omit this, some
      * other class could snap it up. (The risk is particularly great for
      * Object.prototype.)
      *
      * All callers of JSObject::initSharingEmptyShape depend on this.
--- a/js/src/jstracer.cpp
+++ b/js/src/jstracer.cpp
@@ -494,35 +494,27 @@ static JSBool
 jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 {
     int index = -1;
 
     if (JSID_IS_STRING(id)) {
         JSAtom* str = JSID_TO_ATOM(id);
         if (StringEqualsAscii(str, "HOTLOOP")) {
             *vp = INT_TO_JSVAL(HOTLOOP);
-
-            if (!cx->addTypePropertyId(obj->getType(), id, Valueify(*vp)))
-                return JS_FALSE;
-
             return JS_TRUE;
         }
 
         if (StringEqualsAscii(str, "adaptive")) {
 #ifdef JS_METHODJIT
             *vp = BOOLEAN_TO_JSVAL(cx->profilingEnabled ||
                                    (cx->methodJitEnabled &&
                                     !cx->hasRunOption(JSOPTION_METHODJIT_ALWAYS)));
 #else
             *vp = BOOLEAN_TO_JSVAL(false);
 #endif
-
-            if (!cx->addTypePropertyId(obj->getType(), id, Valueify(*vp)))
-                return JS_FALSE;
-
             return JS_TRUE;
         }
     }
 
     if (JSID_IS_INT(id))
         index = JSID_TO_INT(id);
 
     uint64 result = 0;
--- a/js/src/jstypedarray.cpp
+++ b/js/src/jstypedarray.cpp
@@ -1537,26 +1537,21 @@ do {                                    
                          &TypedArray::slowClasses[TypedArray::_type],          \
                          _typedArray::class_constructor, 3,                    \
                          JS_TypeHandlerNew,                                    \
                          _typedArray::jsprops,                                 \
                          _typedArray::jsfuncs,                                 \
                          NULL, NULL);                                          \
     if (!proto)                                                                \
         return NULL;                                                           \
-    if (!cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32))       \
-        return NULL;                                                           \
-    if (_typedArray::ArrayElementTypeMayBeDouble() &&                          \
-        !cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE)) {    \
-        return NULL;                                                           \
-    }                                                                          \
-    if (!cx->addTypeProperty(proto->getType(), "buffer",                       \
-                             (types::jstype) bufferType)) {                    \
-        return NULL;                                                           \
-    }                                                                          \
+    cx->addTypeProperty(proto->getType(), NULL, types::TYPE_INT32);            \
+    if (_typedArray::ArrayElementTypeMayBeDouble())                            \
+        cx->addTypeProperty(proto->getType(), NULL, types::TYPE_DOUBLE);       \
+    cx->addTypeProperty(proto->getType(), "buffer",                            \
+                        (types::jstype) bufferType);                           \
     JSObject *ctor = JS_GetConstructor(cx, proto);                             \
     if (!ctor ||                                                               \
         !JS_DefineProperty(cx, ctor, "BYTES_PER_ELEMENT",                      \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
                            JS_PropertyStub, JS_StrictPropertyStub,             \
                            JSPROP_PERMANENT | JSPROP_READONLY) ||              \
         !JS_DefineProperty(cx, proto, "BYTES_PER_ELEMENT",                     \
                            INT_TO_JSVAL(sizeof(_typedArray::ThisType)),        \
--- a/js/src/jsvalue.h
+++ b/js/src/jsvalue.h
@@ -649,16 +649,21 @@ class Value
         return data.s.payload.u32;
     }
 
     JS_ALWAYS_INLINE
     uint64 asRawBits() const {
         return data.asBits;
     }
 
+    JS_ALWAYS_INLINE
+    void setRawBits(uint64 bits) {
+        data.asBits = bits;
+    }
+
     /*
      * In the extract/box/unbox functions below, "NonDouble" means this
      * functions must not be called on a value that is a double. This allows
      * these operations to be implemented more efficiently, since doubles
      * generally already require special handling by the caller.
      */
     JS_ALWAYS_INLINE
     JSValueType extractNonDoubleType() const {
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -137,23 +137,20 @@ JSWrapper::getOwnPropertyDescriptor(JSCo
     CHECKED(GetOwnPropertyDescriptor(cx, wrappedObject(wrapper), id, JSRESOLVE_QUALIFIED,
                                      Jsvalify(desc)), set ? SET : GET);
 }
 
 bool
 JSWrapper::defineProperty(JSContext *cx, JSObject *wrapper, jsid id,
                           PropertyDescriptor *desc)
 {
-    if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
-        if (!cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, types::TYPE_UNKNOWN))
-            return false;
-    } else {
-        if (!cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, desc->value))
-            return false;
-    }
+    if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER))
+        cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, types::TYPE_UNKNOWN);
+    else
+        cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, desc->value);
 
     SET(JS_DefinePropertyById(cx, wrappedObject(wrapper), id, Jsvalify(desc->value),
                               Jsvalify(desc->getter), Jsvalify(desc->setter), desc->attrs));
 }
 
 bool
 JSWrapper::getOwnPropertyNames(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
@@ -225,18 +222,17 @@ JSWrapper::get(JSContext *cx, JSObject *
     vp->setUndefined(); // default result if we refuse to perform this action
     GET(wrappedObject(wrapper)->getProperty(cx, receiver, id, vp));
 }
 
 bool
 JSWrapper::set(JSContext *cx, JSObject *wrapper, JSObject *receiver, jsid id, bool strict,
                Value *vp)
 {
-    if (!cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, *vp))
-        return false;
+    cx->addTypePropertyId(wrappedObject(wrapper)->getType(), id, *vp);
 
     // FIXME (bug 596351): Need deal with strict mode.
     SET(wrappedObject(wrapper)->setProperty(cx, id, vp, false));
 }
 
 bool
 JSWrapper::keys(JSContext *cx, JSObject *wrapper, AutoIdVector &props)
 {
@@ -624,18 +620,18 @@ Reify(JSContext *cx, JSCompartment *orig
     if (isKeyIter)
         return VectorToKeyIterator(cx, obj, ni->flags, keys, vp);
     return VectorToValueIterator(cx, obj, ni->flags, keys, vp); 
 }
 
 bool
 JSCrossCompartmentWrapper::iterate(JSContext *cx, JSObject *wrapper, uintN flags, Value *vp)
 {
-    if (!(flags & JSITER_OWNONLY) && !cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN))
-        return false;
+    if (!(flags & JSITER_OWNONLY))
+        cx->markTypeCallerUnexpected(types::TYPE_UNKNOWN);
 
     PIERCE(cx, wrapper, GET,
            NOTHING,
            JSWrapper::iterate(cx, wrapper, flags, vp),
            CanReify(vp) ? Reify(cx, call.origin, vp) : call.origin->wrap(cx, vp));
 }
 
 bool
--- a/js/src/jsxml.cpp
+++ b/js/src/jsxml.cpp
@@ -6857,17 +6857,18 @@ CopyXMLSettings(JSContext *cx, JSObject 
             return false;
         if (name == js_prettyIndent_str) {
             if (!JSVAL_IS_NUMBER(v))
                 continue;
         } else {
             if (!JSVAL_IS_BOOLEAN(v))
                 continue;
         }
-        if (!JS_AddTypeProperty(cx, to, name, v) || !JS_SetProperty(cx, to, name, &v))
+        JS_AddTypeProperty(cx, to, name, v);
+        if (!JS_SetProperty(cx, to, name, &v))
             return false;
     }
 
     return true;
 }
 
 static JSBool
 SetDefaultXMLSettings(JSContext *cx, JSObject *obj)
@@ -7150,21 +7151,20 @@ js_InitQNameClass(JSContext *cx, JSObjec
 {
     JSObject *proto = js_InitClass(cx, obj, NULL, &js_QNameClass, QName, 2, JS_TypeHandlerDynamic,
                                    qname_props, qname_methods, NULL, NULL);
     if (!proto)
         return NULL;
 
     /* Properties of QName objects are not modeled by type inference. */
     TypeObject *type = proto->getNewType(cx);
-    if (!type ||
-        !cx->markTypeObjectUnknownProperties(type) ||
-        !cx->markTypeObjectUnknownProperties(proto->getType())) {
+    if (!type)
         return NULL;
-    }
+    cx->markTypeObjectUnknownProperties(type);
+    cx->markTypeObjectUnknownProperties(proto->getType());
 
     return proto;
 }
 
 JSObject *
 js_InitXMLClass(JSContext *cx, JSObject *obj)
 {
     JSObject *proto, *pobj;
@@ -7183,21 +7183,20 @@ js_InitXMLClass(JSContext *cx, JSObject 
     proto = js_InitClass(cx, obj, NULL, &js_XMLClass, XML, 1, JS_TypeHandlerDynamic,
                          NULL, xml_methods,
                          xml_static_props, xml_static_methods);
     if (!proto)
         return NULL;
 
     /* Properties of XML objects are not modeled by type inference. */
     TypeObject *type = proto->getNewType(cx);
-    if (!type ||
-        !cx->markTypeObjectUnknownProperties(type) ||
-        !cx->markTypeObjectUnknownProperties(proto->getType())) {
+    if (!type)
         return NULL;
-    }
+    cx->markTypeObjectUnknownProperties(type);
+    cx->markTypeObjectUnknownProperties(proto->getType());
 
     xml = js_NewXML(cx, JSXML_CLASS_TEXT);
     if (!xml)
         return NULL;
     proto->setPrivate(xml);
     xml->object = proto;
     METER(xml_stats.xmlobj);
 
@@ -7312,18 +7311,17 @@ js_GetDefaultXMLNamespace(JSContext *cx,
             return JS_FALSE;
         if (!JSVAL_IS_PRIMITIVE(v)) {
             *vp = v;
             return JS_TRUE;
         }
         obj = tmp;
     }
 
-    if (!cx->addTypePropertyId(obj->getType(), JS_DEFAULT_XML_NAMESPACE_ID, types::TYPE_UNKNOWN))
-        return JS_FALSE;
+    cx->addTypePropertyId(obj->getType(), JS_DEFAULT_XML_NAMESPACE_ID, types::TYPE_UNKNOWN);
 
     ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, obj, 0, NULL);
     if (!ns)
         return JS_FALSE;
     v = OBJECT_TO_JSVAL(ns);
     if (!obj->defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, Valueify(v),
                              PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
@@ -7339,18 +7337,17 @@ js_SetDefaultXMLNamespace(JSContext *cx,
     argv[0].setString(cx->runtime->emptyString);
     argv[1] = v;
     JSObject *ns = js_ConstructObject(cx, &js_NamespaceClass, NULL, NULL, 2, argv);
     if (!ns)
         return JS_FALSE;
 
     JSObject &varobj = cx->stack.currentVarObj();
 
-    if (!cx->addTypePropertyId(varobj.getType(), JS_DEFAULT_XML_NAMESPACE_ID, types::TYPE_UNKNOWN))
-        return JS_FALSE;
+    cx->addTypePropertyId(varobj.getType(), JS_DEFAULT_XML_NAMESPACE_ID, types::TYPE_UNKNOWN);
     if (!varobj.defineProperty(cx, JS_DEFAULT_XML_NAMESPACE_ID, ObjectValue(*ns),
                                PropertyStub, StrictPropertyStub, JSPROP_PERMANENT)) {
         return JS_FALSE;
     }
     return JS_TRUE;
 }
 
 JSBool
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -85,26 +85,23 @@ static const char *OpcodeNames[] = {
 #endif
 
 /*
  * Number of times a script must be called or had a backedge before we try to
  * inline its calls.
  */
 static const size_t CALLS_BACKEDGES_BEFORE_INLINING = 10000;
 
-mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing,
-                         const Vector<PatchableFrame> *patchFrames)
+mjit::Compiler::Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing)
   : BaseCompiler(cx),
     outerScript(outerScript),
     isConstructing(isConstructing),
     ssa(cx, outerScript),
     globalObj(outerScript->global),
     globalSlots((globalObj && globalObj->isGlobal()) ? globalObj->getRawSlots() : NULL),
-    patchFrames(patchFrames),
-    savedTraps(NULL),
     frame(cx, *thisFromCtor(), masm, stubcc),
     a(NULL), outer(NULL), script(NULL), PC(NULL), loop(NULL),
     inlineFrames(CompilerAllocPolicy(cx, *thisFromCtor())),
     branchPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
 #if defined JS_MONOIC
     getGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     setGlobalNames(CompilerAllocPolicy(cx, *thisFromCtor())),
     callICs(CompilerAllocPolicy(cx, *thisFromCtor())),
@@ -113,17 +110,16 @@ mjit::Compiler::Compiler(JSContext *cx, 
 #endif
 #if defined JS_POLYIC
     pics(CompilerAllocPolicy(cx, *thisFromCtor())), 
     getElemICs(CompilerAllocPolicy(cx, *thisFromCtor())),
     setElemICs(CompilerAllocPolicy(cx, *thisFromCtor())),
 #endif
     callPatches(CompilerAllocPolicy(cx, *thisFromCtor())),
     callSites(CompilerAllocPolicy(cx, *thisFromCtor())),
-    rejoinSites(CompilerAllocPolicy(cx, *thisFromCtor())),
     doubleList(CompilerAllocPolicy(cx, *thisFromCtor())),
     fixedDoubleEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
     jumpTables(CompilerAllocPolicy(cx, *thisFromCtor())),
     jumpTableOffsets(CompilerAllocPolicy(cx, *thisFromCtor())),
     loopEntries(CompilerAllocPolicy(cx, *thisFromCtor())),
     stubcc(cx, *thisFromCtor(), frame),
     debugMode_(cx->compartment->debugMode),
 #if defined JS_TRACER
@@ -172,18 +168,18 @@ mjit::Compiler::compile()
         // just need a pointer so the VM can quickly decide whether this
         // method can be JIT'd or not. Global scripts cannot be IC'd, since
         // they have no functions, so there is no danger.
         *checkAddr = (*jit)->arityCheckEntry
                      ? (*jit)->arityCheckEntry
                      : (*jit)->invokeEntry;
     } else {
         *checkAddr = JS_UNJITTABLE_SCRIPT;
-        if (outerScript->fun && !cx->markTypeFunctionUninlineable(outerScript->fun->getType()))
-            return Compile_Error;
+        if (outerScript->fun)
+            cx->markTypeFunctionUninlineable(outerScript->fun->getType());
     }
 
     return status;
 }
 
 CompileStatus
 mjit::Compiler::checkAnalysis(JSScript *script)
 {
@@ -522,54 +518,16 @@ mjit::Compiler::performCompilation(JITSc
 #endif
 
     JaegerSpew(JSpew_Scripts, "successfully compiled (code \"%p\") (size \"%ld\")\n",
                (*jitp)->code.m_code.executableAddress(), (*jitp)->code.m_size);
 
     if (!*jitp)
         return Compile_Abort;
 
-    /*
-     * Make sure any inlined scripts have JIT code associated with all rejoin
-     * points added, so we can always expand the inlined frames.
-     */
-    bool expanded = false;
-    for (unsigned i = 0; i < (*jitp)->nInlineFrames; i++) {
-        JSScript *script = (*jitp)->inlineFrames()[i].fun->script();
-
-        script->inlineParents = true;
-
-        /* We should have bailed out while inlining if the script is unjittable. */
-        JS_ASSERT(script->jitArityCheckNormal != JS_UNJITTABLE_SCRIPT);
-
-        if (script->jitNormal && !script->jitNormal->rejoinPoints) {
-            if (!expanded) {
-                ExpandInlineFrames(cx, true);
-                expanded = true;
-            }
-            mjit::Recompiler recompiler(cx, script);
-            if (!recompiler.recompile()) {
-                ReleaseScriptCode(cx, outerScript, true);
-                return Compile_Error;
-            }
-        }
-
-        if (!script->jitNormal) {
-            CompileStatus status = Compile_Retry;
-            while (status == Compile_Retry) {
-                mjit::Compiler cc(cx, script, isConstructing, NULL);
-                status = cc.compile();
-            }
-            if (status != Compile_Okay) {
-                ReleaseScriptCode(cx, outerScript, true);
-                return status;
-            }
-        }
-    }
-
     return Compile_Okay;
 }
 
 #undef CHECK_STATUS
 
 mjit::Compiler::ActiveFrame::ActiveFrame(JSContext *cx)
     : parent(NULL), parentPC(NULL), script(NULL), jumpMap(NULL),
       inlineIndex(uint32(-1)), needReturnValue(false), syncReturnValue(false),
@@ -583,18 +541,16 @@ mjit::Compiler::ActiveFrame::~ActiveFram
 }
 
 mjit::Compiler::~Compiler()
 {
     if (outer)
         cx->delete_(outer);
     for (unsigned i = 0; i < inlineFrames.length(); i++)
         cx->delete_(inlineFrames[i]);
-
-    cx->free_(savedTraps);
 }
 
 CompileStatus
 mjit::Compiler::prepareInferenceTypes(JSScript *script, ActiveFrame *a)
 {
     /*
      * During our walk of the script, we need to preserve the invariant that at
      * join points the in memory type tag is always in sync with the known type
@@ -652,41 +608,23 @@ mjit::TryCompile(JSContext *cx, StackFra
 
     types::AutoEnterTypeInference enter(cx, true);
 
     // If there were recoverable compilation failures in the function from
     // static overflow or bad inline callees, try recompiling a few times
     // before giving up.
     CompileStatus status = Compile_Retry;
     for (unsigned i = 0; status == Compile_Retry && i < 5; i++) {
-        Compiler cc(cx, fp->script(), fp->isConstructing(), NULL);
+        Compiler cc(cx, fp->script(), fp->isConstructing());
         status = cc.compile();
     }
 
     return status;
 }
 
-bool
-mjit::Compiler::loadOldTraps(const Vector<CallSite> &sites)
-{
-    savedTraps = (bool *)cx->calloc_(sizeof(bool) * outerScript->length);
-    if (!savedTraps)
-        return false;
-    
-    for (size_t i = 0; i < sites.length(); i++) {
-        const CallSite &site = sites[i];
-        if (site.isTrap()) {
-            JS_ASSERT(site.inlineIndex == uint32(-1) && site.pcOffset < outerScript->length);
-            savedTraps[site.pcOffset] = true;
-        }
-    }
-
-    return true;
-}
-
 CompileStatus
 mjit::Compiler::generatePrologue()
 {
     invokeLabel = masm.label();
 
     /*
      * If there is no function, then this can only be called via JaegerShot(),
      * which expects an existing frame to be initialized like the interpreter.
@@ -701,18 +639,16 @@ mjit::Compiler::generatePrologue()
         invokeLabel = masm.label();
 
         Label fastPath = masm.label();
 
         /* Store this early on so slow paths can access it. */
         masm.storePtr(ImmPtr(script->fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
 
         {
-            REJOIN_SITE(stubs::CheckArgumentTypes);
-
             /*
              * Entry point #3: The caller has partially constructed a frame,
              * but argc might be != nargs, so an arity check might be called.
              *
              * This loops back to entry point #2.
              */
             arityLabel = stubcc.masm.label();
 
@@ -720,29 +656,29 @@ mjit::Compiler::generatePrologue()
                                                  Imm32(script->fun->nargs));
 
             if (JSParamReg_Argc != Registers::ArgReg1)
                 stubcc.masm.move(JSParamReg_Argc, Registers::ArgReg1);
 
             /* Slow path - call the arity check function. Returns new fp. */
             stubcc.masm.storePtr(ImmPtr(script->fun),
                                  Address(JSFrameReg, StackFrame::offsetOfExec()));
-            OOL_STUBCALL_NO_REJOIN(stubs::FixupArity);
+            OOL_STUBCALL(stubs::FixupArity, REJOIN_NONE);
             stubcc.masm.move(Registers::ReturnReg, JSFrameReg);
             argMatch.linkTo(stubcc.masm.label(), &stubcc.masm);
 
             /* Type check the arguments as well. */
             if (cx->typeInferenceEnabled()) {
 #ifdef JS_MONOIC
                 this->argsCheckJump = stubcc.masm.jump();
                 this->argsCheckStub = stubcc.masm.label();
                 this->argsCheckJump.linkTo(this->argsCheckStub, &stubcc.masm);
 #endif
                 stubcc.masm.storePtr(ImmPtr(script->fun), Address(JSFrameReg, StackFrame::offsetOfExec()));
-                OOL_STUBCALL(stubs::CheckArgumentTypes);
+                OOL_STUBCALL(stubs::CheckArgumentTypes, REJOIN_CHECK_ARGUMENTS);
 #ifdef JS_MONOIC
                 this->argsCheckFallthrough = stubcc.masm.label();
 #endif
             }
 
             stubcc.crossJump(stubcc.masm.jump(), fastPath);
         }
 
@@ -755,17 +691,17 @@ mjit::Compiler::generatePrologue()
         uint32 nvals = script->nslots + VALUES_PER_STACK_FRAME + StackSpace::STACK_EXTRA;
         masm.addPtr(Imm32(nvals * sizeof(Value)), JSFrameReg, Registers::ReturnReg);
         Jump stackCheck = masm.branchPtr(Assembler::AboveOrEqual, Registers::ReturnReg,
                                          FrameAddress(offsetof(VMFrame, stackLimit)));
 
         /* If the stack check fails... */
         {
             stubcc.linkExitDirect(stackCheck, stubcc.masm.label());
-            OOL_STUBCALL_NO_REJOIN(stubs::HitStackQuota);
+            OOL_STUBCALL(stubs::HitStackQuota, REJOIN_NONE);
             stubcc.crossJump(stubcc.masm.jump(), masm.label());
         }
 
         /*
          * Set locals to undefined, as in initCallFrameLatePrologue.
          * Skip locals which aren't closed and are known to be defined before used,
          * :FIXME: bug 604541: write undefined if we might be using the tracer, so it works.
          */
@@ -774,17 +710,17 @@ mjit::Compiler::generatePrologue()
                 Address local(JSFrameReg, sizeof(StackFrame) + i * sizeof(Value));
                 masm.storeValue(UndefinedValue(), local);
             }
         }
 
         /* Create the call object. */
         if (script->fun->isHeavyweight()) {
             prepareStubCall(Uses(0));
-            INLINE_STUBCALL_NO_REJOIN(stubs::CreateFunCallObject);
+            INLINE_STUBCALL(stubs::CreateFunCallObject, REJOIN_NONE);
         }
 
         j.linkTo(masm.label(), &masm);
 
         if (analysis->usesScopeChain() && !script->fun->isHeavyweight()) {
             /*
              * Load the scope chain into the frame if necessary.  The scope chain
              * is always set for global and eval frames, and will have been set by
@@ -798,20 +734,18 @@ mjit::Compiler::generatePrologue()
             masm.storePtr(t0, Address(JSFrameReg, StackFrame::offsetOfScopeChain()));
             hasScope.linkTo(masm.label(), &masm);
         }
     }
 
     if (isConstructing)
         constructThis();
 
-    if (debugMode() || Probes::callTrackingActive(cx)) {
-        REJOIN_SITE(stubs::ScriptDebugPrologue);
-        INLINE_STUBCALL(stubs::ScriptDebugPrologue);
-    }
+    if (debugMode() || Probes::callTrackingActive(cx))
+        INLINE_STUBCALL(stubs::ScriptDebugPrologue, REJOIN_RESUME);
 
     if (cx->typeInferenceEnabled()) {
         /* Convert integer arguments which were inferred as (int|double) to doubles. */
         for (uint32 i = 0; script->fun && i < script->fun->nargs; i++) {
             uint32 slot = ArgSlot(i);
             if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE && analysis->trackSlot(slot))
                 frame.ensureDouble(frame.getArg(i));
         }
@@ -882,17 +816,16 @@ mjit::Compiler::finishThisUp(JITScript *
         }
     }
 
     /* Please keep in sync with JITScript::scriptDataSize! */
     size_t totalBytes = sizeof(JITScript) +
                         sizeof(NativeMapEntry) * nNmapLive +
                         sizeof(InlineFrame) * inlineFrames.length() +
                         sizeof(CallSite) * callSites.length() +
-                        sizeof(RejoinSite) * rejoinSites.length() +
 #if defined JS_MONOIC
                         sizeof(ic::GetGlobalNameIC) * getGlobalNames.length() +
                         sizeof(ic::SetGlobalNameIC) * setGlobalNames.length() +
                         sizeof(ic::CallICInfo) * callICs.length() +
                         sizeof(ic::EqualityICInfo) * equalityICs.length() +
                         sizeof(ic::TraceICInfo) * traceICs.length() +
 #endif
 #if defined JS_POLYIC
@@ -913,17 +846,16 @@ mjit::Compiler::finishThisUp(JITScript *
     cursor += sizeof(JITScript);
 
     JS_ASSERT(outerScript == script);
 
     jit->script = script;
     jit->code = JSC::MacroAssemblerCodeRef(result, execPool, masm.size() + stubcc.size());
     jit->invokeEntry = result;
     jit->singleStepMode = script->singleStepMode;
-    jit->rejoinPoints = script->inlineParents;
     if (script->fun) {
         jit->arityCheckEntry = stubCode.locationOf(arityLabel).executableAddress();
         jit->fastEntry = fullCode.locationOf(invokeLabel).executableAddress();
     }
 
     /* 
      * WARNING: mics(), callICs() et al depend on the ordering of these
      * variable-length sections.  See JITScript's declaration for details.
@@ -984,71 +916,43 @@ mjit::Compiler::finishThisUp(JITScript *
     /* Build the table of call sites. */
     CallSite *jitCallSites = (CallSite *)cursor;
     jit->nCallSites = callSites.length();
     cursor += sizeof(CallSite) * jit->nCallSites;
     for (size_t i = 0; i < jit->nCallSites; i++) {
         CallSite &to = jitCallSites[i];
         InternalCallSite &from = callSites[i];
 
-        /*
-         * Make sure that we emitted rejoin sites for at least the calls in
-         * this compilation. This doesn't ensure we have rejoin sites for
-         * calls emitted in *other* compilations, but catches many of the
-         * cases we have insufficient code for rejoining.
-         */
-        JS_ASSERT_IF(cx->typeInferenceEnabled(), !from.needsRejoin);
-
         /* Patch stores of f.regs.inlined for stubs called from within inline frames. */
         if (cx->typeInferenceEnabled() &&
-            from.id != CallSite::NCODE_RETURN_ID &&
-            from.id != CallSite::MAGIC_TRAP_ID &&
+            from.rejoin != REJOIN_TRAP &&
+            from.rejoin != REJOIN_SCRIPTED &&
             from.inlineIndex != uint32(-1)) {
             if (from.ool)
                 stubCode.patch(from.inlinePatch, &to);
             else
                 fullCode.patch(from.inlinePatch, &to);
         }
 
         JSScript *script =
             (from.inlineIndex == uint32(-1)) ? outerScript : inlineFrames[from.inlineIndex]->script;
         uint32 codeOffset = from.ool
                             ? masm.size() + from.returnOffset
                             : from.returnOffset;
-        to.initialize(codeOffset, from.inlineIndex, from.inlinepc - script->code, from.id);
+        to.initialize(codeOffset, from.inlineIndex, from.inlinepc - script->code, from.rejoin);
 
         /*
          * Patch stores of the base call's return address for InvariantFailure
          * calls. InvariantFailure will patch its own return address to this
          * pointer before triggering recompilation.
          */
         if (from.loopPatch.hasPatch)
             stubCode.patch(from.loopPatch.codePatch, result + codeOffset);
     }
 
-    /* Build the table of rejoin sites. */
-    RejoinSite *jitRejoinSites = (RejoinSite *)cursor;
-    jit->nRejoinSites = rejoinSites.length();
-    cursor += sizeof(RejoinSite) * jit->nRejoinSites;
-    for (size_t i = 0; i < jit->nRejoinSites; i++) {
-        RejoinSite &to = jitRejoinSites[i];
-        InternalRejoinSite &from = rejoinSites[i];
-
-        uint32 codeOffset = (uint8 *) stubCode.locationOf(from.label).executableAddress() - result;
-        to.initialize(codeOffset, from.pc - outerScript->code, from.id);
-
-        /*
-         * Patch stores of the rejoin site's return address for InvariantFailure
-         * calls. We need to preserve the rejoin site we were at in case of
-         * cascading recompilations and loop invariant failures.
-         */
-        if (from.loopPatch.hasPatch)
-            stubCode.patch(from.loopPatch.codePatch, result + codeOffset);
-    }
-
 #if defined JS_MONOIC
     JS_INIT_CLIST(&jit->callers);
 
     if (script->fun && cx->typeInferenceEnabled()) {
         jit->argsCheckStub = stubCode.locationOf(argsCheckStub);
         jit->argsCheckFallthrough = stubCode.locationOf(argsCheckFallthrough);
         jit->argsCheckJump = stubCode.locationOf(argsCheckJump);
         jit->argsCheckPool = NULL;
@@ -1538,58 +1442,21 @@ mjit::Compiler::generateMethod()
         }
 
         a->jumpMap[uint32(PC - script->code)] = masm.label();
 
         SPEW_OPCODE();
         JS_ASSERT(frame.stackDepth() == opinfo->stackDepth);
 
         if (trap) {
-            REJOIN_SITE(CallSite::MAGIC_TRAP_ID);
             prepareStubCall(Uses(0));
             masm.move(Imm32(trap), Registers::ArgReg1);
             Call cl = emitStubCall(JS_FUNC_TO_DATA_PTR(void *, stubs::Trap), NULL);
             InternalCallSite site(masm.callReturnOffset(cl), a->inlineIndex, PC,
-                                  CallSite::MAGIC_TRAP_ID, false, true);
-            addCallSite(site);
-        } else if (!a->parent && savedTraps && savedTraps[PC - script->code]) {
-            // Normally when we patch return addresses, we have generated the
-            // same exact code at that site. For example, patching a stub call's
-            // return address will resume at the same stub call.
-            //
-            // In the case we're handling here, we could potentially be
-            // recompiling to remove a trap, and therefore we won't generate
-            // a call to the trap. However, we could be re-entering from that
-            // trap. The callsite will be missing, and fixing the stack will
-            // fail! Worse, we can't just put a label here, because on some
-            // platforms the stack needs to be adjusted when returning from
-            // the old trap call.
-            //
-            // To deal with this, we add a small bit of code in the OOL path
-            // that will adjust the stack and jump back into the script.
-            // Note that this uses MAGIC_TRAP_ID, which is necessary for
-            // repatching to detect the callsite as identical to the return
-            // address.
-            //
-            // Unfortunately, this means that if a bytecode is ever trapped,
-            // we will always generate a CallSite (either Trapped or not) for
-            // every debug recompilation of the script thereafter. The reason
-            // is that MAGIC_TRAP_ID callsites always propagate to the next
-            // recompilation. That's okay, and not worth fixing - it's a small
-            // amount of memory.
-            REJOIN_SITE(CallSite::MAGIC_TRAP_ID);
-            uint32 offset = stubcc.masm.distanceOf(stubcc.masm.label());
-            if (Assembler::ReturnStackAdjustment) {
-                stubcc.masm.addPtr(Imm32(Assembler::ReturnStackAdjustment),
-                                   Assembler::stackPointerRegister);
-            }
-            stubcc.crossJump(stubcc.masm.jump(), masm.label());
-
-            InternalCallSite site(offset, a->inlineIndex, PC,
-                                  CallSite::MAGIC_TRAP_ID, true, true);
+                                  REJOIN_TRAP, false);
             addCallSite(site);
         }
 
     /**********************
      * BEGIN COMPILER OPS *
      **********************/ 
 
         jsbytecode *oldPC = PC;
@@ -1766,58 +1633,51 @@ mjit::Compiler::generateMethod()
             FrameEntry *lhs = frame.peek(-2);
 
             /* Check for easy cases that the parser does not constant fold. */
             if (lhs->isConstant() && rhs->isConstant()) {
                 /* Primitives can be trivially constant folded. */
                 const Value &lv = lhs->getValue();
                 const Value &rv = rhs->getValue();
 
-                AutoRejoinSite autoRejoin(this, (void *) RejoinSite::VARIADIC_ID);
-
                 if (lv.isPrimitive() && rv.isPrimitive()) {
                     bool result = compareTwoValues(cx, op, lv, rv);
 
                     frame.pop();
                     frame.pop();
 
                     if (!target) {
                         frame.push(Value(BooleanValue(result)));
                     } else {
                         if (fused == JSOP_IFEQ)
                             result = !result;
 
                         if (result) {
                             fixDoubleTypes(target);
                             if (!frame.syncForBranch(target, Uses(0)))
                                 return Compile_Error;
-                            if (needRejoins(PC)) {
-                                autoRejoin.oolRejoin(stubcc.masm.label());
-                                stubcc.rejoin(Changes(0));
-                            }
                             Jump j = masm.jump();
                             if (!jumpAndTrace(j, target))
                                 return Compile_Error;
                         } else {
                             /*
                              * Branch is never taken, but clean up any loop
                              * if this is a backedge.
                              */
                             if (target < PC && !finishLoop(target))
                                 return Compile_Error;
                         }
                     }
                 } else {
-                    if (!emitStubCmpOp(stub, autoRejoin, target, fused))
+                    if (!emitStubCmpOp(stub, target, fused))
                         return Compile_Error;
                 }
             } else {
                 /* Anything else should go through the fast path generator. */
-                AutoRejoinSite autoRejoin(this, (void *) RejoinSite::VARIADIC_ID);
-                if (!jsop_relational(op, stub, autoRejoin, target, fused))
+                if (!jsop_relational(op, stub, target, fused))
                     return Compile_Error;
             }
 
             /* Advance PC manually. */
             JS_STATIC_ASSERT(JSOP_LT_LENGTH == JSOP_GE_LENGTH);
             JS_STATIC_ASSERT(JSOP_LE_LENGTH == JSOP_GE_LENGTH);
             JS_STATIC_ASSERT(JSOP_GT_LENGTH == JSOP_GE_LENGTH);
             JS_STATIC_ASSERT(JSOP_EQ_LENGTH == JSOP_GE_LENGTH);
@@ -1885,17 +1745,16 @@ mjit::Compiler::generateMethod()
             } else {
                 jsop_bitnot();
             }
           }
           END_CASE(JSOP_BITNOT)
 
           BEGIN_CASE(JSOP_NEG)
           {
-            REJOIN_SITE(stubs::Neg);
             FrameEntry *top = frame.peek(-1);
             if (top->isConstant() && top->getValue().isPrimitive()) {
                 double d;
                 ValueToNumber(cx, top->getValue(), &d);
                 d = -d;
                 Value v = NumberValue(d);
 
                 /* Watch for overflow in constant propagation. */
@@ -1914,46 +1773,43 @@ mjit::Compiler::generateMethod()
           END_CASE(JSOP_NEG)
 
           BEGIN_CASE(JSOP_POS)
             jsop_pos();
           END_CASE(JSOP_POS)
 
           BEGIN_CASE(JSOP_DELNAME)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             JSAtom *atom = script->getAtom(index);
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(atom), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::DelName);
+            INLINE_STUBCALL(stubs::DelName, REJOIN_FALLTHROUGH);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELNAME)
 
           BEGIN_CASE(JSOP_DELPROP)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             JSAtom *atom = script->getAtom(index);
 
             prepareStubCall(Uses(1));
             masm.move(ImmPtr(atom), Registers::ArgReg1);
-            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelProp));
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelProp), REJOIN_FALLTHROUGH);
             frame.pop();
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELPROP) 
 
           BEGIN_CASE(JSOP_DELELEM)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(2));
-            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelElem));
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DelElem), REJOIN_FALLTHROUGH);
             frame.popn(2);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_DELELEM)
 
           BEGIN_CASE(JSOP_TYPEOF)
           BEGIN_CASE(JSOP_TYPEOFEXPR)
             jsop_typeof();
@@ -1964,116 +1820,104 @@ mjit::Compiler::generateMethod()
             frame.push(UndefinedValue());
           END_CASE(JSOP_VOID)
 
           BEGIN_CASE(JSOP_INCNAME)
           {
             CompileStatus status = jsop_nameinc(op, STRICT_VARIANT(stubs::IncName), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_INCNAME)
 
           BEGIN_CASE(JSOP_INCGNAME)
             if (!jsop_gnameinc(op, STRICT_VARIANT(stubs::IncGlobalName), fullAtomIndex(PC)))
                 return Compile_Retry;
-            break;
           END_CASE(JSOP_INCGNAME)
 
           BEGIN_CASE(JSOP_INCPROP)
           {
             CompileStatus status = jsop_propinc(op, STRICT_VARIANT(stubs::IncProp), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_INCPROP)
 
           BEGIN_CASE(JSOP_INCELEM)
             jsop_eleminc(op, STRICT_VARIANT(stubs::IncElem));
           END_CASE(JSOP_INCELEM)
 
           BEGIN_CASE(JSOP_DECNAME)
           {
             CompileStatus status = jsop_nameinc(op, STRICT_VARIANT(stubs::DecName), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_DECNAME)
 
           BEGIN_CASE(JSOP_DECGNAME)
             if (!jsop_gnameinc(op, STRICT_VARIANT(stubs::DecGlobalName), fullAtomIndex(PC)))
                 return Compile_Retry;
-            break;
           END_CASE(JSOP_DECGNAME)
 
           BEGIN_CASE(JSOP_DECPROP)
           {
             CompileStatus status = jsop_propinc(op, STRICT_VARIANT(stubs::DecProp), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_DECPROP)
 
           BEGIN_CASE(JSOP_DECELEM)
             jsop_eleminc(op, STRICT_VARIANT(stubs::DecElem));
           END_CASE(JSOP_DECELEM)
 
           BEGIN_CASE(JSOP_NAMEINC)
           {
             CompileStatus status = jsop_nameinc(op, STRICT_VARIANT(stubs::NameInc), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_NAMEINC)
 
           BEGIN_CASE(JSOP_GNAMEINC)
             if (!jsop_gnameinc(op, STRICT_VARIANT(stubs::GlobalNameInc), fullAtomIndex(PC)))
                 return Compile_Retry;
-            break;
           END_CASE(JSOP_GNAMEINC)
 
           BEGIN_CASE(JSOP_PROPINC)
           {
             CompileStatus status = jsop_propinc(op, STRICT_VARIANT(stubs::PropInc), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_PROPINC)
 
           BEGIN_CASE(JSOP_ELEMINC)
             jsop_eleminc(op, STRICT_VARIANT(stubs::ElemInc));
           END_CASE(JSOP_ELEMINC)
 
           BEGIN_CASE(JSOP_NAMEDEC)
           {
             CompileStatus status = jsop_nameinc(op, STRICT_VARIANT(stubs::NameDec), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_NAMEDEC)
 
           BEGIN_CASE(JSOP_GNAMEDEC)
             if (!jsop_gnameinc(op, STRICT_VARIANT(stubs::GlobalNameDec), fullAtomIndex(PC)))
                 return Compile_Retry;
-            break;
           END_CASE(JSOP_GNAMEDEC)
 
           BEGIN_CASE(JSOP_PROPDEC)
           {
             CompileStatus status = jsop_propinc(op, STRICT_VARIANT(stubs::PropDec), fullAtomIndex(PC));
             if (status != Compile_Okay)
                 return status;
-            break;
           }
           END_CASE(JSOP_PROPDEC)
 
           BEGIN_CASE(JSOP_ELEMDEC)
             jsop_eleminc(op, STRICT_VARIANT(stubs::ElemDec));
           END_CASE(JSOP_ELEMDEC)
 
           BEGIN_CASE(JSOP_GETPROP)
@@ -2094,50 +1938,41 @@ mjit::Compiler::generateMethod()
             bool pop = (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next));
             if (!jsop_setelem(pop))
                 return Compile_Error;
           }
           END_CASE(JSOP_SETELEM);
 
           BEGIN_CASE(JSOP_CALLNAME)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             prepareStubCall(Uses(0));
             masm.move(Imm32(index), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::CallName);
+            INLINE_STUBCALL(stubs::CallName, REJOIN_FALLTHROUGH);
             pushSyncedEntry(0);
             pushSyncedEntry(1);
             frame.extra(frame.peek(-2)).name = script->getAtom(index);
           }
           END_CASE(JSOP_CALLNAME)
 
           BEGIN_CASE(JSOP_EVAL)
           {
-            REJOIN_SITE_ANY();
             JaegerSpew(JSpew_Insns, " --- EVAL --- \n");
             emitEval(GET_ARGC(PC));
             JaegerSpew(JSpew_Insns, " --- END EVAL --- \n");
           }
           END_CASE(JSOP_EVAL)
 
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_NEW)
           BEGIN_CASE(JSOP_FUNAPPLY)
           BEGIN_CASE(JSOP_FUNCALL)
           {
-            REJOIN_SITE_ANY();
-          {
             bool callingNew = (op == JSOP_NEW);
 
-            AutoRejoinSite autoRejoinCall(this,
-                JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call),
-                JS_FUNC_TO_DATA_PTR(void *, callingNew ? stubs::UncachedNew : stubs::UncachedCall));
-            AutoRejoinSite autoRejoinNcode(this, (void *) CallSite::NCODE_RETURN_ID);
-
             bool done = false;
             bool inlined = false;
             if (op == JSOP_CALL) {
                 CompileStatus status = inlineNativeFunction(GET_ARGC(PC), callingNew);
                 if (status == Compile_Okay)
                     done = true;
                 else if (status != Compile_InlineAbort)
                     return status;
@@ -2155,87 +1990,17 @@ mjit::Compiler::generateMethod()
             FrameSize frameSize;
             frameSize.initStatic(frame.totalDepth(), GET_ARGC(PC));
 
             if (!done) {
                 JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n");
                 inlineCallHelper(GET_ARGC(PC), callingNew, frameSize);
                 JaegerSpew(JSpew_Insns, " --- END SCRIPTED CALL --- \n");
             }
-
-            /*
-             * Generate skeleton rejoin paths for calls which either triggered
-             * a recompilation while compiling or within a scripted call.
-             * We always need this rejoin if we inlined frames at this site,
-             * in case we end up expanding those frames. Note that the ncode
-             * join is in the slow path, which will break nativeCodeForPC and
-             * keep us from computing the implicit prevpc/prevInline for the
-             * next frame. All next frames manipulated here must have had these
-             * set explicitly when they were pushed by a stub, expanded or
-             * redirected by a recompilation.
-             */
-            if (needRejoins(PC) || inlined) {
-                if (inlined)
-                    autoRejoinNcode.forceGeneration();
-
-                autoRejoinCall.oolRejoin(stubcc.masm.label());
-                Jump fallthrough = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
-                                                             Registers::ReturnReg);
-                if (frameSize.isStatic())
-                    stubcc.masm.move(Imm32(frameSize.staticArgc()), JSParamReg_Argc);
-                else
-                    stubcc.masm.load32(FrameAddress(offsetof(VMFrame, u.call.dynamicArgc)), JSParamReg_Argc);
-                stubcc.masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), JSFrameReg);
-
-                CallPatchInfo callPatch;
-                callPatch.hasSlowNcode = true;
-                callPatch.slowNcodePatch =
-                    stubcc.masm.storePtrWithPatch(ImmPtr(NULL),
-                                                  Address(JSFrameReg, StackFrame::offsetOfNcode()));
-                stubcc.masm.jump(Registers::ReturnReg);
-
-                callPatch.joinPoint = stubcc.masm.label();
-                callPatch.joinSlow = true;
-
-                addReturnSite(true /* ool */);
-
-                autoRejoinNcode.oolRejoin(stubcc.masm.label());
-
-                /*
-                 * Watch for lowered calls and applies, which behave differently
-                 * from every other rejoin path in JM and require the return
-                 * value to be loaded from a different address.
-                 */
-                bool loweredCallApply =
-                    (frameSize.isDynamic() || frameSize.staticArgc() != GET_ARGC(PC));
-                Address address = frame.addressOf(frame.peek(-1));
-                if (loweredCallApply) {
-                    frame.pushSynced(JSVAL_TYPE_UNKNOWN);
-                    address = frame.addressOf(frame.peek(-1));
-                    frame.pop();
-                }
-
-                stubcc.masm.storeValueFromComponents(JSReturnReg_Type, JSReturnReg_Data, address);
-                fallthrough.linkTo(stubcc.masm.label(), &stubcc.masm);
-
-                /*
-                 * We can't just reload from the return address as inlineCallHelper
-                 * does, as if we inlined a call here there may be other registers
-                 * that need to be reloaded.
-                 */
-                if (loweredCallApply) {
-                    frame.reloadEntry(stubcc.masm, address, frame.peek(-1));
-                    stubcc.crossJump(stubcc.masm.jump(), masm.label());
-                } else {
-                    stubcc.rejoin(Changes(1));
-                }
-
-                callPatches.append(callPatch);
-            }
-          } }
+          }
           END_CASE(JSOP_CALL)
 
           BEGIN_CASE(JSOP_NAME)
           {
             JSAtom *atom = script->getAtom(fullAtomIndex(PC));
             jsop_name(atom, knownPushedType(0));
             frame.extra(frame.peek(-1)).name = atom;
           }
@@ -2291,34 +2056,34 @@ mjit::Compiler::generateMethod()
              * double types, as we don't track types of slots in scripts with
              * switch statements (could be fixed).
              */
 #if defined JS_CPU_ARM /* Need to implement jump(BaseIndex) for ARM */
             frame.syncAndKillEverything();
             masm.move(ImmPtr(PC), Registers::ArgReg1);
 
             /* prepareStubCall() is not needed due to syncAndForgetEverything() */
-            INLINE_STUBCALL_NO_REJOIN(stubs::TableSwitch);
+            INLINE_STUBCALL(stubs::TableSwitch, REJOIN_NONE);
             frame.pop();
 
             masm.jump(Registers::ReturnReg);
 #else
             if (!jsop_tableswitch(PC))
                 return Compile_Error;
 #endif
             PC += js_GetVariableBytecodeLength(PC);
             break;
           END_CASE(JSOP_TABLESWITCH)
 
           BEGIN_CASE(JSOP_LOOKUPSWITCH)
             frame.syncAndForgetEverything();
             masm.move(ImmPtr(PC), Registers::ArgReg1);
 
             /* prepareStubCall() is not needed due to syncAndForgetEverything() */
-            INLINE_STUBCALL_NO_REJOIN(stubs::LookupSwitch);
+            INLINE_STUBCALL(stubs::LookupSwitch, REJOIN_NONE);
             frame.pop();
 
             masm.jump(Registers::ReturnReg);
             PC += js_GetVariableBytecodeLength(PC);
             break;
           END_CASE(JSOP_LOOKUPSWITCH)
 
           BEGIN_CASE(JSOP_CASE)
@@ -2488,47 +2253,26 @@ mjit::Compiler::generateMethod()
             jsop_initelem();
             frame.popn(2);
           END_CASE(JSOP_INITELEM)
 
           BEGIN_CASE(JSOP_INCARG)
           BEGIN_CASE(JSOP_DECARG)
           BEGIN_CASE(JSOP_ARGINC)
           BEGIN_CASE(JSOP_ARGDEC)
-          {
-            jsbytecode *next = &PC[JSOP_ARGINC_LENGTH];
-            bool popped = false;
-            if (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next))
-                popped = true;
-            if (!jsop_arginc(op, GET_SLOTNO(PC), popped))
+            if (!jsop_arginc(op, GET_SLOTNO(PC)))
                 return Compile_Retry;
-            PC += JSOP_ARGINC_LENGTH;
-            if (popped)
-                PC += JSOP_POP_LENGTH;
-            break;
-          }
           END_CASE(JSOP_ARGDEC)
 
           BEGIN_CASE(JSOP_INCLOCAL)
           BEGIN_CASE(JSOP_DECLOCAL)
           BEGIN_CASE(JSOP_LOCALINC)
           BEGIN_CASE(JSOP_LOCALDEC)
-          {
-            jsbytecode *next = &PC[JSOP_LOCALINC_LENGTH];
-            bool popped = false;
-            if (JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next))
-                popped = true;
-            /* These manually advance the PC. */
-            if (!jsop_localinc(op, GET_SLOTNO(PC), popped))
+            if (!jsop_localinc(op, GET_SLOTNO(PC)))
                 return Compile_Retry;
-            PC += JSOP_LOCALINC_LENGTH;
-            if (popped)
-                PC += JSOP_POP_LENGTH;
-            break;
-          }
           END_CASE(JSOP_LOCALDEC)
 
           BEGIN_CASE(JSOP_FORNAME)
             jsop_forname(script->getAtom(fullAtomIndex(PC)));
           END_CASE(JSOP_FORNAME)
 
           BEGIN_CASE(JSOP_FORGNAME)
             jsop_forgname(script->getAtom(fullAtomIndex(PC)));
@@ -2564,41 +2308,39 @@ mjit::Compiler::generateMethod()
             bool pop = JSOp(*next) == JSOP_POP && !analysis->jumpTarget(next);
             if (!jsop_setprop(script->getAtom(fullAtomIndex(PC)), true, pop))
                 return Compile_Error;
           }
           END_CASE(JSOP_SETNAME)
 
           BEGIN_CASE(JSOP_THROW)
             prepareStubCall(Uses(1));
-            INLINE_STUBCALL_NO_REJOIN(stubs::Throw);
+            INLINE_STUBCALL(stubs::Throw, REJOIN_NONE);
             frame.pop();
           END_CASE(JSOP_THROW)
 
           BEGIN_CASE(JSOP_IN)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(2));
-            INLINE_STUBCALL(stubs::In);
+            INLINE_STUBCALL(stubs::In, REJOIN_PUSH_BOOLEAN);
             frame.popn(2);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg);
           }
           END_CASE(JSOP_IN)
 
           BEGIN_CASE(JSOP_INSTANCEOF)
             if (!jsop_instanceof())
                 return Compile_Error;
           END_CASE(JSOP_INSTANCEOF)
 
           BEGIN_CASE(JSOP_EXCEPTION)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(0));
-            INLINE_STUBCALL(stubs::Exception);
+            INLINE_STUBCALL(stubs::Exception, REJOIN_FALLTHROUGH);
             frame.pushSynced(JSVAL_TYPE_UNKNOWN);
           }
           END_CASE(JSOP_EXCEPTION)
 
           BEGIN_CASE(JSOP_LINENO)
           END_CASE(JSOP_LINENO)
 
           BEGIN_CASE(JSOP_ENUMELEM)
@@ -2632,66 +2374,62 @@ mjit::Compiler::generateMethod()
           END_CASE(JSOP_NULLBLOCKCHAIN)
 
           BEGIN_CASE(JSOP_CONDSWITCH)
             /* No-op for the decompiler. */
           END_CASE(JSOP_CONDSWITCH)
 
           BEGIN_CASE(JSOP_DEFFUN)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             JSFunction *innerFun = script->getFunction(index);
 
             if (script->fun && script->bindings.hasBinding(cx, innerFun->atom))
                 frame.syncAndForgetEverything();
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(innerFun), Registers::ArgReg1);
-            INLINE_STUBCALL(STRICT_VARIANT(stubs::DefFun));
+            INLINE_STUBCALL(STRICT_VARIANT(stubs::DefFun), REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEFFUN)
 
           BEGIN_CASE(JSOP_DEFVAR)
           BEGIN_CASE(JSOP_DEFCONST)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             JSAtom *atom = script->getAtom(index);
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(atom), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::DefVarOrConst);
+            INLINE_STUBCALL(stubs::DefVarOrConst, REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEFVAR)
 
           BEGIN_CASE(JSOP_SETCONST)
           {
-            REJOIN_SITE_ANY();
             uint32 index = fullAtomIndex(PC);
             JSAtom *atom = script->getAtom(index);
 
             if (script->fun && script->bindings.hasBinding(cx, atom))
                 frame.syncAndForgetEverything();
 
             prepareStubCall(Uses(1));
             masm.move(ImmPtr(atom), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::SetConst);
+            INLINE_STUBCALL(stubs::SetConst, REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_SETCONST)
 
           BEGIN_CASE(JSOP_DEFLOCALFUN_FC)
           {
-            REJOIN_SITE_ANY();
             updateVarType();
             uint32 slot = GET_SLOTNO(PC);
             JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
             prepareStubCall(Uses(frame.frameSlots()));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::DefLocalFun_FC);
+            INLINE_STUBCALL(stubs::DefLocalFun_FC, REJOIN_DEFLOCALFUN);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
             frame.storeLocal(slot, JSVAL_TYPE_OBJECT, true);
             frame.pop();
           }
           END_CASE(JSOP_DEFLOCALFUN_FC)
 
           BEGIN_CASE(JSOP_LAMBDA)
@@ -2717,23 +2455,21 @@ mjit::Compiler::generateMethod()
                     stub = stubs::LambdaJoinableForNull;
                 }
             }
 
             prepareStubCall(Uses(uses));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
 
             if (stub == stubs::Lambda) {
-                REJOIN_SITE(stub);
-                INLINE_STUBCALL(stub);
+                INLINE_STUBCALL(stub, REJOIN_PUSH_OBJECT);
             } else {
-                REJOIN_SITE(stub);
                 jsbytecode *savedPC = PC;
                 PC = pc2;
-                INLINE_STUBCALL(stub);
+                INLINE_STUBCALL(stub, REJOIN_PUSH_OBJECT);
                 PC = savedPC;
             }
 
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
           }
           END_CASE(JSOP_LAMBDA)
 
@@ -2759,42 +2495,39 @@ mjit::Compiler::generateMethod()
             frame.push(Address(reg, index * sizeof(Value)), knownPushedType(0));
             if (op == JSOP_CALLFCSLOT)
                 frame.push(UndefinedValue());
           }
           END_CASE(JSOP_CALLFCSLOT)
 
           BEGIN_CASE(JSOP_ARGSUB)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(0));
             masm.move(Imm32(GET_ARGNO(PC)), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::ArgSub);
+            INLINE_STUBCALL(stubs::ArgSub, REJOIN_FALLTHROUGH);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_ARGSUB)
 
           BEGIN_CASE(JSOP_ARGCNT)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(0));
-            INLINE_STUBCALL(stubs::ArgCnt);
+            INLINE_STUBCALL(stubs::ArgCnt, REJOIN_FALLTHROUGH);
             pushSyncedEntry(0);
           }
           END_CASE(JSOP_ARGCNT)
 
           BEGIN_CASE(JSOP_DEFLOCALFUN)
           {
-            REJOIN_SITE_ANY();
             updateVarType();
             uint32 slot = GET_SLOTNO(PC);
             JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::DefLocalFun);
+            INLINE_STUBCALL(stubs::DefLocalFun, REJOIN_DEFLOCALFUN);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
             frame.storeLocal(slot, JSVAL_TYPE_OBJECT, true);
             frame.pop();
           }
           END_CASE(JSOP_DEFLOCALFUN)
 
           BEGIN_CASE(JSOP_RETRVAL)
@@ -2820,51 +2553,34 @@ mjit::Compiler::generateMethod()
           }
           END_CASE(JSOP_SETGNAME)
 
           BEGIN_CASE(JSOP_REGEXP)
           {
             JSObject *regex = script->getRegExp(fullAtomIndex(PC));
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(regex), Registers::ArgReg1);
-            INLINE_STUBCALL_NO_REJOIN(stubs::RegExp);
+            INLINE_STUBCALL(stubs::RegExp, REJOIN_NONE);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
           }
           END_CASE(JSOP_REGEXP)
 
           BEGIN_CASE(JSOP_OBJECT)
           {
             JSObject *object = script->getObject(fullAtomIndex(PC));
             RegisterID reg = frame.allocReg();
             masm.move(ImmPtr(object), reg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
           }
           END_CASE(JSOP_OBJECT)
 
           BEGIN_CASE(JSOP_CALLPROP)
-          {
-              /*
-               * We can rejoin from a getprop if we took the callprop_str case
-               * in an earlier compilation. Rejoin from this differently as
-               * after the getprop the top two stack values will be reversed.
-               */
-              AutoRejoinSite rejoinGetProp(this, JS_FUNC_TO_DATA_PTR(void *, stubs::GetProp),
-                                           JS_FUNC_TO_DATA_PTR(void *, ic::GetProp));
-
-              if (!jsop_callprop(script->getAtom(fullAtomIndex(PC))))
-                  return Compile_Error;
-
-              if (needRejoins(PC)) {
-                  rejoinGetProp.oolRejoin(stubcc.masm.label());
-                  stubcc.masm.infallibleVMCall(JS_FUNC_TO_DATA_PTR(void *, stubs::CallPropSwap),
-                                               frame.totalDepth());
-                  stubcc.rejoin(Changes(2));
-              }
-          }
+            if (!jsop_callprop(script->getAtom(fullAtomIndex(PC))))
+                return Compile_Error;
           END_CASE(JSOP_CALLPROP)
 
           BEGIN_CASE(JSOP_UINT24)
             frame.push(Value(Int32Value((int32_t) GET_UINT24(PC))));
           END_CASE(JSOP_UINT24)
 
           BEGIN_CASE(JSOP_CALLELEM)
             jsop_getelem(true);
@@ -2911,20 +2627,17 @@ mjit::Compiler::generateMethod()
             frame.push(MagicValue(JS_ARRAY_HOLE));
           END_CASE(JSOP_HOLE)
 
           BEGIN_CASE(JSOP_LAMBDA_FC)
           {
             JSFunction *fun = script->getFunction(fullAtomIndex(PC));
             prepareStubCall(Uses(frame.frameSlots()));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
-            {
-                REJOIN_SITE(stubs::FlatLambda);
-                INLINE_STUBCALL(stubs::FlatLambda);
-            }
+            INLINE_STUBCALL(stubs::FlatLambda, REJOIN_PUSH_OBJECT);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
           }
           END_CASE(JSOP_LAMBDA_FC)
 
           BEGIN_CASE(JSOP_TRACE)
           BEGIN_CASE(JSOP_NOTRACE)
           {
@@ -2932,20 +2645,19 @@ mjit::Compiler::generateMethod()
                 interruptCheckHelper();
                 recompileCheckHelper();
             }
           }
           END_CASE(JSOP_TRACE)
 
           BEGIN_CASE(JSOP_DEBUGGER)
           {
-            REJOIN_SITE_ANY();
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(PC), Registers::ArgReg1);
-            INLINE_STUBCALL(stubs::Debugger);
+            INLINE_STUBCALL(stubs::Debugger, REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEBUGGER)
 
           BEGIN_CASE(JSOP_UNBRAND)
             jsop_unbrand();
           END_CASE(JSOP_UNBRAND)
 
           BEGIN_CASE(JSOP_UNBRANDTHIS)
@@ -3041,18 +2753,16 @@ mjit::Compiler::jumpInScript(Jump j, jsb
         return true;
     }
     return branchPatches.append(BranchPatch(j, pc, a->inlineIndex));
 }
 
 void
 mjit::Compiler::jsop_getglobal(uint32 index)
 {
-    REJOIN_SITE_ANY();
-
     JS_ASSERT(globalObj);
     uint32 slot = script->getGlobalSlot(index);
 
     JSObject *singleton = pushedSingleton(0);
     if (singleton && !globalObj->getSlot(slot).isUndefined()) {
         frame.push(ObjectValue(*singleton));
         return;
     }
@@ -3079,17 +2789,17 @@ mjit::Compiler::jsop_getglobal(uint32 in
      * of this access, which type inference will not account for. Insert a check.
      */
     if (cx->typeInferenceEnabled() &&
         globalObj->getSlot(slot).isUndefined() &&
         (JSOp(*PC) == JSOP_CALLGLOBAL || PC[JSOP_GETGLOBAL_LENGTH] != JSOP_POP)) {
         Jump jump = masm.testUndefined(Assembler::Equal, address);
         stubcc.linkExit(jump, Uses(0));
         stubcc.leave();
-        OOL_STUBCALL(stubs::UndefinedHelper);
+        OOL_STUBCALL(stubs::UndefinedHelper, REJOIN_GETTER);
         stubcc.rejoin(Changes(1));
     }
 }
 
 void
 mjit::Compiler::emitFinalReturn(Assembler &masm)
 {
     masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfNcode()), Registers::ReturnReg);
@@ -3267,19 +2977,18 @@ void
 mjit::Compiler::emitReturn(FrameEntry *fe)
 {
     JS_ASSERT_IF(!script->fun, JSOp(*PC) == JSOP_STOP);
 
     /* Only the top of the stack can be returned. */
     JS_ASSERT_IF(fe, fe == frame.peek(-1));
 
     if (debugMode() || Probes::callTrackingActive(cx)) {
-        REJOIN_SITE(stubs::ScriptDebugEpilogue);
         prepareStubCall(Uses(0));
-        INLINE_STUBCALL(stubs::ScriptDebugEpilogue);
+        INLINE_STUBCALL(stubs::ScriptDebugEpilogue, REJOIN_RESUME);
     }
 
     if (a != outer) {
         /*
          * Returning from an inlined script. The checks we do for inlineability
          * and recompilation triggered by args object construction ensure that
          * there can't be an arguments or call object.
          */
@@ -3321,26 +3030,26 @@ mjit::Compiler::emitReturn(FrameEntry *f
      * perform this branch (by instead using a trampoline at the return address
      * to handle exiting mjit code) and thus always puts activation objects,
      * even on the entry frame. To avoid double-putting, EnterMethodJIT clears
      * out the entry frame's activation objects.
      */
     if (script->fun && script->fun->isHeavyweight()) {
         /* There will always be a call object. */
         prepareStubCall(Uses(fe ? 1 : 0));
-        INLINE_STUBCALL_NO_REJOIN(stubs::PutActivationObjects);
+        INLINE_STUBCALL(stubs::PutActivationObjects, REJOIN_NONE);
     } else {
         /* if (hasCallObj() || hasArgsObj()) */
         Jump putObjs = masm.branchTest32(Assembler::NonZero,
                                          Address(JSFrameReg, StackFrame::offsetOfFlags()),
                                          Imm32(StackFrame::HAS_CALL_OBJ | StackFrame::HAS_ARGS_OBJ));
         stubcc.linkExit(putObjs, Uses(frame.frameSlots()));
 
         stubcc.leave();
-        OOL_STUBCALL_NO_REJOIN(stubs::PutActivationObjects);
+        OOL_STUBCALL(stubs::PutActivationObjects, REJOIN_NONE);
 
         emitReturnValue(&stubcc.masm, fe);
         emitFinalReturn(stubcc.masm);
     }
 
     emitReturnValue(&masm, fe);
     emitFinalReturn(masm);
 
@@ -3369,18 +3078,16 @@ mjit::Compiler::emitStubCall(void *ptr, 
                                   ptr, outerPC(), pinline, frame.totalDepth());
     JaegerSpew(JSpew_Insns, " ---- END STUB CALL ---- \n");
     return cl;
 }
 
 void
 mjit::Compiler::interruptCheckHelper()
 {
-    REJOIN_SITE(stubs::Interrupt);
-
     /*
      * Bake in and test the address of the interrupt counter for the runtime.
      * This is faster than doing two additional loads for the context's
      * thread data, but will cause this thread to run slower if there are
      * pending interrupts on some other thread.  For non-JS_THREADSAFE builds
      * we can skip this, as there is only one flag to poll.
      */
 #ifdef JS_THREADSAFE
@@ -3398,25 +3105,23 @@ mjit::Compiler::interruptCheckHelper()
     Jump jump = masm.branchTest32(Assembler::NonZero, Address(reg, 0));
     frame.freeReg(reg);
 #endif
 
     stubcc.linkExitDirect(jump, stubcc.masm.label());
 
     frame.sync(stubcc.masm, Uses(0));
     stubcc.masm.move(ImmPtr(PC), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::Interrupt);
+    OOL_STUBCALL(stubs::Interrupt, REJOIN_RESUME);
     stubcc.rejoin(Changes(0));
 }
 
 void
 mjit::Compiler::recompileCheckHelper()
 {
-    REJOIN_SITE(stubs::RecompileForInline);
-
     if (inlining() || debugMode() || !analysis->hasFunctionCalls() || !cx->typeInferenceEnabled())
         return;
 
     size_t *addr = script->addressOfCallCount();
     masm.add32(Imm32(1), AbsoluteAddress(addr));
 #if defined(JS_CPU_X86) || defined(JS_CPU_ARM)
     Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, AbsoluteAddress(addr),
                               Imm32(CALLS_BACKEDGES_BEFORE_INLINING));
@@ -3426,42 +3131,42 @@ mjit::Compiler::recompileCheckHelper()
     masm.move(ImmPtr(addr), reg);
     Jump jump = masm.branch32(Assembler::GreaterThanOrEqual, Address(reg, 0),
                               Imm32(CALLS_BACKEDGES_BEFORE_INLINING));
     frame.freeReg(reg);
 #endif
     stubcc.linkExit(jump, Uses(0));
     stubcc.leave();
 
-    OOL_STUBCALL(stubs::RecompileForInline);
+    OOL_STUBCALL(stubs::RecompileForInline, REJOIN_RESUME);
     stubcc.rejoin(Changes(0));
 }
 
 void
 mjit::Compiler::addReturnSite(bool ool)
 {
     Assembler &masm = ool ? stubcc.masm : this->masm;
     InternalCallSite site(masm.distanceOf(masm.label()), a->inlineIndex, PC,
-                          CallSite::NCODE_RETURN_ID, ool, true);
+                          REJOIN_SCRIPTED, ool);
     addCallSite(site);
     masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfPrev()), JSFrameReg);
 }
 
 void
 mjit::Compiler::emitUncachedCall(uint32 argc, bool callingNew)
 {
     CallPatchInfo callPatch;
 
     RegisterID r0 = Registers::ReturnReg;
     VoidPtrStubUInt32 stub = callingNew ? stubs::UncachedNew : stubs::UncachedCall;
 
     frame.syncAndKill(Uses(argc + 2));
     prepareStubCall(Uses(argc + 2));
     masm.move(Imm32(argc), Registers::ArgReg1);
-    INLINE_STUBCALL(stub);
+    INLINE_STUBCALL(stub, REJOIN_CALL_PROLOGUE);
 
     Jump notCompiled = masm.branchTestPtr(Assembler::Zero, r0, r0);
 
     masm.loadPtr(FrameAddress(offsetof(VMFrame, regs.sp)), JSFrameReg);
     callPatch.hasFastNcode = true;
     callPatch.fastNcodePatch =
         masm.storePtrWithPatch(ImmPtr(NULL),
                                Address(JSFrameReg, StackFrame::offsetOfNcode()));
@@ -3523,26 +3228,26 @@ mjit::Compiler::checkCallApplySpeculatio
     {
         if (isObj.isSet())
             stubcc.linkExitDirect(isObj.getJump(), stubcc.masm.label());
         stubcc.linkExitDirect(isFun, stubcc.masm.label());
         stubcc.linkExitDirect(isNative, stubcc.masm.label());
 
         int32 frameDepthAdjust;
         if (applyTricks == LazyArgsObj) {
-            OOL_STUBCALL_NO_REJOIN(stubs::Arguments);
+            OOL_STUBCALL(stubs::Arguments, REJOIN_NONE);
             frameDepthAdjust = +1;
         } else {
             frameDepthAdjust = 0;
         }
 
         stubcc.masm.move(Imm32(callImmArgc), Registers::ArgReg1);
         JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW CALL CODE ---- \n");
         OOL_STUBCALL_LOCAL_SLOTS(JS_FUNC_TO_DATA_PTR(void *, stubs::SlowCall),
-                                 frame.totalDepth() + frameDepthAdjust);
+                                 REJOIN_FALLTHROUGH, frame.totalDepth() + frameDepthAdjust);
         JaegerSpew(JSpew_Insns, " ---- END SLOW CALL CODE ---- \n");
 
         /*
          * inlineCallHelper will link uncachedCallSlowRejoin to the join point
          * at the end of the ic. At that join point, the return value of the
          * call is assumed to be in registers, so load them before jumping.
          */
         JaegerSpew(JSpew_Insns, " ---- BEGIN SLOW RESTORE CODE ---- \n");
@@ -3772,23 +3477,16 @@ mjit::Compiler::inlineCallHelper(uint32 
     Jump j = masm.branchPtrWithPatch(Assembler::NotEqual, icCalleeData, callIC.funGuard);
     callIC.funJump = j;
 
     /* Reserve space just before initialization of slowPathStart. */
     RESERVE_OOL_SPACE(stubcc.masm);
 
     Jump rejoin1, rejoin2;
     {
-        /*
-         * Rejoin site for recompiling from SplatApplyArgs. We ensure that this
-         * call is always either emitted or not emitted across compilations.
-         */
-        AutoRejoinSite autoRejoinSplat(this,
-            JS_FUNC_TO_DATA_PTR(void *, ic::SplatApplyArgs));
-
         RESERVE_OOL_SPACE(stubcc.masm);
         stubcc.linkExitDirect(j, stubcc.masm.label());
         callIC.slowPathStart = stubcc.masm.label();
 
         /*
          * Test if the callee is even a function. If this doesn't match, we
          * take a _really_ slow path later.
          */
@@ -3802,41 +3500,42 @@ mjit::Compiler::inlineCallHelper(uint32 
         Jump isNative = stubcc.masm.branch32(Assembler::Below, tmp, Imm32(JSFUN_INTERPRETED));
         tempRegs.putReg(tmp);
 
         /*
          * N.B. After this call, the frame will have a dynamic frame size.
          * Check after the function is known not to be a native so that the
          * catch-all/native path has a static depth.
          */
-        if (callIC.frameSize.isDynamic()) {
-            OOL_STUBCALL(ic::SplatApplyArgs);
-            autoRejoinSplat.oolRejoin(stubcc.masm.label());
-        }
+        if (callIC.frameSize.isDynamic())
+            OOL_STUBCALL(ic::SplatApplyArgs, REJOIN_CALL_SPLAT);
 
         /*
          * No-op jump that gets patched by ic::New/Call to the stub generated
          * by generateFullCallStub.
          */
         Jump toPatch = stubcc.masm.jump();
         toPatch.linkTo(stubcc.masm.label(), &stubcc.masm);
         callIC.oolJump = toPatch;
         callIC.icCall = stubcc.masm.label();
 
+        RejoinState rejoinState = callIC.frameSize.rejoinState(PC, false);
+
         /*
          * At this point the function is definitely scripted, so we try to
          * compile it and patch either funGuard/funJump or oolJump. This code
          * is only executed once.
          */
         callIC.addrLabel1 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
         void *icFunPtr = JS_FUNC_TO_DATA_PTR(void *, callingNew ? ic::New : ic::Call);
-        if (callIC.frameSize.isStatic())
-            callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, frame.totalDepth());
-        else
-            callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, -1);
+        if (callIC.frameSize.isStatic()) {
+            callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, rejoinState, frame.totalDepth());
+        } else {
+            callIC.oolCall = OOL_STUBCALL_LOCAL_SLOTS(icFunPtr, rejoinState, -1);
+        }
 
         callIC.funObjReg = icCalleeData;
         callIC.funPtrReg = funPtrReg;
 
         /*
          * The IC call either returns NULL, meaning call completed, or a
          * function pointer to jump to.
          */
@@ -3863,17 +3562,17 @@ mjit::Compiler::inlineCallHelper(uint32 
          * path through js::Invoke.
          */
         if (notObjectJump.isSet())
             stubcc.linkExitDirect(notObjectJump.get(), stubcc.masm.label());
         notFunction.linkTo(stubcc.masm.label(), &stubcc.masm);
         isNative.linkTo(stubcc.masm.label(), &stubcc.masm);
 
         callIC.addrLabel2 = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
-        OOL_STUBCALL(callingNew ? ic::NativeNew : ic::NativeCall);
+        OOL_STUBCALL(callingNew ? ic::NativeNew : ic::NativeCall, rejoinState);
 
         rejoin2 = stubcc.masm.jump();
     }
 
     /*
      * If the call site goes to a closure over the same function, it will
      * generate an out-of-line stub that joins back here.
      */
@@ -3994,31 +3693,31 @@ mjit::Compiler::callArrayBuiltin(uint32 
             stubcc.linkExit(belowZero, Uses(argc + 2));
         }
     } else {
         knownSize = 0;
     }
 
     stubcc.leave();
     stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
-    OOL_STUBCALL(callingNew ? stubs::SlowNew : stubs::SlowCall);
+    OOL_STUBCALL(callingNew ? stubs::SlowNew : stubs::SlowCall, REJOIN_FALLTHROUGH);
 
     {
         PinRegAcrossSyncAndKill p1(frame, sizeReg);
         frame.popn(argc + 2);
         frame.syncAndKill(Uses(0));
     }
 
     prepareStubCall(Uses(0));
     masm.storePtr(ImmPtr(arrayProto), FrameAddress(offsetof(VMFrame, scratch)));
     if (sizeReg.isSet())
         masm.move(sizeReg.reg(), Registers::ArgReg1);
     else
         masm.move(Imm32(knownSize), Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::NewDenseUnallocatedArray);
+    INLINE_STUBCALL(stubs::NewDenseUnallocatedArray, REJOIN_PUSH_OBJECT);
 
     frame.takeReg(Registers::ReturnReg);
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
     frame.forgetType(frame.peek(-1));
 
     stubcc.rejoin(Changes(1));
 
     return Compile_Okay;
@@ -4128,18 +3827,17 @@ mjit::Compiler::inlineScriptedFunction(u
             a->returnRegister = returnRegister;
         }
 
         status = generateMethod();
         if (status != Compile_Okay) {
             popActiveFrame();
             if (status == Compile_Abort) {
                 /* The callee is uncompileable, mark it as uninlineable and retry. */
-                if (!cx->markTypeFunctionUninlineable(script->fun->getType()))
-                    return Compile_Error;
+                cx->markTypeFunctionUninlineable(script->fun->getType());
                 return Compile_Retry;
             }
             return status;
         }
 
         if (needReturnValue && !returnSet) {
             if (a->returnSet) {
                 returnSet = true;
@@ -4191,96 +3889,31 @@ mjit::Compiler::inlineScriptedFunction(u
  */
 void
 mjit::Compiler::addCallSite(const InternalCallSite &site)
 {
     callSites.append(site);
 }
 
 void
-mjit::Compiler::inlineStubCall(void *stub, bool needsRejoin)
+mjit::Compiler::inlineStubCall(void *stub, RejoinState rejoin)
 {
     DataLabelPtr inlinePatch;
     Call cl = emitStubCall(stub, &inlinePatch);
     InternalCallSite site(masm.callReturnOffset(cl), a->inlineIndex, PC,
-                          (size_t)stub, false, needsRejoin);
+                          rejoin, false);
     site.inlinePatch = inlinePatch;
     if (loop && loop->generatingInvariants()) {
         Jump j = masm.jump();
         Label l = masm.label();
-        loop->addInvariantCall(j, l, false, false, callSites.length(), true);
+        loop->addInvariantCall(j, l, false, false, callSites.length());
     }
     addCallSite(site);
 }
 
-#ifdef DEBUG
-void
-mjit::Compiler::checkRejoinSite(uint32 nCallSites, uint32 nRejoinSites, void *stub)
-{
-    JS_ASSERT(!variadicRejoin);
-    size_t id = (size_t) stub;
-
-    if (id == RejoinSite::VARIADIC_ID) {
-        for (unsigned i = nCallSites; i < callSites.length(); i++)
-            callSites[i].needsRejoin = false;
-        variadicRejoin = true;
-        return;
-    }
-
-    for (unsigned i = nCallSites; i < callSites.length(); i++) {
-        if (callSites[i].id == id)
-            callSites[i].needsRejoin = false;
-    }
-}
-#endif
-
-void
-mjit::Compiler::addRejoinSite(void *stub, bool ool, Label oolLabel)
-{
-    JS_ASSERT(a == outer);
-
-    InternalRejoinSite rejoin(stubcc.masm.label(), PC, (size_t) stub);
-    rejoinSites.append(rejoin);
-
-    /*
-     * Get the right frame to use for restoring doubles and for subsequent code.
-     * For calls the register is restored from f.regs.fp, for scripted calls
-     * we pop the frame first.
-     */
-    if (stub == (void *) CallSite::NCODE_RETURN_ID)
-        stubcc.masm.loadPtr(Address(JSFrameReg, StackFrame::offsetOfPrev()), JSFrameReg);
-    else
-        stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
-
-    /*
-     * Ensure that all entries which we assume are doubles are in fact doubles.
-     * Any value assumed to be a double in this compilation may instead be an
-     * int in the earlier compilation and stack frames. Other transitions
-     * between known types are not possible --- type sets can only grow, and if
-     * new non-double type tags become possible we will treat that slot as
-     * unknown in this compilation.
-     */
-    frame.ensureInMemoryDoubles(stubcc.masm);
-
-    /* Regenerate any loop invariants. */
-    if (loop && loop->generatingInvariants()) {
-        Jump j = stubcc.masm.jump();
-        Label l = stubcc.masm.label();
-        loop->addInvariantCall(j, l, true, false, rejoinSites.length() - 1, false);
-    }
-
-    if (ool) {
-        /* Jump to the specified label, without syncing. */
-        stubcc.masm.jump().linkTo(oolLabel, &stubcc.masm);
-    } else {
-        /* Rejoin as from an out of line stub call. */
-        stubcc.rejoin(Changes(0));
-    }
-}
-
 bool
 mjit::Compiler::compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs)
 {
     JS_ASSERT(lhs.isPrimitive());
     JS_ASSERT(rhs.isPrimitive());
 
     if (lhs.isString() && rhs.isString()) {
         int32 cmp;
@@ -4334,83 +3967,79 @@ mjit::Compiler::compareTwoValues(JSConte
         }
     }
 
     JS_NOT_REACHED("NYI");
     return false;
 }
 
 bool
-mjit::Compiler::emitStubCmpOp(BoolStub stub, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused)
+mjit::Compiler::emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused)
 {
     if (target) {
         fixDoubleTypes(target);
         frame.syncAndKillEverything();
     } else {
         frame.syncAndKill(Uses(2));
     }
 
     prepareStubCall(Uses(2));
-    INLINE_STUBCALL(stub);
+    INLINE_STUBCALL(stub, target ? REJOIN_BRANCH : REJOIN_PUSH_BOOLEAN);
     frame.pop();
     frame.pop();
 
     if (!target) {
         frame.takeReg(Registers::ReturnReg);
         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, Registers::ReturnReg);
         return true;
     }
 
-    if (needRejoins(PC)) {
-        autoRejoin.oolRejoin(stubcc.masm.label());
-        stubcc.rejoin(Changes(0));
-    }
-
     JS_ASSERT(fused == JSOP_IFEQ || fused == JSOP_IFNE);
-    Assembler::Condition cond = (fused == JSOP_IFEQ)
-                                ? Assembler::Zero
-                                : Assembler::NonZero;
-    Jump j = masm.branchTest32(cond, Registers::ReturnReg,
+    Jump j = masm.branchTest32(GetStubCompareCondition(fused), Registers::ReturnReg,
                                Registers::ReturnReg);
     return jumpAndTrace(j, target);
 }
 
 void
 mjit::Compiler::jsop_setprop_slow(JSAtom *atom, bool usePropCache)
 {
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     if (usePropCache)
-        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetName));
+        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
     else
-        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache));
+        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache), REJOIN_FALLTHROUGH);
     JS_STATIC_ASSERT(JSOP_SETNAME_LENGTH == JSOP_SETPROP_LENGTH);
     frame.shimmy(1);
 }
 
 void
 mjit::Compiler::jsop_getprop_slow(JSAtom *atom, bool usePropCache)
 {
+    /* See ::jsop_getprop */
+    RejoinState rejoin = usePropCache ? REJOIN_GETTER : REJOIN_THIS_PROTOTYPE;
+
     prepareStubCall(Uses(1));
     if (usePropCache) {
-        INLINE_STUBCALL(stubs::GetProp);
+        INLINE_STUBCALL(stubs::GetProp, rejoin);
     } else {
         masm.move(ImmPtr(atom), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::GetPropNoCache);
-    }
+        INLINE_STUBCALL(stubs::GetPropNoCache, rejoin);
+    }
+
     frame.pop();
     frame.pushSynced(JSVAL_TYPE_UNKNOWN);
 }
 
 bool
 mjit::Compiler::jsop_callprop_slow(JSAtom *atom)
 {
     prepareStubCall(Uses(1));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::CallProp);
+    INLINE_STUBCALL(stubs::CallProp, REJOIN_FALLTHROUGH);
     frame.pop();
     pushSyncedEntry(0);
     pushSyncedEntry(1);
     return true;
 }
 
 #ifdef JS_MONOIC
 void
@@ -4426,19 +4055,29 @@ mjit::Compiler::passICAddress(BaseICInfo
 {
     ic->paramAddr = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
 }
 
 bool
 mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType,
                              bool doTypeCheck, bool usePropCache)
 {
-    REJOIN_SITE_3(ic::GetProp, ic::GetPropNoCache, stubs::GetProp);
     FrameEntry *top = frame.peek(-1);
 
+    /*
+     * Use a different rejoin for GETPROP computing the 'this' object, as we
+     * can't use the current bytecode within InternalInterpret to tell this is
+     * fetching the 'this' value.
+     */
+    RejoinState rejoin = REJOIN_GETTER;
+    if (!usePropCache) {
+        JS_ASSERT(top->isType(JSVAL_TYPE_OBJECT) && atom == cx->runtime->atomState.classPrototypeAtom);
+        rejoin = REJOIN_THIS_PROTOTYPE;
+    }
+
     /* Handle length accesses on known strings without using a PIC. */
     if (atom == cx->runtime->atomState.lengthAtom &&
         top->isTypeKnown() && top->getKnownType() == JSVAL_TYPE_STRING) {
         if (top->isConstant()) {
             JSString *str = top->getValue().toString();
             Value v;
             v.setNumber(uint32(str->length()));
             frame.pop();
@@ -4485,17 +4124,17 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
         types::TypeSet *types = frame.extra(top).types;
         types::ObjectKind kind = types ? types->getKnownObjectKind(cx) : types::OBJECT_UNKNOWN;
         if (kind == types::OBJECT_DENSE_ARRAY || kind == types::OBJECT_PACKED_ARRAY) {
             bool isObject = top->isTypeKnown();
             if (!isObject) {
                 Jump notObject = frame.testObject(Assembler::NotEqual, top);
                 stubcc.linkExit(notObject, Uses(1));
                 stubcc.leave();
-                OOL_STUBCALL(stubs::GetProp);
+                OOL_STUBCALL(stubs::GetProp, rejoin);
             }
             RegisterID reg = frame.tempRegForData(top);
             frame.pop();
             frame.push(Address(reg, offsetof(JSObject, privateData)), JSVAL_TYPE_INT32);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             return true;
         }
@@ -4531,17 +4170,17 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
         if (propertyTypes->isDefiniteProperty() && !propertyTypes->isOwnProperty(cx, true)) {
             types->addFreeze(cx);
             uint32 slot = propertyTypes->definiteSlot();
             bool isObject = top->isTypeKnown();
             if (!isObject) {
                 Jump notObject = frame.testObject(Assembler::NotEqual, top);
                 stubcc.linkExit(notObject, Uses(1));
                 stubcc.leave();
-                OOL_STUBCALL(stubs::GetProp);
+                OOL_STUBCALL(stubs::GetProp, rejoin);
             }
             RegisterID reg = frame.tempRegForData(top);
             frame.pop();
             frame.push(Address(reg, JSObject::getFixedSlotOffset(slot)), knownType);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             return true;
         }
@@ -4601,17 +4240,17 @@ mjit::Compiler::jsop_getprop(JSAtom *ato
                                     inlineShapeLabel);
     Label inlineShapeJump = masm.label();
 
     RESERVE_OOL_SPACE(stubcc.masm);
     pic.slowPathStart = stubcc.linkExit(j, Uses(1));
 
     stubcc.leave();
     passICAddress(&pic);
-    pic.slowPathCall = OOL_STUBCALL(usePropCache ? ic::GetProp : ic::GetPropNoCache);
+    pic.slowPathCall = OOL_STUBCALL(usePropCache ? ic::GetProp : ic::GetPropNoCache, rejoin);
     CHECK_OOL_SPACE();
 
     /* Load the base slot address. */
     Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
                                                                objReg);
 
     /* Copy the slot value to the expression stack. */
     Address slot(objReg, 1 << 24);
@@ -4711,17 +4350,17 @@ mjit::Compiler::jsop_callprop_generic(JS
                            inlineShapeLabel);
     Label inlineShapeJump = masm.label();
 
     /* Slow path. */
     RESERVE_OOL_SPACE(stubcc.masm);
     pic.slowPathStart = stubcc.linkExit(j, Uses(1));
     stubcc.leave();
     passICAddress(&pic);
-    pic.slowPathCall = OOL_STUBCALL(ic::CallProp);
+    pic.slowPathCall = OOL_STUBCALL(ic::CallProp, REJOIN_FALLTHROUGH);
     CHECK_OOL_SPACE();
 
     /* Adjust the frame. None of this will generate code. */
     frame.pop();
     frame.pushRegs(shapeReg, objReg, knownPushedType(0));
     pushSyncedEntry(1);
 
     /* Load the base slot address. */
@@ -4848,17 +4487,17 @@ mjit::Compiler::jsop_callprop_obj(JSAtom
                            inlineShapeLabel);
     Label inlineShapeJump = masm.label();
 
     /* Slow path. */
     RESERVE_OOL_SPACE(stubcc.masm);
     pic.slowPathStart = stubcc.linkExit(j, Uses(1));
     stubcc.leave();
     passICAddress(&pic);
-    pic.slowPathCall = OOL_STUBCALL(ic::CallProp);
+    pic.slowPathCall = OOL_STUBCALL(ic::CallProp, REJOIN_FALLTHROUGH);
     CHECK_OOL_SPACE();
 
     /* Load the base slot address. */
     Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
                                                                objReg);
 
     /* Copy the slot value to the expression stack. */
     Address slot(objReg, 1 << 24);
@@ -5001,30 +4640,28 @@ mjit::Compiler::testSingletonPropertyTyp
         return NULL;
 
     return testSingletonProperty(proto, id);
 }
 
 bool
 mjit::Compiler::jsop_callprop(JSAtom *atom)
 {
-    REJOIN_SITE_2(stubs::CallProp, ic::CallProp);
-
     FrameEntry *top = frame.peek(-1);
 
     bool testObject;
     JSObject *singleton = pushedSingleton(0);
     if (singleton && singleton->isFunction() &&
         testSingletonPropertyTypes(top, ATOM_TO_JSID(atom), &testObject)) {
         if (testObject) {
             Jump notObject = frame.testObject(Assembler::NotEqual, top);
             stubcc.linkExit(notObject, Uses(1));
             stubcc.leave();
             stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
-            OOL_STUBCALL(stubs::CallProp);
+            OOL_STUBCALL(stubs::CallProp, REJOIN_FALLTHROUGH);
         }
 
         // THIS
 
         frame.dup();
         // THIS THIS
 
         frame.push(ObjectValue(*singleton));
@@ -5049,21 +4686,16 @@ mjit::Compiler::jsop_callprop(JSAtom *at
     if (top->isTypeKnown())
         return jsop_callprop_obj(atom);
     return jsop_callprop_generic(atom);
 }
 
 bool
 mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache, bool popGuaranteed)
 {
-    REJOIN_SITE_2(usePropCache
-                  ? STRICT_VARIANT(stubs::SetName)
-                  : STRICT_VARIANT(stubs::SetPropNoCache),
-                  ic::SetProp);
-
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     /* If the incoming type will never PIC, take slow path. */
     if (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_OBJECT) {
         jsop_setprop_slow(atom, usePropCache);
         return true;
     }
@@ -5085,17 +4717,17 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
             types->addFreeze(cx);
             uint32 slot = propertyTypes->definiteSlot();
             bool isObject = lhs->isTypeKnown();
             if (!isObject) {
                 Jump notObject = frame.testObject(Assembler::NotEqual, lhs);
                 stubcc.linkExit(notObject, Uses(2));
                 stubcc.leave();
                 stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
-                OOL_STUBCALL(STRICT_VARIANT(stubs::SetName));
+                OOL_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
             }
             RegisterID reg = frame.tempRegForData(lhs);
             frame.storeTo(rhs, Address(reg, JSObject::getFixedSlotOffset(slot)), popGuaranteed);
             frame.shimmy(1);
             if (!isObject)
                 stubcc.rejoin(Changes(1));
             return true;
         }
@@ -5136,19 +4768,19 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
         pic.fastPathStart = masm.label();
         Jump j = masm.testObject(Assembler::NotEqual, reg);
 
         pic.typeCheck = stubcc.linkExit(j, Uses(2));
         stubcc.leave();
 
         stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
         if (usePropCache)
-            OOL_STUBCALL(STRICT_VARIANT(stubs::SetName));
+            OOL_STUBCALL(STRICT_VARIANT(stubs::SetName), REJOIN_FALLTHROUGH);
         else
-            OOL_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache));
+            OOL_STUBCALL(STRICT_VARIANT(stubs::SetPropNoCache), REJOIN_FALLTHROUGH);
         typeCheck = stubcc.masm.jump();
         pic.hasTypeCheck = true;
     } else {
         pic.fastPathStart = masm.label();
         pic.hasTypeCheck = false;
         pic.typeReg = Registers::ReturnReg;
     }
 
@@ -5178,17 +4810,17 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
     Label afterInlineShapeJump = masm.label();
 
     /* Slow path. */
     {
         pic.slowPathStart = stubcc.linkExit(j, Uses(2));
 
         stubcc.leave();
         passICAddress(&pic);
-        pic.slowPathCall = OOL_STUBCALL(ic::SetProp);
+        pic.slowPathCall = OOL_STUBCALL(ic::SetProp, REJOIN_FALLTHROUGH);
         CHECK_OOL_SPACE();
     }
 
     /* Load dslots. */
     Label dslotsLoadLabel = masm.loadPtrWithPatchToLEA(Address(objReg, offsetof(JSObject, slots)),
                                                        objReg);
 
     /* Store RHS into object slot. */
@@ -5219,18 +4851,16 @@ mjit::Compiler::jsop_setprop(JSAtom *ato
 
     pics.append(pic);
     return true;
 }
 
 void
 mjit::Compiler::jsop_name(JSAtom *atom, JSValueType type)
 {
-    REJOIN_SITE_2(ic::Name, stubs::UndefinedHelper);
-
     PICGenInfo pic(ic::PICInfo::NAME, JSOp(*PC), true);
 
     RESERVE_IC_SPACE(masm);
 
     pic.shapeReg = frame.allocReg();
     pic.objReg = frame.allocReg();
     pic.typeReg = Registers::ReturnReg;
     pic.atom = atom;
@@ -5240,17 +4870,17 @@ mjit::Compiler::jsop_name(JSAtom *atom, 
     /* There is no inline implementation, so we always jump to the slow path or to a stub. */
     pic.shapeGuard = masm.label();
     Jump inlineJump = masm.jump();
     {
         RESERVE_OOL_SPACE(stubcc.masm);
         pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0));
         stubcc.leave();
         passICAddress(&pic);
-        pic.slowPathCall = OOL_STUBCALL(ic::Name);
+        pic.slowPathCall = OOL_STUBCALL(ic::Name, REJOIN_GETTER);
         CHECK_OOL_SPACE();
     }
     pic.fastPathRejoin = masm.label();
 
     /* Initialize op labels. */
     ScopeNameLabels &labels = pic.scopeNameLabels();
     labels.setInlineJump(masm, pic.fastPathStart, inlineJump);
 
@@ -5274,27 +4904,26 @@ mjit::Compiler::jsop_name(JSAtom *atom, 
         frame.pushRegs(pic.shapeReg, pic.objReg, type);
     }
 
     stubcc.rejoin(Changes(1));
 
     if (cx->typeInferenceEnabled()) {
         stubcc.linkExit(undefinedGuard.get(), Uses(0));
         stubcc.leave();
-        OOL_STUBCALL(stubs::UndefinedHelper);
+        OOL_STUBCALL(stubs::UndefinedHelper, REJOIN_GETTER);
         stubcc.rejoin(Changes(1));
     }
 
     pics.append(pic);
 }
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
-    REJOIN_SITE_ANY();
     PICGenInfo pic(ic::PICInfo::XNAME, JSOp(*PC), true);
 
     FrameEntry *fe = frame.peek(-1);
     if (fe->isNotType(JSVAL_TYPE_OBJECT)) {
         return jsop_getprop(atom, knownPushedType(0));
     }
 
     if (!fe->isTypeKnown()) {
@@ -5316,17 +4945,17 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
     /* There is no inline implementation, so we always jump to the slow path or to a stub. */
     pic.shapeGuard = masm.label();
     Jump inlineJump = masm.jump();
     {
         RESERVE_OOL_SPACE(stubcc.masm);
         pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(1));
         stubcc.leave();
         passICAddress(&pic);
-        pic.slowPathCall = OOL_STUBCALL(ic::XName);
+        pic.slowPathCall = OOL_STUBCALL(ic::XName, REJOIN_GETTER);
         CHECK_OOL_SPACE();
     }
 
     pic.fastPathRejoin = masm.label();
 
     RETURN_IF_OOM(false);
 
     /* Initialize op labels. */
@@ -5342,28 +4971,27 @@ mjit::Compiler::jsop_xname(JSAtom *atom)
         undefinedGuard = masm.testUndefined(Assembler::Equal, pic.shapeReg);
     }
 
     stubcc.rejoin(Changes(1));
 
     if (cx->typeInferenceEnabled()) {
         stubcc.linkExit(undefinedGuard.get(), Uses(0));
         stubcc.leave();
-        OOL_STUBCALL(stubs::UndefinedHelper);
+        OOL_STUBCALL(stubs::UndefinedHelper, REJOIN_GETTER);
         stubcc.rejoin(Changes(1));
     }
 
     pics.append(pic);
     return true;
 }
 
 void
 mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
-    REJOIN_SITE(ic::BindName);
     PICGenInfo pic(ic::PICInfo::BIND, JSOp(*PC), usePropCache);
 
     // This code does not check the frame flags to see if scopeChain has been
     // set. Rather, it relies on the up-front analysis statically determining
     // whether BINDNAME can be used, which reifies the scope chain at the
     // prologue.
     JS_ASSERT(analysis->usesScopeChain());
 
@@ -5381,17 +5009,17 @@ mjit::Compiler::jsop_bindname(JSAtom *at
 
     pic.shapeGuard = masm.label();
     Jump inlineJump = masm.branchPtr(Assembler::NotEqual, parent, ImmPtr(0));
     {
         RESERVE_OOL_SPACE(stubcc.masm);
         pic.slowPathStart = stubcc.linkExit(inlineJump, Uses(0));
         stubcc.leave();
         passICAddress(&pic);
-        pic.slowPathCall = OOL_STUBCALL(ic::BindName);
+        pic.slowPathCall = OOL_STUBCALL(ic::BindName, REJOIN_BINDNAME);
         CHECK_OOL_SPACE();
     }
 
     pic.fastPathRejoin = masm.label();
 
     /* Initialize op labels. */
     BindNameLabels &labels = pic.bindNameLabels();
     labels.setInlineJump(masm, pic.shapeGuard, inlineJump);
@@ -5404,87 +5032,77 @@ mjit::Compiler::jsop_bindname(JSAtom *at
     pics.append(pic);
 }
 
 #else /* !JS_POLYIC */
 
 void
 mjit::Compiler::jsop_name(JSAtom *atom, JSValueType type, types::TypeSet *typeSet)
 {
-    REJOIN_SITE(stubs::Name);
     prepareStubCall(Uses(0));
-    INLINE_STUBCALL(stubs::Name);
+    INLINE_STUBCALL(stubs::Name, REJOIN_FALLTHROUGH);
     frame.pushSynced(type, typeSet);
 }
 
 bool
 mjit::Compiler::jsop_xname(JSAtom *atom)
 {
     return jsop_getprop(atom, knownPushedType(0), pushedTypeSet(0));
 }
 
 bool
 mjit::Compiler::jsop_getprop(JSAtom *atom, JSValueType knownType, types::TypeSet *typeSet,
                              bool typecheck, bool usePropCache)
 {
-    REJOIN_SITE_2(ic::GetProp, ic::GetPropNoCache);
     jsop_getprop_slow(atom, usePropCache);
     return true;
 }
 
 bool
 mjit::Compiler::jsop_callprop(JSAtom *atom)
 {
-    REJOIN_SITE_2(stubs::CallProp);
     return jsop_callprop_slow(atom);
 }
 
 bool
 mjit::Compiler::jsop_setprop(JSAtom *atom, bool usePropCache)
 {
-    REJOIN_SITE(usePropCache
-                ? STRICT_VARIANT(stubs::SetName)
-                : STRICT_VARIANT(stubs::SetPropNoCache));
-
     jsop_setprop_slow(atom, usePropCache);
     return true;
 }
 
 void
 mjit::Compiler::jsop_bindname(JSAtom *atom, bool usePropCache)
 {
-    REJOIN_SITE_2(stubs::BindName, stubs::BindNameNoCache);
     RegisterID reg = frame.allocReg();
     Address scopeChain(JSFrameReg, StackFrame::offsetOfScopeChain());
     masm.loadPtr(scopeChain, reg);
 
     Address address(reg, offsetof(JSObject, parent));
 
     Jump j = masm.branchPtr(Assembler::NotEqual, address, ImmPtr(0));
 
     stubcc.linkExit(j, Uses(0));
     stubcc.leave();
     if (usePropCache) {
-        OOL_STUBCALL(stubs::BindName);
+        OOL_STUBCALL(stubs::BindName, REJOIN_BINDNAME);
     } else {
         stubcc.masm.move(ImmPtr(atom), Registers::ArgReg1);
-        OOL_STUBCALL(stubs::BindNameNoCache);
+        OOL_STUBCALL(stubs::BindNameNoCache, REJOIN_BINDNAME);
     }
 
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
 
     stubcc.rejoin(Changes(1));
 }
 #endif
 
 void
 mjit::Compiler::jsop_this()
 {
-    REJOIN_SITE(stubs::This);
-
     frame.pushThis();
 
     /* 
      * In strict mode code, we don't wrap 'this'.
      * In direct-call eval code, we wrapped 'this' before entering the eval.
      * In global code, 'this' is always an object.
      */
     if (script->fun && !script->strictModeCode) {
@@ -5494,17 +5112,17 @@ mjit::Compiler::jsop_this()
                 ? script->thisTypes()->getKnownTypeTag(cx)
                 : JSVAL_TYPE_UNKNOWN;
             if (type != JSVAL_TYPE_OBJECT) {
                 Jump notObj = thisFe->isTypeKnown()
                     ? masm.jump()
                     : frame.testObject(Assembler::NotEqual, thisFe);
                 stubcc.linkExit(notObj, Uses(1));
                 stubcc.leave();
-                OOL_STUBCALL(stubs::This);
+                OOL_STUBCALL(stubs::This, REJOIN_FALLTHROUGH);
                 stubcc.rejoin(Changes(1));
             }
 
             // Now we know that |this| is an object.
             frame.pop();
             frame.learnThisIsObject(type != JSVAL_TYPE_OBJECT);
             frame.pushThis();
         }
@@ -5514,292 +5132,205 @@ mjit::Compiler::jsop_this()
 }
 
 bool
 mjit::Compiler::jsop_gnameinc(JSOp op, VoidStubAtom stub, uint32 index)
 {
     JSAtom *atom = script->getAtom(index);
 
 #if defined JS_MONOIC
-    jsbytecode *next = &PC[JSOP_GNAMEINC_LENGTH];
-    bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next);
-    int amt = (op == JSOP_GNAMEINC || op == JSOP_INCGNAME) ? -1 : 1;
-
-    if (pop || (op == JSOP_INCGNAME || op == JSOP_DECGNAME)) {
-        /* These cases are easy, the original value is not observed. */
-
-        jsop_getgname(index);
-        // V
-
-        frame.push(Int32Value(amt));
-        // V 1
+    int amt = (op == JSOP_GNAMEINC || op == JSOP_INCGNAME) ? 1 : -1;
+
+    jsop_bindgname();
+    // OBJ
+
+    jsop_getgname(index);
+    // OBJ V
+
+    if (!analysis->incrementInitialValueObserved(PC)) {
+        frame.push(Int32Value(-amt));
+        // OBJ V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
         if (!jsop_binary(JSOP_SUB, stubs::Sub, knownPushedType(0), pushedTypeSet(0)))
             return false;
+        // OBJ N+1
+
+        jsop_setgname(atom, false, analysis->popGuaranteed(PC));
         // N+1
-
-        jsop_bindgname();
-        // V+1 OBJ
-
-        frame.dup2();
-        // V+1 OBJ V+1 OBJ
-
-        frame.shift(-3);
-        // OBJ OBJ V+1
-
-        frame.shift(-1);
-        // OBJ V+1
-
-        jsop_setgname(atom, false, pop);
-        // V+1
-
-        if (pop)
-            frame.pop();
     } else {
-        /* The pre-value is observed, making this more tricky. */
-
-        jsop_getgname(index);
-        // V
-
         jsop_pos();
-        // N
-
-        frame.dup();
-        // N N
-
-        frame.push(Int32Value(-amt));
-        // N N 1
+        // OBJ N
+
+        frame.swap();
+        // N OBJ
+
+        frame.dupAt(-2);
+        // N OBJ N
+
+        frame.push(Int32Value(amt));
+        // N OBJ N 1
 
         if (!jsop_binary(JSOP_ADD, stubs::Add, knownPushedType(0), pushedTypeSet(0)))
             return false;
-        // N N+1
-
-        jsop_bindgname();
-        // N N+1 OBJ
-
-        frame.dup2();
-        // N N+1 OBJ N+1 OBJ
-
-        frame.shift(-3);
-        // N OBJ OBJ N+1
-
-        frame.shift(-1);
         // N OBJ N+1
 
         jsop_setgname(atom, false, true);
         // N N+1
 
         frame.pop();
         // N
     }
-
-    if (pop)
-        PC += JSOP_POP_LENGTH;
 #else
     prepareStubCall(Uses(0));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
-    INLINE_STUBCALL(stub);
+    INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
     frame.pushSynced(knownPushedType(0));
 #endif
 
-    PC += JSOP_GNAMEINC_LENGTH;
     return true;
 }
 
 CompileStatus
 mjit::Compiler::jsop_nameinc(JSOp op, VoidStubAtom stub, uint32 index)
 {
     JSAtom *atom = script->getAtom(index);
 #if defined JS_POLYIC
-    jsbytecode *next = &PC[JSOP_NAMEINC_LENGTH];
-    bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next);
-    int amt = (op == JSOP_NAMEINC || op == JSOP_INCNAME) ? -1 : 1;
-
-    if (pop || (op == JSOP_INCNAME || op == JSOP_DECNAME)) {
-        /* These cases are easy, the original value is not observed. */
-
-        jsop_bindname(atom, false);
-        // OBJ
-
-        jsop_name(atom, JSVAL_TYPE_UNKNOWN);
-        // OBJ V
-
-        frame.push(Int32Value(amt));
+    int amt = (op == JSOP_NAMEINC || op == JSOP_INCNAME) ? 1 : -1;
+
+    jsop_bindname(atom, false);
+    // OBJ
+
+    jsop_name(atom, JSVAL_TYPE_UNKNOWN);
+    // OBJ V
+
+    if (!analysis->incrementInitialValueObserved(PC)) {
+        frame.push(Int32Value(-amt));
         // OBJ V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
         frame.syncAt(-3);
-        if (!jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0)))
+        if (!jsop_binary(JSOP_SUB, stubs::Sub, knownPushedType(0), pushedTypeSet(0)))
             return Compile_Retry;
         // OBJ N+1
 
-        if (!jsop_setprop(atom, false, pop))
+        if (!jsop_setprop(atom, false, analysis->popGuaranteed(PC)))
             return Compile_Error;
         // N+1
-
-        if (pop)
-            frame.pop();
     } else {
-        /* The pre-value is observed, making this more tricky. */
-
-        jsop_name(atom, JSVAL_TYPE_UNKNOWN);
-        // V
-
         jsop_pos();
-        // N
-
-        jsop_bindname(atom, false);
+        // OBJ N
+
+        frame.swap();
         // N OBJ
 
         frame.dupAt(-2);
         // N OBJ N
 
-        frame.push(Int32Value(-amt));
+        frame.push(Int32Value(amt));
         // N OBJ N 1
 
         frame.syncAt(-3);
-        if (!jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0)))
+        if (!jsop_binary(JSOP_ADD, stubs::Add, knownPushedType(0), pushedTypeSet(0)))
             return Compile_Retry;
         // N OBJ N+1
 
         if (!jsop_setprop(atom, false, true))
             return Compile_Error;
         // N N+1
 
         frame.pop();
         // N
     }
-
-    if (pop)
-        PC += JSOP_POP_LENGTH;
 #else
     prepareStubCall(Uses(0));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     INLINE_STUBCALL(stub);
     frame.pushSynced(knownPushedType(0));
 #endif
 
-    PC += JSOP_NAMEINC_LENGTH;
     return Compile_Okay;
 }
 
 CompileStatus
 mjit::Compiler::jsop_propinc(JSOp op, VoidStubAtom stub, uint32 index)
 {
     JSAtom *atom = script->getAtom(index);
 #if defined JS_POLYIC
-    jsbytecode *next = &PC[JSOP_PROPINC_LENGTH];
-    bool pop = (JSOp(*next) == JSOP_POP) && !analysis->jumpTarget(next);
-    int amt = (op == JSOP_PROPINC || op == JSOP_INCPROP) ? -1 : 1;
-
-    if (pop || (op == JSOP_INCPROP || op == JSOP_DECPROP)) {
-        /*
-         * These cases are easier, the original value is not observed.
-         * Use a consistent stack layout for the value as the observed case,
-         * so that if the operation overflows the stub will be able to find
-         * the modified object.
-         */
-
-        frame.dup();
-        // OBJ OBJ
-
-        frame.dup();
-        // OBJ * OBJ
-
-        if (!jsop_getprop(atom, JSVAL_TYPE_UNKNOWN))
-            return Compile_Error;
-        // OBJ * V
-
-        frame.push(Int32Value(amt));
-        // OBJ * V 1
+    int amt = (op == JSOP_PROPINC || op == JSOP_INCPROP) ? 1 : -1;
+
+    frame.dup();
+    // OBJ OBJ
+
+    if (!jsop_getprop(atom, JSVAL_TYPE_UNKNOWN))
+        return Compile_Error;
+    // OBJ V
+
+    if (!analysis->incrementInitialValueObserved(PC)) {
+        frame.push(Int32Value(-amt));
+        // OBJ V 1
 
         /* Use sub since it calls ValueToNumber instead of string concat. */
-        frame.syncAt(-4);
-        if (!jsop_binary(JSOP_SUB, stubs::Sub, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0)))
+        frame.syncAt(-3);
+        if (!jsop_binary(JSOP_SUB, stubs::Sub, knownPushedType(0), pushedTypeSet(0)))
             return Compile_Retry;
-        // OBJ * V+1
-
-        frame.shimmy(1);
-        // OBJ V+1
-
-        if (!jsop_setprop(atom, false, pop))
+        // OBJ N+1
+
+        if (!jsop_setprop(atom, false, analysis->popGuaranteed(PC)))
             return Compile_Error;
-        // V+1
-
-        if (pop)
-            frame.pop();
+        // N+1
     } else {
-        /* The pre-value is observed, making this more tricky. */
-
-        frame.dup();
-        // OBJ OBJ 
-
-        if (!jsop_getprop(atom, JSVAL_TYPE_UNKNOWN))
-            return Compile_Error;
-        // OBJ V
-
         jsop_pos();
         // OBJ N
 
-        frame.dup();
-        // OBJ N N
-
-        frame.push(Int32Value(-amt));
-        // OBJ N N 1
-
-        frame.syncAt(-4);
-        if (!jsop_binary(JSOP_ADD, stubs::Add, JSVAL_TYPE_UNKNOWN, pushedTypeSet(0)))
-            return Compile_Retry;
-        // OBJ N N+1
-
-        frame.dupAt(-3);
-        // OBJ N N+1 OBJ
+        frame.swap();
+        // N OBJ
 
         frame.dupAt(-2);
-        // OBJ N N+1 OBJ N+1
+        // N OBJ N
+
+        frame.push(Int32Value(amt));
+        // N OBJ N 1
+
+        frame.syncAt(-3);
+        if (!jsop_binary(JSOP_ADD, stubs::Add, knownPushedType(0), pushedTypeSet(0)))
+            return Compile_Retry;
+        // N OBJ N+1
 
         if (!jsop_setprop(atom, false, true))
             return Compile_Error;
-        // OBJ N N+1 N+1
-
-        frame.popn(2);
-        // OBJ N
-
-        frame.shimmy(1);
+        // N N+1
+
+        frame.pop();
         // N
     }
-    if (pop)
-        PC += JSOP_POP_LENGTH;
 #else
     prepareStubCall(Uses(1));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     INLINE_STUBCALL(stub);
     frame.pop();
     pushSyncedEntry(0);
 #endif
 
-    PC += JSOP_PROPINC_LENGTH;
     return Compile_Okay;
 }
 
 bool
 mjit::Compiler::iter(uintN flags)
 {
-    REJOIN_SITE_ANY();
     FrameEntry *fe = frame.peek(-1);
 
     /*
      * Stub the call if this is not a simple 'for in' loop or if the iterated
      * value is known to not be an object.
      */
     if ((flags != JSITER_ENUMERATE) || fe->isNotType(JSVAL_TYPE_OBJECT)) {
         prepareStubCall(Uses(1));
         masm.move(Imm32(flags), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::Iter);
+        INLINE_STUBCALL(stubs::Iter, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(JSVAL_TYPE_UNKNOWN);
         return true;
     }
 
     if (!fe->isTypeKnown()) {
         Jump notObject = frame.testObject(Assembler::NotEqual, fe);
         stubcc.linkExit(notObject, Uses(1));
@@ -5877,17 +5408,17 @@ mjit::Compiler::iter(uintN flags)
     masm.storePtr(ioreg, Address(T1, offsetof(JSContext, enumerators)));
 
     frame.freeReg(nireg);
     frame.freeReg(T1);
     frame.freeReg(T2);
 
     stubcc.leave();
     stubcc.masm.move(Imm32(flags), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::Iter);
+    OOL_STUBCALL(stubs::Iter, REJOIN_FALLTHROUGH);
 
     /* Push the iterator object. */
     frame.pop();
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, ioreg);
 
     stubcc.rejoin(Changes(1));
 
     return true;
@@ -5895,18 +5426,16 @@ mjit::Compiler::iter(uintN flags)
 
 /*
  * This big nasty function emits a fast-path for native iterators, producing
  * a temporary value on the stack for FORLOCAL,ARG,GLOBAL,etc ops to use.
  */
 void
 mjit::Compiler::iterNext()
 {
-    REJOIN_SITE(stubs::IterNext);
-
     FrameEntry *fe = frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
 
     /* Is it worth trying to pin this longer? Prolly not. */
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
@@ -5941,29 +5470,27 @@ mjit::Compiler::iterNext()
     masm.addPtr(Imm32(sizeof(jsid)), T2, T4);
     masm.storePtr(T4, Address(T1, offsetof(NativeIterator, props_cursor)));
 
     frame.freeReg(T4);
     frame.freeReg(T1);
     frame.freeReg(T2);
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::IterNext);
+    OOL_STUBCALL(stubs::IterNext, REJOIN_NONE);
 
     frame.pushUntypedPayload(JSVAL_TYPE_STRING, T3);
 
     /* Join with the stub call. */
     stubcc.rejoin(Changes(1));
 }
 
 bool
 mjit::Compiler::iterMore()
 {
-    AutoRejoinSite autoRejoin(this, JS_FUNC_TO_DATA_PTR(void *, stubs::IterMore));
-
     jsbytecode *target = &PC[JSOP_MOREITER_LENGTH];
     JSOp next = JSOp(*target);
     JS_ASSERT(next == JSOP_IFNE || next == JSOP_IFNEX);
 
     target += (next == JSOP_IFNE)
               ? GET_JUMP_OFFSET(target)
               : GET_JUMPX_OFFSET(target);
 
@@ -5989,31 +5516,29 @@ mjit::Compiler::iterMore()
 
     /* Get props_cursor, test */
     masm.loadPtr(Address(reg, offsetof(NativeIterator, props_cursor)), tempreg);
     masm.loadPtr(Address(reg, offsetof(NativeIterator, props_end)), reg);
 
     Jump jFast = masm.branchPtr(Assembler::LessThan, tempreg, reg);
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::IterMore);
-    autoRejoin.oolRejoin(stubcc.masm.label());
+    OOL_STUBCALL(stubs::IterMore, REJOIN_BRANCH);
     Jump j = stubcc.masm.branchTest32(Assembler::NonZero, Registers::ReturnReg,
                                       Registers::ReturnReg);
 
     stubcc.rejoin(Changes(1));
     frame.freeReg(tempreg);
 
     return jumpAndTrace(jFast, target, &j);
 }
 
 void
 mjit::Compiler::iterEnd()
 {
-    REJOIN_SITE_ANY();
     FrameEntry *fe= frame.peek(-1);
     RegisterID reg = frame.tempRegForData(fe);
 
     frame.pinReg(reg);
     RegisterID T1 = frame.allocReg();
     frame.unpinReg(reg);
 
     /* Test clasp */
@@ -6045,63 +5570,58 @@ mjit::Compiler::iterEnd()
     masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), T2);
     masm.loadPtr(Address(T1, offsetof(NativeIterator, next)), T1);
     masm.storePtr(T1, Address(T2, offsetof(JSContext, enumerators)));
 
     frame.freeReg(T1);
     frame.freeReg(T2);
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::EndIter);
+    OOL_STUBCALL(stubs::EndIter, REJOIN_FALLTHROUGH);
 
     frame.pop();
 
     stubcc.rejoin(Changes(1));
 }
 
 void
 mjit::Compiler::jsop_eleminc(JSOp op, VoidStub stub)
 {
-    REJOIN_SITE_ANY();
     prepareStubCall(Uses(2));
-    INLINE_STUBCALL(stub);
+    INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
     frame.popn(2);
     pushSyncedEntry(0);
 }
 
 void
 mjit::Compiler::jsop_getgname_slow(uint32 index)
 {
     prepareStubCall(Uses(0));
-    INLINE_STUBCALL(stubs::GetGlobalName);
+    INLINE_STUBCALL(stubs::GetGlobalName, REJOIN_GETTER);
     frame.pushSynced(JSVAL_TYPE_UNKNOWN);
 }
 
 void
 mjit::Compiler::jsop_bindgname()
 {
-    REJOIN_SITE(stubs::BindGlobalName);
-
     if (script->compileAndGo && globalObj) {
         frame.push(ObjectValue(*globalObj));
         return;
     }
 
     /* :TODO: this is slower than it needs to be. */
     prepareStubCall(Uses(0));
-    INLINE_STUBCALL(stubs::BindGlobalName);
+    INLINE_STUBCALL(stubs::BindGlobalName, REJOIN_NONE);
     frame.takeReg(Registers::ReturnReg);
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
 }
 
 void
 mjit::Compiler::jsop_getgname(uint32 index)
 {
-    REJOIN_SITE_2(ic::GetGlobalName, stubs::GetGlobalName);
-
     /* Optimize undefined, NaN and Infinity. */
     JSAtom *atom = script->getAtom(index);
     if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID]) {
         frame.push(UndefinedValue());
         return;
     }
     if (atom == cx->runtime->atomState.NaNAtom) {
         frame.push(cx->runtime->NaNValue);
@@ -6180,17 +5700,17 @@ mjit::Compiler::jsop_getgname(uint32 ind
         shapeGuard = masm.branch32WithPatch(Assembler::NotEqual, reg,
                                             Imm32(int32(INVALID_SHAPE)), ic.shape);
         frame.freeReg(reg);
     }
     stubcc.linkExit(shapeGuard, Uses(0));
 
     stubcc.leave();
     passMICAddress(ic);
-    ic.slowPathCall = OOL_STUBCALL(ic::GetGlobalName);
+    ic.slowPathCall = OOL_STUBCALL(ic::GetGlobalName, REJOIN_GETTER);
 
     /* Garbage value. */
     uint32 slot = 1 << 24;
 
     masm.loadPtr(Address(objReg, offsetof(JSObject, slots)), objReg);
     Address address(objReg, slot);
     
     /* Allocate any register other than objReg. */
@@ -6224,17 +5744,17 @@ mjit::Compiler::jsop_getgname(uint32 ind
 void
 mjit::Compiler::jsop_callgname_epilogue()
 {
     /*
      * This slow path does the same thing as the interpreter.
      */
     if (!script->compileAndGo) {
         prepareStubCall(Uses(1));
-        INLINE_STUBCALL_NO_REJOIN(stubs::PushImplicitThisForGlobal);
+        INLINE_STUBCALL(stubs::PushImplicitThisForGlobal, REJOIN_NONE);
         frame.pushSynced(JSVAL_TYPE_UNKNOWN);
         return;
     }
 
     /* Fast path for known-not-an-object callee. */
     FrameEntry *fval = frame.peek(-1);
     if (fval->isNotType(JSVAL_TYPE_OBJECT)) {
         frame.push(UndefinedValue());
@@ -6243,17 +5763,17 @@ mjit::Compiler::jsop_callgname_epilogue(
 
     /* Paths for known object callee. */
     if (fval->isConstant()) {
         JSObject *obj = &fval->getValue().toObject();
         if (obj->getParent() == globalObj) {
             frame.push(UndefinedValue());
         } else {
             prepareStubCall(Uses(1));
-            INLINE_STUBCALL_NO_REJOIN(stubs::PushImplicitThisForGlobal);
+            INLINE_STUBCALL(stubs::PushImplicitThisForGlobal, REJOIN_NONE);
             frame.pushSynced(JSVAL_TYPE_UNKNOWN);
         }
         return;
     }
 
     /*
      * Optimized version. This inlines the common case, calling a
      * (non-proxied) function that has the same global as the current
@@ -6286,47 +5806,42 @@ mjit::Compiler::jsop_callgname_epilogue(
      */
     masm.loadPtr(Address(objReg, offsetof(JSObject, parent)), objReg);
     Jump globalMismatch = masm.branchPtr(Assembler::NotEqual, objReg, ImmPtr(globalObj));
     stubcc.linkExit(globalMismatch, Uses(1));
     frame.freeReg(objReg);
 
     /* OOL stub call path. */
     stubcc.leave();
-    OOL_STUBCALL_NO_REJOIN(stubs::PushImplicitThisForGlobal);
+    OOL_STUBCALL(stubs::PushImplicitThisForGlobal, REJOIN_NONE);
 
     /* Fast path. */
     if (isNotObj.isSet())
         isNotObj.getJump().linkTo(masm.label(), &masm);
     frame.pushUntypedValue(UndefinedValue());
 
     stubcc.rejoin(Changes(1));
 }
 
 void
 mjit::Compiler::jsop_setgname_slow(JSAtom *atom, bool usePropertyCache)
 {
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
     if (usePropertyCache)
-        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalName));
+        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalName), REJOIN_FALLTHROUGH);
     else
-        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalNameNoCache));
+        INLINE_STUBCALL(STRICT_VARIANT(stubs::SetGlobalNameNoCache), REJOIN_FALLTHROUGH);
     frame.popn(2);
     pushSyncedEntry(0);
 }
 
 void
 mjit::Compiler::jsop_setgname(JSAtom *atom, bool usePropertyCache, bool popGuaranteed)
 {
-    REJOIN_SITE_2(ic::SetGlobalName,
-                  usePropertyCache
-                  ? STRICT_VARIANT(stubs::SetGlobalName)
-                  : STRICT_VARIANT(stubs::SetGlobalNameNoCache));
-
     if (monitored(PC)) {
         /* Global accesses are monitored only for a few names like __proto__. */
         jsop_setgname_slow(atom, usePropertyCache);
         return;
     }
 
     if (cx->typeInferenceEnabled() && globalObj->isGlobal() &&
         !globalObj->getType()->unknownProperties()) {
@@ -6392,17 +5907,17 @@ mjit::Compiler::jsop_setgname(JSAtom *at
                                             ic.shape);
         frame.freeReg(ic.shapeReg);
     }
     ic.shapeGuardJump = shapeGuard;
     ic.slowPathStart = stubcc.linkExit(shapeGuard, Uses(2));
 
     stubcc.leave();
     passMICAddress(ic);
-    ic.slowPathCall = OOL_STUBCALL(ic::SetGlobalName);
+    ic.slowPathCall = OOL_STUBCALL(ic::SetGlobalName, REJOIN_FALLTHROUGH);
 
     /* Garbage value. */
     uint32 slot = 1 << 24;
 
     ic.usePropertyCache = usePropertyCache;
 
     masm.loadPtr(Address(ic.objReg, offsetof(JSObject, slots)), ic.objReg);
     Address address(ic.objReg, slot);
@@ -6428,43 +5943,40 @@ mjit::Compiler::jsop_setgname(JSAtom *at
     jsop_setgname_slow(atom, usePropertyCache);
 #endif
 }
 
 void
 mjit::Compiler::jsop_setelem_slow()
 {
     prepareStubCall(Uses(3));
-    INLINE_STUBCALL(STRICT_VARIANT(stubs::SetElem));
+    INLINE_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
     frame.popn(3);
     frame.pushSynced(JSVAL_TYPE_UNKNOWN);
 }
 
 void
 mjit::Compiler::jsop_getelem_slow()
 {
     prepareStubCall(Uses(2));
-    INLINE_STUBCALL(stubs::GetElem);
+    INLINE_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
     frame.popn(2);
     pushSyncedEntry(0);
 }
 
 void
 mjit::Compiler::jsop_unbrand()
 {
-    REJOIN_SITE(stubs::Unbrand);
     prepareStubCall(Uses(1));
-    INLINE_STUBCALL(stubs::Unbrand);
+    INLINE_STUBCALL(stubs::Unbrand, REJOIN_FALLTHROUGH);
 }
 
 bool
 mjit::Compiler::jsop_instanceof()
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     // The fast path applies only when both operands are objects.
     if (rhs->isNotType(JSVAL_TYPE_OBJECT) || lhs->isNotType(JSVAL_TYPE_OBJECT)) {
         stubcc.linkExit(masm.jump(), Uses(2));
         frame.discardFe(lhs);
         frame.discardFe(rhs);
@@ -6484,17 +5996,17 @@ mjit::Compiler::jsop_instanceof()
     stubcc.linkExit(notFunction, Uses(2));
 
     /* Test for bound functions. */
     Jump isBound = masm.branchTest32(Assembler::NonZero, Address(obj, offsetof(JSObject, flags)),
                                      Imm32(JSObject::BOUND_FUNCTION));
     {
         stubcc.linkExit(isBound, Uses(2));
         stubcc.leave();
-        OOL_STUBCALL(stubs::InstanceOf);
+        OOL_STUBCALL(stubs::InstanceOf, REJOIN_FALLTHROUGH);
         firstSlow = stubcc.masm.jump();
     }
     
 
     /* This is sadly necessary because the error case needs the object. */
     frame.dup();
 
     if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, JSVAL_TYPE_UNKNOWN, false))
@@ -6530,17 +6042,17 @@ mjit::Compiler::jsop_instanceof()
     isFalse2.linkTo(masm.label(), &masm);
     masm.move(Imm32(0), temp);
     isTrue.linkTo(masm.label(), &masm);
 
     frame.freeReg(proto);
     frame.freeReg(obj);
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::FastInstanceOf);
+    OOL_STUBCALL(stubs::FastInstanceOf, REJOIN_FALLTHROUGH);
 
     frame.popn(3);
     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, temp);
 
     if (firstSlow.isSet())
         firstSlow.getJump().linkTo(stubcc.masm.label(), &stubcc.masm);
     stubcc.rejoin(Changes(1));
     return true;
@@ -6550,27 +6062,26 @@ void
 mjit::Compiler::emitEval(uint32 argc)
 {
     /* Check for interrupts on function call */
     interruptCheckHelper();
 
     frame.syncAndKill(Uses(argc + 2));
     prepareStubCall(Uses(argc + 2));
     masm.move(Imm32(argc), Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::Eval);
+    INLINE_STUBCALL(stubs::Eval, REJOIN_FALLTHROUGH);
     frame.popn(argc + 2);
     pushSyncedEntry(0);
 }
 
 void
 mjit::Compiler::jsop_arguments()
 {
-    REJOIN_SITE(stubs::Arguments);
     prepareStubCall(Uses(0));
-    INLINE_STUBCALL(stubs::Arguments);
+    INLINE_STUBCALL(stubs::Arguments, REJOIN_NONE);
 }
 
 bool
 mjit::Compiler::jsop_newinit()
 {
     bool isArray;
     unsigned count = 0;
     JSObject *baseobj = NULL;
@@ -6599,20 +6110,20 @@ mjit::Compiler::jsop_newinit()
         type = script->getTypeInitObject(cx, PC, isArray);
         if (!type)
             return false;
     }
     masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
 
     if (isArray) {
         masm.move(Imm32(count), Registers::ArgReg1);
-        INLINE_STUBCALL_NO_REJOIN(stubs::NewInitArray);
+        INLINE_STUBCALL(stubs::NewInitArray, REJOIN_NONE);
     } else {
         masm.move(ImmPtr(baseobj), Registers::ArgReg1);
-        INLINE_STUBCALL_NO_REJOIN(stubs::NewInitObject);
+        INLINE_STUBCALL(stubs::NewInitObject, REJOIN_NONE);
     }
     frame.takeReg(Registers::ReturnReg);
     frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
 
     frame.extra(frame.peek(-1)).initArray = (*PC == JSOP_NEWARRAY);
     frame.extra(frame.peek(-1)).initObject = baseobj;
 
     return true;
@@ -6675,18 +6186,17 @@ mjit::Compiler::finishLoop(jsbytecode *h
 #endif
 
     loop->entryJump().linkTo(masm.label(), &masm);
 
     jsbytecode *oldPC = PC;
 
     PC = entryTarget;
     {
-        REJOIN_SITE(stubs::MissedBoundsCheckEntry);
-        OOL_STUBCALL(stubs::MissedBoundsCheckEntry);
+        OOL_STUBCALL(stubs::MissedBoundsCheckEntry, REJOIN_RESUME);
 
         if (loop->generatingInvariants()) {
             /*
              * To do the initial load of the invariants, jump to the invariant
              * restore point after the call just emitted. :XXX: fix hackiness.
              */
             if (oomInVector)
                 return false;
@@ -6706,18 +6216,17 @@ mjit::Compiler::finishLoop(jsbytecode *h
     if (!analysis->getCode(head).safePoint) {
         /*
          * Emit a stub into the OOL path which loads registers from a synced state
          * and jumps to the loop head, for rejoining from the interpreter.
          */
         LoopEntry entry;
         entry.pcOffset = head - script->code;
 
-        AutoRejoinSite autoRejoinHead(this, JS_FUNC_TO_DATA_PTR(void *, stubs::MissedBoundsCheckHead));
-        OOL_STUBCALL(stubs::MissedBoundsCheckHead);
+        OOL_STUBCALL(stubs::MissedBoundsCheckHead, REJOIN_RESUME);
 
         if (loop->generatingInvariants()) {
             if (oomInVector)
                 return false;
             entry.label = callSites[callSites.length() - 1].loopJumpLabel;
         } else {
             entry.label = stubcc.masm.label();
         }
@@ -6731,17 +6240,16 @@ mjit::Compiler::finishLoop(jsbytecode *h
          */
         for (uint32 slot = ArgSlot(0); slot < TotalSlots(script); slot++) {
             if (a->varTypes[slot].type == JSVAL_TYPE_DOUBLE) {
                 FrameEntry *fe = frame.getSlotEntry(slot);
                 stubcc.masm.ensureInMemoryDouble(frame.addressOf(fe));
             }
         }
 
-        autoRejoinHead.oolRejoin(stubcc.masm.label());
         frame.prepareForJump(head, stubcc.masm, true);
         if (!stubcc.jumpInScript(stubcc.masm.jump(), head))
             return false;
 
         loopEntries.append(entry);
     }
     PC = oldPC;
 
@@ -6882,17 +6390,17 @@ mjit::Compiler::jumpAndTrace(Jump j, jsb
                                                    offsetof(TraceICInfo, loopCounter)));
 # endif
 
     /* Save and restore compiler-tracked PC, so cx->regs is right in InvokeTracer. */
     {
         jsbytecode* pc = PC;
         PC = target;
 
-        OOL_STUBCALL(stubs::InvokeTracer);
+        OOL_STUBCALL(stubs::InvokeTracer, REJOIN_NONE);
 
         PC = pc;
     }
 
     Jump no = stubcc.masm.branchTestPtr(Assembler::Zero, Registers::ReturnReg,
                                         Registers::ReturnReg);
     if (!cx->typeInferenceEnabled())
         stubcc.masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
@@ -6951,48 +6459,47 @@ mjit::Compiler::enterBlock(JSObject *obj
         masm.loadPtr(FrameAddress(VMFrame::offsetOfFp), JSFrameReg);
         interruptCheckHelper();
     }
 
     /* For now, don't bother doing anything for this opcode. */
     frame.syncAndForgetEverything();
     masm.move(ImmPtr(obj), Registers::ArgReg1);
     uint32 n = js_GetEnterBlockStackDefs(cx, script, PC);
-    INLINE_STUBCALL_NO_REJOIN(stubs::EnterBlock);
+    INLINE_STUBCALL(stubs::EnterBlock, REJOIN_NONE);
     frame.enterBlock(n);
 }
 
 void
 mjit::Compiler::leaveBlock()
 {
     /*
      * Note: After bug 535912, we can pass the block obj directly, inline
      * PutBlockObject, and do away with the muckiness in PutBlockObject.
      */
     uint32 n = js_GetVariableStackUses(JSOP_LEAVEBLOCK, PC);
     JSObject *obj = script->getObject(fullAtomIndex(PC + UINT16_LEN));
     prepareStubCall(Uses(n));
     masm.move(ImmPtr(obj), Registers::ArgReg1);
-    INLINE_STUBCALL_NO_REJOIN(stubs::LeaveBlock);
+    INLINE_STUBCALL(stubs::LeaveBlock, REJOIN_NONE);
     frame.leaveBlock(n);
 }
 
 // Creates the new object expected for constructors, and places it in |thisv|.
 // It is broken down into the following operations:
 //   CALLEE
 //   GETPROP "prototype"
 //   IFPRIMTOP:
 //       NULL
 //   call js_CreateThisFromFunctionWithProto(...)
 //
 bool
 mjit::Compiler::constructThis()
 {
     JS_ASSERT(isConstructing);
-    REJOIN_SITE(stubs::CreateThis);
 
     // Load the callee.
     frame.pushCallee();
 
     // Get callee.prototype.
     if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, JSVAL_TYPE_UNKNOWN, false, false))
         return false;
 
@@ -7010,17 +6517,17 @@ mjit::Compiler::constructThis()
     }
 
     // Done with the protoFe.
     frame.pop();
 
     prepareStubCall(Uses(0));
     if (protoReg != Registers::ArgReg1)
         masm.move(protoReg, Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::CreateThis);
+    INLINE_STUBCALL(stubs::CreateThis, REJOIN_RESUME);
     frame.freeReg(protoReg);
     return true;
 }
 
 bool
 mjit::Compiler::jsop_tableswitch(jsbytecode *pc)
 {
 #if defined JS_CPU_ARM
@@ -7049,17 +6556,17 @@ mjit::Compiler::jsop_tableswitch(jsbytec
     }
 
     FrameEntry *fe = frame.peek(-1);
     if (fe->isNotType(JSVAL_TYPE_INT32) || numJumps > 256) {
         frame.syncAndForgetEverything();
         masm.move(ImmPtr(originalPC), Registers::ArgReg1);
 
         /* prepareStubCall() is not needed due to forgetEverything() */
-        INLINE_STUBCALL_NO_REJOIN(stubs::TableSwitch);
+        INLINE_STUBCALL(stubs::TableSwitch, REJOIN_NONE);
         frame.pop();
         masm.jump(Registers::ReturnReg);
         return true;
     }
 
     RegisterID dataReg;
     if (fe->isConstant()) {
         JS_ASSERT(fe->isType(JSVAL_TYPE_INT32));
@@ -7094,29 +6601,29 @@ mjit::Compiler::jsop_tableswitch(jsbytec
     Jump defaultCase = masm.branch32(Assembler::AboveOrEqual, dataReg, Imm32(numJumps));
     BaseIndex jumpTarget(reg, dataReg, Assembler::ScalePtr);
     masm.jump(jumpTarget);
 
     if (notInt.isSet()) {
         stubcc.linkExitDirect(notInt.get(), stubcc.masm.label());
         stubcc.leave();
         stubcc.masm.move(ImmPtr(originalPC), Registers::ArgReg1);
-        OOL_STUBCALL_NO_REJOIN(stubs::TableSwitch);
+        OOL_STUBCALL(stubs::TableSwitch, REJOIN_NONE);
         stubcc.masm.jump(Registers::ReturnReg);
     }
     frame.pop();
     return jumpAndTrace(defaultCase, originalPC + defaultTarget);
 #endif
 }
 
 void
 mjit::Compiler::jsop_callelem_slow()
 {
     prepareStubCall(Uses(2));
-    INLINE_STUBCALL(stubs::CallElem);
+    INLINE_STUBCALL(stubs::CallElem, REJOIN_FALLTHROUGH);
     frame.popn(2);
     pushSyncedEntry(0);
     pushSyncedEntry(1);
 }
 
 void
 mjit::Compiler::jsop_forprop(JSAtom *atom)
 {
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -48,22 +48,16 @@
 #include "BaseCompiler.h"
 #include "StubCompiler.h"
 #include "MonoIC.h"
 #include "PolyIC.h"
 
 namespace js {
 namespace mjit {
 
-struct PatchableFrame {
-    StackFrame *fp;
-    jsbytecode *pc;
-    bool scriptedCall;
-};
-
 /*
  * Patch for storing call site and rejoin site return addresses at, for
  * redirecting the return address in InvariantFailure.
  */
 struct InvariantCodePatch {
     bool hasPatch;
     JSC::MacroAssembler::DataLabelPtr codePatch;
     InvariantCodePatch() : hasPatch(false) {}
@@ -328,104 +322,30 @@ class Compiler : public BaseCompiler
         uint32 ndefs;
     };
 
     struct InternalCallSite {
         uint32 returnOffset;
         DataLabelPtr inlinePatch;
         uint32 inlineIndex;
         jsbytecode *inlinepc;
-        size_t id;
+        RejoinState rejoin;
         bool ool;
         Label loopJumpLabel;
         InvariantCodePatch loopPatch;
 
-        // An AutoRejoinSite needs to capture this call site.
-        bool needsRejoin;
-
         InternalCallSite(uint32 returnOffset,
-                         uint32 inlineIndex, jsbytecode *inlinepc, size_t id,
-                         bool ool, bool needsRejoin)
+                         uint32 inlineIndex, jsbytecode *inlinepc,
+                         RejoinState rejoin, bool ool)
           : returnOffset(returnOffset),
-            inlineIndex(inlineIndex), inlinepc(inlinepc), id(id),
-            ool(ool), needsRejoin(needsRejoin)
-        { }
-    };
-
-    struct InternalRejoinSite {
-        Label label;
-        jsbytecode *pc;
-        size_t id;
-        InvariantCodePatch loopPatch;
-
-        InternalRejoinSite(Label label, jsbytecode *pc, size_t id)
-            : label(label), pc(pc), id(id)
+            inlineIndex(inlineIndex), inlinepc(inlinepc),
+            rejoin(rejoin), ool(ool)
         { }
     };
 
-    struct AutoRejoinSite {
-        Compiler *cc;
-        jsbytecode *pc;
-
-        bool force;
-        bool ool;
-        Label oolLabel;
-
-        // number of call/rejoin sites when this AutoRejoinSite was created.
-        uint32 startSites;
-        uint32 rejoinSites;
-
-        void *stub1;
-        void *stub2;
-        void *stub3;
-
-        AutoRejoinSite(Compiler *cc, void *stub1, void *stub2 = NULL, void *stub3 = NULL)
-            : cc(cc), pc(cc->PC), force(false), ool(false),
-              startSites(cc->callSites.length()),
-              rejoinSites(cc->rejoinSites.length()),
-              stub1(stub1), stub2(stub2), stub3(stub3)
-        {}
-
-        void forceGeneration()
-        {
-            force = true;
-        }
-
-        /*
-         * Rejoin a particular slow path label in a synced state, rather than
-         * the current point of the fast path when the AutoRejoinSite finishes.
-         */
-        void oolRejoin(Label label)
-        {
-            ool = true;
-            oolLabel = label;
-        }
-
-        ~AutoRejoinSite()
-        {
-            if (cc->a != cc->outer)
-                return;
-#ifdef DEBUG
-            JS_ASSERT(pc == cc->PC);
-            cc->checkRejoinSite(startSites, rejoinSites, stub1);
-            if (stub2)
-                cc->checkRejoinSite(startSites, rejoinSites, stub2);
-            if (stub3)
-                cc->checkRejoinSite(startSites, rejoinSites, stub3);
-#endif
-            if (force || cc->needRejoins(pc)) {
-                cc->addRejoinSite(stub1, ool, oolLabel);
-                if (stub2)
-                    cc->addRejoinSite(stub2, ool, oolLabel);
-                if (stub3)
-                    cc->addRejoinSite(stub3, ool, oolLabel);
-            }
-        }
-    };
-
     struct DoublePatch {
         double d;
         DataLabelPtr label;
         bool ool;
     };
 
     struct JumpTable {
         DataLabelPtr label;
@@ -453,20 +373,16 @@ class Compiler : public BaseCompiler
     bool isConstructing;
 
     /* SSA information for the outer script and all frames we will be inlining. */
     analyze::CrossScriptSSA ssa;
 
     JSObject *globalObj;
     Value *globalSlots;
 
-    /* Existing frames on the stack whose slots may need to be updated. */
-    const Vector<PatchableFrame> *patchFrames;
-
-    bool *savedTraps;
     Assembler masm;
     FrameState frame;
 
     /*
      * State for the current stack frame, and links to its parents going up to
      * the outermost script.
      */
 
@@ -526,17 +442,16 @@ class Compiler : public BaseCompiler
 #endif
 #if defined JS_POLYIC
     js::Vector<PICGenInfo, 16, CompilerAllocPolicy> pics;
     js::Vector<GetElementICInfo, 16, CompilerAllocPolicy> getElemICs;
     js::Vector<SetElementICInfo, 16, CompilerAllocPolicy> setElemICs;
 #endif
     js::Vector<CallPatchInfo, 64, CompilerAllocPolicy> callPatches;
     js::Vector<InternalCallSite, 64, CompilerAllocPolicy> callSites;
-    js::Vector<InternalRejoinSite, 64, CompilerAllocPolicy> rejoinSites;
     js::Vector<DoublePatch, 16, CompilerAllocPolicy> doubleList;
     js::Vector<uint32, 4, CompilerAllocPolicy> fixedDoubleEntries;
     js::Vector<JumpTable, 16> jumpTables;
     js::Vector<uint32, 16> jumpTableOffsets;
     js::Vector<LoopEntry, 16> loopEntries;
     StubCompiler stubcc;
     Label invokeLabel;
     Label arityLabel;
@@ -551,75 +466,50 @@ class Compiler : public BaseCompiler
     bool hasGlobalReallocation;
     bool oomInVector;       // True if we have OOM'd appending to a vector. 
     enum { NoApplyTricks, LazyArgsObj } applyTricks;
 
     Compiler *thisFromCtor() { return this; }
 
     friend class CompilerAllocPolicy;
   public:
-    Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing,
-             const Vector<PatchableFrame> *patchFrames);
+    Compiler(JSContext *cx, JSScript *outerScript, bool isConstructing);
     ~Compiler();
 
     CompileStatus compile();
 
     Label getLabel() { return masm.label(); }
     bool knownJump(jsbytecode *pc);
     Label labelOf(jsbytecode *target, uint32 inlineIndex);
     void addCallSite(const InternalCallSite &callSite);
     void addReturnSite(bool ool);
-    void inlineStubCall(void *stub, bool needsRejoin);
-    bool loadOldTraps(const Vector<CallSite> &site);
+    void inlineStubCall(void *stub, RejoinState rejoin);
 
     bool debugMode() { return debugMode_; }
     bool inlining() { return inlining_; }
 
-#ifdef DEBUG
-    void checkRejoinSite(uint32 nCallSites, uint32 nRejoinSites, void *stub);
-#endif
-    void addRejoinSite(void *stub, bool ool, Label oolLabel);
-
-    bool needRejoins(jsbytecode *pc)
-    {
-        // We'll never rejoin into an inlined frame.
-        if (a != outer)
-            return false;
-
-        // We need all rejoin points if we might expand an inline frame.
-        if (outerScript->inlineParents)
-            return true;
-
-        // Otherwise, only add rejoin points where there are active frames on stack.
-        for (unsigned i = 0; patchFrames && i < patchFrames->length(); i++) {
-            if ((*patchFrames)[i].pc == pc)
-                return true;
-        }
-        return false;
-    }
-
     jsbytecode *outerPC() {
         if (a == outer)
             return PC;
         ActiveFrame *scan = a;
         while (scan && scan->parent != outer)
             scan = scan->parent;
         return scan->parentPC;
     }
 
     jsbytecode *inlinePC() { return PC; }
     uint32 inlineIndex() { return a->inlineIndex; }
 
     Assembler &getAssembler(bool ool) { return ool ? stubcc.masm : masm; }
 
-    InvariantCodePatch *getInvariantPatch(unsigned index, bool call) {
-        return call ? &callSites[index].loopPatch : &rejoinSites[index].loopPatch;
+    InvariantCodePatch *getInvariantPatch(unsigned index) {
+        return &callSites[index].loopPatch;
     }
-    jsbytecode *getInvariantPC(unsigned index, bool call) {
-        return call ? callSites[index].inlinepc : rejoinSites[index].pc;
+    jsbytecode *getInvariantPC(unsigned index) {
+        return callSites[index].inlinepc;
     }
 
     bool arrayPrototypeHasIndexedProperty();
 
     bool activeFrameHasMultipleExits() {
         ActiveFrame *na = a;
         while (na->parent) {
             if (na->exitState)
@@ -658,17 +548,17 @@ class Compiler : public BaseCompiler
     /* Non-emitting helpers. */
     void pushSyncedEntry(uint32 pushed);
     uint32 fullAtomIndex(jsbytecode *pc);
     bool jumpInScript(Jump j, jsbytecode *pc);
     bool compareTwoValues(JSContext *cx, JSOp op, const Value &lhs, const Value &rhs);
     bool canUseApplyTricks();
 
     /* Emitting helpers. */
-    bool emitStubCmpOp(BoolStub stub, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused);
+    bool emitStubCmpOp(BoolStub stub, jsbytecode *target, JSOp fused);
     bool iter(uintN flags);
     void iterNext();
     bool iterMore();
     void iterEnd();
     MaybeJump loadDouble(FrameEntry *fe, FPRegisterID *fpReg, bool *allocated);
 #ifdef JS_POLYIC
     void passICAddress(BaseICInfo *ic);
 #endif
@@ -758,20 +648,20 @@ class Compiler : public BaseCompiler
     void jsop_binary_double(FrameEntry *lhs, FrameEntry *rhs, JSOp op, VoidStub stub,
                             JSValueType type);
     void slowLoadConstantDouble(Assembler &masm, FrameEntry *fe,
                                 FPRegisterID fpreg);
     void maybeJumpIfNotInt32(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
                              MaybeRegisterID &mreg);
     void maybeJumpIfNotDouble(Assembler &masm, MaybeJump &mj, FrameEntry *fe,
                               MaybeRegisterID &mreg);
-    bool jsop_relational(JSOp op, BoolStub stub, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused);
-    bool jsop_relational_full(JSOp op, BoolStub stub, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused);
-    bool jsop_relational_double(JSOp op, BoolStub stub, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused);
-    bool jsop_relational_int(JSOp op, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused);
+    bool jsop_relational(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+    bool jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+    bool jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+    bool jsop_relational_int(JSOp op, jsbytecode *target, JSOp fused);
 
     void emitLeftDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                             MaybeJump &lhsNotDouble, MaybeJump &rhsNotNumber,
                             MaybeJump &lhsUnknownDone);
     void emitRightDoublePath(FrameEntry *lhs, FrameEntry *rhs, FrameState::BinaryAlloc &regs,
                              MaybeJump &rhsNotNumber2);
     bool tryBinaryConstantFold(JSContext *cx, FrameState &frame, JSOp op,
                                FrameEntry *lhs, FrameEntry *rhs, Value *vp);
@@ -781,30 +671,30 @@ class Compiler : public BaseCompiler
     bool jsop_mod();
     void jsop_neg();
     void jsop_bitnot();
     void jsop_not();
     void jsop_typeof();
     bool booleanJumpScript(JSOp op, jsbytecode *target);
     bool jsop_ifneq(JSOp op, jsbytecode *target);
     bool jsop_andor(JSOp op, jsbytecode *target);
-    bool jsop_arginc(JSOp op, uint32 slot, bool popped);
-    bool jsop_localinc(JSOp op, uint32 slot, bool popped);
+    bool jsop_arginc(JSOp op, uint32 slot);
+    bool jsop_localinc(JSOp op, uint32 slot);
     bool jsop_newinit();
     void jsop_initmethod();
     void jsop_initprop();
     void jsop_initelem();
     void jsop_setelem_dense();
     bool jsop_setelem(bool popGuaranteed);
     bool jsop_getelem(bool isCall);
     void jsop_getelem_dense(bool isPacked);
     bool isCacheableBaseAndIndex(FrameEntry *obj, FrameEntry *id);
     void jsop_stricteq(JSOp op);
-    bool jsop_equality(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused);
-    bool jsop_equality_int_string(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused);
+    bool jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
+    bool jsop_equality_int_string(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused);
     void jsop_pos();
 
     static inline Assembler::Condition
     GetCompareCondition(JSOp op, JSOp fused)
     {
         bool ifeq = fused == JSOP_IFEQ;
         switch (op) {
           case JSOP_GT:
@@ -846,57 +736,27 @@ class Compiler : public BaseCompiler
 
     enum GetCharMode { GetChar, GetCharCode };
     CompileStatus compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode);
 
     void prepareStubCall(Uses uses);
     Call emitStubCall(void *ptr, DataLabelPtr *pinline);
 };
 
-// Given a stub call, emits the call into the inline assembly path. If
-// debug mode is on, adds the appropriate instrumentation for recompilation.
-#define INLINE_STUBCALL(stub)                                               \
-    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), true)
+// Given a stub call, emits the call into the inline assembly path. rejoin
+// indicates how to rejoin should this call trigger expansion/discarding.
+#define INLINE_STUBCALL(stub, rejoin)                                       \
+    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin)
 
-// Same as INLINE_STUBCALL, but cannot trigger recompilation.
-#define INLINE_STUBCALL_NO_REJOIN(stub)                                     \
-    inlineStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), false)
-
-// Given a stub call, emits the call into the out-of-line assembly path. If
-// debug mode is on, adds the appropriate instrumentation for recompilation.
+// Given a stub call, emits the call into the out-of-line assembly path.
 // Unlike the INLINE_STUBCALL variant, this returns the Call offset.
-#define OOL_STUBCALL(stub)                                                  \
-    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), true)
+#define OOL_STUBCALL(stub, rejoin)                                          \
+    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin)
 
 // Same as OOL_STUBCALL, but specifies a slot depth.
-#define OOL_STUBCALL_LOCAL_SLOTS(stub, slots)                               \
-    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), true, (slots))
-
-// Same as OOL_STUBCALL, but cannot trigger recompilation.
-#define OOL_STUBCALL_NO_REJOIN(stub)                                        \
-    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), false)
-
-// Define rejoin sites at a PC. For every stub or scripted call emitted, there
-// must be a rejoin site which captures it. These are scope based, so the
-// rejoin site must be declared before the stub call and finish its scope after
-// the call has been emitted. If it is emitted, the rejoin site will rejoin
-// the inline code once the scope is finished.
-
-#define REJOIN_SITE(stub)                                                   \
-    AutoRejoinSite autoRejoin(this, JS_FUNC_TO_DATA_PTR(void *, (stub)))
-
-#define REJOIN_SITE_2(stub1, stub2)                                         \
-    AutoRejoinSite autoRejoin(this, JS_FUNC_TO_DATA_PTR(void *, (stub1)),   \
-                              JS_FUNC_TO_DATA_PTR(void *, (stub2)))
-
-#define REJOIN_SITE_3(stub1, stub2, stub3)                                  \
-    AutoRejoinSite autoRejoin(this, JS_FUNC_TO_DATA_PTR(void *, (stub1)),   \
-                              JS_FUNC_TO_DATA_PTR(void *, (stub2)),         \
-                              JS_FUNC_TO_DATA_PTR(void *, (stub3)))
-
-#define REJOIN_SITE_ANY()                                                   \
-    AutoRejoinSite autoRejoin(this, (void *) RejoinSite::VARIADIC_ID)
+#define OOL_STUBCALL_LOCAL_SLOTS(stub, rejoin, slots)                       \
+    stubcc.emitStubCall(JS_FUNC_TO_DATA_PTR(void *, (stub)), rejoin, (slots))
 
 } /* namespace js */
 } /* namespace mjit */
 
 #endif
 
--- a/js/src/methodjit/FastArithmetic.cpp
+++ b/js/src/methodjit/FastArithmetic.cpp
@@ -187,18 +187,16 @@ mjit::Compiler::maybeJumpIfNotDouble(Ass
     } else if (fe->getKnownType() != JSVAL_TYPE_DOUBLE) {
         mj.setJump(masm.jump());
     }
 }
 
 bool
 mjit::Compiler::jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet)
 {
-    REJOIN_SITE(stub);
-
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, op, lhs, rhs, &v)) {
         if (!v.isInt32() && typeSet && !typeSet->hasType(types::TYPE_DOUBLE)) {
             /*
              * OK to ignore failure here, we aren't performing the operation
@@ -226,17 +224,17 @@ mjit::Compiler::jsop_binary(JSOp op, Voi
 #endif /* JS_CPU_ARM */
     ) {
         bool isStringResult = (op == JSOP_ADD) &&
                               (lhs->isType(JSVAL_TYPE_STRING) ||
                                rhs->isType(JSVAL_TYPE_STRING));
         JS_ASSERT_IF(isStringResult && type != JSVAL_TYPE_UNKNOWN, type == JSVAL_TYPE_STRING);
 
         prepareStubCall(Uses(2));
-        INLINE_STUBCALL(stub);
+        INLINE_STUBCALL(stub, REJOIN_BINARY);
         frame.popn(2);
         frame.pushSynced(isStringResult ? JSVAL_TYPE_STRING : type);
         return true;
     }
 
     /*
      * If this is an operation on which integer overflows can be ignored, treat
      * the result as an integer even if it has been marked as overflowing by
@@ -406,17 +404,17 @@ mjit::Compiler::jsop_binary_double(Frame
         if (type != JSVAL_TYPE_DOUBLE)
             masm.storeDouble(fpLeft, frame.addressOf(lhs));
     }
 
     if (done.isSet())
         done.getJump().linkTo(masm.label(), &masm);
 
     stubcc.leave();
-    OOL_STUBCALL(stub);
+    OOL_STUBCALL(stub, REJOIN_BINARY);
 
     if (allocateRight)
         frame.freeReg(fpRight);
 
     frame.popn(2);
 
     if (type == JSVAL_TYPE_DOUBLE) {
         frame.pushDouble(fpLeft);
@@ -506,17 +504,17 @@ mjit::Compiler::jsop_binary_full_simple(
 
     /* Slow paths funnel here. */
     if (notNumber.isSet())
         notNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 
     /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */
     frame.sync(stubcc.masm, Uses(2));
     stubcc.leave();
-    OOL_STUBCALL(stub);
+    OOL_STUBCALL(stub, REJOIN_BINARY);
 
     /* Finish up stack operations. */
     frame.popn(2);
 
     if (type == JSVAL_TYPE_INT32)
         frame.pushTypedPayload(type, regs.result);
     else
         frame.pushNumber(regs.result, true);
@@ -768,17 +766,17 @@ mjit::Compiler::jsop_binary_full(FrameEn
             rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
     }
     if (rhsNotNumber2.isSet())
         rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 
     /* Slow call - use frame.sync to avoid erroneous jump repatching in stubcc. */
     frame.sync(stubcc.masm, Uses(2));
     stubcc.leave();
-    OOL_STUBCALL(stub);
+    OOL_STUBCALL(stub, REJOIN_BINARY);
 
     /* Finish up stack operations. */
     frame.popn(2);
 
     /*
      * Steal the result register if we remat the LHS/RHS by undoing the operation.
      * In this case the result register was still assigned to the corresponding
      * frame entry (so it is synced properly in OOL paths), so steal it back.
@@ -804,17 +802,17 @@ mjit::Compiler::jsop_binary_full(FrameEn
 void
 mjit::Compiler::jsop_neg()
 {
     FrameEntry *fe = frame.peek(-1);
     JSValueType type = knownPushedType(0);
 
     if (fe->isTypeKnown() && fe->getKnownType() > JSVAL_UPPER_INCL_TYPE_OF_NUMBER_SET) {
         prepareStubCall(Uses(1));
-        INLINE_STUBCALL(stubs::Neg);
+        INLINE_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(type);
         return;
     }
 
     JS_ASSERT(!fe->isConstant());
 
     /* Handle negation of a known double, or of a known integer which has previously overflowed. */
@@ -847,17 +845,17 @@ mjit::Compiler::jsop_neg()
 
         /* Test for 0 and -2147483648 (both result in a double). */
         Jump zeroOrMinInt = masm.branchTest32(Assembler::Zero, reg, Imm32(0x7fffffff));
         stubcc.linkExit(zeroOrMinInt, Uses(1));
 
         masm.neg32(reg);
 
         stubcc.leave();
-        OOL_STUBCALL(stubs::Neg);
+        OOL_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
 
         frame.pop();
         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
         stubcc.rejoin(Changes(1));
         return;
     }
 
@@ -913,17 +911,17 @@ mjit::Compiler::jsop_neg()
         jmpIntRejoin.setJump(stubcc.masm.jump());
     }
 
     frame.freeReg(reg);
     if (feTypeReg.isSet())
         frame.unpinReg(feTypeReg.reg());
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::Neg);
+    OOL_STUBCALL(stubs::Neg, REJOIN_FALLTHROUGH);
 
     frame.pop();
     frame.pushSynced(type);
 
     /* Link jumps. */
     if (jmpNotDbl.isSet())
         stubcc.linkExitDirect(jmpNotDbl.getJump(), lblIntPath);
 
@@ -935,18 +933,16 @@ mjit::Compiler::jsop_neg()
         stubcc.crossJump(jmpIntRejoin.getJump(), masm.label());
 
     stubcc.rejoin(Changes(1));
 }
 
 bool
 mjit::Compiler::jsop_mod()
 {
-    REJOIN_SITE_ANY();
-
 #if defined(JS_CPU_X86)
     JSValueType type = knownPushedType(0);
 
     FrameEntry *lhs = frame.peek(-2);
     FrameEntry *rhs = frame.peek(-1);
 
     Value v;
     if (tryBinaryConstantFold(cx, frame, JSOP_MOD, lhs, rhs, &v)) {
@@ -962,17 +958,17 @@ mjit::Compiler::jsop_mod()
 
     if ((lhs->isConstant() && rhs->isConstant()) ||
         (lhs->isTypeKnown() && lhs->getKnownType() != JSVAL_TYPE_INT32) ||
         (rhs->isTypeKnown() && rhs->getKnownType() != JSVAL_TYPE_INT32) ||
         (type != JSVAL_TYPE_INT32 && type != JSVAL_TYPE_UNKNOWN))
 #endif
     {
         prepareStubCall(Uses(2));
-        INLINE_STUBCALL(stubs::Mod);
+        INLINE_STUBCALL(stubs::Mod, REJOIN_FALLTHROUGH);
         frame.popn(2);
         frame.pushSynced(knownPushedType(0));
         return true;
     }
 
 #if defined(JS_CPU_X86)
     if (!lhs->isTypeKnown()) {
         Jump j = frame.testInt32(Assembler::NotEqual, lhs);
@@ -1069,42 +1065,42 @@ mjit::Compiler::jsop_mod()
     /* Better - integer. */
     masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), frame.addressOf(lhs));
 
     if (done.isSet())
         done.getJump().linkTo(masm.label(), &masm);
 
     if (slowPath) {
         stubcc.leave();
-        OOL_STUBCALL(stubs::Mod);
+        OOL_STUBCALL(stubs::Mod, REJOIN_FALLTHROUGH);
     }
 
     frame.popn(2);
 
     if (type == JSVAL_TYPE_INT32)
         frame.pushTypedPayload(type, X86Registers::edx);
     else
         frame.pushNumber(X86Registers::edx);
 
     if (slowPath)
         stubcc.rejoin(Changes(1));
 
     if (gotNegZero.isSet()) {
         stubcc.linkExit(gotNegZero.getJump(), Uses(2));
         stubcc.leave();
-        OOL_STUBCALL(stubs::NegZeroHelper);
+        OOL_STUBCALL(stubs::NegZeroHelper, REJOIN_FALLTHROUGH);
         stubcc.rejoin(Changes(1));
     }
 #endif
 
     return true;
 }
 
 bool
-mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin,
+mjit::Compiler::jsop_equality_int_string(JSOp op, BoolStub stub,
                                          jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* Swap the LHS and RHS if it makes register allocation better... or possible. */
     if (lhs->isConstant() ||
         (frame.shouldAvoidDataRemat(lhs) && !rhs->isConstant())) {
@@ -1184,30 +1180,29 @@ mjit::Compiler::jsop_equality_int_string
         ic.stub = stub;
 
         bool useIC = (!addTraceHints || target >= PC) && !a->parent;
 
         /* Call the IC stub, which may generate a fast path. */
         if (useIC) {
             /* Adjust for the two values just pushed. */
             ic.addrLabel = stubcc.masm.moveWithPatch(ImmPtr(NULL), Registers::ArgReg1);
-            ic.stubCall = OOL_STUBCALL_LOCAL_SLOTS(ic::Equality,
+            ic.stubCall = OOL_STUBCALL_LOCAL_SLOTS(ic::Equality, REJOIN_BRANCH,
                                                    frame.totalDepth() + 2);
             needStub = false;
         }
 #endif
 
         if (needStub)
-            OOL_STUBCALL_LOCAL_SLOTS(stub, frame.totalDepth() + 2);
+            OOL_STUBCALL_LOCAL_SLOTS(stub, REJOIN_BRANCH, frame.totalDepth() + 2);
 
         /*
          * The stub call has no need to rejoin, since state is synced.
          * Instead, we can just test the return value.
          */
-        autoRejoin.oolRejoin(stubcc.masm.label());
         Jump stubBranch = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                                    Registers::ReturnReg, Registers::ReturnReg);
         Jump stubFallthrough = stubcc.masm.jump();
 
         JaegerSpew(JSpew_Insns, " ---- END STUB CALL CODE ---- \n");
         CHECK_OOL_SPACE();
 
         Jump fast;
@@ -1283,17 +1278,17 @@ mjit::Compiler::jsop_equality_int_string
             }
             if (!rhsInt) {
                 Jump rhsFail = frame.testInt32(Assembler::NotEqual, rhs);
                 stubcc.linkExit(rhsFail, Uses(2));
             }
         }
 
         stubcc.leave();
-        OOL_STUBCALL(stub);
+        OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
         RegisterID reg = frame.ownRegForData(lhs);
 
         /* x86/64's SET instruction can only take single-byte regs.*/
         RegisterID resultReg = reg;
         if (!(Registers::maskReg(reg) & Registers::SingleByteRegs))
             resultReg = frame.allocReg(Registers::SingleByteRegs).reg();
 
@@ -1413,17 +1408,17 @@ DoubleCondForOp(JSOp op, JSOp fused)
                : Assembler::DoubleLessThanOrEqual;
       default:
         JS_NOT_REACHED("unrecognized op");
         return Assembler::DoubleLessThan;
     }
 }
 
 bool
-mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused)
+mjit::Compiler::jsop_relational_double(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     if (target)
         fixDoubleTypes(target);
 
     JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
@@ -1442,29 +1437,28 @@ mjit::Compiler::jsop_relational_double(J
     Assembler::DoubleCondition dblCond = DoubleCondForOp(op, fused);
 
     if (target) {
         if (lhsNotNumber.isSet())
             stubcc.linkExitForBranch(lhsNotNumber.get());
         if (rhsNotNumber.isSet())
             stubcc.linkExitForBranch(rhsNotNumber.get());
         stubcc.leave();
-        OOL_STUBCALL(stub);
+        OOL_STUBCALL(stub, REJOIN_BRANCH);
 
         frame.syncAndKillEverything();
         Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
 
         if (allocateLeft)
             frame.freeReg(fpLeft);
         if (allocateRight)
             frame.freeReg(fpRight);
 
         frame.popn(2);
 
-        autoRejoin.oolRejoin(stubcc.masm.label());
         Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                            Registers::ReturnReg, Registers::ReturnReg);
 
         /* Rejoin from the slow path. */
         stubcc.rejoin(Changes(0));
 
         /*
          * NB: jumpAndTrace emits to the OOL path, so make sure not to use it
@@ -1473,17 +1467,17 @@ mjit::Compiler::jsop_relational_double(J
         if (!jumpAndTrace(j, target, &sj))
             return false;
     } else {
         if (lhsNotNumber.isSet())
             stubcc.linkExit(lhsNotNumber.get(), Uses(2));
         if (rhsNotNumber.isSet())
             stubcc.linkExit(rhsNotNumber.get(), Uses(2));
         stubcc.leave();
-        OOL_STUBCALL(stub);
+        OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
         frame.popn(2);
 
         RegisterID reg = frame.allocReg();
         Jump j = masm.branchDouble(dblCond, fpLeft, fpRight);
         masm.move(Imm32(0), reg);
         Jump skip = masm.jump();
         j.linkTo(masm.label(), &masm);
@@ -1499,17 +1493,17 @@ mjit::Compiler::jsop_relational_double(J
         if (allocateRight)
             frame.freeReg(fpRight);
     }
 
     return true;
 }
 
 bool
-mjit::Compiler::jsop_relational_int(JSOp op, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused)
+mjit::Compiler::jsop_relational_int(JSOp op, jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* Reverse N cmp A comparisons.  The left side must be in a register. */
     if (lhs->isConstant()) {
         JS_ASSERT(!rhs->isConstant());
         FrameEntry *tmp = lhs;
@@ -1533,17 +1527,16 @@ mjit::Compiler::jsop_relational_int(JSOp
         } else {
             frame.pinReg(lreg);
             RegisterID rreg = frame.tempRegForData(rhs);
             frame.unpinReg(lreg);
             fast = masm.branch32(cond, lreg, rreg);
         }
         frame.popn(2);
 
-        autoRejoin.oolRejoin(stubcc.masm.label());
         Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                            Registers::ReturnReg, Registers::ReturnReg);
 
         return jumpAndTrace(fast, target, &sj);
     } else {
         RegisterID result = frame.allocReg();
         RegisterID lreg = frame.tempRegForData(lhs);
 
@@ -1560,20 +1553,18 @@ mjit::Compiler::jsop_relational_int(JSOp
         frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
     }
 
     return true;
 }
 
 /* See jsop_binary_full() for more information on how this works. */
 bool
-mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, AutoRejoinSite &rejoin, jsbytecode *target, JSOp fused)
+mjit::Compiler::jsop_relational_full(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
 {
-    AutoRejoinSite autoRejoin(this, JS_FUNC_TO_DATA_PTR(void *, stub));
-
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     if (target)
         fixDoubleTypes(target);
 
     /* Allocate all registers up-front. */
     FrameState::BinaryAlloc regs;
@@ -1642,18 +1633,17 @@ mjit::Compiler::jsop_relational_full(JSO
 
             /*
              * For fusions, spill the tracker state. xmm* remain intact. Note
              * that frame.sync() must be used directly, to avoid syncExit()'s
              * jumping logic.
              */
             frame.sync(stubcc.masm, Uses(frame.frameSlots()));
             stubcc.leave();
-            OOL_STUBCALL(stub);
-            autoRejoin.oolRejoin(stubcc.masm.label());
+            OOL_STUBCALL(stub, REJOIN_BRANCH);
         }
 
         /* Forget the world, preserving data. */
         frame.pinReg(cmpReg);
         if (reg.isSet())
             frame.pinReg(reg.reg());
         
         frame.popn(2);
@@ -1674,17 +1664,16 @@ mjit::Compiler::jsop_relational_full(JSO
             fast = masm.branch32(i32Cond, cmpReg, reg.reg());
         else
             fast = masm.branch32(i32Cond, cmpReg, Imm32(value));
 
         /*
          * The stub call has no need to rejoin since state is synced. Instead,
          * we can just test the return value.
          */
-        autoRejoin.oolRejoin(stubcc.masm.label());
         Jump j = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                           Registers::ReturnReg, Registers::ReturnReg);
 
         /* Rejoin from the slow path. */
         Jump j2 = stubcc.masm.jump();
         stubcc.crossJump(j2, masm.label());
 
         /* :TODO: make double path invoke tracer. */
@@ -1730,17 +1719,17 @@ mjit::Compiler::jsop_relational_full(JSO
                     rhsNotNumber.get().linkTo(stubcc.masm.label(), &stubcc.masm);
             }
             if (rhsNotNumber2.isSet())
                 rhsNotNumber2.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 
             /* Emit the slow path - note full frame syncage. */
             frame.sync(stubcc.masm, Uses(2));
             stubcc.leave();
-            OOL_STUBCALL(stub);
+            OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
         }
 
         /* Get an integer comparison condition. */
         Assembler::Condition i32Cond = GetCompareCondition(cmpOp, fused);
 
         /* Emit the compare & set. */
         if (reg.isSet())
             masm.branchValue(i32Cond, cmpReg, reg.reg(), regs.result);
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -69,17 +69,17 @@ mjit::Compiler::compileMathAbsInt(FrameE
     stubcc.linkExit(isMinInt, Uses(3));
 
     masm.neg32(reg);
 
     isPositive.linkTo(masm.label(), &masm);
 
     stubcc.leave();
     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::SlowCall);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
 
     frame.popn(3);
     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
     stubcc.rejoin(Changes(1));
     return Compile_Okay;
 }
 
@@ -141,17 +141,17 @@ mjit::Compiler::compileRound(FrameEntry 
     stubcc.linkExit(overflow, Uses(3));
 
     if (allocate)
         frame.freeReg(fpReg);
     frame.freeReg(fpScratchReg);
 
     stubcc.leave();
     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::SlowCall);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
 
     frame.popn(3);
     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
     stubcc.rejoin(Changes(1));
     return Compile_Okay;
 }
 
@@ -213,17 +213,17 @@ mjit::Compiler::compileMathPowSimple(Fra
 
     frame.freeReg(fpScratchReg);
 
     if (allocate)
         frame.freeReg(fpReg);
 
     stubcc.leave();
     stubcc.masm.move(Imm32(2), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::SlowCall);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
 
     frame.popn(4);
     frame.pushDouble(fpResultReg);
 
     stubcc.rejoin(Changes(1));
     return Compile_Okay;
 }
 
@@ -292,17 +292,17 @@ mjit::Compiler::compileGetChar(FrameEntr
     if (thisValue->isConstant())
         frame.freeReg(strReg);
     if (arg->isConstant())
         frame.freeReg(argReg);
     frame.freeReg(reg1);
 
     stubcc.leave();
     stubcc.masm.move(Imm32(1), Registers::ArgReg1);
-    OOL_STUBCALL(stubs::SlowCall);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
 
     frame.popn(3);
     switch(mode) {
       case GetCharCode:
         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg2);
         break;
       case GetChar:
         frame.pushTypedPayload(JSVAL_TYPE_STRING, reg2);
--- a/js/src/methodjit/FastOps.cpp
+++ b/js/src/methodjit/FastOps.cpp
@@ -120,47 +120,43 @@ mjit::Compiler::ensureInteger(FrameEntry
 
         frame.learnType(fe, JSVAL_TYPE_INT32, dataReg);
     }
 }
 
 void
 mjit::Compiler::jsop_bitnot()
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *top = frame.peek(-1);
 
     /* We only want to handle integers here. */
     if (top->isNotType(JSVAL_TYPE_INT32) && top->isNotType(JSVAL_TYPE_DOUBLE)) {
         prepareStubCall(Uses(1));
-        INLINE_STUBCALL(stubs::BitNot);
+        INLINE_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
         frame.pop();
         frame.pushSynced(JSVAL_TYPE_INT32);
         return;
     }
 
     ensureInteger(top, Uses(1));
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::BitNot);
+    OOL_STUBCALL(stubs::BitNot, REJOIN_FALLTHROUGH);
 
     RegisterID reg = frame.ownRegForData(top);
     masm.not32(reg);
     frame.pop();
     frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
     stubcc.rejoin(Changes(1));
 }
 
 void
 mjit::Compiler::jsop_bitop(JSOp op)
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* The operands we ensure are integers cannot be copied by each other. */
     frame.separateBinaryEntries(lhs, rhs);
 
     VoidStub stub;
     switch (op) {
@@ -193,17 +189,17 @@ mjit::Compiler::jsop_bitop(JSOp op)
     /* Fast-path double to int conversion. */
     if (!lhs->isConstant() && rhs->isConstant() && lhsIntOrDouble &&
         rhs->isType(JSVAL_TYPE_INT32) && rhs->getValue().toInt32() == 0 &&
         (op == JSOP_BITOR || op == JSOP_LSH)) {
         ensureInteger(lhs, Uses(2));
         RegisterID reg = frame.ownRegForData(lhs);
 
         stubcc.leave();
-        OOL_STUBCALL(stub);
+        OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
         frame.popn(2);
         frame.pushTypedPayload(JSVAL_TYPE_INT32, reg);
 
         stubcc.rejoin(Changes(1));
         return;
     }
 
@@ -211,17 +207,17 @@ mjit::Compiler::jsop_bitop(JSOp op)
     if (rhs->isConstant() && rhs->getValue().isDouble())
         rhs->convertConstantDoubleToInt32(cx);
 
     /* We only want to handle integers here. */
     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE)) ||
         (op == JSOP_URSH && rhs->isConstant() && rhs->getValue().toInt32() % 32 == 0)) {
         prepareStubCall(Uses(2));
-        INLINE_STUBCALL(stub);
+        INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
         frame.popn(2);
         frame.pushSynced(op != JSOP_URSH ? JSVAL_TYPE_INT32 : knownPushedType(0));
         return;
     }
 
     ensureInteger(lhs, Uses(2));
     ensureInteger(rhs, Uses(2));
 
@@ -308,17 +304,17 @@ mjit::Compiler::jsop_bitop(JSOp op)
       case JSOP_URSH:
       {
         /* Not commutative. */
         if (rhs->isConstant()) {
             RegisterID reg = frame.ownRegForData(lhs);
             int shift = rhs->getValue().toInt32() & 0x1F;
 
             stubcc.leave();
-            OOL_STUBCALL(stub);
+            OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
             if (shift) {
                 if (op == JSOP_LSH)
                     masm.lshift32(Imm32(shift), reg);
                 else if (op == JSOP_RSH)
                     masm.rshift32(Imm32(shift), reg);
                 else
                     masm.urshift32(Imm32(shift), reg);
@@ -371,17 +367,17 @@ mjit::Compiler::jsop_bitop(JSOp op)
       }
 
       default:
         JS_NOT_REACHED("NYI");
         return;
     }
 
     stubcc.leave();
-    OOL_STUBCALL(stub);
+    OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
 
     frame.pop();
     frame.pop();
 
     JSValueType type = knownPushedType(0);
 
     if (type != JSVAL_TYPE_UNKNOWN && type != JSVAL_TYPE_DOUBLE)
         frame.pushTypedPayload(type, reg);
@@ -398,48 +394,47 @@ CheckNullOrUndefined(FrameEntry *fe)
 {
     if (!fe->isTypeKnown())
         return false;
     JSValueType type = fe->getKnownType();
     return type == JSVAL_TYPE_NULL || type == JSVAL_TYPE_UNDEFINED;
 }
 
 bool
-mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin, jsbytecode *target, JSOp fused)
+mjit::Compiler::jsop_equality(JSOp op, BoolStub stub, jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* The compiler should have handled constant folding. */
     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
 
     bool lhsTest;
     if ((lhsTest = CheckNullOrUndefined(lhs)) || CheckNullOrUndefined(rhs)) {
         /* What's the other mask? */
         FrameEntry *test = lhsTest ? rhs : lhs;
 
         if (test->isTypeKnown())
-            return emitStubCmpOp(stub, autoRejoin, target, fused);
+            return emitStubCmpOp(stub, target, fused);
 
         /* The other side must be null or undefined. */
         RegisterID reg = frame.ownRegForType(test);
         frame.pop();
         frame.pop();
 
         /*
          * :FIXME: Easier test for undefined || null?
          * Maybe put them next to each other, subtract, do a single compare?
          */
 
         if (target) {
             fixDoubleTypes(target);
             frame.syncAndKillEverything();
             frame.freeReg(reg);
 
-            autoRejoin.oolRejoin(stubcc.masm.label());
             Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                                Registers::ReturnReg, Registers::ReturnReg);
 
             if ((op == JSOP_EQ && fused == JSOP_IFNE) ||
                 (op == JSOP_NE && fused == JSOP_IFEQ)) {
                 /*
                  * It would be easier to just have two jumpAndTrace calls here, but since
                  * each jumpAndTrace creates a TRACE IC, and since we want the bytecode
@@ -494,17 +489,16 @@ mjit::Compiler::jsop_equality(JSOp op, B
         if (lhsKind != types::OBJECT_UNKNOWN && rhsKind != types::OBJECT_UNKNOWN) {
             /* :TODO: Merge with jsop_relational_int? */
             JS_ASSERT_IF(!target, fused != JSOP_IFEQ);
             frame.forgetMismatchedObject(lhs);
             frame.forgetMismatchedObject(rhs);
             Assembler::Condition cond = GetCompareCondition(op, fused);
             if (target) {
                 fixDoubleTypes(target);
-                autoRejoin.oolRejoin(stubcc.masm.label());
                 Jump sj = stubcc.masm.branchTest32(GetStubCompareCondition(fused),
                                                    Registers::ReturnReg, Registers::ReturnReg);
                 if (!frame.syncForBranch(target, Uses(2)))
                     return false;
                 RegisterID lreg = frame.tempRegForData(lhs);
                 frame.pinReg(lreg);
                 RegisterID rreg = frame.tempRegForData(rhs);
                 frame.unpinReg(lreg);
@@ -521,71 +515,69 @@ mjit::Compiler::jsop_equality(JSOp op, B
 
                 frame.popn(2);
                 frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
                 return true;
             }
         }
     }
 
-    return emitStubCmpOp(stub, autoRejoin, target, fused);
+    return emitStubCmpOp(stub, target, fused);
 }
 
 bool
-mjit::Compiler::jsop_relational(JSOp op, BoolStub stub, AutoRejoinSite &autoRejoin,
+mjit::Compiler::jsop_relational(JSOp op, BoolStub stub,
                                 jsbytecode *target, JSOp fused)
 {
     FrameEntry *rhs = frame.peek(-1);
     FrameEntry *lhs = frame.peek(-2);
 
     /* The compiler should have handled constant folding. */
     JS_ASSERT(!(rhs->isConstant() && lhs->isConstant()));
 
     /* Always slow path... */
     if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_DOUBLE) &&
          lhs->isNotType(JSVAL_TYPE_STRING)) ||
         (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_DOUBLE) &&
          rhs->isNotType(JSVAL_TYPE_STRING))) {
         if (op == JSOP_EQ || op == JSOP_NE)
-            return jsop_equality(op, stub, autoRejoin, target, fused);
-        return emitStubCmpOp(stub, autoRejoin, target, fused);
+            return jsop_equality(op, stub, target, fused);
+        return emitStubCmpOp(stub, target, fused);
     }
 
     if (op == JSOP_EQ || op == JSOP_NE) {
         if ((lhs->isNotType(JSVAL_TYPE_INT32) && lhs->isNotType(JSVAL_TYPE_STRING)) ||
             (rhs->isNotType(JSVAL_TYPE_INT32) && rhs->isNotType(JSVAL_TYPE_STRING))) {
-            return emitStubCmpOp(stub, autoRejoin, target, fused);
+            return emitStubCmpOp(stub, target, fused);
         } else if (!target && (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING))) {
-            return emitStubCmpOp(stub, autoRejoin, target, fused);
+            return emitStubCmpOp(stub, target, fused);
         } else if (frame.haveSameBacking(lhs, rhs)) {
-            return emitStubCmpOp(stub, autoRejoin, target, fused);
+            return emitStubCmpOp(stub, target, fused);
         } else {
-            return jsop_equality_int_string(op, stub, autoRejoin, target, fused);
+            return jsop_equality_int_string(op, stub, target, fused);
         }
     }
 
     if (frame.haveSameBacking(lhs, rhs)) {
-        return emitStubCmpOp(stub, autoRejoin, target, fused);
+        return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_STRING) || rhs->isType(JSVAL_TYPE_STRING)) {
-        return emitStubCmpOp(stub, autoRejoin, target, fused);
+        return emitStubCmpOp(stub, target, fused);
     } else if (lhs->isType(JSVAL_TYPE_DOUBLE) || rhs->isType(JSVAL_TYPE_DOUBLE)) {
-        return jsop_relational_double(op, stub, autoRejoin, target, fused);
+        return jsop_relational_double(op, stub, target, fused);
     } else if (cx->typeInferenceEnabled() &&
                lhs->isType(JSVAL_TYPE_INT32) && rhs->isType(JSVAL_TYPE_INT32)) {
-        return jsop_relational_int(op, autoRejoin, target, fused);
+        return jsop_relational_int(op, target, fused);
     } else {
-        return jsop_relational_full(op, stub, autoRejoin, target, fused);
+        return jsop_relational_full(op, stub, target, fused);
     }
 }
 
 void
 mjit::Compiler::jsop_not()
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *top = frame.peek(-1);
 
     if (top->isConstant()) {
         const Value &v = top->getValue();
         frame.pop();
         frame.push(BooleanValue(!js_ValueToBoolean(v)));
         return;
     }
@@ -627,17 +619,17 @@ mjit::Compiler::jsop_not()
             frame.pop();
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
             break;
           }
 
           default:
           {
             prepareStubCall(Uses(1));
-            INLINE_STUBCALL(stubs::ValueToBoolean);
+            INLINE_STUBCALL(stubs::ValueToBoolean, REJOIN_NONE);
 
             RegisterID reg = Registers::ReturnReg;
             frame.takeReg(reg);
             masm.xor32(Imm32(1), reg);
 
             frame.pop();
             frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, reg);
             break;
@@ -684,17 +676,17 @@ mjit::Compiler::jsop_not()
     stubcc.crossJump(jmpInt32Exit, lblRejoin);
 
     jmpNotObject.linkTo(syncTarget, &stubcc.masm);
     stubcc.crossJump(jmpObjectExit, lblRejoin);
     
 
     /* Leave. */
     stubcc.leave();
-    OOL_STUBCALL(stubs::Not);
+    OOL_STUBCALL(stubs::Not, REJOIN_FALLTHROUGH);
 
     frame.pop();
     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, data);
 
     stubcc.rejoin(Changes(1));
 }
 
 void
@@ -777,17 +769,17 @@ mjit::Compiler::jsop_typeof()
                 frame.pop();
                 frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, result);
                 return;
             }
         }
     }
 
     prepareStubCall(Uses(1));
-    INLINE_STUBCALL_NO_REJOIN(stubs::TypeOf);
+    INLINE_STUBCALL(stubs::TypeOf, REJOIN_NONE);
     frame.pop();
     frame.takeReg(Registers::ReturnReg);
     frame.pushTypedPayload(JSVAL_TYPE_STRING, Registers::ReturnReg);
 }
 
 bool
 mjit::Compiler::booleanJumpScript(JSOp op, jsbytecode *target)
 {
@@ -919,49 +911,44 @@ mjit::Compiler::jsop_andor(JSOp op, jsby
         frame.pop();
         return true;
     }
 
     return booleanJumpScript(op, target);
 }
 
 bool
-mjit::Compiler::jsop_localinc(JSOp op, uint32 slot, bool popped)
+mjit::Compiler::jsop_localinc(JSOp op, uint32 slot)
 {
     updateVarType();
 
     types::TypeSet *types = pushedTypeSet(0);
     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
 
-    if (popped || (op == JSOP_INCLOCAL || op == JSOP_DECLOCAL)) {
-        int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? -1 : 1;
+    int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1;
 
+    if (!analysis->incrementInitialValueObserved(PC)) {
         // Before: 
         // After:  V
         frame.pushLocal(slot);
 
         // Before: V
         // After:  V 1
-        frame.push(Int32Value(amt));
+        frame.push(Int32Value(-amt));
 
         // Note, SUB will perform integer conversion for us.
         // Before: V 1
         // After:  N+1
         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
             return false;
 
         // Before: N+1
         // After:  N+1
-        frame.storeLocal(slot, popped, true);
-
-        if (popped)
-            frame.pop();
+        frame.storeLocal(slot, analysis->popGuaranteed(PC), true);
     } else {
-        int amt = (op == JSOP_LOCALINC || op == JSOP_INCLOCAL) ? 1 : -1;
-
         // Before:
         // After: V
         frame.pushLocal(slot);
 
         // Before: V
         // After:  N
         jsop_pos();
 
@@ -986,49 +973,44 @@ mjit::Compiler::jsop_localinc(JSOp op, u
         // After:  N
         frame.pop();
     }
 
     return true;
 }
 
 bool
-mjit::Compiler::jsop_arginc(JSOp op, uint32 slot, bool popped)
+mjit::Compiler::jsop_arginc(JSOp op, uint32 slot)
 {
     updateVarType();
 
     types::TypeSet *types = pushedTypeSet(0);
     JSValueType type = types ? types->getKnownTypeTag(cx) : JSVAL_TYPE_UNKNOWN;
 
-    if (popped || (op == JSOP_INCARG || op == JSOP_DECARG)) {
-        int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? -1 : 1;
+    int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
 
+    if (!analysis->incrementInitialValueObserved(PC)) {
         // Before: 
         // After:  V
         frame.pushArg(slot);
 
         // Before: V
         // After:  V 1
-        frame.push(Int32Value(amt));
+        frame.push(Int32Value(-amt));
 
         // Note, SUB will perform integer conversion for us.
         // Before: V 1
         // After:  N+1
         if (!jsop_binary(JSOP_SUB, stubs::Sub, type, types))
             return false;
 
         // Before: N+1
         // After:  N+1
-        frame.storeArg(slot, popped);
-
-        if (popped)
-            frame.pop();
+        frame.storeArg(slot, analysis->popGuaranteed(PC));
     } else {
-        int amt = (op == JSOP_ARGINC || op == JSOP_INCARG) ? 1 : -1;
-
         // Before:
         // After: V
         frame.pushArg(slot);
 
         // Before: V
         // After:  N
         jsop_pos();
 
@@ -1189,29 +1171,27 @@ mjit::Compiler::jsop_setelem_dense()
     // Fully store the value. :TODO: don't need to do this in the non-initlen case
     // if the array is packed and monomorphic.
     if (key.isConstant())
         masm.storeValue(vr, Address(slotsReg, key.index() * sizeof(Value)));
     else
         masm.storeValue(vr, BaseIndex(slotsReg, key.reg(), masm.JSVAL_SCALE));
 
     stubcc.leave();
-    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem));
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 
     if (!hoisted)
         frame.freeReg(slotsReg);
     frame.shimmy(2);
     stubcc.rejoin(Changes(2));
 }
 
 bool
 mjit::Compiler::jsop_setelem(bool popGuaranteed)
 {
-    REJOIN_SITE_2(STRICT_VARIANT(ic::SetElement), STRICT_VARIANT(stubs::SetElem));
-
     FrameEntry *obj = frame.peek(-3);
     FrameEntry *id = frame.peek(-2);
     FrameEntry *value = frame.peek(-1);
 
     if (!IsCacheableSetElem(obj, id, value) || monitored(PC)) {
         jsop_setelem_slow();
         return true;
     }
@@ -1337,19 +1317,19 @@ mjit::Compiler::jsop_setelem(bool popGua
         ic.holeGuard = masm.guardNotHole(slot);
         masm.storeValue(ic.vr, slot);
     }
     stubcc.linkExitDirect(ic.holeGuard, ic.slowPathStart);
 
     stubcc.leave();
 #if defined JS_POLYIC
     passICAddress(&ic);
-    ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement));
+    ic.slowPathCall = OOL_STUBCALL(STRICT_VARIANT(ic::SetElement), REJOIN_FALLTHROUGH);
 #else
-    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem));
+    OOL_STUBCALL(STRICT_VARIANT(stubs::SetElem), REJOIN_FALLTHROUGH);
 #endif
 
     ic.fastPathRejoin = masm.label();
 
     // When generating typed array stubs, it may be necessary to call
     // js_DoubleToECMAInt32(), which would clobber registers. To deal with
     // this, we tell the IC exactly which registers need to be saved
     // across calls.
@@ -1501,17 +1481,17 @@ mjit::Compiler::jsop_getelem_dense(bool 
         BaseIndex slot(slotsReg, key.reg(), masm.JSVAL_SCALE);
         holeCheck = masm.fastArrayLoadSlot(slot, !isPacked, typeReg, dataReg);
     }
 
     if (!isPacked && !allowUndefined)
         stubcc.linkExit(holeCheck, Uses(2));
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::GetElem);
+    OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
 
     frame.popn(2);
 
     if (type == JSVAL_TYPE_UNKNOWN || type == JSVAL_TYPE_DOUBLE)
         frame.pushRegs(typeReg.reg(), dataReg, type);
     else
         frame.pushTypedPayload(type, dataReg);
 
@@ -1529,19 +1509,16 @@ mjit::Compiler::jsop_getelem_dense(bool 
             stubcc.masm.loadValueAsComponents(UndefinedValue(), typeReg.reg(), dataReg);
         stubcc.linkRejoin(stubcc.masm.jump());
     }
 }
 
 bool
 mjit::Compiler::jsop_getelem(bool isCall)
 {
-    REJOIN_SITE_2(isCall ? ic::CallElement : ic::GetElement,
-                  isCall ? stubs::CallElem : stubs::GetElem);
-
     FrameEntry *obj = frame.peek(-2);
     FrameEntry *id = frame.peek(-1);
 
     if (!IsCacheableGetElem(obj, id)) {
         if (isCall)
             jsop_callelem_slow();
         else
             jsop_getelem_slow();
@@ -1662,24 +1639,24 @@ mjit::Compiler::jsop_getelem(bool isCall
     }
 
     stubcc.leave();
     if (objTypeGuard.isSet())
         objTypeGuard.get().linkTo(stubcc.masm.label(), &stubcc.masm);
 #ifdef JS_POLYIC
     passICAddress(&ic);
     if (isCall)
-        ic.slowPathCall = OOL_STUBCALL(ic::CallElement);
+        ic.slowPathCall = OOL_STUBCALL(ic::CallElement, REJOIN_FALLTHROUGH);
     else
-        ic.slowPathCall = OOL_STUBCALL(ic::GetElement);
+        ic.slowPathCall = OOL_STUBCALL(ic::GetElement, REJOIN_FALLTHROUGH);
 #else
     if (isCall)
-        ic.slowPathCall = OOL_STUBCALL(stubs::CallElem);
+        ic.slowPathCall = OOL_STUBCALL(stubs::CallElem, REJOIN_FALLTHROUGH);
     else
-        ic.slowPathCall = OOL_STUBCALL(stubs::GetElem);
+        ic.slowPathCall = OOL_STUBCALL(stubs::GetElem, REJOIN_FALLTHROUGH);
 #endif
 
     ic.fastPathRejoin = masm.label();
 
     frame.popn(2);
     frame.pushRegs(ic.typeReg, ic.objReg, knownPushedType(0));
     if (isCall)
         frame.pushSynced(knownPushedType(1));
@@ -1852,19 +1829,19 @@ mjit::Compiler::jsop_stricteq(JSOp op)
     }
 
     /* Is it impossible that both Values are ints? */
     if ((lhs->isTypeKnown() && lhs->isNotType(JSVAL_TYPE_INT32)) ||
         (rhs->isTypeKnown() && rhs->isNotType(JSVAL_TYPE_INT32))) {
         prepareStubCall(Uses(2));
 
         if (op == JSOP_STRICTEQ)
-            INLINE_STUBCALL_NO_REJOIN(stubs::StrictEq);
+            INLINE_STUBCALL(stubs::StrictEq, REJOIN_NONE);
         else
-            INLINE_STUBCALL_NO_REJOIN(stubs::StrictNe);
+            INLINE_STUBCALL(stubs::StrictNe, REJOIN_NONE);
 
         frame.popn(2);
         frame.pushSynced(JSVAL_TYPE_BOOLEAN);
         return;
     }
 
 #if !defined JS_CPU_ARM && !defined JS_CPU_SPARC
     /* Try an integer fast-path. */
@@ -1906,106 +1883,100 @@ mjit::Compiler::jsop_stricteq(JSOp op)
         masm.set32(cond, testReg, otherReg, resultReg);
     }
 
     frame.unpinReg(testReg);
 
     if (needStub) {
         stubcc.leave();
         if (op == JSOP_STRICTEQ)
-            OOL_STUBCALL_NO_REJOIN(stubs::StrictEq);
+            OOL_STUBCALL(stubs::StrictEq, REJOIN_NONE);
         else
-            OOL_STUBCALL_NO_REJOIN(stubs::StrictNe);
+            OOL_STUBCALL(stubs::StrictNe, REJOIN_NONE);
     }
 
     frame.popn(2);
     frame.pushTypedPayload(JSVAL_TYPE_BOOLEAN, resultReg);
 
     if (needStub)
         stubcc.rejoin(Changes(1));
 #else
     /* TODO: Port set32() logic to ARM. */
     prepareStubCall(Uses(2));
 
     if (op == JSOP_STRICTEQ)
-        INLINE_STUBCALL_NO_REJOIN(stubs::StrictEq);
+        INLINE_STUBCALL(stubs::StrictEq, REJOIN_NONE);
     else
-        INLINE_STUBCALL_NO_REJOIN(stubs::StrictNe);
+        INLINE_STUBCALL(stubs::StrictNe, REJOIN_NONE);
 
     frame.popn(2);
     frame.pushSyncedType(JSVAL_TYPE_BOOLEAN);
     return;
 #endif
 }
 
 void
 mjit::Compiler::jsop_pos()
 {
-    REJOIN_SITE(stubs::Pos);
-
     FrameEntry *top = frame.peek(-1);
 
     if (top->isTypeKnown()) {
         if (top->getKnownType() <= JSVAL_TYPE_INT32)
             return;
         prepareStubCall(Uses(1));
-        INLINE_STUBCALL(stubs::Pos);
+        INLINE_STUBCALL(stubs::Pos, REJOIN_POS);
         frame.pop();
         frame.pushSynced(knownPushedType(0));
         return;
     }
 
     frame.giveOwnRegs(top);
 
     Jump j;
     if (frame.shouldAvoidTypeRemat(top))
         j = masm.testNumber(Assembler::NotEqual, frame.addressOf(top));
     else
         j = masm.testNumber(Assembler::NotEqual, frame.tempRegForType(top));
     stubcc.linkExit(j, Uses(1));
 
     stubcc.leave();
-    OOL_STUBCALL(stubs::Pos);
+    OOL_STUBCALL(stubs::Pos, REJOIN_POS);
 
     stubcc.rejoin(Changes(1));
 }
 
 void
 mjit::Compiler::jsop_initmethod()
 {
-    REJOIN_SITE_ANY();
-
 #ifdef DEBUG
     FrameEntry *obj = frame.peek(-2);
 #endif
     JSAtom *atom = script->getAtom(fullAtomIndex(PC));
 
     /* Initializers with INITMETHOD are not fast yet. */
     JS_ASSERT(!frame.extra(obj).initObject);
 
     prepareStubCall(Uses(2));
     masm.move(ImmPtr(atom), Registers::ArgReg1);
-    INLINE_STUBCALL(stubs::InitMethod);
+    INLINE_STUBCALL(stubs::InitMethod, REJOIN_FALLTHROUGH);
 }
 
 void
 mjit::Compiler::jsop_initprop()
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *obj = frame.peek(-2);
     FrameEntry *fe = frame.peek(-1);
     JSAtom *atom = script->getAtom(fullAtomIndex(PC));
 
     JSObject *baseobj = frame.extra(obj).initObject;
 
     if (!baseobj || monitored(PC)) {
         prepareStubCall(Uses(2));
         masm.move(ImmPtr(atom), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::InitProp);
+        INLINE_STUBCALL(stubs::InitProp, REJOIN_FALLTHROUGH);
         return;
     }
 
     JSObject *holder;
     JSProperty *prop = NULL;
 #ifdef DEBUG
     int res =
 #endif
@@ -2020,35 +1991,33 @@ mjit::Compiler::jsop_initprop()
     Address address = masm.objPropAddress(baseobj, objReg, shape->slot);
     frame.storeTo(fe, address);
     frame.freeReg(objReg);
 }
 
 void
 mjit::Compiler::jsop_initelem()
 {
-    REJOIN_SITE_ANY();
-
     FrameEntry *obj = frame.peek(-3);
     FrameEntry *id = frame.peek(-2);
     FrameEntry *fe = frame.peek(-1);
 
     /*
      * The initialized index is always a constant, but we won't remember which
      * constant if there are branches inside the code computing the initializer
      * expression (e.g. the expression uses the '?' operator).  Slow path those
      * cases, as well as those where INITELEM is used on an object initializer
      * or a non-fast array initializer.
      */
     if (!id->isConstant() || !frame.extra(obj).initArray) {
         JSOp next = JSOp(PC[JSOP_INITELEM_LENGTH]);
 
         prepareStubCall(Uses(3));
         masm.move(Imm32(next == JSOP_ENDINIT ? 1 : 0), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::InitElem);
+        INLINE_STUBCALL(stubs::InitElem, REJOIN_FALLTHROUGH);
         return;
     }
 
     int32 idx = id->getValue().toInt32();
 
     RegisterID objReg = frame.copyDataIntoReg(obj);
 
     if (cx->typeInferenceEnabled()) {
--- a/js/src/methodjit/FrameEntry.h
+++ b/js/src/methodjit/FrameEntry.h
@@ -141,17 +141,17 @@ class FrameEntry
     // and thus potentially type_ at runtime.
     bool mightBeType(JSValueType type_) const {
         return !isNotType(type_);
     }
 
     /* Accessors for entries which are copies of other mutable entries. */
 
     bool isCopy() const { return !!copy; }
-    bool isCopied() const { return copied; }
+    bool isCopied() const { return copied != 0; }
 
     const FrameEntry *backing() const {
         return isCopy() ? copyOf() : this;
     }
 
     bool hasSameBacking(const FrameEntry *other) const {
         return backing() == other->backing();
     }
@@ -165,24 +165,29 @@ class FrameEntry
 #elif defined JS_PUNBOX64
         v_.asBits &= JSVAL_PAYLOAD_MASK;
         v_.asBits |= JSVAL_TYPE_TO_SHIFTED_TAG(type_);
 #endif
         knownType = type_;
     }
 
     void track(uint32 index) {
-        clear();
+        copied = 0;
+        copy = NULL;
         index_ = index;
         tracked = true;
     }
 
     void clear() {
-        copied = false;
-        copy = NULL;
+        JS_ASSERT(copied == 0);
+        if (copy) {
+            JS_ASSERT(copy->copied != 0);
+            copy->copied--;
+            copy = NULL;
+        }
     }
 
     uint32 trackerIndex() {
         return index_;
     }
 
     /*
      * Marks the FE as unsynced & invalid.
@@ -216,40 +221,32 @@ class FrameEntry
         v_.asBits = JSVAL_BITS(v);
         Value cv = Valueify(v);
         if (cv.isDouble())
             knownType = JSVAL_TYPE_DOUBLE;
         else
             knownType = cv.extractNonDoubleType();
     }
 
-    void setCopied() {
-        JS_ASSERT(!isCopy());
-        copied = true;
-    }
-
     FrameEntry *copyOf() const {
         JS_ASSERT(isCopy());
         JS_ASSERT_IF(!copy->temporary, copy < this);
         return copy;
     }
 
-    void setNotCopied() {
-        copied = false;
-    }
-
     /*
      * Set copy index.
      */
     void setCopyOf(FrameEntry *fe) {
-        JS_ASSERT(!isCopied());
+        clear();
         copy = fe;
         if (fe) {
             type.invalidate();
             data.invalidate();
+            fe->copied++;
         }
     }
 
     inline bool isTracked() const {
         return tracked;
     }
 
     inline void untrack() {
@@ -265,28 +262,26 @@ class FrameEntry
 
   private:
     JSValueType knownType;
     jsval_layout v_;
     RematInfo  type;
     RematInfo  data;
     uint32     index_;
     FrameEntry *copy;
-    bool       copied;
     bool       tracked;
     bool       temporary;
 
+    /* Number of copies of this entry. */
+    uint32     copied;
+
     /*
      * Offset of the last loop in which this entry was written or had a loop
      * register assigned.
      */
     uint32     lastLoop;
-
-#if JS_BITS_PER_WORD == 32
-    void *padding;
-#endif
 };
 
 } /* namespace mjit */
 } /* namespace js */
 
 #endif /* jsjaeger_valueinfo_h__ */
 
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -403,17 +403,16 @@ FrameState::pushTypedPayload(JSValueType
 }
 
 inline void
 FrameState::pushNumber(RegisterID payload, bool asInt32)
 {
     JS_ASSERT(!freeRegs.hasReg(payload));
 
     FrameEntry *fe = rawPush();
-    fe->clear();
 
     if (asInt32) {
         if (!fe->type.synced())
             masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
         fe->type.setMemory();
     } else {
         fe->type.setMemory();
     }
@@ -422,67 +421,58 @@ FrameState::pushNumber(RegisterID payloa
     fe->data.setRegister(payload);
     regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushInt32(RegisterID payload)
 {
     FrameEntry *fe = rawPush();
-    fe->clear();
 
     masm.storeTypeTag(ImmType(JSVAL_TYPE_INT32), addressOf(fe));
     fe->type.setMemory();
 
     fe->data.unsync();
     fe->data.setRegister(payload);
     regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushUntypedPayload(JSValueType type, RegisterID payload)
 {
     JS_ASSERT(!freeRegs.hasReg(payload));
 
     FrameEntry *fe = rawPush();
 
-    fe->clear();
-
     masm.storeTypeTag(ImmType(type), addressOf(fe));
 
     /* The forceful type sync will assert otherwise. */
 #ifdef DEBUG
     fe->type.unsync();
 #endif
     fe->type.setMemory();
     fe->data.unsync();
-    fe->setNotCopied();
-    fe->setCopyOf(NULL);
     fe->data.setRegister(payload);
     regstate(payload).associate(fe, RematInfo::DATA);
 }
 
 inline void
 FrameState::pushUntypedValue(const Value &v)
 {
     FrameEntry *fe = rawPush();
 
-    fe->clear();
-
     masm.storeValue(v, addressOf(fe));
 
     /* The forceful type sync will assert otherwise. */
 #ifdef DEBUG
     fe->type.unsync();
 #endif
     fe->type.setMemory();
     fe->data.unsync();
     fe->data.setMemory();
-    fe->setNotCopied();
-    fe->setCopyOf(NULL);
 }
 
 inline JSC::MacroAssembler::RegisterID
 FrameState::tempRegForType(FrameEntry *fe, RegisterID fallback)
 {
     JS_ASSERT(!regstate(fallback).fe());
     if (fe->isCopy())
         fe = fe->copyOf();
@@ -914,18 +904,17 @@ FrameState::learnType(FrameEntry *fe, JS
     fe->setType(type);
     if (unsync)
         fe->type.unsync();
 }
 
 inline void
 FrameState::learnType(FrameEntry *fe, JSValueType type, RegisterID data)
 {
-    /* The copied bit may be set on an entry, but there should not be any actual copies. */
-    JS_ASSERT_IF(fe->isCopied(), !isEntryCopied(fe));
+    JS_ASSERT(!fe->isCopied());
 
     forgetAllRegs(fe);
     fe->clear();
 
     fe->type.setConstant();
     fe->knownType = type;
 
     fe->data.setRegister(data);
@@ -1287,20 +1276,17 @@ FrameState::enterBlock(uint32 n)
 
     a->sp += n;
 }
 
 inline void
 FrameState::eviscerate(FrameEntry *fe)
 {
     forgetAllRegs(fe);
-    fe->type.invalidate();
-    fe->data.invalidate();
-    fe->setNotCopied();
-    fe->setCopyOf(NULL);
+    fe->resetUnsynced();
 }
 
 inline StateRemat
 FrameState::dataRematInfo(const FrameEntry *fe) const
 {
     if (fe->isCopy())
         fe = fe->copyOf();
 
--- a/js/src/methodjit/FrameState.cpp
+++ b/js/src/methodjit/FrameState.cpp
@@ -162,27 +162,22 @@ FrameState::associateReg(FrameEntry *fe,
 }
 
 void
 FrameState::popActiveFrame()
 {
     a->analysis->clearAllocations();
 
     if (a->parent) {
-        /* Free registers associated with local variables. */
-        Registers regs(Registers::AvailAnyRegs);
-        while (!regs.empty()) {
-            AnyRegisterID reg = regs.takeAnyReg();
-            if (!freeRegs.hasReg(reg)) {
-                FrameEntry *fe = regstate(reg).usedBy();
-                if (fe >= a->locals && !isTemporary(fe)) {
-                    syncAndForgetFe(fe);
-                    fe->clear();
-                }
-            }
+        /* Clear registers and copies used by local variables and stack slots. */
+        for (FrameEntry *fe = a->sp - 1; fe >= a->locals; fe--) {
+            if (!fe->isTracked())
+                continue;
+            forgetAllRegs(fe);
+            fe->clear();
         }
     }
 
     ActiveFrame *parent = a->parent;
     cx->delete_(a);
     a = parent;
 }
 
@@ -258,34 +253,16 @@ FrameState::variableLive(FrameEntry *fe,
 {
     JS_ASSERT(cx->typeInferenceEnabled());
     JS_ASSERT(fe > a->callee_ && fe < a->spBase);
 
     uint32 offset = pc - a->script->code;
     return a->analysis->liveness(entrySlot(fe)).live(offset);
 }
 
-bool
-FrameState::isEntryCopied(FrameEntry *fe) const
-{
-    /*
-     * :TODO: It would be better for fe->isCopied() to mean 'is actually copied'
-     * rather than 'might have copies', removing the need for this walk.
-     */
-    JS_ASSERT(fe->isCopied());
-
-    for (uint32 i = fe->trackerIndex() + 1; i < tracker.nentries; i++) {
-        FrameEntry *nfe = tracker[i];
-        if (!deadEntry(nfe) && nfe->isCopy() && nfe->copyOf() == fe)
-            return true;
-    }
-
-    return false;
-}
-
 AnyRegisterID
 FrameState::bestEvictReg(uint32 mask, bool includePinned) const
 {
     JS_ASSERT(cx->typeInferenceEnabled());
 
     /* Must be looking for a specific type of register. */
     JS_ASSERT((mask