[INFER] Inline creation of objects for {}, [], Array() and monomorphic scripted new, bug 677006.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 09 Aug 2011 09:26:08 -0700
changeset 77413 05261f44a8ac1016905fe922f1a347c92e6c77ea
parent 77412 3b40e4462464f75fed8ea71f839de5f2a2ef7108
child 77414 bde71d2d88fbf0eebd289c847395415fb5b4bb84
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs677006
milestone8.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
[INFER] Inline creation of objects for {}, [], Array() and monomorphic scripted new, bug 677006.
js/src/jsinfer.cpp
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/Compiler.h
js/src/methodjit/FastBuiltins.cpp
js/src/methodjit/FrameState-inl.h
js/src/methodjit/FrameState.h
js/src/methodjit/StubCalls.cpp
js/src/methodjit/StubCalls.h
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1080,25 +1080,40 @@ TypeConstraintCall::newType(JSContext *c
              * specialized natives which operate on properties. :XXX: use
              * better factoring for both this and the compiler code itself
              * which specializes particular natives.
              */
 
             Native native = obj->getFunctionPrivate()->native();
 
             if (native == js::array_push) {
-                for (size_t ind = 0; ind < callsite->argumentCount; ind++) {
+                for (size_t i = 0; i < callsite->argumentCount; i++) {
                     callsite->thisTypes->addSetProperty(cx, script, pc,
-                                                        callsite->argumentTypes[ind], JSID_VOID);
+                                                        callsite->argumentTypes[i], JSID_VOID);
                 }
             }
 
             if (native == js::array_pop)
                 callsite->thisTypes->addGetProperty(cx, script, pc, callsite->returnTypes, JSID_VOID);
 
+            if (native == js_Array) {
+                TypeObject *res = TypeScript::InitObject(cx, script, pc, JSProto_Array);
+                if (!res)
+                    return;
+
+                callsite->returnTypes->addType(cx, Type::ObjectType(res));
+
+                if (callsite->argumentCount >= 2) {
+                    for (unsigned i = 0; i < callsite->argumentCount; i++) {
+                        PropertyAccess(cx, script, pc, res, true,
+                                       callsite->argumentTypes[i], JSID_VOID);
+                    }
+                }
+            }
+
             return;
         }
 
         callee = obj->getFunctionPrivate()->script();
     } else if (type.isTypeObject()) {
         callee = type.typeObject()->functionScript;
         if (!callee)
             return;
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -1206,16 +1206,92 @@ static const JSC::MacroAssembler::Regist
             return false;
 
         for (unsigned i = 0; i < matches.length(); i++)
             matches[i].linkTo(label(), this);
 
         return true;
     }
 
