Bug 1241088: SharedStubs - part 2: port NewArray and NewObject shared stubs to work in ion, r=efaust
authorHannes Verschore <hv1989@gmail.com>
Wed, 20 Apr 2016 06:40:16 -0400
changeset 294025 be2f6cb7251c22cec13209cc2314789e7ae0d0ea
parent 294024 37d592080a032a01c2110b0c6d9ba489aded0891
child 294026 7c1f8d3d4f69add3995d27d4c70c92d286aa54b9
push id30196
push userkwierso@gmail.com
push dateWed, 20 Apr 2016 20:55:01 +0000
treeherdermozilla-central@93090fa30653 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1241088
milestone48.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
Bug 1241088: SharedStubs - part 2: port NewArray and NewObject shared stubs to work in ion, r=efaust
js/src/jit/BaselineCompiler.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/SharedIC.cpp
js/src/jit/SharedIC.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/jit/shared/Lowering-shared-inl.h
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1897,17 +1897,17 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
 
     // Pass length in R0.
     masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
 
     ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
     if (!group)
         return false;
 
-    ICNewArray_Fallback::Compiler stubCompiler(cx, group);
+    ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::Baseline);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.push(R0);
     return true;
 }
 
 bool
@@ -1967,17 +1967,17 @@ BaselineCompiler::emit_JSOP_INITELEM_ARR
     return true;
 }
 
 bool
 BaselineCompiler::emit_JSOP_NEWOBJECT()
 {
     frame.syncStack(0);
 
-    ICNewObject_Fallback::Compiler stubCompiler(cx);
+    ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.push(R0);
     return true;
 }
 
 bool
@@ -1989,23 +1989,23 @@ BaselineCompiler::emit_JSOP_NEWINIT()
     if (key == JSProto_Array) {
         // Pass length in R0.
         masm.move32(Imm32(0), R0.scratchReg());
 
         ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
         if (!group)
             return false;
 
-        ICNewArray_Fallback::Compiler stubCompiler(cx, group);
+        ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::Baseline);
         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
             return false;
     } else {
         MOZ_ASSERT(key == JSProto_Object);
 
-        ICNewObject_Fallback::Compiler stubCompiler(cx);
+        ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::Baseline);
         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
             return false;
     }
 
     frame.push(R0);
     return true;
 }
 
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jit/CodeGenerator.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/Casting.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/EnumeratedRange.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/SizePrintfMacros.h"
 
 #include "jslibmath.h"
@@ -49,16 +50,17 @@
 #include "jit/MacroAssembler-inl.h"
 #include "jit/shared/CodeGenerator-shared-inl.h"
 #include "jit/shared/Lowering-shared-inl.h"
 #include "vm/Interpreter-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::AssertedCast;
 using mozilla::DebugOnly;
 using mozilla::FloatingPoint;
 using mozilla::Maybe;
 using mozilla::NegativeInfinity;
 using mozilla::PositiveInfinity;
 using JS::GenericNaN;
 
 namespace js {
@@ -2372,16 +2374,51 @@ CodeGenerator::visitUnarySharedStub(LUna
       case JSOP_LENGTH:
         emitSharedStub(ICStub::Kind::GetProp_Fallback, lir);
         break;
       default:
         MOZ_CRASH("Unsupported jsop in shared stubs.");
     }
 }
 
