Bug 720316 - Convert the various object and function indexes into uint32_t. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Thu, 19 Jan 2012 17:15:33 -0800
changeset 88862 551dcf40a209ee3ce2e708643fe2cee98acbf315
parent 88861 f91f161171dd7c6c9419c33020b23a8bda2b8934
child 88863 19addd0f1a6d04d483d5d6df2064b7fcd8e41620
push idunknown
push userunknown
push dateunknown
reviewersjorendorff
bugs720316
milestone13.0a1
Bug 720316 - Convert the various object and function indexes into uint32_t. r=jorendorff
js/src/frontend/BytecodeEmitter.cpp
js/src/jit-test/tests/basic/adjacent-trycatch-second-nested.js
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
js/src/jsanalyze.cpp
js/src/jsinfer.cpp
js/src/jsinterp.cpp
js/src/jsopcode.cpp
js/src/jsopcode.h
js/src/jsopcode.tbl
js/src/jsscript.cpp
js/src/jsxdrapi.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/InvokeHelpers.cpp
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -560,27 +560,36 @@ CheckTypeSet(JSContext *cx, BytecodeEmit
         CheckTypeSet(cx, bce, op);                                            \
     JS_END_MACRO
 
 #define EMIT_UINT16PAIR_IMM_OP(op, i, j)                                      \
     JS_BEGIN_MACRO                                                            \
         ptrdiff_t off_ = EmitN(cx, bce, op, 2 * UINT16_LEN);                  \
         if (off_ < 0)                                                         \
             return JS_FALSE;                                                  \
-        jsbytecode *pc_ = bce->code(off_);                                 \
+        jsbytecode *pc_ = bce->code(off_);                                    \
         SET_UINT16(pc_, i);                                                   \
         pc_ += UINT16_LEN;                                                    \
         SET_UINT16(pc_, j);                                                   \
     JS_END_MACRO
 
 #define EMIT_UINT16_IN_PLACE(offset, op, i)                                   \
     JS_BEGIN_MACRO                                                            \
-        bce->code(offset)[0] = op;                                         \
-        bce->code(offset)[1] = UINT16_HI(i);                               \
-        bce->code(offset)[2] = UINT16_LO(i);                               \
+        bce->code(offset)[0] = op;                                            \
+        bce->code(offset)[1] = UINT16_HI(i);                                  \
+        bce->code(offset)[2] = UINT16_LO(i);                                  \
+    JS_END_MACRO
+
+#define EMIT_UINT32_IN_PLACE(offset, op, i)                                   \
+    JS_BEGIN_MACRO                                                            \
+        bce->code(offset)[0] = op;                                            \
+        bce->code(offset)[1] = jsbytecode(i >> 24);                           \
+        bce->code(offset)[2] = jsbytecode(i >> 16);                           \
+        bce->code(offset)[3] = jsbytecode(i >> 8);                            \
+        bce->code(offset)[4] = jsbytecode(i);                                 \
     JS_END_MACRO
 
 static JSBool
 FlushPops(JSContext *cx, BytecodeEmitter *bce, intN *npops)
 {
     JS_ASSERT(*npops != 0);
     if (NewSrcNote(cx, bce, SRC_HIDDEN) < 0)
         return JS_FALSE;
@@ -965,77 +974,67 @@ EmitAtomOp(JSContext *cx, JSAtom *atom, 
 
 static bool
 EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL)
 {
     JS_ASSERT(pn->pn_atom != NULL);
     return EmitAtomOp(cx, pn->pn_atom, op, bce, psuffix);
 }
 
-static JSBool
-EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
-{
-    JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
-    return EmitIndexOp(cx, op, bce->objectList.index(objbox), bce);
-}
-
 static bool
 EmitIndex32(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
 {
     const size_t len = 1 + UINT32_INDEX_LEN;
+    JS_ASSERT(js_CodeSpec[op].length == len);
     ptrdiff_t offset = EmitCheck(cx, bce, len);
     if (offset < 0)
         return false;
 
     jsbytecode *next = bce->next();
     next[0] = jsbytecode(op);
     SET_UINT32_INDEX(next, index);
     bce->current->next = next + len;
     UpdateDepth(cx, bce, offset);
     CheckTypeSet(cx, bce, op);
     return true;
 }
 
 static bool
+EmitFunctionOp(JSContext *cx, JSOp op, uint32_t index, BytecodeEmitter *bce)
+{
+    return EmitIndex32(cx, op, index, bce);
+}
+
+static bool
+EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
+{
+    JS_ASSERT(JOF_OPTYPE(op) == JOF_OBJECT);
+    return EmitIndex32(cx, op, bce->objectList.index(objbox), bce);
+}
+
+static bool
 EmitRegExp(JSContext *cx, uint32_t index, BytecodeEmitter *bce)
 {
     return EmitIndex32(cx, JSOP_REGEXP, index, bce);
 }
 
-/*
- * What good are ARGNO_LEN and SLOTNO_LEN, you ask?  The answer is that, apart
- * from EmitSlotIndexOp, they abstract out the detail that both are 2, and in
- * other parts of the code there's no necessary relationship between the two.
- * The abstraction cracks here in order to share EmitSlotIndexOp code among
- * the JSOP_DEFLOCALFUN and JSOP_GET{ARG,VAR,LOCAL}PROP cases.
- */
-JS_STATIC_ASSERT(ARGNO_LEN == 2);
-JS_STATIC_ASSERT(SLOTNO_LEN == 2);
-
-static JSBool
-EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index, BytecodeEmitter *bce)
+static bool
+EmitSlotObjectOp(JSContext *cx, JSOp op, uintN slot, uint32_t index, BytecodeEmitter *bce)
 {
-    JSOp bigSuffix;
-    ptrdiff_t off;
-    jsbytecode *pc;
-
     JS_ASSERT(JOF_OPTYPE(op) == JOF_SLOTOBJECT);
-    bigSuffix = EmitBigIndexPrefix(cx, bce, index);
-    if (bigSuffix == JSOP_FALSE)
-        return JS_FALSE;
-
-    /* Emit [op, slot, index]. */
-    off = EmitN(cx, bce, op, 2 + INDEX_LEN);
+
+    ptrdiff_t off = EmitN(cx, bce, op, SLOTNO_LEN + UINT32_INDEX_LEN);
     if (off < 0)
-        return JS_FALSE;
-    pc = bce->code(off);
+        return false;
+
+    jsbytecode *pc = bce->code(off);
     SET_UINT16(pc, slot);
-    pc += 2;
-    SET_INDEX(pc, index);
-    return bigSuffix == JSOP_NOP || Emit1(cx, bce, bigSuffix) >= 0;
+    pc += SLOTNO_LEN;
+    SET_UINT32_INDEX(pc, index);
+    return true;
 }
 
 bool
 BytecodeEmitter::shouldNoteClosedName(ParseNode *pn)
 {
     return !callsEval() && pn->isDefn() && pn->isClosed();
 }
 
@@ -3905,18 +3904,29 @@ EmitFunctionDefNop(JSContext *cx, Byteco
 {
     return NewSrcNote2(cx, bce, SRC_FUNCDEF, (ptrdiff_t)index) >= 0 &&
            Emit1(cx, bce, JSOP_NOP) >= 0;
 }
 
 static bool
 EmitNewInit(JSContext *cx, BytecodeEmitter *bce, JSProtoKey key, ParseNode *pn)
 {
-    if (Emit3(cx, bce, JSOP_NEWINIT, (jsbytecode) key, 0) < 0)
-        return false;
+    const size_t len = 1 + UINT32_INDEX_LEN;
+    ptrdiff_t offset = EmitCheck(cx, bce, len);
+    if (offset < 0)
+        return false;
+
+    jsbytecode *next = bce->next();
+    next[0] = JSOP_NEWINIT;
+    next[1] = jsbytecode(key);
+    next[2] = 0;
+    next[3] = 0;
+    next[4] = 0;
+    bce->current->next = next + len;
+    UpdateDepth(cx, bce, offset);
     CheckTypeSet(cx, bce, JSOP_NEWINIT);
     return true;
 }
 
 bool
 ParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
 {
     switch (getKind()) {
@@ -5104,18 +5114,18 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
 
     /* Emit a bytecode pointing to the closure object in its immediate. */
     if (pn->getOp() != JSOP_NOP) {
         if ((pn->pn_funbox->tcflags & TCF_GENEXP_LAMBDA) &&
             NewSrcNote(cx, bce, SRC_GENEXP) < 0)
         {
             return false;
         }
-        EMIT_INDEX_OP(pn->getOp(), index);
-        return true;
+
+        return EmitFunctionOp(cx, pn->getOp(), index, bce);
     }
 
     /*
      * For a script we emit the code as we parse. Thus the bytecode for
      * top-level functions should go in the prolog to predefine their
      * names in the variable object before the already-generated main code
      * is executed. This extra work for top-level scripts is not necessary
      * when we emit the code for a function. It is fully parsed prior to
@@ -5124,17 +5134,18 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
      */
     if (!bce->inFunction()) {
         JS_ASSERT(!bce->topStmt);
         if (!BindGlobal(cx, bce, pn, fun->atom))
             return false;
         if (pn->pn_cookie.isFree()) {
             bce->switchToProlog();
             JSOp op = fun->isFlatClosure() ? JSOP_DEFFUN_FC : JSOP_DEFFUN;
-            EMIT_INDEX_OP(op, index);
+            if (!EmitFunctionOp(cx, op, index, bce))
+                return false;
             bce->switchToMain();
         }
 
         /* Emit NOP for the decompiler. */
         if (!EmitFunctionDefNop(cx, bce, index))
             return false;
     } else {
         uintN slot;
@@ -5144,17 +5155,17 @@ EmitFunc(JSContext *cx, BytecodeEmitter 
         pn->pn_index = index;
         JSOp op = fun->isFlatClosure() ? JSOP_DEFLOCALFUN_FC : JSOP_DEFLOCALFUN;
         if (pn->isClosed() &&
             !bce->callsEval() &&
             !bce->closedVars.append(pn->pn_cookie.slot()))
         {
             return false;
         }
-        return EmitSlotIndexOp(cx, op, slot, index, bce);
+        return EmitSlotObjectOp(cx, op, slot, index, bce);
     }
 
     return true;
 }
 
 static bool
 EmitDo(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
@@ -6041,18 +6052,21 @@ EmitObject(JSContext *cx, BytecodeEmitte
         /*
          * The object survived and has a predictable shape.  Update the original bytecode,
          * as long as we can do so without using a big index prefix/suffix.
          */
         ObjectBox *objbox = bce->parser->newObjectBox(obj);
         if (!objbox)
             return false;
         uintN index = bce->objectList.index(objbox);
-        if (FitsWithoutBigIndex(index))
-            EMIT_UINT16_IN_PLACE(offset, JSOP_NEWOBJECT, uint16_t(index));
+        if (FitsWithoutBigIndex(index)) {
+            MOZ_STATIC_ASSERT(JSOP_NEWINIT_LENGTH == JSOP_NEWOBJECT_LENGTH,
+                              "newinit and newobject must have equal length to edit in-place");
+            EMIT_UINT32_IN_PLACE(offset, JSOP_NEWOBJECT, uint32_t(index));
+        }
     }
 
     return true;
 }
 
 static bool
 EmitArray(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
 {
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/adjacent-trycatch-second-nested.js
@@ -0,0 +1,9 @@
+try { }
+catch (e) { }
+
+try { throw 2; }
+catch (e)
+{
+  try { throw 3; }
+  catch (e2) { }
+}
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-inline.js
@@ -1,13 +1,13 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in main. */
-  a = { valueOf: function () { trap(main, 34, "success()"); } };
+  a = { valueOf: function () { trap(main, 39, "success()"); } };
   a + "";
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
 assertEq(x, "success");
--- a/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
+++ b/js/src/jit-test/tests/jaeger/bug563000/trap-from-add-ool.js
@@ -1,14 +1,14 @@
 // |jit-test| debug
 setDebug(true);
 x = "notset";
 function main() {
   /* The JSOP_STOP in main. */
-  a = { valueOf: function () { trap(main, 55, "success()"); } };
+  a = { valueOf: function () { trap(main, 60, "success()"); } };
   b = "";
   eval();
   a + b;
   x = "failure";
 }
 function success() { x = "success"; }
 
 main();
--- a/js/src/jsanalyze.cpp
+++ b/js/src/jsanalyze.cpp
@@ -114,17 +114,17 @@ ScriptAnalysis::checkAliasedName(JSConte
      * current script, and mark that local/arg as escaping. We don't need to
      * worry about marking locals/arguments in scripts this is nested in, as
      * the escaping name will be caught by the parser and the nested local/arg
      * will be marked as closed.
      */
 
     JSAtom *atom;
     if (JSOp(*pc) == JSOP_DEFFUN) {
-        JSFunction *fun = script->getFunction(js_GetIndexFromBytecode(script, pc, 0));
+        JSFunction *fun = script->getFunction(GET_UINT32_INDEX(pc));
         atom = fun->atom;
     } else {
         JS_ASSERT(JOF_TYPE(js_CodeSpec[*pc].format) == JOF_ATOM);
         atom = script->getAtom(js_GetIndexFromBytecode(script, pc, 0));
     }
 
     uintN index;
     BindingKind kind = script->bindings.lookup(cx, atom, &index);
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -2021,17 +2021,17 @@ TypeCompartment::newAllocationSiteTypeOb
     jsbytecode *pc = key.script->code + key.offset;
 
     if (JSOp(*pc) == JSOP_NEWOBJECT) {
         /*
          * This object is always constructed the same way and will not be
          * observed by other code before all properties have been added. Mark
          * all the properties as definite properties of the object.
          */
-        JSObject *baseobj = key.script->getObject(GET_SLOTNO(pc));
+        JSObject *baseobj = key.script->getObject(GET_UINT32_INDEX(pc));
 
         if (!res->addDefiniteProperties(cx, baseobj))
             return NULL;
     }
 
     if (!allocationSiteTable->add(p, key, res)) {
         cx->compartment->types.setPendingNukeTypes(cx);
         return NULL;
@@ -2042,23 +2042,16 @@ TypeCompartment::newAllocationSiteTypeOb
 
 static inline jsid
 GetAtomId(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
 {
     unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, offset);
     return MakeTypeId(cx, ATOM_TO_JSID(script->getAtom(index)));
 }
 
-static inline JSObject *
-GetScriptObject(JSContext *cx, JSScript *script, const jsbytecode *pc, unsigned offset)
-{
-    unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, offset);
-    return script->getObject(index);
-}
-
 static inline const Value &
 GetScriptConst(JSContext *cx, JSScript *script, const jsbytecode *pc)
 {
     unsigned index = js_GetIndexFromBytecode(script, (jsbytecode*) pc, 0);
     return script->getConst(index);
 }
 
 bool
@@ -3523,17 +3516,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
                 return false;
             pushed[0].addType(cx, Type::ObjectType(object));
         } else {
             pushed[0].addType(cx, Type::UnknownType());
         }
         break;
 
       case JSOP_OBJECT: {
-        JSObject *obj = GetScriptObject(cx, script, pc, 0);
+        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
         pushed[0].addType(cx, Type::ObjectType(obj));
         break;
       }
 
       case JSOP_STOP:
         /* If a stop is reachable then the return type may be void. */
           if (script->function())
             TypeScript::ReturnTypes(script)->addType(cx, Type::UndefinedType());
@@ -3828,17 +3821,17 @@ ScriptAnalysis::analyzeTypesBytecode(JSC
 
       case JSOP_LAMBDA:
       case JSOP_LAMBDA_FC:
       case JSOP_DEFFUN:
       case JSOP_DEFFUN_FC:
       case JSOP_DEFLOCALFUN:
       case JSOP_DEFLOCALFUN_FC: {
         unsigned off = (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) ? SLOTNO_LEN : 0;
-        JSObject *obj = GetScriptObject(cx, script, pc, off);
+        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc + off));
 
         TypeSet *res = NULL;
         if (op == JSOP_LAMBDA || op == JSOP_LAMBDA_FC) {
             res = &pushed[0];
         } else if (op == JSOP_DEFLOCALFUN || op == JSOP_DEFLOCALFUN_FC) {
             uint32_t slot = GetBytecodeSlot(script, pc);
             if (trackSlot(slot)) {
                 res = &pushed[0];
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -1405,16 +1405,17 @@ js::Interpret(JSContext *cx, StackFrame 
  * To share the code for all len == 1 cases we use the specialized label with
  * code that falls through to advance_pc: .
  */
 # define END_CASE_LEN1      goto advance_pc_by_one;
 # define END_CASE_LEN2      len = 2; goto advance_pc;
 # define END_CASE_LEN3      len = 3; goto advance_pc;
 # define END_CASE_LEN4      len = 4; goto advance_pc;
 # define END_CASE_LEN5      len = 5; goto advance_pc;
+# define END_CASE_LEN7      len = 7; goto advance_pc;
 # define END_VARLEN_CASE    goto advance_pc;
 # define ADD_EMPTY_CASE(OP) BEGIN_CASE(OP)
 # define END_EMPTY_CASES    goto advance_pc_by_one;
 
 #endif /* !JS_THREADED_INTERP */
 
 #define ENABLE_INTERRUPTS() (interruptEnabler.enableInterrupts())
 
@@ -1430,22 +1431,16 @@ js::Interpret(JSContext *cx, StackFrame 
         JSAtom *atom;                                                         \
         LOAD_ATOM((PCOFF), atom);                                             \
         name = atom->asPropertyName();                                        \
     JS_END_MACRO
 
 #define GET_FULL_INDEX(PCOFF)                                                 \
     (atoms - script->atoms + GET_INDEX(regs.pc + (PCOFF)))
 
-#define LOAD_OBJECT(PCOFF, obj)                                               \
-    (obj = script->getObject(GET_FULL_INDEX(PCOFF)))
-
-#define LOAD_FUNCTION(PCOFF)                                                  \
-    (fun = script->getFunction(GET_FULL_INDEX(PCOFF)))
-
 #define LOAD_DOUBLE(PCOFF, dbl)                                               \
     (dbl = script->getConst(GET_FULL_INDEX(PCOFF)).toDouble())
 
 #if defined(JS_METHODJIT)
     bool useMethodJIT = false;
 #endif
 
 #ifdef JS_METHODJIT
@@ -2942,19 +2937,17 @@ BEGIN_CASE(JSOP_STRING)
     JSAtom *atom;
     LOAD_ATOM(0, atom);
     PUSH_STRING(atom);
 }
 END_CASE(JSOP_STRING)
 
 BEGIN_CASE(JSOP_OBJECT)
 {
-    JSObject *obj;
-    LOAD_OBJECT(0, obj);
-    PUSH_OBJECT(*obj);
+    PUSH_OBJECT(*script->getObject(GET_UINT32_INDEX(regs.pc)));
 }
 END_CASE(JSOP_OBJECT)
 
 BEGIN_CASE(JSOP_REGEXP)
 {
     /*
      * Push a regexp object cloned from the regexp literal object mapped by the
      * bytecode at pc.
@@ -3223,18 +3216,17 @@ END_CASE(JSOP_DEFVAR)
 BEGIN_CASE(JSOP_DEFFUN)
 {
     /*
      * A top-level function defined in Global or Eval code (see ECMA-262
      * Ed. 3), or else a SpiderMonkey extension: a named function statement in
      * a compound statement (not at the top statement level of global code, or
      * at the top level of a function body).
      */
-    JSFunction *fun;
-    LOAD_FUNCTION(0);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
     JSObject *obj = fun;
 
     JSObject *obj2;
     if (fun->isNullClosure()) {
         /*
          * Even a null closure needs a parent for principals finding.
          * FIXME: bug 476950, although debugger users may also demand some kind
          * of scope link for debugger-assisted eval-in-frame.
@@ -3333,18 +3325,17 @@ BEGIN_CASE(JSOP_DEFFUN)
         if (!parent->setProperty(cx, name, &rval, script->strictModeCode))
             goto error;
     } while (false);
 }
 END_CASE(JSOP_DEFFUN)
 
 BEGIN_CASE(JSOP_DEFFUN_FC)
 {
-    JSFunction *fun;
-    LOAD_FUNCTION(0);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
 
     JSObject *obj = js_NewFlatClosure(cx, fun);
     if (!obj)
         goto error;
 
     Value rval = ObjectValue(*obj);
 
     uintN attrs = regs.fp()->isEvalFrame()
@@ -3370,18 +3361,17 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
 {
     /*
      * Define a local function (i.e., one nested at the top level of another
      * function), parented by the current scope chain, stored in a local
      * variable slot that the compiler allocated.  This is an optimization over
      * JSOP_DEFFUN that avoids requiring a call object for the outer function's
      * activation.
      */
-    JSFunction *fun;
-    LOAD_FUNCTION(SLOTNO_LEN);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc + SLOTNO_LEN));
     JS_ASSERT(fun->isInterpreted());
     JS_ASSERT(!fun->isFlatClosure());
 
     JSObject *parent;
     if (fun->isNullClosure()) {
         parent = &regs.fp()->scopeChain();
     } else {
         parent = GetScopeChain(cx, regs.fp());
@@ -3396,33 +3386,31 @@ BEGIN_CASE(JSOP_DEFLOCALFUN)
 
     uint32_t slot = GET_SLOTNO(regs.pc);
     regs.fp()->slots()[slot].setObject(*obj);
 }
 END_CASE(JSOP_DEFLOCALFUN)
 
 BEGIN_CASE(JSOP_DEFLOCALFUN_FC)
 {
-    JSFunction *fun;
-    LOAD_FUNCTION(SLOTNO_LEN);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc + SLOTNO_LEN));
 
     JSObject *obj = js_NewFlatClosure(cx, fun);
     if (!obj)
         goto error;
 
     uint32_t slot = GET_SLOTNO(regs.pc);
     regs.fp()->slots()[slot].setObject(*obj);
 }
 END_CASE(JSOP_DEFLOCALFUN_FC)
 
 BEGIN_CASE(JSOP_LAMBDA)
 {
     /* Load the specified function object literal. */
-    JSFunction *fun;
-    LOAD_FUNCTION(0);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
     JSObject *obj = fun;
 
     /* do-while(0) so we can break instead of using a goto. */
     do {
         JSObject *parent;
         if (fun->isNullClosure()) {
             parent = &regs.fp()->scopeChain();
 
@@ -3505,18 +3493,17 @@ BEGIN_CASE(JSOP_LAMBDA)
     JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
 
     PUSH_OBJECT(*obj);
 }
 END_CASE(JSOP_LAMBDA)
 
 BEGIN_CASE(JSOP_LAMBDA_FC)
 {
-    JSFunction *fun;
-    LOAD_FUNCTION(0);
+    JSFunction *fun = script->getFunction(GET_UINT32_INDEX(regs.pc));
 
     JSObject *obj = js_NewFlatClosure(cx, fun);
     if (!obj)
         goto error;
     JS_ASSERT_IF(script->hasGlobal(), obj->getProto() == fun->getProto());
 
     PUSH_OBJECT(*obj);
 }
@@ -3683,18 +3670,17 @@ BEGIN_CASE(JSOP_NEWARRAY)
 
     PUSH_OBJECT(*obj);
     CHECK_INTERRUPT_HANDLER();
 }
 END_CASE(JSOP_NEWARRAY)
 
 BEGIN_CASE(JSOP_NEWOBJECT)
 {
-    JSObject *baseobj;
-    LOAD_OBJECT(0, baseobj);
+    JSObject *baseobj = script->getObject(GET_UINT32_INDEX(regs.pc));
 
     TypeObject *type = TypeScript::InitObject(cx, script, regs.pc, JSProto_Object);
     if (!type)
         goto error;
 
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
     if (!obj)
         goto error;
@@ -4230,19 +4216,17 @@ BEGIN_CASE(JSOP_GETFUNNS)
 }
 END_CASE(JSOP_GETFUNNS)
 #endif /* JS_HAS_XML_SUPPORT */
 
 BEGIN_CASE(JSOP_ENTERBLOCK)
 BEGIN_CASE(JSOP_ENTERLET0)
 BEGIN_CASE(JSOP_ENTERLET1)
 {
-    JSObject *obj;
-    LOAD_OBJECT(0, obj);
-    StaticBlockObject &blockObj = obj->asStaticBlock();
+    StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(regs.pc))->asStaticBlock();
     JS_ASSERT(regs.fp()->maybeBlockChain() == blockObj.enclosingBlock());
 
     if (op == JSOP_ENTERBLOCK) {
         JS_ASSERT(regs.fp()->base() + blockObj.stackDepth() == regs.sp);
         Value *vp = regs.sp + blockObj.slotCount();
         JS_ASSERT(regs.sp < vp);
         JS_ASSERT(vp <= regs.fp()->slots() + script->nslots);
         SetValueRangeToUndefined(regs.sp, vp);
--- a/js/src/jsopcode.cpp
+++ b/js/src/jsopcode.cpp
@@ -144,16 +144,17 @@ Dup(const char *chars, DupBuffer *cb)
     return cb->append(chars, strlen(chars) + 1);
 }
 
 uintN
 js_GetIndexFromBytecode(JSScript *script, jsbytecode *pc, ptrdiff_t pcoff)
 {
     JSOp op = JSOp(*pc);
     JS_ASSERT(js_CodeSpec[op].length >= 1 + pcoff + UINT16_LEN);
+    JS_ASSERT(js_CodeSpec[op].format & JOF_ATOM);
 
     /*
      * We need to detect index base prefix. It presents when resetbase
      * follows the bytecode.
      */
     uintN span = js_CodeSpec[op].length;
     uintN base = 0;
     if (pc - script->code + span < script->length) {
@@ -199,19 +200,17 @@ js_GetVariableBytecodeLength(jsbytecode 
 
 static uint32_t
 NumBlockSlots(JSScript *script, jsbytecode *pc)
 {
     JS_ASSERT(*pc == JSOP_ENTERBLOCK || *pc == JSOP_ENTERLET0 || *pc == JSOP_ENTERLET1);
     JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET0_LENGTH);
     JS_STATIC_ASSERT(JSOP_ENTERBLOCK_LENGTH == JSOP_ENTERLET1_LENGTH);
 
-    JSObject *obj = NULL;
-    GET_OBJECT_FROM_BYTECODE(script, pc, 0, obj);
-    return obj->asStaticBlock().slotCount();
+    return script->getObject(GET_UINT32_INDEX(pc))->asStaticBlock().slotCount();
 }
 
 uintN
 js::StackUses(JSScript *script, jsbytecode *pc)
 {
     JSOp op = (JSOp) *pc;
     const JSCodeSpec &cs = js_CodeSpec[op];
     if (cs.nuses >= 0)
@@ -536,17 +535,17 @@ js_Disassemble1(JSContext *cx, JSScript 
     }
     const JSCodeSpec *cs = &js_CodeSpec[op];
     ptrdiff_t len = (ptrdiff_t) cs->length;
     Sprint(sp, "%05u:", loc);
     if (lines)
         Sprint(sp, "%4u", JS_PCToLineNumber(cx, script, pc));
     Sprint(sp, "  %s", js_CodeName[op]);
 
-    switch (uint32_t type = JOF_TYPE(cs->format)) {
+    switch (JOF_TYPE(cs->format)) {
       case JOF_BYTE:
           // Scan the trynotes to find the associated catch block
           // and make the try opcode look like a jump instruction
           // with an offset. This simplifies code coverage analysis
           // based on this disassembled output.
           if (op == JSOP_TRY) {
               JSTryNoteArray *trynotes = script->trynotes();
               uint32_t i;
@@ -563,48 +562,51 @@ js_Disassemble1(JSContext *cx, JSScript 
         break;
 
       case JOF_JUMP: {
         ptrdiff_t off = GET_JUMP_OFFSET(pc);
         Sprint(sp, " %u (%+d)", loc + (intN) off, (intN) off);
         break;
       }
 
-      case JOF_ATOM:
-      case JOF_OBJECT: {
+      case JOF_ATOM: {
         uintN index = js_GetIndexFromBytecode(script, pc, 0);
         jsval v;
-        if (type == JOF_ATOM) {
-            if (op == JSOP_DOUBLE) {
-                v = script->getConst(index);
-            } else {
-                JSAtom *atom = script->getAtom(index);
-                v = STRING_TO_JSVAL(atom);
-            }
+        if (op == JSOP_DOUBLE) {
+            v = script->getConst(index);
         } else {
-            JS_ASSERT(type == JOF_OBJECT);
-
-            /* Don't call obj.toSource if analysis/inference is active. */
-            if (cx->compartment->activeAnalysis) {
-                Sprint(sp, " object");
-                break;
-            }
-
-            JSObject *obj = script->getObject(index);
-            v = OBJECT_TO_JSVAL(obj);
+            JSAtom *atom = script->getAtom(index);
+            v = STRING_TO_JSVAL(atom);
         }
         {
             JSAutoByteString bytes;
             if (!ToDisassemblySource(cx, v, &bytes))
                 return 0;
             Sprint(sp, " %s", bytes.ptr());
         }
         break;
       }
 
+      case JOF_OBJECT: {
+        /* Don't call obj.toSource if analysis/inference is active. */
+        if (cx->compartment->activeAnalysis) {
+            Sprint(sp, " object");
+            break;
+        }
+
+        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
+        {
+            JSAutoByteString bytes;
+            if (!ToDisassemblySource(cx, ObjectValue(*obj), &bytes))
+                return 0;
+            Sprint(sp, " %s", bytes.ptr());
+        }
+        break;
+      }
+
       case JOF_REGEXP: {
         JSObject *obj = script->getRegExp(GET_UINT32_INDEX(pc));
         JSAutoByteString bytes;
         if (!ToDisassemblySource(cx, ObjectValue(*obj), &bytes))
             return 0;
         Sprint(sp, " %s", bytes.ptr());
         break;
       }
@@ -659,20 +661,19 @@ js_Disassemble1(JSContext *cx, JSScript 
         break;
 
       case JOF_LOCAL:
         Sprint(sp, " %u", GET_SLOTNO(pc));
         break;
 
       case JOF_SLOTOBJECT: {
         Sprint(sp, " %u", GET_SLOTNO(pc));
-        uintN index = js_GetIndexFromBytecode(script, pc, SLOTNO_LEN);
-        jsval v = OBJECT_TO_JSVAL(script->getObject(index));
+        JSObject *obj = script->getObject(GET_UINT32_INDEX(pc + SLOTNO_LEN));
         JSAutoByteString bytes;
-        if (!ToDisassemblySource(cx, v, &bytes))
+        if (!ToDisassemblySource(cx, ObjectValue(*obj), &bytes))
             return 0;
         Sprint(sp, " %s", bytes.ptr());
         break;
       }
 
       {
         int i;
 
@@ -1852,18 +1853,17 @@ GetLocal(SprintStack *ss, jsint i)
     // hoping the right object is found.
     if (off <= -2 && ss->printer->pcstack) {
         jsbytecode *pc = ss->printer->pcstack[-2 - off];
 
         JS_ASSERT(ss->printer->script->code <= pc);
         JS_ASSERT(pc < (ss->printer->script->code + ss->printer->script->length));
 
         if (JSOP_ENTERBLOCK == (JSOp)*pc) {
-            jsatomid j = js_GetIndexFromBytecode(ss->printer->script, pc, 0);
-            JSObject *obj = script->getObject(j);
+            JSObject *obj = script->getObject(GET_UINT32_INDEX(pc));
 
             if (obj->isBlock()) {
                 uint32_t depth = obj->asBlock().stackDepth();
                 uint32_t count = obj->asBlock().slotCount();
                 if (jsuint(i - depth) < jsuint(count))
                     return GetLocalInSlot(ss, i, jsint(i - depth), obj);
             }
         }
@@ -2655,22 +2655,16 @@ Decompile(SprintStack *ss, jsbytecode *p
             fmt = ufmt;                                                       \
         }                                                                     \
         rval = QuoteString(&ss->sprinter, atom, quote_);                      \
         rval = SprintDupeStr(ss, rval);                                       \
         if (!rval)                                                            \
             return NULL;                                                      \
     JS_END_MACRO
 
-#define LOAD_OBJECT(PCOFF)                                                    \
-    GET_OBJECT_FROM_BYTECODE(jp->script, pc, PCOFF, obj)
-
-#define LOAD_FUNCTION(PCOFF)                                                  \
-    GET_FUNCTION_FROM_BYTECODE(jp->script, pc, PCOFF, fun)
-
 #define GET_SOURCE_NOTE_ATOM(sn, atom)                                        \
     JS_BEGIN_MACRO                                                            \
         jsatomid atomIndex_ = (jsatomid) js_GetSrcNoteOffset((sn), 0);        \
                                                                               \
         LOCAL_ASSERT(atomIndex_ < jp->script->natoms);                        \
         (atom) = jp->script->atoms[atomIndex_];                               \
     JS_END_MACRO
 
@@ -2731,19 +2725,18 @@ Decompile(SprintStack *ss, jsbytecode *p
          * set to nop or otherwise mutated to suppress auto-parens.
          */
         lastop = saveop;
         op = (JSOp) *pc;
         cs = &js_CodeSpec[op];
         if (cs->format & JOF_INDEXBASE) {
             /*
              * The decompiler uses js_GetIndexFromBytecode to get atoms and
-             * objects and ignores these suffix/prefix bytecodes, thus
-             * simplifying code that must process JSOP_GETTER/JSOP_SETTER
-             * prefixes.
+             * ignores these suffix/prefix bytecodes, thus simplifying code
+             * that must process JSOP_GETTER/JSOP_SETTER prefixes.
              */
             pc += cs->length;
             if (pc >= endpc)
                 break;
             op = (JSOp) *pc;
             cs = &js_CodeSpec[op];
         }
         saveop = op;
@@ -3287,17 +3280,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 rval = POP_STR();
                 LOCAL_ASSERT(strcmp(rval, with_cookie) == 0);
                 jp->indent -= 4;
                 js_printf(jp, "\t}\n");
                 break;
 
               case JSOP_ENTERBLOCK:
               {
-                LOAD_OBJECT(0);
+                obj = jp->script->getObject(GET_UINT32_INDEX(pc));
                 AtomVector atoms(cx);
                 StaticBlockObject &blockObj = obj->asStaticBlock();
 
                 if (!GetBlockNames(cx, blockObj, &atoms) || !PushBlockNames(cx, ss, atoms))
                     return NULL;
 
                 sn = js_GetSrcNote(jp->script, pc);
                 switch (sn ? SN_TYPE(sn) : SRC_NULL) {
@@ -3430,17 +3423,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 ss->sprinter.setOffset(GetOff(ss, top));
                 if (op == JSOP_LEAVEBLOCKEXPR)
                     todo = SprintCString(&ss->sprinter, rval);
                 break;
               }
 
               case JSOP_ENTERLET0:
               {
-                LOAD_OBJECT(0);
+                obj = jp->script->getObject(GET_UINT32_INDEX(pc));
                 StaticBlockObject &blockObj = obj->asStaticBlock();
 
                 AtomVector atoms(cx);
                 if (!GetBlockNames(cx, blockObj, &atoms))
                     return NULL;
 
                 sn = js_GetSrcNote(jp->script, pc);
                 LOCAL_ASSERT(SN_TYPE(sn) == SRC_DECL);
@@ -3549,17 +3542,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                *    the loop body prologue; there is no let head to decompile
                *    with switch.
                * Hence, the only thing to do is update the let vars' slots with
                * their names, taking care to preserve the iter/condition value
                * on top of the stack.
                */
               case JSOP_ENTERLET1:
               {
-                LOAD_OBJECT(0);
+                obj = jp->script->getObject(GET_UINT32_INDEX(pc));
                 StaticBlockObject &blockObj = obj->asStaticBlock();
 
                 AtomVector atoms(cx);
                 if (!GetBlockNames(cx, blockObj, &atoms))
                     return NULL;
 
                 LOCAL_ASSERT(js_GetSrcNote(jp->script, pc) == NULL);
                 LOCAL_ASSERT(ss->top - 1 == blockObj.stackDepth() + blockObj.slotCount());
@@ -4224,17 +4217,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                         op = saveop = JSOP_ENUMELEM;
                         len = 0;
                     } else {
                         LOCAL_ASSERT(SN_TYPE(sn) == SRC_DESTRUCTLET);
 
                         ptrdiff_t offsetToLet = js_GetSrcNoteOffset(sn, 0);
                         LOCAL_ASSERT(*(pc + offsetToLet) == JSOP_ENTERLET0);
 
-                        GET_OBJECT_FROM_BYTECODE(jp->script, pc + offsetToLet, 0, obj);
+                        obj = jp->script->getObject(GET_UINT32_INDEX(pc + offsetToLet));
                         StaticBlockObject &blockObj = obj->asStaticBlock();
 
                         uint32_t blockDepth = blockObj.stackDepth();
                         LOCAL_ASSERT(blockDepth < ss->top);
                         LOCAL_ASSERT(ss->top <= blockDepth + blockObj.slotCount());
 
                         AtomVector atoms(cx);
                         if (!GetBlockNames(cx, blockObj, &atoms))
@@ -4771,17 +4764,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 if (sn && SN_TYPE(sn) == SRC_GENEXP) {
                     Vector<JSAtom *> *innerLocalNames;
                     Vector<JSAtom *> *outerLocalNames;
                     JSScript *inner, *outer;
                     Vector<DecompiledOpcode> *decompiledOpcodes;
                     SprintStack ss2(cx);
                     JSFunction *outerfun;
 
-                    LOAD_FUNCTION(0);
+                    fun = jp->script->getFunction(GET_UINT32_INDEX(pc));
 
                     /*
                      * All allocation when decompiling is LIFO, using malloc or,
                      * more commonly, arena-allocating from cx->tempLifoAlloc
                      * Therefore after InitSprintStack succeeds, we must release
                      * to mark before returning.
                      */
                     LifoAllocScope las(&cx->tempLifoAlloc());
@@ -4897,17 +4890,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                         return NULL;
                     todo = SprintCString(&ss->sprinter, rval);
                     cx->free_((void *)rval);
                     break;
                 }
 #endif /* JS_HAS_GENERATOR_EXPRS */
                 /* FALL THROUGH */
 
-                LOAD_FUNCTION(0);
+                fun = jp->script->getFunction(GET_UINT32_INDEX(pc));
                 {
                     /*
                      * Always parenthesize expression closures. We can't force
                      * saveop to a low-precedence op to arrange for auto-magic
                      * parenthesization without confusing getter/setter code
                      * that checks for JSOP_LAMBDA.
                      */
                     bool grouped = !(fun->flags & JSFUN_EXPR_CLOSURE);
@@ -4923,17 +4916,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 break;
 
               case JSOP_CALLEE:
                 JS_ASSERT(jp->fun && jp->fun->atom);
                 todo = SprintString(&ss->sprinter, jp->fun->atom);
                 break;
 
               case JSOP_OBJECT:
-                LOAD_OBJECT(0);
+                obj = jp->script->getObject(GET_UINT32_INDEX(pc));
                 str = js_ValueToSource(cx, ObjectValue(*obj));
                 if (!str)
                     return NULL;
                 goto sprint_string;
 
               case JSOP_REGEXP:
                 obj = jp->script->getRegExp(GET_UINT32_INDEX(pc));
                 str = obj->asRegExp().toString(cx);
@@ -5127,17 +5120,17 @@ Decompile(SprintStack *ss, jsbytecode *p
                 SprintOpcodePermanent(jp, lval, lvalpc);
                 js_printf(jp, ":\n");
                 todo = -2;
                 break;
               }
 
               case JSOP_DEFFUN:
               case JSOP_DEFFUN_FC:
-                LOAD_FUNCTION(0);
+                fun = jp->script->getFunction(GET_UINT32_INDEX(pc));
                 todo = -2;
                 goto do_function;
                 break;
 
               case JSOP_HOLE:
                 todo = SprintPut(&ss->sprinter, "", 0);
                 break;
 
--- a/js/src/jsopcode.h
+++ b/js/src/jsopcode.h
@@ -202,21 +202,20 @@ SET_UINT32_INDEX(jsbytecode *pc, uint32_
 {
     pc[1] = (jsbytecode)(index >> 24);
     pc[2] = (jsbytecode)(index >> 16);
     pc[3] = (jsbytecode)(index >> 8);
     pc[4] = (jsbytecode)index;
 }
 
 /*
- * A literal is indexed by a per-script atom or object maps. Most scripts
- * have relatively few literals, so the standard JOF_ATOM and JOF_OBJECT
- * format specifies a fixed 16 bits of immediate operand index.
- * A script with more than 64K literals must wrap the bytecode into
- * JSOP_INDEXBASE and JSOP_RESETBASE pair.
+ * A literal is indexed by a per-script atom map.  Most scripts have relatively
+ * few literals, so the standard JOF_ATOM format specifies a fixed 16 bits of
+ * immediate operand index.  A script with more than 64K literals must wrap the
+ * bytecode into an JSOP_INDEXBASE and JSOP_RESETBASE pair.
  */
 #define INDEX_LEN               2
 #define INDEX_HI(i)             ((jsbytecode)((i) >> 8))
 #define INDEX_LO(i)             ((jsbytecode)(i))
 #define GET_INDEX(pc)           GET_UINT16(pc)
 #define SET_INDEX(pc,i)         ((pc)[1] = INDEX_HI(i), (pc)[2] = INDEX_LO(i))
 
 #define GET_INDEXBASE(pc)       (JS_ASSERT(*(pc) == JSOP_INDEXBASE),          \
@@ -355,28 +354,16 @@ js_GetIndexFromBytecode(JSScript *script
 
 #define GET_DOUBLE_FROM_BYTECODE(script, pc, pcoff, dbl)                      \
     JS_BEGIN_MACRO                                                            \
         uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
         JS_ASSERT(index_ < (script)->consts()->length);                       \
         (dbl) = (script)->getConst(index_).toDouble();                        \
     JS_END_MACRO
 
-#define GET_OBJECT_FROM_BYTECODE(script, pc, pcoff, obj)                      \
-    JS_BEGIN_MACRO                                                            \
-        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
-        obj = (script)->getObject(index_);                                    \
-    JS_END_MACRO
-
-#define GET_FUNCTION_FROM_BYTECODE(script, pc, pcoff, fun)                    \
-    JS_BEGIN_MACRO                                                            \
-        uintN index_ = js_GetIndexFromBytecode((script), (pc), (pcoff));      \
-        fun = (script)->getFunction(index_);                                  \
-    JS_END_MACRO
-
 #ifdef __cplusplus
 namespace js {
 
 extern uintN
 StackUses(JSScript *script, jsbytecode *pc);
 
 extern uintN
 StackDefs(JSScript *script, jsbytecode *pc);
--- a/js/src/jsopcode.tbl
+++ b/js/src/jsopcode.tbl
@@ -219,17 +219,17 @@ OPDEF(JSOP_SETCALL,   74, "setcall",    
 OPDEF(JSOP_ITER,      75, "iter",       NULL,         2,  1,  1,  0,  JOF_UINT8)
 OPDEF(JSOP_MOREITER,  76, "moreiter",   NULL,         1,  1,  2,  0,  JOF_BYTE)
 OPDEF(JSOP_ITERNEXT,  77, "iternext",   "<next>",     2,  0,  1,  0,  JOF_UINT8)
 OPDEF(JSOP_ENDITER,   78, "enditer",    NULL,         1,  1,  0,  0,  JOF_BYTE)
 
 OPDEF(JSOP_FUNAPPLY,  79, "funapply",   NULL,         3, -1,  1, 18,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 /* Push object literal: either an XML object or initialiser object. */
-OPDEF(JSOP_OBJECT,    80, "object",     NULL,         3,  0,  1, 19,  JOF_OBJECT)
+OPDEF(JSOP_OBJECT,    80, "object",     NULL,         5,  0,  1, 19,  JOF_OBJECT)
 
 /* Pop value and discard it. */
 OPDEF(JSOP_POP,       81, "pop",        NULL,         1,  1,  0,  2,  JOF_BYTE)
 
 /* Call a function as a constructor; operand is argc. */
 OPDEF(JSOP_NEW,       82, js_new_str,   NULL,         3, -1,  1, 17,  JOF_UINT16|JOF_INVOKE|JOF_TYPESET)
 
 OPDEF(JSOP_UNUSED0,   83, "unused0",    NULL,         1,  0,  0,  0,  JOF_BYTE)
@@ -246,19 +246,19 @@ OPDEF(JSOP_UINT16,    88, "uint16",     
 /*
  * Object and array literal support.  NEWINIT takes the kind of initializer
  * (JSProto_Array or JSProto_Object).  NEWARRAY is an array initializer
  * taking the final length, which can be filled in at the start and initialized
  * directly.  NEWOBJECT is an object initializer taking an object with the final
  * shape, which can be set at the start and slots then filled in directly.
  * NEWINIT has an extra byte so it can be exchanged with NEWOBJECT during emit.
  */
-OPDEF(JSOP_NEWINIT,   89, "newinit",    NULL,         3,  0,  1, 19,  JOF_UINT8|JOF_TYPESET)
+OPDEF(JSOP_NEWINIT,   89, "newinit",    NULL,         5,  0,  1, 19,  JOF_UINT8|JOF_TYPESET)
 OPDEF(JSOP_NEWARRAY,  90, "newarray",   NULL,         4,  0,  1, 19,  JOF_UINT24|JOF_TYPESET)
-OPDEF(JSOP_NEWOBJECT, 91, "newobject",  NULL,         3,  0,  1, 19,  JOF_OBJECT|JOF_TYPESET)
+OPDEF(JSOP_NEWOBJECT, 91, "newobject",  NULL,         5,  0,  1, 19,  JOF_OBJECT|JOF_TYPESET)
 OPDEF(JSOP_ENDINIT,   92, "endinit",    NULL,         1,  0,  0, 19,  JOF_BYTE)
 OPDEF(JSOP_INITPROP,  93, "initprop",   NULL,         3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_INITELEM,  94, "initelem",   NULL,         1,  3,  1,  3,  JOF_BYTE|JOF_ELEM|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_UNUSED14,  95, "unused14",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED15,  96, "unused15",   NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /* Fast inc/dec ops for args and locals. */
 OPDEF(JSOP_INCARG,    97, "incarg",     NULL,         3,  0,  1, 15,  JOF_QARG |JOF_NAME|JOF_INC|JOF_TMPSLOT3)
@@ -333,22 +333,22 @@ OPDEF(JSOP_ENUMELEM,  124,"enumelem",   
  * getter or setter.
  */
 OPDEF(JSOP_GETTER,    125,js_getter_str,NULL,         1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_SETTER,    126,js_setter_str,NULL,         1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Prolog bytecodes for defining function, var, and const names.
  */
-OPDEF(JSOP_DEFFUN,    127,"deffun",     NULL,         3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
+OPDEF(JSOP_DEFFUN,    127,"deffun",     NULL,         5,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
 OPDEF(JSOP_DEFCONST,  128,"defconst",   NULL,         3,  0,  0,  0,  JOF_ATOM|JOF_DECLARING)
 OPDEF(JSOP_DEFVAR,    129,"defvar",     NULL,         3,  0,  0,  0,  JOF_ATOM|JOF_DECLARING)
 
 /* Push a closure for a named or anonymous function expression. */
-OPDEF(JSOP_LAMBDA,    130, "lambda",    NULL,         3,  0,  1, 19,  JOF_OBJECT)
+OPDEF(JSOP_LAMBDA,    130, "lambda",    NULL,         5,  0,  1, 19,  JOF_OBJECT)
 
 /* Used for named function expression self-naming, if lightweight. */
 OPDEF(JSOP_CALLEE,    131, "callee",    NULL,         1,  0,  1, 19,  JOF_BYTE)
 
 /*
  * Like JSOP_SETLOCAL, but specialized to avoid requiring JSOP_POP immediately
  * after to throw away the exception value.
  */
@@ -372,17 +372,17 @@ OPDEF(JSOP_FINALLY,     135,"finally",  
 OPDEF(JSOP_GETFCSLOT,   136,"getfcslot",  NULL,       3,  0,  1, 19,  JOF_UINT16|JOF_NAME|JOF_TYPESET)
 OPDEF(JSOP_CALLFCSLOT,  137,"callfcslot", NULL,       3,  0,  1, 19,  JOF_UINT16|JOF_NAME|JOF_TYPESET)
 
 /*
  * Define a local function object as a local variable.
  * The local variable's slot number is the first immediate two-byte operand.
  * The function object's atom index is the second immediate operand.
  */
-OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
+OPDEF(JSOP_DEFLOCALFUN, 138,"deflocalfun",NULL,       7,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
 
 /* Extended jumps. */
 OPDEF(JSOP_UNUSED4,       139,"unused4",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED5,       140,"unused5",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED6,       141,"unused6",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED7,       142,"unused7",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED8,       143,"unused8",  NULL,       1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED9,       144,"unused9",  NULL,       1,  0,  0,  0,  JOF_BYTE)
@@ -436,20 +436,20 @@ OPDEF(JSOP_XMLELTEXPR,    179,"xmleltexp
 OPDEF(JSOP_XMLCDATA,      180,"xmlcdata",   NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLCOMMENT,    181,"xmlcomment", NULL,     3,  0,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_XMLPI,         182,"xmlpi",      NULL,     3,  1,  1, 19,  JOF_ATOM)
 OPDEF(JSOP_DELDESC,       183,"deldesc",    NULL,     1,  2,  1, 15,  JOF_BYTE|JOF_ELEM|JOF_DEL)
 
 OPDEF(JSOP_CALLPROP,      184,"callprop",   NULL,     3,  1,  1, 18,  JOF_ATOM|JOF_PROP|JOF_TYPESET|JOF_TMPSLOT3)
 
 /* Enter a let block/expr whose slots are at the top of the stack. */
-OPDEF(JSOP_ENTERLET0,     185,"enterlet0",  NULL,     3, -1, -1,  0,  JOF_OBJECT)
+OPDEF(JSOP_ENTERLET0,     185,"enterlet0",  NULL,     5, -1, -1,  0,  JOF_OBJECT)
 
 /* Enter a let block/expr whose slots are 1 below the top of the stack. */
-OPDEF(JSOP_ENTERLET1,     186,"enterlet1",  NULL,     3, -1, -1,  0,  JOF_OBJECT)
+OPDEF(JSOP_ENTERLET1,     186,"enterlet1",  NULL,     5, -1, -1,  0,  JOF_OBJECT)
 
 /*
  * Opcode to hold 24-bit immediate integer operands.
  */
 OPDEF(JSOP_UINT24,        187,"uint24",     NULL,     4,  0,  1, 16,  JOF_UINT24)
 
 /*
  * Opcodes to allow 24-bit atom or object indexes. Whenever an index exceeds
@@ -486,17 +486,17 @@ OPDEF(JSOP_CALLXMLNAME,   196, "callxmln
 /*
  * Specialized JSOP_TYPEOF to avoid reporting undefined for typeof(0, undef).
  */
 OPDEF(JSOP_TYPEOFEXPR,    197,"typeofexpr",  NULL,    1,  1,  1, 15,  JOF_BYTE|JOF_DETECTING)
 
 /*
  * Block-local scope support.
  */
-OPDEF(JSOP_ENTERBLOCK,    198,"enterblock",  NULL,    3,  0, -1,  0,  JOF_OBJECT)
+OPDEF(JSOP_ENTERBLOCK,    198,"enterblock",  NULL,    5,  0, -1,  0,  JOF_OBJECT)
 OPDEF(JSOP_LEAVEBLOCK,    199,"leaveblock",  NULL,    3, -1,  0,  0,  JOF_UINT16)
 
 
 OPDEF(JSOP_UNUSED1,       200,"unused1",    NULL,     1,  0,  0,  0,  JOF_BYTE)
 OPDEF(JSOP_UNUSED2,       201,"unused2",    NULL,     1,  0,  0,  0,  JOF_BYTE)
 
 /*
  * Generator and array comprehension support.
@@ -550,19 +550,19 @@ OPDEF(JSOP_LENGTH,        217, "length",
  * an array literal (e.g. property 0 in the array [, 1]).  This opcode is used
  * with the JSOP_NEWARRAY opcode.
  */
 OPDEF(JSOP_HOLE,          218, "hole",         NULL,  1,  0,  1,  0,  JOF_BYTE)
 
 /*
  * Variants of JSOP_{DEF{,LOCAL}FUN,LAMBDA} optimized for the flat closure case.
  */
-OPDEF(JSOP_DEFFUN_FC,     219,"deffun_fc",     NULL,  3,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
-OPDEF(JSOP_DEFLOCALFUN_FC,220,"deflocalfun_fc",NULL,  5,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
-OPDEF(JSOP_LAMBDA_FC,     221,"lambda_fc",     NULL,  3,  0,  1, 19,  JOF_OBJECT)
+OPDEF(JSOP_DEFFUN_FC,     219,"deffun_fc",     NULL,  5,  0,  0,  0,  JOF_OBJECT|JOF_DECLARING)
+OPDEF(JSOP_DEFLOCALFUN_FC,220,"deflocalfun_fc",NULL,  7,  0,  0,  0,  JOF_SLOTOBJECT|JOF_DECLARING|JOF_TMPSLOT)
+OPDEF(JSOP_LAMBDA_FC,     221,"lambda_fc",     NULL,  5,  0,  1, 19,  JOF_OBJECT)
 
 /*
  * Joined function object as method optimization support.
  */
 OPDEF(JSOP_SETMETHOD,     222,"setmethod",     NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
 OPDEF(JSOP_INITMETHOD,    223,"initmethod",    NULL,  3,  2,  1,  3,  JOF_ATOM|JOF_PROP|JOF_SET|JOF_DETECTING)
 
 OPDEF(JSOP_UNUSED16,      224,"unused16",      NULL,  1,  0,  0,  0,  JOF_BYTE)
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -1454,21 +1454,18 @@ js_PCToLineNumber(JSContext *cx, JSScrip
 
     /*
      * Special case: function definition needs no line number note because
      * the function's script contains its starting line number.
      */
     JSOp op = JSOp(*pc);
     if (js_CodeSpec[op].format & JOF_INDEXBASE)
         pc += js_CodeSpec[op].length;
-    if (*pc == JSOP_DEFFUN) {
-        JSFunction *fun;
-        GET_FUNCTION_FROM_BYTECODE(script, pc, 0, fun);
-        return fun->script()->lineno;
-    }
+    if (*pc == JSOP_DEFFUN)
+        return script->getFunction(GET_UINT32_INDEX(pc))->script()->lineno;
 
     /*
      * General case: walk through source notes accumulating their deltas,
      * keeping track of line-number notes, until we pass the note for pc's
      * offset within script->code.
      */
     uintN lineno = script->lineno;
     ptrdiff_t offset = 0;
--- a/js/src/jsxdrapi.h
+++ b/js/src/jsxdrapi.h
@@ -221,17 +221,17 @@ JS_XDRFindClassById(JSXDRState *xdr, uin
  * Bytecode version number. Increment the subtrahend whenever JS bytecode
  * changes incompatibly.
  *
  * This version number is XDR'd near the front of xdr bytecode and
  * aborts deserialization if there is a mismatch between the current
  * and saved versions. If deserialization fails, the data should be
  * invalidated if possible.
  */
-#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 105)
+#define JSXDR_BYTECODE_VERSION      (0xb973c0de - 106)
 
 /*
  * Library-private functions.
  */
 extern JSBool
 js_XDRAtom(JSXDRState *xdr, JSAtom **atomp);
 
 JS_END_EXTERN_C
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -3014,18 +3014,17 @@ mjit::Compiler::generateMethod()
             /* No-op for the decompiler. */
           END_CASE(JSOP_CONDSWITCH)
 
           BEGIN_CASE(JSOP_LABEL)
           END_CASE(JSOP_LABEL)
 
           BEGIN_CASE(JSOP_DEFFUN)
           {
-            uint32_t index = fullAtomIndex(PC);
-            JSFunction *innerFun = script->getFunction(index);
+            JSFunction *innerFun = script->getFunction(GET_UINT32_INDEX(PC));
 
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(innerFun), Registers::ArgReg1);
             INLINE_STUBCALL(STRICT_VARIANT(stubs::DefFun), REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_DEFFUN)
 
           BEGIN_CASE(JSOP_DEFVAR)
@@ -3049,31 +3048,31 @@ mjit::Compiler::generateMethod()
             masm.move(ImmPtr(name), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::SetConst, REJOIN_FALLTHROUGH);
           }
           END_CASE(JSOP_SETCONST)
 
           BEGIN_CASE(JSOP_DEFLOCALFUN_FC)
           {
             uint32_t slot = GET_SLOTNO(PC);
-            JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
+            JSFunction *fun = script->getFunction(GET_UINT32_INDEX(PC + SLOTNO_LEN));
             prepareStubCall(Uses(frame.frameSlots()));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::DefLocalFun_FC, REJOIN_DEFLOCALFUN);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
             frame.storeLocal(slot, true);
             frame.pop();
             updateVarType();
           }
           END_CASE(JSOP_DEFLOCALFUN_FC)
 
           BEGIN_CASE(JSOP_LAMBDA)
           {
-            JSFunction *fun = script->getFunction(fullAtomIndex(PC));
+            JSFunction *fun = script->getFunction(GET_UINT32_INDEX(PC));
 
             JSObjStubFun stub = stubs::Lambda;
             uint32_t uses = 0;
 
             jsbytecode *pc2 = NULL;
             if (fun->joinable()) {
                 pc2 = PC + JSOP_LAMBDA_LENGTH;
                 JSOp next = JSOp(*pc2);
@@ -3129,17 +3128,17 @@ mjit::Compiler::generateMethod()
                                                            knownPushedType(0), true);
             finishBarrier(barrier, REJOIN_GETTER, 0);
           }
           END_CASE(JSOP_CALLFCSLOT)
 
           BEGIN_CASE(JSOP_DEFLOCALFUN)
           {
             uint32_t slot = GET_SLOTNO(PC);
-            JSFunction *fun = script->getFunction(fullAtomIndex(&PC[SLOTNO_LEN]));
+            JSFunction *fun = script->getFunction(GET_UINT32_INDEX(PC + SLOTNO_LEN));
             prepareStubCall(Uses(0));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::DefLocalFun, REJOIN_DEFLOCALFUN);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
             frame.storeLocal(slot, true);
             frame.pop();
             updateVarType();
@@ -3170,17 +3169,17 @@ mjit::Compiler::generateMethod()
 
           BEGIN_CASE(JSOP_REGEXP)
             if (!jsop_regexp())
                 return Compile_Error;
           END_CASE(JSOP_REGEXP)
 
           BEGIN_CASE(JSOP_OBJECT)
           {
-            JSObject *object = script->getObject(fullAtomIndex(PC));
+            JSObject *object = script->getObject(GET_UINT32_INDEX(PC));
             RegisterID reg = frame.allocReg();
             masm.move(ImmPtr(object), reg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, reg);
           }
           END_CASE(JSOP_OBJECT)
 
           BEGIN_CASE(JSOP_UINT24)
             frame.push(Value(Int32Value((int32_t) GET_UINT24(PC))));
@@ -3196,17 +3195,17 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_GETXPROP)
             if (!jsop_xname(script->getName(fullAtomIndex(PC))))
                 return Compile_Error;
           END_CASE(JSOP_GETXPROP)
 
           BEGIN_CASE(JSOP_ENTERBLOCK)
           BEGIN_CASE(JSOP_ENTERLET0)
           BEGIN_CASE(JSOP_ENTERLET1)
-            enterBlock(script->getObject(fullAtomIndex(PC)));
+            enterBlock(&script->getObject(GET_UINT32_INDEX(PC))->asStaticBlock());
           END_CASE(JSOP_ENTERBLOCK);
 
           BEGIN_CASE(JSOP_LEAVEBLOCK)
             leaveBlock();
           END_CASE(JSOP_LEAVEBLOCK)
 
           BEGIN_CASE(JSOP_INT8)
             frame.push(Value(Int32Value(GET_INT8(PC))));
@@ -3217,17 +3216,17 @@ mjit::Compiler::generateMethod()
           END_CASE(JSOP_INT32)
 
           BEGIN_CASE(JSOP_HOLE)
             frame.push(MagicValue(JS_ARRAY_HOLE));
           END_CASE(JSOP_HOLE)
 
           BEGIN_CASE(JSOP_LAMBDA_FC)
           {
-            JSFunction *fun = script->getFunction(fullAtomIndex(PC));
+            JSFunction *fun = script->getFunction(GET_UINT32_INDEX(PC));
             prepareStubCall(Uses(frame.frameSlots()));
             masm.move(ImmPtr(fun), Registers::ArgReg1);
             INLINE_STUBCALL(stubs::FlatLambda, REJOIN_PUSH_OBJECT);
             frame.takeReg(Registers::ReturnReg);
             frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
           }
           END_CASE(JSOP_LAMBDA_FC)
 
@@ -6793,17 +6792,17 @@ mjit::Compiler::jsop_newinit()
         break;
       case JSOP_NEWOBJECT:
         /*
          * Scripts with NEWOBJECT must be compileAndGo, but treat these like
          * NEWINIT if the script's associated global is not known (or is not
          * actually a global object). This should only happen in chrome code.
          */
         isArray = false;
-        baseobj = globalObj ? script->getObject(fullAtomIndex(PC)) : NULL;
+        baseobj = globalObj ? script->getObject(GET_UINT32_INDEX(PC)) : NULL;
         break;
       default:
         JS_NOT_REACHED("Bad op");
         return false;
     }
 
     void *stub, *stubArg;
     if (isArray) {
@@ -7210,21 +7209,21 @@ mjit::Compiler::jumpAndRun(Jump j, jsbyt
     }
 
     if (target < PC)
         return finishLoop(target);
     return true;
 }
 
 void
-mjit::Compiler::enterBlock(JSObject *obj)
+mjit::Compiler::enterBlock(StaticBlockObject *block)
 {
     /* For now, don't bother doing anything for this opcode. */
     frame.syncAndForgetEverything();
-    masm.move(ImmPtr(obj), Registers::ArgReg1);
+    masm.move(ImmPtr(block), Registers::ArgReg1);
     INLINE_STUBCALL(stubs::EnterBlock, REJOIN_NONE);
     if (*PC == JSOP_ENTERBLOCK)
         frame.enterBlock(StackDefs(script, PC));
 }
 
 void
 mjit::Compiler::leaveBlock()
 {
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -678,17 +678,17 @@ private:
     bool jsop_getprop(PropertyName *name, JSValueType type,
                       bool typeCheck = true, bool forPrototype = false);
     bool jsop_getprop_dispatch(PropertyName *name);
     bool jsop_setprop(PropertyName *name, bool popGuaranteed);
     void jsop_setprop_slow(PropertyName *name);
     bool jsop_instanceof();
     void jsop_name(PropertyName *name, JSValueType type);
     bool jsop_xname(PropertyName *name);
-    void enterBlock(JSObject *obj);
+    void enterBlock(StaticBlockObject *block);
     void leaveBlock();
     void emitEval(uint32_t argc);
     void jsop_arguments(RejoinState rejoin);
     bool jsop_tableswitch(jsbytecode *pc);
 
     /* Fast arithmetic. */
     bool jsop_binary_slow(JSOp op, VoidStub stub, JSValueType type, FrameEntry *lhs, FrameEntry *rhs);
     bool jsop_binary(JSOp op, VoidStub stub, JSValueType type, types::TypeSet *typeSet);
--- a/js/src/methodjit/InvokeHelpers.cpp
+++ b/js/src/methodjit/InvokeHelpers.cpp
@@ -621,17 +621,17 @@ js_InternalThrow(VMFrame &f)
 
     /*
      * Interpret the ENTERBLOCK and EXCEPTION opcodes, so that we don't go
      * back into the interpreter with a pending exception. This will cause
      * it to immediately rethrow.
      */
     if (cx->isExceptionPending()) {
         JS_ASSERT(JSOp(*pc) == JSOP_ENTERBLOCK);
-        StaticBlockObject &blockObj = script->getObject(GET_SLOTNO(pc))->asStaticBlock();
+        StaticBlockObject &blockObj = script->getObject(GET_UINT32_INDEX(pc))->asStaticBlock();
         Value *vp = cx->regs().sp + blockObj.slotCount();
         SetValueRangeToUndefined(cx->regs().sp, vp);
         cx->regs().sp = vp;
         JS_ASSERT(JSOp(pc[JSOP_ENTERBLOCK_LENGTH]) == JSOP_EXCEPTION);
         cx->regs().sp[0] = cx->getPendingException();
         cx->clearPendingException();
         cx->regs().sp++;
         cx->regs().pc = pc + JSOP_ENTERBLOCK_LENGTH + JSOP_EXCEPTION_LENGTH;