+    /*
+     * Get a free object for the specified GC kind in compartment, writing it
+     * to result and filling it in according to templateObject. Returns a jump
+     * taken if a free thing was not retrieved.
+     */
+    Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject)
+    {
+        unsigned thingKind = templateObject->arenaHeader()->getThingKind();
+
+        JS_ASSERT(thingKind >= gc::FINALIZE_OBJECT0 && thingKind <= gc::FINALIZE_OBJECT_LAST);
+        size_t thingSize = gc::GCThingSizeMap[thingKind];
+
+        JS_ASSERT(cx->typeInferenceEnabled());
+        JS_ASSERT(!templateObject->hasSlotsArray());
+
+#ifdef JS_GC_ZEAL
+        if (cx->runtime->needZealousGC())
+            return jump();
+#endif
+
+        /*
+         * Inline FreeLists::getNext. Only the case where the current freelist
+         * span is not empty is handled.
+         */
+        gc::FreeSpan *list = &cx->compartment->freeLists.lists[thingKind];
+
+        loadPtr(&list->start, result);
+        Jump jump = branchPtr(Assembler::Equal, AbsoluteAddress(&list->end), result);
+
+        addPtr(Imm32(thingSize), result);
+        storePtr(result, &list->start);
+
+        /*
+         * Fill in the blank object. Order doesn't matter here, from here
+         * everything is infallible. Note that this bakes GC thing pointers
+         * into the code without explicitly pinning them. With type inference
+         * enabled, JIT code is collected on GC except when analysis or
+         * compilation is active, in which case type objects won't be collected
+         * but other things may be. The shape held by templateObject *must* be
+         * pinned against GC either by the script or by some type object.
+         */
+
+        /*
+         * Write out the slots pointer before readjusting the result register,
+         * as for dense arrays this is relative to the JSObject itself.
+         */
+        if (templateObject->isDenseArray()) {
+            JS_ASSERT(!templateObject->initializedLength);
+            addPtr(Imm32(-thingSize + sizeof(JSObject)), result);
+            storePtr(result, Address(result, -sizeof(JSObject) + JSObject::offsetOfSlots()));
+            addPtr(Imm32(-sizeof(JSObject)), result);
+        } else {
+            JS_ASSERT(!templateObject->newType);
+            addPtr(Imm32(-thingSize), result);
+            storePtr(ImmPtr(NULL), Address(result, JSObject::offsetOfSlots()));
+        }
+
+        storePtr(ImmPtr(templateObject->lastProp), Address(result, offsetof(JSObject, lastProp)));
+        storePtr(ImmPtr(templateObject->clasp), Address(result, offsetof(JSObject, clasp)));
+        store32(Imm32(templateObject->flags), Address(result, offsetof(JSObject, flags)));
+        store32(Imm32(templateObject->objShape), Address(result, offsetof(JSObject, objShape)));
+        storePtr(ImmPtr(templateObject->newType), Address(result, offsetof(JSObject, newType)));
+        storePtr(ImmPtr(templateObject->parent), Address(result, offsetof(JSObject, parent)));
+        storePtr(ImmPtr(templateObject->privateData), Address(result, offsetof(JSObject, privateData)));
+        storePtr(ImmPtr((void *) templateObject->capacity), Address(result, offsetof(JSObject, capacity)));
+        storePtr(ImmPtr(templateObject->gctype()), Address(result, JSObject::offsetOfType()));
+
+        /* Fixed slots of non-array objects are required to be initialized. */
+        if (!templateObject->isDenseArray()) {
+            for (unsigned i = 0; i < templateObject->numFixedSlots(); i++)
+                storeValue(UndefinedValue(), Address(result, JSObject::getFixedSlotOffset(i)));
+        }
+
+        return jump;
+    }
+
     /* Add the value stored in 'value' to the accumulator 'counter'. */
     void addCounter(const double *value, double *counter, RegisterID scratch)
     {
         loadDouble(value, Registers::FPConversionTemp);
         move(ImmPtr(counter), scratch);
         addDouble(Address(scratch), Registers::FPConversionTemp);
         storeDouble(Registers::FPConversionTemp, Address(scratch));
     }
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -780,25 +780,30 @@ mjit::Compiler::generatePrologue()
                           Address(JSFrameReg, StackFrame::offsetOfArgs()));
             hasArgs.linkTo(masm.label(), &masm);
         }
     }
 
     if (isConstructing)
         constructThis();
 