+void
+CodeGenerator::visitNullarySharedStub(LNullarySharedStub* lir)
+{
+    jsbytecode* pc = lir->mir()->resumePoint()->pc();
+    JSOp jsop = JSOp(*pc);
+    switch (jsop) {
+      case JSOP_NEWARRAY: {
+        uint32_t length = GET_UINT32(pc);
+        MOZ_ASSERT(length <= INT32_MAX,
+                   "the bytecode emitter must fail to compile code that would "
+                   "produce JSOP_NEWARRAY with a length exceeding int32_t range");
+
+        // Pass length in R0.
+        masm.move32(Imm32(AssertedCast<int32_t>(length)), R0.scratchReg());
+        emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
+        break;
+      }
+      case JSOP_NEWOBJECT:
+        emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
+        break;
+      case JSOP_NEWINIT: {
+        JSProtoKey key = JSProtoKey(GET_UINT8(pc));
+        if (key == JSProto_Array) {
+            masm.move32(Imm32(0), R0.scratchReg());
+            emitSharedStub(ICStub::Kind::NewArray_Fallback, lir);
+        } else {
+            emitSharedStub(ICStub::Kind::NewObject_Fallback, lir);
+        }
+        break;
+      }
+      default:
+        MOZ_CRASH("Unsupported jsop in shared stubs.");
+    }
+}
+
 typedef JSObject* (*LambdaFn)(JSContext*, HandleFunction, HandleObject);
 static const VMFunction LambdaInfo = FunctionInfo<LambdaFn>(js::Lambda);
 
 void
 CodeGenerator::visitLambdaForSingleton(LLambdaForSingleton* lir)
 {
     pushArg(ToRegister(lir->scopeChain()));
     pushArg(ImmGCPtr(lir->mir()->info().fun));
@@ -5141,17 +5178,17 @@ CodeGenerator::visitNewArray(LNewArray* 
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
     JSObject* templateObject = lir->mir()->templateObject();
     DebugOnly<uint32_t> length = lir->mir()->length();
 
     MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
 
-    if (lir->mir()->shouldUseVM()) {
+    if (!templateObject) {
         visitNewArrayCallVM(lir);
         return;
     }
 
     OutOfLineNewArray* ool = new(alloc()) OutOfLineNewArray(lir);
     addOutOfLineCode(ool, lir->mir());
 
     masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(),
@@ -5398,17 +5435,17 @@ ShouldInitFixedSlots(LInstruction* lir, 
 
 void
 CodeGenerator::visitNewObject(LNewObject* lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
     JSObject* templateObject = lir->mir()->templateObject();
 
-    if (lir->mir()->shouldUseVM()) {
+    if (!templateObject) {
         visitNewObjectVMCall(lir);
         return;
     }
 
     OutOfLineNewObject* ool = new(alloc()) OutOfLineNewObject(lir);
     addOutOfLineCode(ool, lir->mir());
 
     bool initContents = ShouldInitFixedSlots(lir, templateObject);
@@ -8864,16 +8901,32 @@ CodeGenerator::linkSharedStubs(JSContext
             stub = stubCompiler.getStub(&stubSpace_);
             break;
           }
           case ICStub::Kind::GetProp_Fallback: {
             ICGetProp_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey);
             stub = stubCompiler.getStub(&stubSpace_);
             break;
           }
+          case ICStub::Kind::NewArray_Fallback: {
+            JSScript* script = sharedStubs_[i].entry.script();
+            jsbytecode* pc = sharedStubs_[i].entry.pc(script);
+            ObjectGroup* group = ObjectGroup::allocationSiteGroup(cx, script, pc, JSProto_Array);
+            if (!group)
+                return false;
+
+            ICNewArray_Fallback::Compiler stubCompiler(cx, group, ICStubCompiler::Engine::IonMonkey);
+            stub = stubCompiler.getStub(&stubSpace_);
+            break;
+          }
+          case ICStub::Kind::NewObject_Fallback: {
+            ICNewObject_Fallback::Compiler stubCompiler(cx, ICStubCompiler::Engine::IonMonkey);
+            stub = stubCompiler.getStub(&stubSpace_);
+            break;
+          }
           default:
             MOZ_CRASH("Unsupported shared stub.");
         }
 
         if (!stub)
             return false;
 
         sharedStubs_[i].entry.setFirstStub(stub);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -121,16 +121,17 @@ class CodeGenerator : public CodeGenerat
     void visitRegExpPrototypeOptimizable(LRegExpPrototypeOptimizable* lir);
     void visitOutOfLineRegExpPrototypeOptimizable(OutOfLineRegExpPrototypeOptimizable* ool);
     void visitRegExpInstanceOptimizable(LRegExpInstanceOptimizable* lir);
     void visitOutOfLineRegExpInstanceOptimizable(OutOfLineRegExpInstanceOptimizable* ool);
     void visitStringReplace(LStringReplace* lir);
     void emitSharedStub(ICStub::Kind kind, LInstruction* lir);
     void visitBinarySharedStub(LBinarySharedStub* lir);
     void visitUnarySharedStub(LUnarySharedStub* lir);
+    void visitNullarySharedStub(LNullarySharedStub* lir);
     void visitLambda(LLambda* lir);
     void visitOutOfLineLambdaArrow(OutOfLineLambdaArrow* ool);
     void visitLambdaArrow(LLambdaArrow* lir);
     void visitLambdaForSingleton(LLambdaForSingleton* lir);
     void visitPointer(LPointer* lir);
     void visitKeepAliveObject(LKeepAliveObject* lir);
     void visitSlots(LSlots* lir);
     void visitLoadSlotT(LLoadSlotT* lir);
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -7185,42 +7185,128 @@ IonBuilder::compareTrySharedStub(bool* e
     current->add(unbox);
     current->push(unbox);
 
     *emitted = true;
     return true;
 }
 
 bool
-IonBuilder::jsop_newarray(uint32_t length)
-{
-    JSObject* templateObject = inspector->getTemplateObject(pc);
-    gc::InitialHeap heap;
-    MConstant* templateConst;
-
-    if (templateObject) {
-        heap = templateObject->group()->initialHeap(constraints());
-        templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
-    } else {
-        heap = gc::DefaultHeap;
-        templateConst = MConstant::New(alloc(), NullValue());
-    }
+IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    if (!templateObject)
+        return true;
+
+    if (templateObject->is<UnboxedArrayObject>()) {
+        MOZ_ASSERT(templateObject->as<UnboxedArrayObject>().capacity() >= length);
+        if (!templateObject->as<UnboxedArrayObject>().hasInlineElements())
+            return true;
+    }
+
+    MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
+
+    size_t arraySlots =
+        gc::GetGCKindSlots(templateObject->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
+
+    if (length > arraySlots)
+        return true;
+
+    // Emit fastpath.
+
+    gc::InitialHeap heap = templateObject->group()->initialHeap(constraints());
+    MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     current->add(templateConst);
 
     MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc);
     current->add(ins);
     current->push(ins);
 
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::newArrayTrySharedStub(bool* emitted)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    // Try to emit a shared stub cache.
+
+    if (JitOptions.disableSharedStubs)
+        return true;
+
+    if (*pc != JSOP_NEWINIT && *pc != JSOP_NEWARRAY)
+        return true;
+
+    MInstruction* stub = MNullarySharedStub::New(alloc());
+    current->add(stub);
+    current->push(stub);
+
+    if (!resumeAfter(stub))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::newArrayTryVM(bool* emitted, uint32_t length)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    // Emit a VM call.
+
+    gc::InitialHeap heap = gc::DefaultHeap;
+    MConstant* templateConst = MConstant::New(alloc(), NullValue());
+    current->add(templateConst);
+
+    MNewArray* ins = MNewArray::New(alloc(), constraints(), length, templateConst, heap, pc);
+    current->add(ins);
+    current->push(ins);
+
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::jsop_newarray(uint32_t length)
+{
+    JSObject* templateObject = inspector->getTemplateObject(pc);
+    if (!jsop_newarray(templateObject, length))
+        return false;
+
+    // Improve resulting typeset.
     ObjectGroup* templateGroup = inspector->getTemplateObjectGroup(pc);
     if (templateGroup) {
         TemporaryTypeSet* types = MakeSingletonTypeSet(constraints(), templateGroup);
-        ins->setResultTypeSet(types);
-    }
-
-    return true;
+        current->peek(-1)->setResultTypeSet(types);
+    }
+
+    return true;
+}
+
+bool
+IonBuilder::jsop_newarray(JSObject* templateObject, uint32_t length)
+{
+    bool emitted = false;
+
+    if (!forceInlineCaches()) {
+        if (!newArrayTryTemplateObject(&emitted, templateObject, length) || emitted)
+            return emitted;
+    }
+
+    if (!newArrayTrySharedStub(&emitted) || emitted)
+        return emitted;
+
+    if (!newArrayTryVM(&emitted, length) || emitted)
+        return emitted;
+
+    MOZ_CRASH("newarray should have been emited");
 }
 
 bool
 IonBuilder::jsop_newarray_copyonwrite()
 {
     ArrayObject* templateObject = ObjectGroup::getCopyOnWriteObject(script(), pc);
 
     // The baseline compiler should have ensured the template object has a type
@@ -7236,38 +7322,108 @@ IonBuilder::jsop_newarray_copyonwrite()
 
     current->add(ins);
     current->push(ins);
 
     return true;
 }
 
 bool
-IonBuilder::jsop_newobject()
-{
-    JSObject* templateObject = inspector->getTemplateObject(pc);
-    gc::InitialHeap heap;
-    MConstant* templateConst;
-
-    if (templateObject) {
-        heap = templateObject->group()->initialHeap(constraints());
-        templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
-    } else {
-        heap = gc::DefaultHeap;
-        templateConst = MConstant::New(alloc(), NullValue());
-    }
-
+IonBuilder::newObjectTryTemplateObject(bool* emitted, JSObject* templateObject)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    if (!templateObject)
+        return true;
+
+    if (templateObject->is<PlainObject>() && templateObject->as<PlainObject>().hasDynamicSlots())
+        return true;
+
+    // Emit fastpath.
+
+    MNewObject::Mode mode;
+    if (JSOp(*pc) == JSOP_NEWOBJECT || JSOp(*pc) == JSOP_NEWINIT)
+        mode = MNewObject::ObjectLiteral;
+    else
+        mode = MNewObject::ObjectCreate;
+
+    gc::InitialHeap heap = templateObject->group()->initialHeap(constraints());
+    MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
     current->add(templateConst);
-    MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap,
-                                      MNewObject::ObjectLiteral);
-
+
+    MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap, mode);
     current->add(ins);
     current->push(ins);
 
-    return resumeAfter(ins);
+    if (!resumeAfter(ins))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::newObjectTrySharedStub(bool* emitted)
+{
+    MOZ_ASSERT(*emitted == false);
+
+    // Try to emit a shared stub cache.
+
+    if (JitOptions.disableSharedStubs)
+        return true;
+
+    MInstruction* stub = MNullarySharedStub::New(alloc());
+    current->add(stub);
+    current->push(stub);
+
+    if (!resumeAfter(stub))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::newObjectTryVM(bool* emitted)
+{
+    // Emit a VM call.
+
+    gc::InitialHeap heap = gc::DefaultHeap;
+    MConstant* templateConst = MConstant::New(alloc(), NullValue());
+    current->add(templateConst);
+
+    MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, heap,
+                                     MNewObject::ObjectLiteral);
+    current->add(ins);
+    current->push(ins);
+
+    if (!resumeAfter(ins))
+        return false;
+
+    *emitted = true;
+    return true;
+}
+
+bool
+IonBuilder::jsop_newobject()
+{
+    bool emitted = false;
+
+    if (!forceInlineCaches()) {
+        JSObject* templateObject = inspector->getTemplateObject(pc);
+        if (!newObjectTryTemplateObject(&emitted, templateObject) || emitted)
+            return emitted;
+    }
+    if (!newObjectTrySharedStub(&emitted) || emitted)
+        return emitted;
+
+    if (!newObjectTryVM(&emitted) || emitted)
+        return emitted;
+
+    MOZ_CRASH("newobject should have been emited");
 }
 
 bool
 IonBuilder::jsop_initelem()
 {
     MDefinition* value = current->pop();
     MDefinition* id = current->pop();
     MDefinition* obj = current->peek(-1);
@@ -7349,17 +7505,20 @@ IonBuilder::initializeArrayElement(MDefi
 
             if (!resumeAfter(increment))
                 return false;
         }
     } else {
         if (NeedsPostBarrier(value))
             current->add(MPostWriteBarrier::New(alloc(), obj, value));
 
-        if (obj->toNewArray()->convertDoubleElements()) {
+        if ((obj->isNewArray() && obj->toNewArray()->convertDoubleElements()) ||
+            (obj->isNullarySharedStub() &&
+            obj->resultTypeSet()->convertDoubleElements(constraints()) == TemporaryTypeSet::AlwaysConvertToDoubles))
+        {
             MInstruction* valueDouble = MToDouble::New(alloc(), value);
             current->add(valueDouble);
             value = valueDouble;
         }
 
         // Store the value.
         MStoreElement* store = MStoreElement::New(alloc(), elements, id, value,
                                                   /* needsHoleCheck = */ false);
@@ -7395,24 +7554,29 @@ bool
 IonBuilder::jsop_initprop(PropertyName* name)
 {
     bool useSlowPath = false;
 
     MDefinition* value = current->peek(-1);
     MDefinition* obj = current->peek(-2);
     if (obj->isLambda()) {
         useSlowPath = true;
-    } else if (JSObject* templateObject = obj->toNewObject()->templateObject()) {
-        if (templateObject->is<PlainObject>()) {
-            if (!templateObject->as<PlainObject>().containsPure(name))
-                useSlowPath = true;
+    } else if (obj->isNewObject()) {
+        if (JSObject* templateObject = obj->toNewObject()->templateObject()) {
+            if (templateObject->is<PlainObject>()) {
+                if (!templateObject->as<PlainObject>().containsPure(name))
+                    useSlowPath = true;
+            } else {
+                MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name));
+            }
         } else {
-            MOZ_ASSERT(templateObject->as<UnboxedPlainObject>().layout().lookup(name));
+            useSlowPath = true;
         }
     } else {
+        MOZ_ASSERT(obj->isNullarySharedStub());
         useSlowPath = true;
     }
 
     if (useSlowPath) {
         current->pop();
         MInitProp* init = MInitProp::New(alloc(), obj, name, value);
         current->add(init);
         return resumeAfter(init);
@@ -10496,30 +10660,26 @@ IonBuilder::jsop_rest()
         return true;
     }
 
     // We know the exact number of arguments the callee pushed.
     unsigned numActuals = inlineCallInfo_->argc();
     unsigned numFormals = info().nargs() - 1;
     unsigned numRest = numActuals > numFormals ? numActuals - numFormals : 0;
 
-    MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
-    current->add(templateConst);
-
-    MNewArray* array = MNewArray::New(alloc(), constraints(), numRest, templateConst,
-                                      templateObject->group()->initialHeap(constraints()), pc);
-    current->add(array);
+    if (!jsop_newarray(numRest))
+        return false;
 
     if (numRest == 0) {
         // No more updating to do. (Note that in this one case the length from
         // the template object is already correct.)
-        current->push(array);
-        return true;
-    }
-
+        return true;
+    }
+
+    MDefinition *array = current->peek(-1);
     MElements* elements = MElements::New(alloc(), array);
     current->add(elements);
 
     // Unroll the argument copy loop. We don't need to do any bounds or hole
     // checking here.
     MConstant* index = nullptr;
     for (unsigned i = numFormals; i < numActuals; i++) {
         index = MConstant::New(alloc(), Int32Value(i - numFormals));
@@ -10540,17 +10700,16 @@ IonBuilder::jsop_rest()
     MSetArrayLength* length = MSetArrayLength::New(alloc(), elements, index);
     current->add(length);
 
     // Update the initialized length for all the (necessarily non-hole)
     // elements added.
     MSetInitializedLength* initLength = MSetInitializedLength::New(alloc(), elements, index);
     current->add(initLength);
 
-    current->push(array);
     return true;
 }
 
 bool
 IonBuilder::jsop_checkobjcoercible()
 {
     MDefinition* toCheck = current->peek(-1);
 
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -508,16 +508,26 @@ class IonBuilder
 
     // jsop_compare helpers.
     bool compareTrySpecialized(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
     bool compareTryBitwise(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
     bool compareTrySpecializedOnBaselineInspector(bool* emitted, JSOp op, MDefinition* left,
                                                   MDefinition* right);
     bool compareTrySharedStub(bool* emitted, JSOp op, MDefinition* left, MDefinition* right);
 
+    // jsop_newarray helpers.
+    bool newArrayTrySharedStub(bool* emitted);
+    bool newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, uint32_t length);
+    bool newArrayTryVM(bool* emitted, uint32_t length);
+
+    // jsop_newobject helpers.
+    bool newObjectTrySharedStub(bool* emitted);
+    bool newObjectTryTemplateObject(bool* emitted, JSObject* templateObject);
+    bool newObjectTryVM(bool* emitted);
+
     // jsop_in helpers.
     bool inTryDense(bool* emitted, MDefinition* obj, MDefinition* id);
     bool inTryFold(bool* emitted, MDefinition* obj, MDefinition* id);
 
     // binary data lookup helpers.
     TypedObjectPrediction typedObjectPrediction(MDefinition* typedObj);
     TypedObjectPrediction typedObjectPrediction(TemporaryTypeSet* types);
     bool typedObjectHasField(MDefinition* typedObj,
@@ -718,16 +728,17 @@ class IonBuilder
     bool jsop_runonce();
     bool jsop_rest();
     bool jsop_not();
     bool jsop_getprop(PropertyName* name);
     bool jsop_setprop(PropertyName* name);
     bool jsop_delprop(PropertyName* name);
     bool jsop_delelem();
     bool jsop_newarray(uint32_t length);
+    bool jsop_newarray(JSObject* templateObject, uint32_t length);
     bool jsop_newarray_copyonwrite();
     bool jsop_newobject();
     bool jsop_initelem();
     bool jsop_initelem_array();
     bool jsop_initelem_getter_setter();
     bool jsop_mutateproto();
     bool jsop_initprop(PropertyName* name);
     bool jsop_initprop_getter_setter(PropertyName* name);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -2357,16 +2357,27 @@ LIRGenerator::visitUnarySharedStub(MUnar
     MOZ_ASSERT(ins->type() == MIRType_Value);
 
     LUnarySharedStub* lir = new(alloc()) LUnarySharedStub(useBoxFixedAtStart(input, R0));
     defineSharedStubReturn(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
+LIRGenerator::visitNullarySharedStub(MNullarySharedStub* ins)
+{
+    MOZ_ASSERT(ins->type() == MIRType_Value);
+
+    LNullarySharedStub* lir = new(alloc()) LNullarySharedStub();
+
+    defineSharedStubReturn(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
+void
 LIRGenerator::visitLambda(MLambda* ins)
 {
     if (ins->info().singletonType || ins->info().useSingletonForClone) {
         // If the function has a singleton type, this instruction will only be
         // executed once so we don't bother inlining it.
         //
         // If UseSingletonForClone is true, we will assign a singleton type to
         // the clone and we have to clone the script, we can't do that inline.
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -166,16 +166,17 @@ class LIRGenerator : public LIRGenerator
     void visitRegExpMatcher(MRegExpMatcher* ins);
     void visitRegExpSearcher(MRegExpSearcher* ins);
     void visitRegExpTester(MRegExpTester* ins);
     void visitRegExpPrototypeOptimizable(MRegExpPrototypeOptimizable* ins);
     void visitRegExpInstanceOptimizable(MRegExpInstanceOptimizable* ins);
     void visitStringReplace(MStringReplace* ins);
     void visitBinarySharedStub(MBinarySharedStub* ins);
     void visitUnarySharedStub(MUnarySharedStub* ins);
+    void visitNullarySharedStub(MNullarySharedStub* ins);
     void visitLambda(MLambda* ins);
     void visitLambdaArrow(MLambdaArrow* ins);
     void visitKeepAliveObject(MKeepAliveObject* ins);
     void visitSlots(MSlots* ins);
     void visitElements(MElements* ins);
     void visitConstantElements(MConstantElements* ins);
     void visitConvertElementsToDoubles(MConvertElementsToDoubles* ins);
     void visitMaybeToDoubleElement(MMaybeToDoubleElement* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -496,33 +496,29 @@ IonBuilder::inlineArray(CallInfo& callIn
 
         // Don't inline large allocations.
         if (initLength > ArrayObject::EagerAllocationMaxLength)
             return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
-    current->add(templateConst);
-
-    MNewArray* ins = MNewArray::New(alloc(), constraints(), initLength, templateConst,
-                                    templateObject->group()->initialHeap(constraints()), pc);
-    current->add(ins);
-    current->push(ins);
-
+    if (!jsop_newarray(templateObject, initLength))
+        return InliningStatus_Error;
+
+    MDefinition* array = current->peek(-1);
     if (callInfo.argc() >= 2) {
         JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
         for (uint32_t i = 0; i < initLength; i++) {
             MDefinition* value = callInfo.getArg(i);
-            if (!initializeArrayElement(ins, i, value, unboxedType, /* addResumePoint = */ false))
+            if (!initializeArrayElement(array, i, value, unboxedType, /* addResumePoint = */ false))
                 return InliningStatus_Error;
         }
 
-        MInstruction* setLength = setInitializedLength(ins, unboxedType, initLength);
+        MInstruction* setLength = setInitializedLength(array, unboxedType, initLength);
         if (!resumeAfter(setLength))
             return InliningStatus_Error;
     }
 
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
@@ -2062,26 +2058,21 @@ IonBuilder::inlineObjectCreate(CallInfo&
         MOZ_ASSERT(types->getKnownMIRType() == MIRType_Object);
     } else {
         if (arg->type() != MIRType_Null)
             return InliningStatus_NotInlined;
     }
 
     callInfo.setImplicitlyUsedUnchecked();
 
-    MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
-    current->add(templateConst);
-    MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst,
-                                      templateObject->group()->initialHeap(constraints()),
-                                      MNewObject::ObjectCreate);
-    current->add(ins);
-    current->push(ins);
-    if (!resumeAfter(ins))
+    bool emitted = false;
+    if (!newObjectTryTemplateObject(&emitted, templateObject))
         return InliningStatus_Error;
 
+    MOZ_ASSERT(emitted);
     return InliningStatus_Inlined;
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineDefineDataProperty(CallInfo& callInfo)
 {
     MOZ_ASSERT(!callInfo.constructing());
 
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -4315,24 +4315,16 @@ MBeta::printOpcode(GenericPrinter& out) 
 {
     MDefinition::printOpcode(out);
 
     out.printf(" ");
     comparison_->dump(out);
 }
 
 bool
-MNewObject::shouldUseVM() const
-{
-    if (JSObject* obj = templateObject())
-        return obj->is<PlainObject>() && obj->as<PlainObject>().hasDynamicSlots();
-    return true;
-}
-
-bool
 MCreateThisWithTemplate::canRecoverOnBailout() const
 {
     MOZ_ASSERT(templateObject()->is<PlainObject>() || templateObject()->is<UnboxedPlainObject>());
     MOZ_ASSERT_IF(templateObject()->is<PlainObject>(),
                   !templateObject()->as<PlainObject>().denseElementsAreCopyOnWrite());
     return true;
 }
 
@@ -4551,35 +4543,16 @@ MNewArray::MNewArray(CompilerConstraintL
             setResultTypeSet(types);
             if (types->convertDoubleElements(constraints) == TemporaryTypeSet::AlwaysConvertToDoubles)
                 convertDoubleElements_ = true;
         }
     }
 }
 
 bool
-MNewArray::shouldUseVM() const
-{
-    if (!templateObject())
-        return true;
-
-    if (templateObject()->is<UnboxedArrayObject>()) {
-        MOZ_ASSERT(templateObject()->as<UnboxedArrayObject>().capacity() >= length());
-        return !templateObject()->as<UnboxedArrayObject>().hasInlineElements();
-    }
-
-    MOZ_ASSERT(length() <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
-
-    size_t arraySlots =
-        gc::GetGCKindSlots(templateObject()->asTenured().getAllocKind()) - ObjectElements::VALUES_PER_HEADER;
-
-    return length() > arraySlots;
-}
-
-bool
 MLoadFixedSlot::mightAlias(const MDefinition* store) const
 {
     if (store->isStoreFixedSlot() && store->toStoreFixedSlot()->slot() != slot())
         return false;
     return true;
 }
 
 bool
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3086,20 +3086,16 @@ class MNewArray
     jsbytecode* pc() const {
         return pc_;
     }
 
     bool convertDoubleElements() const {
         return convertDoubleElements_;
     }
 
-    // Returns true if the code generator should call through to the
-    // VM rather than the fast path.
-    bool shouldUseVM() const;
-
     // NewArray is marked as non-effectful because all our allocations are
     // either lazy when we are using "new Array(length)" or bounded by the
     // script or the stack size when we are using "new Array(...)" or "[...]"
     // notations.  So we might have to allocate the array twice if we bail
     // during the computation of the first element of the square braket
     // notation.
     virtual AliasSet getAliasSet() const override {
         return AliasSet::None();
@@ -3208,17 +3204,17 @@ class MNewObject
     Mode mode_;
 
     MNewObject(CompilerConstraintList* constraints, MConstant* templateConst,
                gc::InitialHeap initialHeap, Mode mode)
       : MUnaryInstruction(templateConst),
         initialHeap_(initialHeap),
         mode_(mode)
     {
-        MOZ_ASSERT_IF(mode != ObjectLiteral, !shouldUseVM());
+        MOZ_ASSERT_IF(mode != ObjectLiteral, templateObject());
         setResultType(MIRType_Object);
 
         if (JSObject* obj = templateObject())
             setResultTypeSet(MakeSingletonTypeSet(constraints, obj));
 
         // The constant is kept separated in a MConstant, this way we can safely
         // mark it during GC if we recover the object allocation.  Otherwise, by
         // making it emittedAtUses, we do not produce register allocations for
@@ -3233,20 +3229,16 @@ class MNewObject
 
     static MNewObject* New(TempAllocator& alloc, CompilerConstraintList* constraints,
                            MConstant* templateConst, gc::InitialHeap initialHeap,
                            Mode mode)
     {
         return new(alloc) MNewObject(constraints, templateConst, initialHeap, mode);
     }
 
-    // Returns true if the code generator should call through to the
-    // VM rather than the fast path.
-    bool shouldUseVM() const;
-
     Mode mode() const {
         return mode_;
     }
 
     JSObject* templateObject() const {
         return getOperand(0)->toConstant()->toObjectOrNull();
     }
 
@@ -7606,16 +7598,34 @@ class MUnarySharedStub
     INSTRUCTION_HEADER(UnarySharedStub)
 
     static MUnarySharedStub* New(TempAllocator& alloc, MDefinition* input)
     {
         return new(alloc) MUnarySharedStub(input);
     }
 };
 
+class MNullarySharedStub
+  : public MNullaryInstruction
+{
+    explicit MNullarySharedStub()
+      : MNullaryInstruction()
+    {
+        setResultType(MIRType_Value);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NullarySharedStub)
+
+    static MNullarySharedStub* New(TempAllocator& alloc)
+    {
+        return new(alloc) MNullarySharedStub();
+    }
+};
+
 // Check the current frame for over-recursion past the global stack limit.
 class MCheckOverRecursed
   : public MNullaryInstruction
 {
   public:
     INSTRUCTION_HEADER(CheckOverRecursed)
 
     static MCheckOverRecursed* New(TempAllocator& alloc) {
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -47,16 +47,17 @@ namespace jit {
     _(Beta)                                                                 \
     _(OsrValue)                                                             \
     _(OsrScopeChain)                                                        \
     _(OsrReturnValue)                                                       \
     _(OsrArgumentsObject)                                                   \
     _(ReturnFromCtor)                                                       \
     _(BinarySharedStub)                                                     \
     _(UnarySharedStub)                                                      \
+    _(NullarySharedStub)                                                    \
     _(CheckOverRecursed)                                                    \
     _(DefVar)                                                               \
     _(DefLexical)                                                           \
     _(DefFun)                                                               \
     _(CreateThis)                                                           \
     _(CreateThisWithProto)                                                  \
     _(CreateThisWithTemplate)                                               \
     _(CreateArgumentsObject)                                                \
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -4513,55 +4513,55 @@ ICUpdatedStub::addUpdateStubForValue(JSC
     return true;
 }
 
 //
 // NewArray_Fallback
 //
 
 static bool
-DoNewArray(JSContext* cx, BaselineFrame* frame, ICNewArray_Fallback* stub, uint32_t length,
+DoNewArray(JSContext* cx, void* payload, ICNewArray_Fallback* stub, uint32_t length,
            MutableHandleValue res)
 {
+    SharedStubInfo info(cx, payload, stub->icEntry());
+
     FallbackICSpew(cx, stub, "NewArray");
 
     RootedObject obj(cx);
     if (stub->templateObject()) {
         RootedObject templateObject(cx, stub->templateObject());
         obj = NewArrayOperationWithTemplate(cx, templateObject);
         if (!obj)
             return false;
     } else {
-        RootedScript script(cx, frame->script());
-        jsbytecode* pc = stub->icEntry()->pc(script);
+        HandleScript script = info.script();
+        jsbytecode* pc = info.pc();
         obj = NewArrayOperation(cx, script, pc, length);
         if (!obj)
             return false;
 
         if (obj && !obj->isSingleton() && !obj->group()->maybePreliminaryObjects()) {
             JSObject* templateObject = NewArrayOperation(cx, script, pc, length, TenuredObject);
             if (!templateObject)
                 return false;
             stub->setTemplateObject(templateObject);
         }
     }
 
     res.setObject(*obj);
     return true;
 }
 
-typedef bool(*DoNewArrayFn)(JSContext*, BaselineFrame*, ICNewArray_Fallback*, uint32_t,
+typedef bool(*DoNewArrayFn)(JSContext*, void*, ICNewArray_Fallback*, uint32_t,
                             MutableHandleValue);
 static const VMFunction DoNewArrayInfo = FunctionInfo<DoNewArrayFn>(DoNewArray, TailCall);
 
 bool
 ICNewArray_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
 {
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
     EmitRestoreTailCallReg(masm);
 
     masm.push(R0.scratchReg()); // length
     masm.push(ICStubReg); // stub.
     pushStubPayload(masm, R0.scratchReg());
 
     return tailCallVM(DoNewArrayInfo, masm);
 }
@@ -4597,38 +4597,41 @@ GenerateNewObjectWithTemplateCode(JSCont
     EmitStubGuardFailure(masm);
 
     Linker linker(masm);
     AutoFlushICache afc("GenerateNewObjectWithTemplateCode");
     return linker.newCode<CanGC>(cx, BASELINE_CODE);
 }
 
 static bool
-DoNewObject(JSContext* cx, BaselineFrame* frame, ICNewObject_Fallback* stub, MutableHandleValue res)
+DoNewObject(JSContext* cx, void* payload, ICNewObject_Fallback* stub, MutableHandleValue res)
 {
+    SharedStubInfo info(cx, payload, stub->icEntry());
+
     FallbackICSpew(cx, stub, "NewObject");
 
     RootedObject obj(cx);
 
     RootedObject templateObject(cx, stub->templateObject());
     if (templateObject) {
         MOZ_ASSERT(!templateObject->group()->maybePreliminaryObjects());
         obj = NewObjectOperationWithTemplate(cx, templateObject);
     } else {
-        RootedScript script(cx, frame->script());
-        jsbytecode* pc = stub->icEntry()->pc(script);
+        HandleScript script = info.script();
+        jsbytecode* pc = info.pc();
         obj = NewObjectOperation(cx, script, pc);
 
         if (obj && !obj->isSingleton() && !obj->group()->maybePreliminaryObjects()) {
             JSObject* templateObject = NewObjectOperation(cx, script, pc, TenuredObject);
             if (!templateObject)
                 return false;
 
-            if (templateObject->is<UnboxedPlainObject>() ||
-                !templateObject->as<PlainObject>().hasDynamicSlots())
+            if (!stub->invalid() &&
+                (templateObject->is<UnboxedPlainObject>() ||
+                 !templateObject->as<PlainObject>().hasDynamicSlots()))
             {
                 JitCode* code = GenerateNewObjectWithTemplateCode(cx, templateObject);
                 if (!code)
                     return false;
 
                 ICStubSpace* space =
                     ICStubCompiler::StubSpaceForKind(ICStub::NewObject_WithTemplate, script,
                                                      ICStubCompiler::Engine::Baseline);
@@ -4645,24 +4648,22 @@ DoNewObject(JSContext* cx, BaselineFrame
 
     if (!obj)
         return false;
 
     res.setObject(*obj);
     return true;
 }
 
-typedef bool(*DoNewObjectFn)(JSContext*, BaselineFrame*, ICNewObject_Fallback*, MutableHandleValue);
+typedef bool(*DoNewObjectFn)(JSContext*, void*, ICNewObject_Fallback*, MutableHandleValue);
 static const VMFunction DoNewObjectInfo = FunctionInfo<DoNewObjectFn>(DoNewObject, TailCall);
 
 bool
 ICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
 {
-    MOZ_ASSERT(engine_ == Engine::Baseline);
-
     EmitRestoreTailCallReg(masm);
 
     masm.push(ICStubReg); // stub.
     pushStubPayload(masm, R0.scratchReg());
 
     return tailCallVM(DoNewObjectInfo, masm);
 }
 
--- a/js/src/jit/SharedIC.h
+++ b/js/src/jit/SharedIC.h
@@ -3233,16 +3233,17 @@ class ICGetProp_ArgumentsCallee : public
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICGetProp_ArgumentsCallee>(space, getStubCode(), firstMonitorStub_);
         }
     };
 };
 
 // JSOP_NEWARRAY
+// JSOP_NEWINIT
 
 class ICNewArray_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
     HeapPtrObject templateObject_;
 
     // The group used for objects created here is always available, even if the
@@ -3255,18 +3256,18 @@ class ICNewArray_Fallback : public ICFal
     {}
 
   public:
     class Compiler : public ICStubCompiler {
         RootedObjectGroup templateGroup;
         bool generateStubCode(MacroAssembler& masm);
 
       public:
-        Compiler(JSContext* cx, ObjectGroup* templateGroup)
-          : ICStubCompiler(cx, ICStub::NewArray_Fallback, Engine::Baseline),
+        Compiler(JSContext* cx, ObjectGroup* templateGroup, Engine engine)
+          : ICStubCompiler(cx, ICStub::NewArray_Fallback, engine),
             templateGroup(cx, templateGroup)
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICNewArray_Fallback>(space, getStubCode(), templateGroup);
         }
     };
 
@@ -3301,18 +3302,18 @@ class ICNewObject_Fallback : public ICFa
       : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(nullptr)
     {}
 
   public:
     class Compiler : public ICStubCompiler {
         bool generateStubCode(MacroAssembler& masm);
 
       public:
-        explicit Compiler(JSContext* cx)
-          : ICStubCompiler(cx, ICStub::NewObject_Fallback, Engine::Baseline)
+        explicit Compiler(JSContext* cx, Engine engine)
+          : ICStubCompiler(cx, ICStub::NewObject_Fallback, engine)
         {}
 
         ICStub* getStub(ICStubSpace* space) {
             return newStub<ICNewObject_Fallback>(space, getStubCode());
         }
     };
 
     HeapPtrObject& templateObject() {
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -886,17 +886,17 @@ class LNewArray : public LInstructionHel
   public:
     LIR_HEADER(NewArray)
 
     explicit LNewArray(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const char* extraName() const {
-        return mir()->shouldUseVM() ? "VMCall" : nullptr;
+        return mir()->templateObject() ? "VMCall" : nullptr;
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
     MNewArray* mir() const {
         return mir_->toNewArray();
@@ -948,17 +948,17 @@ class LNewObject : public LInstructionHe
   public:
     LIR_HEADER(NewObject)
 
     explicit LNewObject(const LDefinition& temp) {
         setTemp(0, temp);
     }
 
     const char* extraName() const {
-        return mir()->shouldUseVM() ? "VMCall" : nullptr;
+        return mir()->templateObject() ? "VMCall" : nullptr;
     }
 
     const LDefinition* temp() {
         return getTemp(0);
     }
 
     MNewObject* mir() const {
         return mir_->toNewObject();
@@ -4508,16 +4508,26 @@ class LUnarySharedStub : public LCallIns
 
     const MUnarySharedStub* mir() const {
         return mir_->toUnarySharedStub();
     }
 
     static const size_t Input = 0;
 };
 
+class LNullarySharedStub : public LCallInstructionHelper<BOX_PIECES, 0, 0>
+{
+  public:
+    LIR_HEADER(NullarySharedStub)
+
+    const MNullarySharedStub* mir() const {
+        return mir_->toNullarySharedStub();
+    }
+};
+
 class LLambdaForSingleton : public LCallInstructionHelper<1, 1, 0>
 {
   public:
     LIR_HEADER(LambdaForSingleton)
 
     explicit LLambdaForSingleton(const LAllocation& scopeChain)
     {
         setOperand(0, scopeChain);
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -210,16 +210,17 @@
     _(RegExpSearcher)               \
     _(RegExpTester)                 \
     _(RegExpPrototypeOptimizable)   \
     _(RegExpInstanceOptimizable)    \
     _(StringReplace)                \
     _(Substr)                       \
     _(BinarySharedStub)             \
     _(UnarySharedStub)              \
+    _(NullarySharedStub)            \
     _(Lambda)                       \
     _(LambdaArrow)                  \
     _(LambdaForSingleton)           \
     _(KeepAliveObject)              \
     _(Slots)                        \
     _(Elements)                     \
     _(ConvertElementsToDoubles)     \
     _(MaybeToDoubleElement)         \
--- a/js/src/jit/shared/Lowering-shared-inl.h
+++ b/js/src/jit/shared/Lowering-shared-inl.h
@@ -191,17 +191,17 @@ LIRGeneratorShared::defineInt64(LInstruc
     add(lir);
 }
 
 void
 LIRGeneratorShared::defineSharedStubReturn(LInstruction* lir, MDefinition* mir)
 {
     lir->setMir(mir);
 
-    MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub());
+    MOZ_ASSERT(lir->isBinarySharedStub() || lir->isUnarySharedStub() || lir->isNullarySharedStub());
     MOZ_ASSERT(mir->type() == MIRType_Value);
 
     uint32_t vreg = getVirtualRegister();
 
 #if defined(JS_NUNBOX32)
     lir->setDef(TYPE_INDEX, LDefinition(vreg + VREG_TYPE_OFFSET, LDefinition::TYPE,
                                         LGeneralReg(JSReturnReg_Type)));
     lir->setDef(PAYLOAD_INDEX, LDefinition(vreg + VREG_DATA_OFFSET, LDefinition::PAYLOAD,