-    if (debugMode())
+    if (debugMode()) {
+        prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::ScriptDebugPrologue, REJOIN_RESUME);
-    else if (Probes::callTrackingActive(cx))
+    } else if (Probes::callTrackingActive(cx)) {
+        prepareStubCall(Uses(0));
         INLINE_STUBCALL(stubs::ScriptProbeOnlyPrologue, REJOIN_RESUME);
+    }
 
     if (cx->typeInferenceEnabled()) {
 #ifdef DEBUG
-        if (script->hasFunction)
+        if (script->hasFunction) {
+            prepareStubCall(Uses(0));
             INLINE_STUBCALL(stubs::AssertArgumentTypes, REJOIN_NONE);
+        }
 #endif
         ensureDoubleArguments();
     }
 
     recompileCheckHelper();
 
     if (outerScript->pcCounters) {
         size_t length = ssa.frameLength(ssa.numFrames() - 1);
@@ -1966,29 +1971,33 @@ mjit::Compiler::generateMethod()
           BEGIN_CASE(JSOP_CALL)
           BEGIN_CASE(JSOP_NEW)
           BEGIN_CASE(JSOP_FUNAPPLY)
           BEGIN_CASE(JSOP_FUNCALL)
           {
             bool callingNew = (op == JSOP_NEW);
 
             bool done = false;
-            if (op == JSOP_CALL && !monitored(PC)) {
+            if ((op == JSOP_CALL || op == JSOP_NEW) && !monitored(PC)) {
                 CompileStatus status = inlineNativeFunction(GET_ARGC(PC), callingNew);
                 if (status == Compile_Okay)
                     done = true;
                 else if (status != Compile_InlineAbort)
                     return status;
             }
             if (!done && inlining()) {
                 CompileStatus status = inlineScriptedFunction(GET_ARGC(PC), callingNew);
                 if (status == Compile_Okay)
                     done = true;
                 else if (status != Compile_InlineAbort)
                     return status;
+                if (script->pcCounters) {
+                    /* Code generated while inlining has been accounted for. */
+                    updatePCCounters(PC, &codeStart, &countersUpdated);
+                }
             }
 
             FrameSize frameSize;
             frameSize.initStatic(frame.totalDepth(), GET_ARGC(PC));
 
             if (!done) {
                 JaegerSpew(JSpew_Insns, " --- SCRIPTED CALL --- \n");
                 inlineCallHelper(GET_ARGC(PC), callingNew, frameSize);
@@ -6201,37 +6210,76 @@ mjit::Compiler::jsop_newinit()
         isArray = false;
         baseobj = globalObj ? script->getObject(fullAtomIndex(PC)) : NULL;
         break;
       default:
         JS_NOT_REACHED("Bad op");
         return false;
     }
 
-    prepareStubCall(Uses(0));
+    void *stub, *stubArg;
+    if (isArray) {
+        stub = JS_FUNC_TO_DATA_PTR(void *, stubs::NewInitArray);
+        stubArg = (void *) count;
+    } else {
+        stub = JS_FUNC_TO_DATA_PTR(void *, stubs::NewInitObject);
+        stubArg = (void *) baseobj;
+    }
 
     /* Don't bake in types for non-compileAndGo scripts. */
     types::TypeObject *type = NULL;
     if (globalObj) {
         type = types::TypeScript::InitObject(cx, script, PC,
                                              isArray ? JSProto_Array : JSProto_Object);
         if (!type)
             return false;
     }
-    masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
-
+
+    if (!cx->typeInferenceEnabled() ||
+        !globalObj ||
+        (isArray && count >= gc::GetGCKindSlots(gc::FINALIZE_OBJECT_LAST)) ||
+        (!isArray && !baseobj) ||
+        (!isArray && baseobj->hasSlotsArray())) {
+        prepareStubCall(Uses(0));
+        masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
+        masm.move(ImmPtr(stubArg), Registers::ArgReg1);
+        INLINE_STUBCALL(stub, REJOIN_FALLTHROUGH);
+        frame.pushSynced(JSVAL_TYPE_OBJECT);
+
+        frame.extra(frame.peek(-1)).initArray = (*PC == JSOP_NEWARRAY);
+        frame.extra(frame.peek(-1)).initObject = baseobj;
+
+        return true;
+    }
+
+    JSObject *templateObject;
     if (isArray) {
-        masm.move(Imm32(count), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::NewInitArray, REJOIN_PUSH_OBJECT);
+        templateObject = NewDenseUnallocatedArray(cx, count);
+        if (!templateObject)
+            return false;
+        templateObject->setType(type);
     } else {
-        masm.move(ImmPtr(baseobj), Registers::ArgReg1);
-        INLINE_STUBCALL(stubs::NewInitObject, REJOIN_PUSH_OBJECT);
-    }
-    frame.takeReg(Registers::ReturnReg);
-    frame.pushTypedPayload(JSVAL_TYPE_OBJECT, Registers::ReturnReg);
+        templateObject = CopyInitializerObject(cx, baseobj, type);
+        if (!templateObject)
+            return false;
+    }
+
+    RegisterID result = frame.allocReg();
+    Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
+
+    stubcc.linkExit(emptyFreeList, Uses(0));
+    stubcc.leave();
+
+    stubcc.masm.storePtr(ImmPtr(type), FrameAddress(offsetof(VMFrame, scratch)));
+    stubcc.masm.move(ImmPtr(stubArg), Registers::ArgReg1);
+    OOL_STUBCALL(stub, REJOIN_FALLTHROUGH);
+
+    frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
+
+    stubcc.rejoin(Changes(1));
 
     frame.extra(frame.peek(-1)).initArray = (*PC == JSOP_NEWARRAY);
     frame.extra(frame.peek(-1)).initObject = baseobj;
 
     return true;
 }
 
 bool
@@ -6595,16 +6643,40 @@ mjit::Compiler::leaveBlock()
 //       NULL
 //   call js_CreateThisFromFunctionWithProto(...)
 //
 bool
 mjit::Compiler::constructThis()
 {
     JS_ASSERT(isConstructing);
 
+    if (cx->typeInferenceEnabled()) {
+        jsid id = ATOM_TO_JSID(cx->runtime->atomState.classPrototypeAtom);
+        types::TypeSet *protoTypes = script->function()->getType(cx)->getProperty(cx, id, false);
+
+        JSObject *proto = protoTypes->getSingleton(cx, true);
+        if (proto) {
+            JSObject *templateObject = js_CreateThisForFunctionWithProto(cx, script->function(), proto);
+
+            RegisterID result = frame.allocReg();
+            Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
+
+            stubcc.linkExit(emptyFreeList, Uses(0));
+            stubcc.leave();
+
+            stubcc.masm.move(ImmPtr(proto), Registers::ArgReg1);
+            OOL_STUBCALL(stubs::CreateThis, REJOIN_RESUME);
+
+            frame.setThis(result);
+
+            stubcc.rejoin(Changes(1));
+            return true;
+        }
+    }
+
     // Load the callee.
     frame.pushCallee();
 
     // Get callee.prototype.
     if (!jsop_getprop(cx->runtime->atomState.classPrototypeAtom, JSVAL_TYPE_UNKNOWN, false, false))
         return false;
 
     // Reach into the proto Value and grab a register for its data.
--- a/js/src/methodjit/Compiler.h
+++ b/js/src/methodjit/Compiler.h
@@ -750,16 +750,18 @@ class Compiler : public BaseCompiler
     CompileStatus inlineNativeFunction(uint32 argc, bool callingNew);
     CompileStatus inlineScriptedFunction(uint32 argc, bool callingNew);
     CompileStatus compileMathAbsInt(FrameEntry *arg);
     CompileStatus compileMathAbsDouble(FrameEntry *arg);
     CompileStatus compileMathSqrt(FrameEntry *arg);
     CompileStatus compileMathPowSimple(FrameEntry *arg1, FrameEntry *arg2);
     CompileStatus compileArrayPush(FrameEntry *thisv, FrameEntry *arg);
     CompileStatus compileArrayPop(FrameEntry *thisv, bool isPacked);
+    CompileStatus compileArrayWithLength(uint32 argc);
+    CompileStatus compileArrayWithArgs(uint32 argc);
 
     enum RoundingMode { Floor, Round };
     CompileStatus compileRound(FrameEntry *arg, RoundingMode mode);
 
     enum GetCharMode { GetChar, GetCharCode };
     CompileStatus compileGetChar(FrameEntry *thisValue, FrameEntry *arg, GetCharMode mode);
 
     void prepareStubCall(Uses uses);
--- a/js/src/methodjit/FastBuiltins.cpp
+++ b/js/src/methodjit/FastBuiltins.cpp
@@ -434,20 +434,106 @@ mjit::Compiler::compileArrayPop(FrameEnt
         frame.push(UndefinedValue());
     }
 
     stubcc.rejoin(Changes(1));
     return Compile_Okay;
 }
 
 CompileStatus
+mjit::Compiler::compileArrayWithLength(uint32 argc)
+{
+    /* Match Array() or Array(n) for constant n. */
+    JS_ASSERT(argc == 0 || argc == 1);
+
+    int32 length = 0;
+    if (argc == 1) {
+        FrameEntry *arg = frame.peek(-1);
+        if (!arg->isConstant() || !arg->getValue().isInt32())
+            return Compile_InlineAbort;
+        length = arg->getValue().toInt32();
+        if (length < 0)
+            return Compile_InlineAbort;
+    }
+
+    types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
+    if (!type)
+        return Compile_Error;
+
+    JSObject *templateObject = NewDenseUnallocatedArray(cx, length, type->proto);
+    if (!templateObject)
+        return Compile_Error;
+    templateObject->setType(type);
+
+    RegisterID result = frame.allocReg();
+    Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
+
+    stubcc.linkExit(emptyFreeList, Uses(0));
+    stubcc.leave();
+
+    stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
+
+    frame.popn(argc + 2);
+    frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
+
+    stubcc.rejoin(Changes(1));
+    return Compile_Okay;
+}
+
+CompileStatus
+mjit::Compiler::compileArrayWithArgs(uint32 argc)
+{
+    /*
+     * Match Array(x, y, z) with at least two arguments. Don't inline the case
+     * where a non-number argument is passed, so we don't need to care about
+     * the types of the arguments.
+     */
+    JS_ASSERT(argc >= 2);
+
+    if (argc >= gc::GetGCKindSlots(gc::FINALIZE_OBJECT_LAST))
+        return Compile_InlineAbort;
+
+    types::TypeObject *type = types::TypeScript::InitObject(cx, script, PC, JSProto_Array);
+    if (!type)
+        return Compile_Error;
+
+    JSObject *templateObject = NewDenseUnallocatedArray(cx, argc, type->proto);
+    if (!templateObject)
+        return Compile_Error;
+    templateObject->setType(type);
+
+    JS_ASSERT(templateObject->getDenseArrayCapacity() >= argc);
+
+    RegisterID result = frame.allocReg();
+    Jump emptyFreeList = masm.getNewObject(cx, result, templateObject);
+    stubcc.linkExit(emptyFreeList, Uses(0));
+
+    for (unsigned i = 0; i < argc; i++) {
+        FrameEntry *arg = frame.peek(-argc + i);
+        frame.storeTo(arg, Address(result, JSObject::getFixedSlotOffset(i)), /* popped = */ true);
+    }
+
+    masm.storePtr(ImmPtr((void *) argc), Address(result, offsetof(JSObject, initializedLength)));
+
+    stubcc.leave();
+
+    stubcc.masm.move(Imm32(argc), Registers::ArgReg1);
+    OOL_STUBCALL(stubs::SlowCall, REJOIN_FALLTHROUGH);
+
+    frame.popn(argc + 2);
+    frame.pushTypedPayload(JSVAL_TYPE_OBJECT, result);
+
+    stubcc.rejoin(Changes(1));
+    return Compile_Okay;
+}
+
+CompileStatus
 mjit::Compiler::inlineNativeFunction(uint32 argc, bool callingNew)
 {
-    JS_ASSERT(!callingNew);
-
     if (!cx->typeInferenceEnabled())
         return Compile_InlineAbort;
 
     if (applyTricks == LazyArgsObj)
         return Compile_InlineAbort;
 
     FrameEntry *origCallee = frame.peek(-((int)argc + 2));
     FrameEntry *thisValue = frame.peek(-((int)argc + 1));
@@ -473,16 +559,33 @@ mjit::Compiler::inlineNativeFunction(uin
     if (!native)
         return Compile_InlineAbort;
 
     JSValueType type = knownPushedType(0);
     JSValueType thisType = thisValue->isTypeKnown()
                            ? thisValue->getKnownType()
                            : JSVAL_TYPE_UNKNOWN;
 
+    /*
+     * Note: when adding new natives which operate on properties, add relevant
+     * constraint generation to the behavior of TypeConstraintCall.
+     */
+
+    /* Handle natives that can be called either with or without 'new'. */
+
+    if (native == js_Array && type == JSVAL_TYPE_OBJECT && globalObj) {
+        if (argc == 0 || argc == 1)
+            return compileArrayWithLength(argc);
+        return compileArrayWithArgs(argc);
+    }
+
+    /* Remaining natives must not be called with 'new'. */
+    if (callingNew)
+        return Compile_InlineAbort;
+
     if (argc == 0) {
         if (native == js::array_pop && thisType == JSVAL_TYPE_OBJECT) {
             /*
              * Only inline pop() on dense arrays which have never been used in
              * an iterator --- when popping elements we don't account for
              * suppressing deleted properties in active iterators.
              *
              * Constraints propagating properties directly into the result
--- a/js/src/methodjit/FrameState-inl.h
+++ b/js/src/methodjit/FrameState-inl.h
@@ -1311,21 +1311,33 @@ FrameState::pushThis()
 
 void
 FrameState::learnThisIsObject(bool unsync)
 {
     // If the 'this' object is a copy, this must be an inline frame, in which
     // case we will trigger recompilation if the 'this' entry isn't actually
     // an object (thus, it is OK to modify the backing directly).
     FrameEntry *fe = a->this_;
+    if (!fe->isTracked())
+        addToTracker(fe);
     if (fe->isCopy())
         fe = fe->copyOf();
     learnType(fe, JSVAL_TYPE_OBJECT, unsync);
 }
 
+void
+FrameState::setThis(RegisterID reg)
+{
+    FrameEntry *fe = a->this_;
+    if (!fe->isTracked())
+        addToTracker(fe);
+    JS_ASSERT(!fe->isCopy());
+    learnType(fe, JSVAL_TYPE_OBJECT, reg);
+}
+
 inline void
 FrameState::leaveBlock(uint32 n)
 {
     popn(n);
 }
 
 inline void
 FrameState::enterBlock(uint32 n)
--- a/js/src/methodjit/FrameState.h
+++ b/js/src/methodjit/FrameState.h
@@ -387,16 +387,17 @@ class FrameState
 
     // Pushes a copy of a slot (formal argument, local variable, or stack slot)
     // onto the operation stack.
     void pushLocal(uint32 n);
     void pushArg(uint32 n);
     void pushCallee();
     void pushThis();
     void pushCopyOf(FrameEntry *fe);
+    inline void setThis(RegisterID reg);
     inline void learnThisIsObject(bool unsync = true);
 
     inline FrameEntry *getStack(uint32 slot);
     inline FrameEntry *getLocal(uint32 slot);
     inline FrameEntry *getArg(uint32 slot);
     inline FrameEntry *getSlotEntry(uint32 slot);
 
     /*
--- a/js/src/methodjit/StubCalls.cpp
+++ b/js/src/methodjit/StubCalls.cpp
@@ -1313,53 +1313,53 @@ stubs::Neg(VMFrame &f)
     double d;
     if (!ToNumber(f.cx, f.regs.sp[-1], &d))
         THROW();
     d = -d;
     if (!f.regs.sp[-1].setNumber(d))
         TypeScript::MonitorOverflow(f.cx, f.script(), f.pc());
 }
 
-JSObject * JS_FASTCALL
+void JS_FASTCALL
 stubs::NewInitArray(VMFrame &f, uint32 count)
 {
     JSObject *obj = NewDenseAllocatedArray(f.cx, count);
     if (!obj)
-        THROWV(NULL);
+        THROW();
 
     TypeObject *type = (TypeObject *) f.scratch;
     if (type)
         obj->setType(type);
 
-    obj->setArrayLength(f.cx, count);
-    return obj;
+    f.regs.sp[0].setObject(*obj);
 }
 
-JSObject * JS_FASTCALL
+void JS_FASTCALL
 stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
 {
     JSContext *cx = f.cx;
     TypeObject *type = (TypeObject *) f.scratch;
 
     if (!baseobj) {
         gc::FinalizeKind kind = GuessObjectGCKind(0, false);
         JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
         if (!obj)
-            THROWV(NULL);
+            THROW();
         if (type)
             obj->setType(type);
-        return obj;
+        f.regs.sp[0].setObject(*obj);
+        return;
     }
 
     JS_ASSERT(type);
     JSObject *obj = CopyInitializerObject(cx, baseobj, type);
 
     if (!obj)
-        THROWV(NULL);
-    return obj;
+        THROW();
+    f.regs.sp[0].setObject(*obj);
 }
 
 void JS_FASTCALL
 stubs::InitElem(VMFrame &f, uint32 last)
 {
     JSContext *cx = f.cx;
     FrameRegs &regs = f.regs;
 
--- a/js/src/methodjit/StubCalls.h
+++ b/js/src/methodjit/StubCalls.h
@@ -49,18 +49,18 @@ namespace stubs {
 
 typedef enum JSTrapType {
     JSTRAP_NONE = 0,
     JSTRAP_TRAP = 1,
     JSTRAP_SINGLESTEP = 2
 } JSTrapType;
 
 void JS_FASTCALL This(VMFrame &f);
-JSObject * JS_FASTCALL NewInitArray(VMFrame &f, uint32 count);
-JSObject * JS_FASTCALL NewInitObject(VMFrame &f, JSObject *base);
+void JS_FASTCALL NewInitArray(VMFrame &f, uint32 count);
+void JS_FASTCALL NewInitObject(VMFrame &f, JSObject *base);
 void JS_FASTCALL Trap(VMFrame &f, uint32 trapTypes);
 void JS_FASTCALL Debugger(VMFrame &f, jsbytecode *pc);
 void JS_FASTCALL Interrupt(VMFrame &f, jsbytecode *pc);
 void JS_FASTCALL RecompileForInline(VMFrame &f);
 void JS_FASTCALL InitElem(VMFrame &f, uint32 last);
 void JS_FASTCALL InitProp(VMFrame &f, JSAtom *atom);
 void JS_FASTCALL InitMethod(VMFrame &f, JSAtom *atom);