Backout 907d5bc3bd26 (Bug 969012) for bustage on a CLOSED TREE.
authorTerrence Cole <terrence@mozilla.com>
Wed, 12 Mar 2014 13:39:40 -0700
changeset 184226 20e8191247fd97395056ee1e4d7e48e1ba806c40
parent 184225 840df518d026f9f7b9bf896fb7ef8d0b3e9fb9da
child 184227 2645fa20fa257ddeef363e98536e6d67da71d1f8
push idunknown
push userunknown
push dateunknown
bugs969012
milestone30.0a1
backs out907d5bc3bd26ebb6db9fe95128c275cd94aaa698
Backout 907d5bc3bd26 (Bug 969012) for bustage on a CLOSED TREE.
js/src/jit-test/tests/parallel/closure-nested-branch.js
js/src/jit-test/tests/parallel/closure-nested-compute.js
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/Ion.cpp
js/src/jit/IonBuilder.cpp
js/src/jit/IonMacroAssembler.cpp
js/src/jit/IonMacroAssembler.h
js/src/jit/JitCompartment.h
js/src/jit/LIR-Common.h
js/src/jit/LOpcodes.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/ParallelSafetyAnalysis.cpp
js/src/jit/VMFunctions.cpp
js/src/jit/VMFunctions.h
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
--- a/js/src/jit-test/tests/parallel/closure-nested-branch.js
+++ b/js/src/jit-test/tests/parallel/closure-nested-branch.js
@@ -1,13 +1,22 @@
 load(libdir + "parallelarray-helpers.js");
 
 function testClosureCreationAndInvocation() {
   var a = range(0, 64);
   function makeaddv(v) {
+    var u = 1;
+    var t = 2;
+    var s = 3;
+    var r = 4;
+    var q = 5;
+    var p = 6;
+    var o = 7;
+    var n = 8;
+    var m = 9;
     var l = 10;
     var k = 11;
     var j = 12;
     var i = 13;
     var h = 14;
     var g = 15;
     var f = 16;
     var e = 17;
@@ -20,16 +29,21 @@ function testClosureCreationAndInvocatio
             : function (x) {
               switch (x) {
               case 0: return a; case 1: return b;
               case 2: return c; case 3: return d;
               case 4: return e; case 5: return f;
               case 6: return g; case 7: return h;
               case 8: return i; case 9: return j;
               case 10: return k; case 11: return l;
+              case 12: return m; case 13: return n;
+              case 14: return o; case 15: return p;
+              case 16: return q; case 17: return r;
+              case 18: return s; case 19: return t;
+              case 20: return u;
               }
             });
   }
   var m;
   for (var i in MODES) m = a.mapPar(makeaddv, MODES[i]);
   assertEq(m[21](1), 20); // v == 21; x == 1 ==> inner function returns b == 20
 
   var n = a.mapPar(function (v) { return function (x) { return v; }});
--- a/js/src/jit-test/tests/parallel/closure-nested-compute.js
+++ b/js/src/jit-test/tests/parallel/closure-nested-compute.js
@@ -1,13 +1,22 @@
 load(libdir + "parallelarray-helpers.js");
 
 function testClosureCreationAndInvocation() {
   var a = range(0, 64);
   function makeaddv(v) {
+    var u = 1;
+    var t = 2;
+    var s = 3;
+    var r = 4;
+    var q = 5;
+    var p = 6;
+    var o = 7;
+    var n = 8;
+    var m = 9;
     var l = 10;
     var k = 11;
     var j = 12;
     var i = 13;
     var h = 14;
     var g = 15;
     var f = 16;
     var e = 17;
@@ -18,16 +27,21 @@ function testClosureCreationAndInvocatio
     return function (x) {
       switch (x) {
       case 0: return a; case 1: return b;
       case 2: return c; case 3: return d;
       case 4: return e; case 5: return f;
       case 6: return g; case 7: return h;
       case 8: return i; case 9: return j;
       case 10: return k; case 11: return l;
+      case 12: return m; case 13: return n;
+      case 14: return o; case 15: return p;
+      case 16: return q; case 17: return r;
+      case 18: return s; case 19: return t;
+      case 20: return u;
       }
     };
   };
   for (var i in MODES) {
     var m = a.mapPar(makeaddv, MODES[i]);
     assertEq(m[21](1), 20); // v == 21; x == 1 ==> inner function returns b == 20
   }
 }
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -967,17 +967,18 @@ CodeGenerator::visitLambda(LLambda *lir)
 
     OutOfLineCode *ool = oolCallVM(LambdaInfo, lir, (ArgList(), ImmGCPtr(info.fun), scopeChain),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
     JS_ASSERT(!info.singletonType);
 
-    masm.createGCObject(output, tempReg, info.fun, gc::DefaultHeap, ool->entry());
+    masm.newGCThing(output, tempReg, info.fun, ool->entry(), gc::DefaultHeap);
+    masm.initGCThing(output, tempReg, info.fun);
 
     emitLambdaInit(output, scopeChain, info);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 void
@@ -3331,16 +3332,39 @@ CodeGenerator::visitNewDerivedTypedObjec
     JS_ASSERT(gen->info().executionMode() == SequentialExecution);
 
     pushArg(ToRegister(lir->offset()));
     pushArg(ToRegister(lir->owner()));
     pushArg(ToRegister(lir->type()));
     return callVM(CreateDerivedTypedObjInfo, lir);
 }
 
+bool
+CodeGenerator::visitNewSlots(LNewSlots *lir)
+{
+    Register temp1 = ToRegister(lir->temp1());
+    Register temp2 = ToRegister(lir->temp2());
+    Register temp3 = ToRegister(lir->temp3());
+    Register output = ToRegister(lir->output());
+
+    masm.mov(ImmPtr(GetIonContext()->runtime), temp1);
+    masm.mov(ImmWord(lir->mir()->nslots()), temp2);
+
+    masm.setupUnalignedABICall(2, temp3);
+    masm.passABIArg(temp1);
+    masm.passABIArg(temp2);
+    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, NewSlots));
+
+    masm.testPtr(output, output);
+    if (!bailoutIf(Assembler::Zero, lir->snapshot()))
+        return false;
+
+    return true;
+}
+
 bool CodeGenerator::visitAtan2D(LAtan2D *lir)
 {
     Register temp = ToRegister(lir->temp());
     FloatRegister y = ToFloatRegister(lir->y());
     FloatRegister x = ToFloatRegister(lir->x());
 
     masm.setupUnalignedABICall(2, temp);
     masm.passABIArg(y, MoveOp::DOUBLE);
@@ -3379,17 +3403,18 @@ CodeGenerator::visitNewArray(LNewArray *
 
     if (lir->mir()->shouldUseVM())
         return visitNewArrayCallVM(lir);
 
     OutOfLineNewArray *ool = new(alloc()) OutOfLineNewArray(lir);
     if (!addOutOfLineCode(ool))
         return false;
 
-    masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
+    masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
+    masm.initGCThing(objReg, tempReg, templateObject);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitOutOfLineNewArray(OutOfLineNewArray *ool)
 {
@@ -3465,17 +3490,18 @@ CodeGenerator::visitNewObject(LNewObject
 
     if (lir->mir()->shouldUseVM())
         return visitNewObjectVMCall(lir);
 
     OutOfLineNewObject *ool = new(alloc()) OutOfLineNewObject(lir);
     if (!addOutOfLineCode(ool))
         return false;
 
-    masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
+    masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
+    masm.initGCThing(objReg, tempReg, templateObject);
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitOutOfLineNewObject(OutOfLineNewObject *ool)
 {
@@ -3500,64 +3526,91 @@ CodeGenerator::visitNewDeclEnvObject(LNe
     // If we have a template object, we can inline call object creation.
     OutOfLineCode *ool = oolCallVM(NewDeclEnvObjectInfo, lir,
                                    (ArgList(), ImmGCPtr(info.funMaybeLazy()),
                                     Imm32(gc::DefaultHeap)),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
-    masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
-
+    masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
+    masm.initGCThing(objReg, tempReg, templateObj);
     masm.bind(ool->rejoin());
     return true;
 }
 
-typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape, HandleTypeObject);
+typedef JSObject *(*NewCallObjectFn)(JSContext *, HandleScript, HandleShape,
+                                     HandleTypeObject, HeapSlot *);
 static const VMFunction NewCallObjectInfo =
     FunctionInfo<NewCallObjectFn>(NewCallObject);
 
 bool
 CodeGenerator::visitNewCallObject(LNewCallObject *lir)
 {
     Register objReg = ToRegister(lir->output());
     Register tempReg = ToRegister(lir->temp());
 
     JSObject *templateObj = lir->mir()->templateObject();
 
     // If we have a template object, we can inline call object creation.
-    OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
-                                   (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
-                                               ImmGCPtr(templateObj->lastProperty()),
-                                               ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type())),
-                                   StoreRegisterTo(objReg));
+    OutOfLineCode *ool;
+    if (lir->slots()->isRegister()) {
+        ool = oolCallVM(NewCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
+                                    ImmGCPtr(templateObj->lastProperty()),
+                                    ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
+                                    ToRegister(lir->slots())),
+                        StoreRegisterTo(objReg));
+    } else {
+        ool = oolCallVM(NewCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(lir->mir()->block()->info().script()),
+                                    ImmGCPtr(templateObj->lastProperty()),
+                                    ImmGCPtr(templateObj->hasSingletonType() ? nullptr : templateObj->type()),
+                                    ImmPtr(nullptr)),
+                        StoreRegisterTo(objReg));
+    }
     if (!ool)
         return false;
 
     if (lir->mir()->needsSingletonType()) {
         // Objects can only be given singleton types in VM calls.
         masm.jump(ool->entry());
     } else {
-        masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
+        masm.newGCThing(objReg, tempReg, templateObj, ool->entry(), gc::DefaultHeap);
+        masm.initGCThing(objReg, tempReg, templateObj);
+
+        if (lir->slots()->isRegister())
+            masm.storePtr(ToRegister(lir->slots()), Address(objReg, JSObject::offsetOfSlots()));
     }
 
     masm.bind(ool->rejoin());
     return true;
 }
 
 bool
 CodeGenerator::visitNewCallObjectPar(LNewCallObjectPar *lir)
 {
     Register resultReg = ToRegister(lir->output());
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register tempReg1 = ToRegister(lir->getTemp0());
     Register tempReg2 = ToRegister(lir->getTemp1());
     JSObject *templateObj = lir->mir()->templateObj();
 
     emitAllocateGCThingPar(lir, resultReg, cxReg, tempReg1, tempReg2, templateObj);
+
+    // NB: !lir->slots()->isRegister() implies that there is no slots
+    // array at all, and the memory is already zeroed when copying
+    // from the template object
+
+    if (lir->slots()->isRegister()) {
+        Register slotsReg = ToRegister(lir->slots());
+        JS_ASSERT(slotsReg != resultReg);
+        masm.storePtr(slotsReg, Address(resultReg, JSObject::offsetOfSlots()));
+    }
+
     return true;
 }
 
 bool
 CodeGenerator::visitNewDenseArrayPar(LNewDenseArrayPar *lir)
 {
     Register cxReg = ToRegister(lir->forkJoinContext());
     Register lengthReg = ToRegister(lir->length());
@@ -3606,17 +3659,18 @@ CodeGenerator::visitNewStringObject(LNew
 
     StringObject *templateObj = lir->mir()->templateObj();
 
     OutOfLineCode *ool = oolCallVM(NewStringObjectInfo, lir, (ArgList(), input),
                                    StoreRegisterTo(output));
     if (!ool)
         return false;
 
-    masm.createGCObject(output, temp, templateObj, gc::DefaultHeap, ool->entry());
+    masm.newGCThing(output, temp, templateObj, ool->entry(), gc::DefaultHeap);
+    masm.initGCThing(output, temp, templateObj);
 
     masm.loadStringLength(input, temp);
 
     masm.storeValue(JSVAL_TYPE_STRING, input, Address(output, StringObject::offsetOfPrimitiveValue()));
     masm.storeValue(JSVAL_TYPE_INT32, temp, Address(output, StringObject::offsetOfLength()));
 
     masm.bind(ool->rejoin());
     return true;
@@ -3851,17 +3905,17 @@ CodeGenerator::visitCreateThisWithTempla
 
     OutOfLineCode *ool = oolCallVM(NewGCObjectInfo, lir,
                                    (ArgList(), Imm32(allocKind), Imm32(initialHeap)),
                                    StoreRegisterTo(objReg));
     if (!ool)
         return false;
 
     // Allocate. If the FreeList is empty, call to VM, which may GC.
-    masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
+    masm.newGCThing(objReg, tempReg, templateObject, ool->entry(), lir->mir()->initialHeap());
 
     // Initialize based on the templateObject.
     masm.bind(ool->rejoin());
     masm.initGCThing(objReg, tempReg, templateObject);
 
     return true;
 }
 
@@ -4920,80 +4974,16 @@ JitCompartment::generateStringConcatStub
 
 #ifdef JS_ION_PERF
     writePerfSpewerJitCodeProfile(code, "StringConcatStub");
 #endif
 
     return code;
 }
 
-JitCode *
-JitRuntime::generateMallocStub(JSContext *cx)
-{
-    const Register regReturn = CallTempReg0;
-    const Register regNBytes = CallTempReg0;
-    const Register regRuntime = CallTempReg1;
-    const Register regTemp = CallTempReg1;
-
-    MacroAssembler masm(cx);
-
-    RegisterSet regs = RegisterSet::Volatile();
-    regs.takeUnchecked(regNBytes);
-    masm.PushRegsInMask(regs);
-
-    masm.setupUnalignedABICall(2, regTemp);
-    masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
-    masm.passABIArg(regRuntime);
-    masm.passABIArg(regNBytes);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MallocWrapper));
-    masm.storeCallResult(regReturn);
-
-    masm.PopRegsInMask(regs);
-    masm.ret();
-
-    Linker linker(masm);
-    JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
-
-#ifdef JS_ION_PERF
-    writePerfSpewerJitCodeProfile(code, "MallocStub");
-#endif
-
-    return code;
-}
-
-JitCode *
-JitRuntime::generateFreeStub(JSContext *cx)
-{
-    const Register regSlots = CallTempReg0;
-    const Register regTemp = CallTempReg1;
-
-    MacroAssembler masm(cx);
-
-    RegisterSet regs = RegisterSet::Volatile();
-    regs.takeUnchecked(regSlots);
-    masm.PushRegsInMask(regs);
-
-    masm.setupUnalignedABICall(1, regTemp);
-    masm.passABIArg(regSlots);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, js_free));
-
-    masm.PopRegsInMask(regs);
-
-    masm.ret();
-
-    Linker linker(masm);
-    JitCode *code = linker.newCode<NoGC>(cx, JSC::OTHER_CODE);
-
-#ifdef JS_ION_PERF
-    writePerfSpewerJitCodeProfile(code, "FreeStub");
-#endif
-
-    return code;
-}
-
 typedef bool (*CharCodeAtFn)(JSContext *, HandleString, int32_t, uint32_t *);
 static const VMFunction CharCodeAtInfo = FunctionInfo<CharCodeAtFn>(jit::CharCodeAt);
 
 bool
 CodeGenerator::visitCharCodeAt(LCharCodeAt *lir)
 {
     Register str = ToRegister(lir->str());
     Register index = ToRegister(lir->index());
@@ -5637,17 +5627,19 @@ CodeGenerator::visitArrayConcat(LArrayCo
     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
 
     masm.loadPtr(Address(rhs, JSObject::offsetOfElements()), temp1);
     masm.load32(Address(temp1, ObjectElements::offsetOfInitializedLength()), temp2);
     masm.branch32(Assembler::NotEqual, Address(temp1, ObjectElements::offsetOfLength()), temp2, &fail);
 
     // Try to allocate an object.
-    masm.createGCObject(temp1, temp2, lir->mir()->templateObj(), lir->mir()->initialHeap(), &fail);
+    JSObject *templateObj = lir->mir()->templateObj();
+    masm.newGCThing(temp1, temp2, templateObj, &fail, lir->mir()->initialHeap());
+    masm.initGCThing(temp1, temp2, templateObj);
     masm.jump(&call);
     {
         masm.bind(&fail);
         masm.movePtr(ImmPtr(nullptr), temp1);
     }
     masm.bind(&call);
 
     pushArg(temp1);
@@ -6008,17 +6000,18 @@ CodeGenerator::visitRest(LRest *lir)
     Register numActuals = ToRegister(lir->numActuals());
     Register temp0 = ToRegister(lir->getTemp(0));
     Register temp1 = ToRegister(lir->getTemp(1));
     Register temp2 = ToRegister(lir->getTemp(2));
     unsigned numFormals = lir->mir()->numFormals();
     JSObject *templateObject = lir->mir()->templateObject();
 
     Label joinAlloc, failAlloc;
-    masm.createGCObject(temp2, temp0, templateObject, gc::DefaultHeap, &failAlloc);
+    masm.newGCThing(temp2, temp0, templateObject, &failAlloc, gc::DefaultHeap);
+    masm.initGCThing(temp2, temp0, templateObject);
     masm.jump(&joinAlloc);
     {
         masm.bind(&failAlloc);
         masm.movePtr(ImmPtr(nullptr), temp2);
     }
     masm.bind(&joinAlloc);
 
     return emitRest(lir, temp2, numActuals, temp0, temp1, numFormals, templateObject);
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -126,16 +126,17 @@ class CodeGenerator : public CodeGenerat
     bool visitBail(LBail *lir);
     bool visitGetDynamicName(LGetDynamicName *lir);
     bool visitFilterArgumentsOrEvalS(LFilterArgumentsOrEvalS *lir);
     bool visitFilterArgumentsOrEvalV(LFilterArgumentsOrEvalV *lir);
     bool visitCallDirectEvalS(LCallDirectEvalS *lir);
     bool visitCallDirectEvalV(LCallDirectEvalV *lir);
     bool visitDoubleToInt32(LDoubleToInt32 *lir);
     bool visitFloat32ToInt32(LFloat32ToInt32 *lir);
+    bool visitNewSlots(LNewSlots *lir);
     bool visitNewArrayCallVM(LNewArray *lir);
     bool visitNewArray(LNewArray *lir);
     bool visitOutOfLineNewArray(OutOfLineNewArray *ool);
     bool visitNewObjectVMCall(LNewObject *lir);
     bool visitNewObject(LNewObject *lir);
     bool visitOutOfLineNewObject(OutOfLineNewObject *ool);
     bool visitNewDeclEnvObject(LNewDeclEnvObject *lir);
     bool visitNewCallObject(LNewCallObject *lir);
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -24,17 +24,16 @@
 #include "jit/BaselineInspector.h"
 #include "jit/BaselineJIT.h"
 #include "jit/CodeGenerator.h"
 #include "jit/EdgeCaseAnalysis.h"
 #include "jit/EffectiveAddressAnalysis.h"
 #include "jit/ExecutionModeInlines.h"
 #include "jit/IonAnalysis.h"
 #include "jit/IonBuilder.h"
-#include "jit/IonLinker.h"
 #include "jit/IonOptimizationLevels.h"
 #include "jit/IonSpewer.h"
 #include "jit/JitCommon.h"
 #include "jit/JitCompartment.h"
 #include "jit/LICM.h"
 #include "jit/LinearScan.h"
 #include "jit/LIR.h"
 #include "jit/Lowering.h"
@@ -264,26 +263,16 @@ JitRuntime::initialize(JSContext *cx)
     if (!valuePreBarrier_)
         return false;
 
     IonSpew(IonSpew_Codegen, "# Emitting Pre Barrier for Shape");
     shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape);
     if (!shapePreBarrier_)
         return false;
 
-    IonSpew(IonSpew_Codegen, "# Emitting malloc stub");
-    mallocStub_ = generateMallocStub(cx);
-    if (!mallocStub_)
-        return false;
-
-    IonSpew(IonSpew_Codegen, "# Emitting free stub");
-    freeStub_ = generateFreeStub(cx);
-    if (!freeStub_)
-        return false;
-
     IonSpew(IonSpew_Codegen, "# Emitting VM function wrappers");
     for (VMFunction *fun = VMFunction::functions; fun; fun = fun->next) {
         if (!generateVMWrapper(cx, *fun))
             return false;
     }
 
     return true;
 }
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -4592,41 +4592,49 @@ IonBuilder::createDeclEnvObject(MDefinit
 
 MInstruction *
 IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
 {
     // Get a template CallObject that we'll use to generate inline object
     // creation.
     CallObject *templateObj = inspector->templateCallObject();
 
-    // Allocate the object. Run-once scripts need a singleton type, so always do
-    // a VM call in such cases.
-    MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce());
+    // If the CallObject needs dynamic slots, allocate those now.
+    MInstruction *slots;
+    if (templateObj->hasDynamicSlots()) {
+        size_t nslots = JSObject::dynamicSlotsCount(templateObj->numFixedSlots(),
+                                                    templateObj->lastProperty()->slotSpan(templateObj->getClass()),
+                                                    templateObj->getClass());
+        slots = MNewSlots::New(alloc(), nslots);
+    } else {
+        slots = MConstant::New(alloc(), NullValue());
+    }
+    current->add(slots);
+
+    // Allocate the actual object. It is important that no intervening
+    // instructions could potentially bailout, thus leaking the dynamic slots
+    // pointer. Run-once scripts need a singleton type, so always do a VM call
+    // in such cases.
+    MNewCallObject *callObj = MNewCallObject::New(alloc(), templateObj, script()->treatAsRunOnce(), slots);
     current->add(callObj);
 
     // Initialize the object's reserved slots. No post barrier is needed here,
     // for the same reason as in createDeclEnvObject.
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::enclosingScopeSlot(), scope));
     current->add(MStoreFixedSlot::New(alloc(), callObj, CallObject::calleeSlot(), callee));
 
     // Initialize argument slots.
-    MSlots *slots = nullptr;
     for (AliasedFormalIter i(script()); i; i++) {
         unsigned slot = i.scopeSlot();
         unsigned formal = i.frameIndex();
         MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
-        if (slot >= templateObj->numFixedSlots()) {
-            if (!slots) {
-                slots = MSlots::New(alloc(), callObj);
-                current->add(slots);
-            }
+        if (slot >= templateObj->numFixedSlots())
             current->add(MStoreSlot::New(alloc(), slots, slot - templateObj->numFixedSlots(), param));
-        } else {
+        else
             current->add(MStoreFixedSlot::New(alloc(), callObj, slot, param));
-        }
     }
 
     return callObj;
 }
 
 MDefinition *
 IonBuilder::createThisScripted(MDefinition *callee)
 {
@@ -7479,20 +7487,16 @@ IonBuilder::setElemTryTypedStatic(bool *
 
     if (!object->resultTypeSet())
         return true;
     JSObject *tarrObj = object->resultTypeSet()->getSingleton();
     if (!tarrObj)
         return true;
 
     TypedArrayObject *tarr = &tarrObj->as<TypedArrayObject>();
-
-    if (gc::IsInsideNursery(tarr->runtimeFromMainThread(), tarr->viewData()))
-        return true;
-
     ArrayBufferView::ViewType viewType = (ArrayBufferView::ViewType) tarr->type();
 
     MDefinition *ptr = convertShiftToMaskForStaticTypedArray(index, viewType);
     if (!ptr)
         return true;
 
     // Emit StoreTypedArrayElementStatic.
     object->setImplicitlyUsedUnchecked();
--- a/js/src/jit/IonMacroAssembler.cpp
+++ b/js/src/jit/IonMacroAssembler.cpp
@@ -628,208 +628,84 @@ MacroAssembler::clampDoubleToUint8(Float
     {
         move32(Imm32(255), output);
     }
 
     bind(&done);
 #endif
 }
 
-// Inlined version of gc::CheckAllocatorState that checks the bare essentials
-// and bails for anything that cannot be handled with our jit allocators.
 void
-MacroAssembler::checkAllocatorState(Label *fail)
+MacroAssembler::newGCThing(Register result, Register temp, gc::AllocKind allocKind, Label *fail,
+                           gc::InitialHeap initialHeap /* = gc::DefaultHeap */)
 {
+    // Inlined equivalent of js::gc::NewGCThing() without failure case handling.
+
+    int thingSize = int(gc::Arena::thingSize(allocKind));
+
 #ifdef JS_GC_ZEAL
     // Don't execute the inline path if gcZeal is active.
     branch32(Assembler::NotEqual,
              AbsoluteAddress(GetIonContext()->runtime->addressOfGCZeal()), Imm32(0),
              fail);
 #endif
 
     // Don't execute the inline path if the compartment has an object metadata callback,
     // as the metadata to use for the object may vary between executions of the op.
     if (GetIonContext()->compartment->hasObjectMetadataCallback())
         jump(fail);
-}
-
-// Inline version of ShouldNurseryAllocate.
-bool
-MacroAssembler::shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap)
-{
-#ifdef JSGC_GENERATIONAL
-    // Note that Ion elides barriers on writes to objects know to be in the
-    // nursery, so any allocation that can be made into the nursery must be made
-    // into the nursery, even if the nursery is disabled. At runtime these will
-    // take the out-of-line path, which is required to insert a barrier for the
-    // initializing writes.
-    return IsNurseryAllocable(allocKind) && initialHeap != gc::TenuredHeap;
-#else
-    return false;
-#endif
-}
-
-// Inline version of Nursery::allocateObject.
-void
-MacroAssembler::nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind,
-                                size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail)
-{
-#ifdef JSGC_GENERATIONAL
-    JS_ASSERT(IsNurseryAllocable(allocKind));
-    JS_ASSERT(initialHeap != gc::TenuredHeap);
 
-    // This allocation site is requesting too many dynamic slots. Several
-    // allocation sites assume that nursery allocation will succeed to
-    // avoid needing barriers later. Ensure these sites limit their slot
-    // requests appropriately.
-    JS_ASSERT(nDynamicSlots < Nursery::MaxNurserySlots);
-
-    // No explicit check for nursery.isEnabled() is needed, as the comparison
-    // with the nursery's end will always fail in such cases.
-    const Nursery &nursery = GetIonContext()->runtime->gcNursery();
-    Register temp = slots;
-    int thingSize = int(gc::Arena::thingSize(allocKind));
-    int totalSize = thingSize + nDynamicSlots * sizeof(HeapSlot);
-    loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result);
-    computeEffectiveAddress(Address(result, totalSize), temp);
-    branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), temp, fail);
-    storePtr(temp, AbsoluteAddress(nursery.addressOfPosition()));
+#ifdef JSGC_GENERATIONAL
+    // Always use nursery allocation if it is possible to do so. The jit
+    // assumes a nursery pointer is returned to avoid barriers.
+    if (allocKind <= gc::FINALIZE_OBJECT_LAST && initialHeap != gc::TenuredHeap) {
+        // Inline Nursery::allocate. No explicit check for nursery.isEnabled()
+        // is needed, as the comparison with the nursery's end will always fail
+        // in such cases.
+        const Nursery &nursery = GetIonContext()->runtime->gcNursery();
+        loadPtr(AbsoluteAddress(nursery.addressOfPosition()), result);
+        computeEffectiveAddress(Address(result, thingSize), temp);
+        branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(nursery.addressOfCurrentEnd()), temp, fail);
+        storePtr(temp, AbsoluteAddress(nursery.addressOfPosition()));
+        return;
+    }
+#endif // JSGC_GENERATIONAL
 
-    if (nDynamicSlots)
-        computeEffectiveAddress(Address(result, thingSize), slots);
-#endif // JSGC_GENERATIONAL
-}
+    CompileZone *zone = GetIonContext()->compartment->zone();
 
-// Inlined version of FreeSpan::allocate.
-void
-MacroAssembler::freeSpanAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail)
-{
-    CompileZone *zone = GetIonContext()->compartment->zone();
-    int thingSize = int(gc::Arena::thingSize(allocKind));
-
-    // Load FreeSpan::first of |zone|'s freeLists for |allocKind|. If there is
-    // no room remaining in the span, we bail to finish the allocation. The
-    // interpreter will call |refillFreeLists|, setting up a new FreeSpan so
-    // that we can continue allocating in the jit.
+    // Inline FreeSpan::allocate.
+    // There is always exactly one FreeSpan per allocKind per JSCompartment.
+    // If a FreeSpan is replaced, its members are updated in the freeLists table,
+    // which the code below always re-reads.
     loadPtr(AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)), result);
     branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(zone->addressOfFreeListLast(allocKind)), result, fail);
     computeEffectiveAddress(Address(result, thingSize), temp);
     storePtr(temp, AbsoluteAddress(zone->addressOfFreeListFirst(allocKind)));
 }
 
 void
-MacroAssembler::callMallocStub(size_t nbytes, Register result, Label *fail)
+MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObject, Label *fail,
+                           gc::InitialHeap initialHeap)
 {
-    // This register must match the one in JitRuntime::generateMallocStub.
-    const Register regNBytes = CallTempReg0;
-
-    JS_ASSERT(nbytes > 0);
-    JS_ASSERT(nbytes <= INT32_MAX);
-
-    push(regNBytes);
-    move32(Imm32(nbytes), regNBytes);
-    call(GetIonContext()->runtime->jitRuntime()->mallocStub());
-    movePtr(regNBytes, result);
-    pop(regNBytes);
-    branchTest32(Assembler::Zero, result, result, fail);
-}
-
-void
-MacroAssembler::callFreeStub(Register slots)
-{
-    // This register must match the one in JitRuntime::generateFreeStub.
-    const Register regSlots = CallTempReg0;
-
-    push(regSlots);
-    movePtr(slots, regSlots);
-    call(GetIonContext()->runtime->jitRuntime()->freeStub());
-    pop(regSlots);
-}
-
-// Inlined equivalent of gc::AllocateObject, without failure case handling.
-void
-MacroAssembler::allocateObject(Register result, Register slots, gc::AllocKind allocKind,
-                               uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail)
-{
+    gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
     JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
 
-    checkAllocatorState(fail);
-
-    if (shouldNurseryAllocate(allocKind, initialHeap))
-        return nurseryAllocate(result, slots, allocKind, nDynamicSlots, initialHeap, fail);
-
-    if (!nDynamicSlots)
-        return freeSpanAllocate(result, slots, allocKind, fail);
-
-    callMallocStub(nDynamicSlots * sizeof(HeapValue), slots, fail);
-
-    Label failAlloc;
-    Label success;
-
-    push(slots);
-    freeSpanAllocate(result, slots, allocKind, &failAlloc);
-    pop(slots);
-    jump(&success);
-
-    bind(&failAlloc);
-    pop(slots);
-    callFreeStub(slots);
-    jump(fail);
-
-    bind(&success);
-}
-
-void
-MacroAssembler::newGCThing(Register result, Register temp, JSObject *templateObj,
-                            gc::InitialHeap initialHeap, Label *fail)
-{
-    // This method does not initialize the object: if external slots get
-    // allocated into |temp|, there is no easy way for us to ensure the caller
-    // frees them. Instead just assert this case does not happen.
-    JS_ASSERT(!templateObj->numDynamicSlots());
-
-    gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
-    JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
-
-    allocateObject(result, temp, allocKind, templateObj->numDynamicSlots(), initialHeap, fail);
-}
-
-void
-MacroAssembler::createGCObject(Register obj, Register temp, JSObject *templateObj,
-                               gc::InitialHeap initialHeap, Label *fail)
-{
-    uint32_t nDynamicSlots = templateObj->numDynamicSlots();
-    gc::AllocKind allocKind = templateObj->tenuredGetAllocKind();
-    JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
-
-    allocateObject(obj, temp, allocKind, nDynamicSlots, initialHeap, fail);
-    initGCThing(obj, temp, templateObj);
-}
-
-
-// Inlined equivalent of gc::AllocateNonObject, without failure case handling.
-// Non-object allocation does not need to worry about slots, so can take a
-// simpler path.
-void
-MacroAssembler::allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail)
-{
-    checkAllocatorState(fail);
-    freeSpanAllocate(result, temp, allocKind, fail);
+    newGCThing(result, temp, allocKind, fail, initialHeap);
 }
 
 void
 MacroAssembler::newGCString(Register result, Register temp, Label *fail)
 {
-    allocateNonObject(result, temp, js::gc::FINALIZE_STRING, fail);
+    newGCThing(result, temp, js::gc::FINALIZE_STRING, fail);
 }
 
 void
 MacroAssembler::newGCShortString(Register result, Register temp, Label *fail)
 {
-    allocateNonObject(result, temp, js::gc::FINALIZE_SHORT_STRING, fail);
+    newGCThing(result, temp, js::gc::FINALIZE_SHORT_STRING, fail);
 }
 
 void
 MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                               gc::AllocKind allocKind, Label *fail)
 {
     // Similar to ::newGCThing(), except that it allocates from a custom
     // Allocator in the ForkJoinContext*, rather than being hardcoded to the
@@ -894,115 +770,94 @@ MacroAssembler::newGCStringPar(Register 
 void
 MacroAssembler::newGCShortStringPar(Register result, Register cx, Register tempReg1,
                                     Register tempReg2, Label *fail)
 {
     newGCThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_SHORT_STRING, fail);
 }
 
 void
-MacroAssembler::copySlotsFromTemplate(Register obj, const JSObject *templateObj,
+MacroAssembler::copySlotsFromTemplate(Register obj, Register temp, const JSObject *templateObj,
                                       uint32_t start, uint32_t end)
 {
     uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
     for (unsigned i = start; i < nfixed; i++)
         storeValue(templateObj->getFixedSlot(i), Address(obj, JSObject::getFixedSlotOffset(i)));
 }
 
 void
-MacroAssembler::fillSlotsWithUndefined(Address base, Register temp, uint32_t start, uint32_t end)
+MacroAssembler::fillSlotsWithUndefined(Register obj, Register temp, const JSObject *templateObj,
+                                       uint32_t start, uint32_t end)
 {
 #ifdef JS_NUNBOX32
     // We only have a single spare register, so do the initialization as two
     // strided writes of the tag and body.
     jsval_layout jv = JSVAL_TO_IMPL(UndefinedValue());
+    uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
 
-    Address addr = base;
-    move32(Imm32(jv.s.payload.i32), temp);
-    for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
-        store32(temp, ToPayload(addr));
+    mov(ImmWord(jv.s.tag), temp);
+    for (unsigned i = start; i < nfixed; i++)
+        store32(temp, ToType(Address(obj, JSObject::getFixedSlotOffset(i))));
 
-    addr = base;
-    move32(Imm32(jv.s.tag), temp);
-    for (unsigned i = start; i < end; ++i, addr.offset += sizeof(HeapValue))
-        store32(temp, ToType(addr));
+    mov(ImmWord(jv.s.payload.i32), temp);
+    for (unsigned i = start; i < nfixed; i++)
+        store32(temp, ToPayload(Address(obj, JSObject::getFixedSlotOffset(i))));
 #else
     moveValue(UndefinedValue(), temp);
-    for (uint32_t i = start; i < end; ++i, base.offset += sizeof(HeapValue))
-        storePtr(temp, base);
+    uint32_t nfixed = Min(templateObj->numFixedSlots(), end);
+    for (unsigned i = start; i < nfixed; i++)
+        storePtr(temp, Address(obj, JSObject::getFixedSlotOffset(i)));
 #endif
 }
 
 static uint32_t
 FindStartOfUndefinedSlots(JSObject *templateObj, uint32_t nslots)
 {
     JS_ASSERT(nslots == templateObj->lastProperty()->slotSpan(templateObj->getClass()));
     JS_ASSERT(nslots > 0);
     for (uint32_t first = nslots; first != 0; --first) {
         if (templateObj->getSlot(first - 1) != UndefinedValue())
             return first;
     }
     return 0;
 }
 
 void
-MacroAssembler::initGCSlots(Register obj, Register slots, JSObject *templateObj)
+MacroAssembler::initGCSlots(Register obj, Register temp, JSObject *templateObj)
 {
     // Slots of non-array objects are required to be initialized.
     // Use the values currently in the template object.
     uint32_t nslots = templateObj->lastProperty()->slotSpan(templateObj->getClass());
     if (nslots == 0)
         return;
 
-    uint32_t nfixed = templateObj->numFixedSlots();
-    uint32_t ndynamic = templateObj->numDynamicSlots();
-
     // Attempt to group slot writes such that we minimize the amount of
     // duplicated data we need to embed in code and load into registers. In
     // general, most template object slots will be undefined except for any
     // reserved slots. Since reserved slots come first, we split the object
     // logically into independent non-UndefinedValue writes to the head and
     // duplicated writes of UndefinedValue to the tail. For the majority of
     // objects, the "tail" will be the entire slot range.
     uint32_t startOfUndefined = FindStartOfUndefinedSlots(templateObj, nslots);
-    JS_ASSERT(startOfUndefined <= nfixed); // Reserved slots must be fixed.
-
-    // Copy over any preserved reserved slots.
-    copySlotsFromTemplate(obj, templateObj, 0, startOfUndefined);
-
-    // Fill the rest of the fixed slots with undefined.
-    fillSlotsWithUndefined(Address(obj, JSObject::getFixedSlotOffset(startOfUndefined)), slots,
-                           startOfUndefined, nfixed);
-
-    if (ndynamic) {
-        // We are short one register to do this elegantly. Borrow the obj
-        // register briefly for our slots base address.
-        push(obj);
-        loadPtr(Address(obj, JSObject::offsetOfSlots()), obj);
-        fillSlotsWithUndefined(Address(obj, 0), slots, 0, ndynamic);
-        pop(obj);
-    }
+    copySlotsFromTemplate(obj, temp, templateObj, 0, startOfUndefined);
+    fillSlotsWithUndefined(obj, temp, templateObj, startOfUndefined, nslots);
 }
 
 void
-MacroAssembler::initGCThing(Register obj, Register slots, JSObject *templateObj)
+MacroAssembler::initGCThing(Register obj, Register temp, JSObject *templateObj)
 {
-    // Fast initialization of an empty object returned by allocateObject().
+    // Fast initialization of an empty object returned by NewGCThing().
 
     JS_ASSERT(!templateObj->hasDynamicElements());
 
     storePtr(ImmGCPtr(templateObj->lastProperty()), Address(obj, JSObject::offsetOfShape()));
     storePtr(ImmGCPtr(templateObj->type()), Address(obj, JSObject::offsetOfType()));
-    if (templateObj->hasDynamicSlots())
-        storePtr(slots, Address(obj, JSObject::offsetOfSlots()));
-    else
-        storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
+    storePtr(ImmPtr(nullptr), Address(obj, JSObject::offsetOfSlots()));
 
     if (templateObj->is<ArrayObject>()) {
-        Register temp = slots;
         JS_ASSERT(!templateObj->getDenseInitializedLength());
 
         int elementsOffset = JSObject::offsetOfFixedElements();
 
         computeEffectiveAddress(Address(obj, elementsOffset), temp);
         storePtr(temp, Address(obj, JSObject::offsetOfElements()));
 
         // Fill in the elements header.
@@ -1015,17 +870,17 @@ MacroAssembler::initGCThing(Register obj
         store32(Imm32(templateObj->shouldConvertDoubleElements()
                       ? ObjectElements::CONVERT_DOUBLE_ELEMENTS
                       : 0),
                 Address(obj, elementsOffset + ObjectElements::offsetOfFlags()));
         JS_ASSERT(!templateObj->hasPrivate());
     } else {
         storePtr(ImmPtr(emptyObjectElements), Address(obj, JSObject::offsetOfElements()));
 
-        initGCSlots(obj, slots, templateObj);
+        initGCSlots(obj, temp, templateObj);
 
         if (templateObj->hasPrivate()) {
             uint32_t nfixed = templateObj->numFixedSlots();
             storePtr(ImmPtr(templateObj->getPrivate()),
                      Address(obj, JSObject::getPrivateDataOffset(nfixed)));
         }
     }
 }
--- a/js/src/jit/IonMacroAssembler.h
+++ b/js/src/jit/IonMacroAssembler.h
@@ -781,52 +781,38 @@ class MacroAssembler : public MacroAssem
         bind(&done);
     }
 
     // Emit type case branch on tag matching if the type tag in the definition
     // might actually be that type.
     void branchEqualTypeIfNeeded(MIRType type, MDefinition *maybeDef, Register tag, Label *label);
 
     // Inline allocation.
-  private:
-    void checkAllocatorState(Label *fail);
-    bool shouldNurseryAllocate(gc::AllocKind allocKind, gc::InitialHeap initialHeap);
-    void nurseryAllocate(Register result, Register slots, gc::AllocKind allocKind,
-                         size_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
-    void freeSpanAllocate(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
-    void allocateObject(Register result, Register slots, gc::AllocKind allocKind,
-                        uint32_t nDynamicSlots, gc::InitialHeap initialHeap, Label *fail);
-    void allocateNonObject(Register result, Register temp, gc::AllocKind allocKind, Label *fail);
-    void copySlotsFromTemplate(Register obj, const JSObject *templateObj,
-                               uint32_t start, uint32_t end);
-    void fillSlotsWithUndefined(Address addr, Register temp, uint32_t start, uint32_t end);
-    void initGCSlots(Register obj, Register temp, JSObject *templateObj);
-
-  public:
-    void callMallocStub(size_t nbytes, Register result, Label *fail);
-    void callFreeStub(Register slots);
-    void createGCObject(Register result, Register temp, JSObject *templateObj,
-                        gc::InitialHeap initialHeap, Label *fail);
-
-    void newGCThing(Register result, Register temp, JSObject *templateObj,
-                     gc::InitialHeap initialHeap, Label *fail);
-    void initGCThing(Register obj, Register temp, JSObject *templateObj);
-
+    void newGCThing(Register result, Register temp, gc::AllocKind allocKind, Label *fail,
+                    gc::InitialHeap initialHeap = gc::DefaultHeap);
+    void newGCThing(Register result, Register temp, JSObject *templateObject, Label *fail,
+                    gc::InitialHeap initialHeap);
     void newGCString(Register result, Register temp, Label *fail);
     void newGCShortString(Register result, Register temp, Label *fail);
 
     void newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                        gc::AllocKind allocKind, Label *fail);
     void newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                        JSObject *templateObject, Label *fail);
     void newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                         Label *fail);
     void newGCShortStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                              Label *fail);
 
+    void copySlotsFromTemplate(Register obj, Register temp, const JSObject *templateObj,
+                               uint32_t start, uint32_t end);
+    void fillSlotsWithUndefined(Register obj, Register temp, const JSObject *templateObj,
+                                uint32_t start, uint32_t end);
+    void initGCSlots(Register obj, Register temp, JSObject *templateObj);
+    void initGCThing(Register obj, Register temp, JSObject *templateObj);
 
     // Compares two strings for equality based on the JSOP.
     // This checks for identical pointers, atoms and length and fails for everything else.
     void compareStrings(JSOp op, Register left, Register right, Register result,
                         Register temp, Label *fail);
 
     // Checks the flags that signal that parallel code may need to interrupt or
     // abort.  Branches to fail in that case.
--- a/js/src/jit/JitCompartment.h
+++ b/js/src/jit/JitCompartment.h
@@ -181,20 +181,16 @@ class JitRuntime
 
     // Thunk that invalides an (Ion compiled) caller on the Ion stack.
     JitCode *invalidator_;
 
     // Thunk that calls the GC pre barrier.
     JitCode *valuePreBarrier_;
     JitCode *shapePreBarrier_;
 
-    // Thunk to call malloc/free.
-    JitCode *mallocStub_;
-    JitCode *freeStub_;
-
     // Thunk used by the debugger for breakpoint and step mode.
     JitCode *debugTrapHandler_;
 
     // Stub used to inline the ForkJoinGetSlice intrinsic.
     JitCode *forkJoinGetSliceStub_;
 
     // Map VMFunction addresses to the JitCode of the wrapper.
     typedef WeakCache<const VMFunction *, JitCode *> VMWrapperMap;
@@ -220,18 +216,16 @@ class JitRuntime
     JitCode *generateExceptionTailStub(JSContext *cx);
     JitCode *generateBailoutTailStub(JSContext *cx);
     JitCode *generateEnterJIT(JSContext *cx, EnterJitType type);
     JitCode *generateArgumentsRectifier(JSContext *cx, ExecutionMode mode, void **returnAddrOut);
     JitCode *generateBailoutTable(JSContext *cx, uint32_t frameClass);
     JitCode *generateBailoutHandler(JSContext *cx);
     JitCode *generateInvalidator(JSContext *cx);
     JitCode *generatePreBarrier(JSContext *cx, MIRType type);
-    JitCode *generateMallocStub(JSContext *cx);
-    JitCode *generateFreeStub(JSContext *cx);
     JitCode *generateDebugTrapHandler(JSContext *cx);
     JitCode *generateForkJoinGetSliceStub(JSContext *cx);
     JitCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
     JSC::ExecutableAllocator *createIonAlloc(JSContext *cx);
 
   public:
     JitRuntime();
@@ -327,24 +321,16 @@ class JitRuntime
     JitCode *valuePreBarrier() const {
         return valuePreBarrier_;
     }
 
     JitCode *shapePreBarrier() const {
         return shapePreBarrier_;
     }
 
-    JitCode *mallocStub() const {
-        return mallocStub_;
-    }
-
-    JitCode *freeStub() const {
-        return freeStub_;
-    }
-
     bool ensureForkJoinGetSliceStubExists(JSContext *cx);
     JitCode *forkJoinGetSliceStub() const {
         return forkJoinGetSliceStub_;
     }
 };
 
 class JitCompartment
 {
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -297,16 +297,42 @@ class LGoto : public LControlInstruction
          setSuccessor(0, block);
     }
 
     MBasicBlock *target() const {
         return getSuccessor(0);
     }
 };
 
+class LNewSlots : public LCallInstructionHelper<1, 0, 3>
+{
+  public:
+    LIR_HEADER(NewSlots)
+
+    LNewSlots(const LDefinition &temp1, const LDefinition &temp2, const LDefinition &temp3) {
+        setTemp(0, temp1);
+        setTemp(1, temp2);
+        setTemp(2, temp3);
+    }
+
+    const LDefinition *temp1() {
+        return getTemp(0);
+    }
+    const LDefinition *temp2() {
+        return getTemp(1);
+    }
+    const LDefinition *temp3() {
+        return getTemp(2);
+    }
+
+    MNewSlots *mir() const {
+        return mir_->toNewSlots();
+    }
+};
+
 class LNewArray : public LInstructionHelper<1, 0, 1>
 {
   public:
     LIR_HEADER(NewArray)
 
     LNewArray(const LDefinition &temp) {
         setTemp(0, temp);
     }
@@ -433,62 +459,92 @@ class LNewDeclEnvObject : public LInstru
         return getTemp(0);
     }
 
     MNewDeclEnvObject *mir() const {
         return mir_->toNewDeclEnvObject();
     }
 };
 
-// Allocates a new CallObject.
+// Allocates a new CallObject. The inputs are:
+//      slots: either a reg representing a HeapSlot *, or a placeholder
+//             meaning that no slots pointer is needed.
 //
 // This instruction generates two possible instruction sets:
 //   (1) If the call object is extensible, this is a callVM to create the
 //       call object.
 //   (2) Otherwise, an inline allocation of the call object is attempted.
 //
-class LNewCallObject : public LInstructionHelper<1, 0, 1>
+class LNewCallObject : public LInstructionHelper<1, 1, 1>
 {
   public:
     LIR_HEADER(NewCallObject)
 
-    LNewCallObject(const LDefinition &temp) {
+    LNewCallObject(const LAllocation &slots, const LDefinition &temp) {
+        setOperand(0, slots);
         setTemp(0, temp);
     }
 
     const LDefinition *temp() {
         return getTemp(0);
     }
 
+    const LAllocation *slots() {
+        return getOperand(0);
+    }
     MNewCallObject *mir() const {
         return mir_->toNewCallObject();
     }
 };
 
-class LNewCallObjectPar : public LInstructionHelper<1, 1, 2>
-{
-    LNewCallObjectPar(const LAllocation &cx, const LDefinition &temp1, const LDefinition &temp2) {
+class LNewCallObjectPar : public LInstructionHelper<1, 2, 2>
+{
+    LNewCallObjectPar(const LAllocation &cx, const LAllocation &slots,
+                      const LDefinition &temp1, const LDefinition &temp2)
+    {
         setOperand(0, cx);
+        setOperand(1, slots);
         setTemp(0, temp1);
         setTemp(1, temp2);
     }
 
 public:
     LIR_HEADER(NewCallObjectPar);
 
-    static LNewCallObjectPar *New(TempAllocator &alloc, const LAllocation &cx,
-                                  const LDefinition &temp1, const LDefinition &temp2)
+    static LNewCallObjectPar *NewWithSlots(TempAllocator &alloc,
+                                           const LAllocation &cx, const LAllocation &slots,
+                                           const LDefinition &temp1, const LDefinition &temp2)
     {
-        return new(alloc) LNewCallObjectPar(cx, temp1, temp2);
+        return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2);
+    }
+
+    static LNewCallObjectPar *NewSansSlots(TempAllocator &alloc,
+                                           const LAllocation &cx,
+                                           const LDefinition &temp1, const LDefinition &temp2)
+    {
+        LAllocation slots = LConstantIndex::Bogus();
+        return new(alloc) LNewCallObjectPar(cx, slots, temp1, temp2);
     }
 
     const LAllocation *forkJoinContext() {
         return getOperand(0);
     }
 
+    const LAllocation *slots() {
+        return getOperand(1);
+    }
+
+    const bool hasDynamicSlots() {
+        // TO INVESTIGATE: Felix tried using isRegister() method here,
+        // but for useFixed(_, CallTempN), isRegister() is false (and
+        // isUse() is true).  So for now ignore that and try to match
+        // the LConstantIndex::Bogus() generated above instead.
+        return slots() && ! slots()->isConstant();
+    }
+
     const MNewCallObjectPar *mir() const {
         return mir_->toNewCallObjectPar();
     }
 
     const LDefinition *getTemp0() {
         return getTemp(0);
     }
 
--- a/js/src/jit/LOpcodes.h
+++ b/js/src/jit/LOpcodes.h
@@ -20,16 +20,17 @@
     _(CloneLiteral)                 \
     _(Parameter)                    \
     _(Callee)                       \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(NewObject)                    \
+    _(NewSlots)                     \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewStringObject)              \
     _(NewPar)                       \
     _(NewDenseArrayPar)             \
     _(NewCallObjectPar)             \
     _(NewDerivedTypedObject)        \
     _(AbortPar)                     \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -156,16 +156,27 @@ LIRGenerator::visitDefVar(MDefVar *ins)
 bool
 LIRGenerator::visitDefFun(MDefFun *ins)
 {
     LDefFun *lir = new(alloc()) LDefFun(useRegisterAtStart(ins->scopeChain()));
     return add(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
+LIRGenerator::visitNewSlots(MNewSlots *ins)
+{
+    // No safepoint needed, since we don't pass a cx.
+    LNewSlots *lir = new(alloc()) LNewSlots(tempFixed(CallTempReg0), tempFixed(CallTempReg1),
+                                            tempFixed(CallTempReg2));
+    if (!assignSnapshot(lir))
+        return false;
+    return defineReturn(lir, ins);
+}
+
+bool
 LIRGenerator::visitNewArray(MNewArray *ins)
 {
     LNewArray *lir = new(alloc()) LNewArray(temp());
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitNewObject(MNewObject *ins)
@@ -179,17 +190,23 @@ LIRGenerator::visitNewDeclEnvObject(MNew
 {
     LNewDeclEnvObject *lir = new(alloc()) LNewDeclEnvObject(temp());
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitNewCallObject(MNewCallObject *ins)
 {
-    LNewCallObject *lir = new(alloc()) LNewCallObject(temp());
+    LAllocation slots;
+    if (ins->slots()->type() == MIRType_Slots)
+        slots = useRegister(ins->slots());
+    else
+        slots = LConstantIndex::Bogus();
+
+    LNewCallObject *lir = new(alloc()) LNewCallObject(slots, temp());
     if (!define(lir, ins))
         return false;
 
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
@@ -203,17 +220,27 @@ LIRGenerator::visitNewDerivedTypedObject
                                             useRegisterAtStart(ins->offset()));
     return defineReturn(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitNewCallObjectPar(MNewCallObjectPar *ins)
 {
     const LAllocation &parThreadContext = useRegister(ins->forkJoinContext());
-    LNewCallObjectPar *lir = LNewCallObjectPar::New(alloc(), parThreadContext, temp(), temp());
+    const LDefinition &temp1 = temp();
+    const LDefinition &temp2 = temp();
+
+    LNewCallObjectPar *lir;
+    if (ins->slots()->type() == MIRType_Slots) {
+        const LAllocation &slots = useRegister(ins->slots());
+        lir = LNewCallObjectPar::NewWithSlots(alloc(), parThreadContext, slots, temp1, temp2);
+    } else {
+        lir = LNewCallObjectPar::NewSansSlots(alloc(), parThreadContext, temp1, temp2);
+    }
+
     return define(lir, ins);
 }
 
 bool
 LIRGenerator::visitNewStringObject(MNewStringObject *ins)
 {
     JS_ASSERT(ins->input()->type() == MIRType_String);
 
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -61,16 +61,17 @@ class LIRGenerator : public LIRGenerator
 
     // Visitor hooks are explicit, to give CPU-specific versions a chance to
     // intercept without a bunch of explicit gunk in the .cpp.
     bool visitCloneLiteral(MCloneLiteral *ins);
     bool visitParameter(MParameter *param);
     bool visitCallee(MCallee *callee);
     bool visitGoto(MGoto *ins);
     bool visitTableSwitch(MTableSwitch *tableswitch);
+    bool visitNewSlots(MNewSlots *ins);
     bool visitNewArray(MNewArray *ins);
     bool visitNewObject(MNewObject *ins);
     bool visitNewDeclEnvObject(MNewDeclEnvObject *ins);
     bool visitNewCallObject(MNewCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
     bool visitNewPar(MNewPar *ins);
     bool visitNewCallObjectPar(MNewCallObjectPar *ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -8927,16 +8927,43 @@ class MPostWriteBarrier : public MBinary
     bool isConsistentFloat32Use(MUse *use) const {
         // During lowering, values that neither have object nor value MIR type
         // are ignored, thus Float32 can show up at this point without any issue.
         return use->index() == 1;
     }
 #endif
 };
 
+class MNewSlots : public MNullaryInstruction
+{
+    unsigned nslots_;
+
+    MNewSlots(unsigned nslots)
+      : nslots_(nslots)
+    {
+        setResultType(MIRType_Slots);
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewSlots)
+
+    static MNewSlots *New(TempAllocator &alloc, unsigned nslots) {
+        return new(alloc) MNewSlots(nslots);
+    }
+    unsigned nslots() const {
+        return nslots_;
+    }
+    AliasSet getAliasSet() const {
+        return AliasSet::None();
+    }
+    bool possiblyCalls() const {
+        return true;
+    }
+};
+
 class MNewDeclEnvObject : public MNullaryInstruction
 {
     CompilerRootObject templateObj_;
 
     MNewDeclEnvObject(JSObject *templateObj)
       : MNullaryInstruction(),
         templateObj_(templateObj)
     {
@@ -8953,70 +8980,78 @@ class MNewDeclEnvObject : public MNullar
     JSObject *templateObj() {
         return templateObj_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MNewCallObject : public MNullaryInstruction
+class MNewCallObject : public MUnaryInstruction
 {
     CompilerRootObject templateObj_;
     bool needsSingletonType_;
 
-    MNewCallObject(JSObject *templateObj, bool needsSingletonType)
-      : MNullaryInstruction(),
+    MNewCallObject(JSObject *templateObj, bool needsSingletonType, MDefinition *slots)
+      : MUnaryInstruction(slots),
         templateObj_(templateObj),
         needsSingletonType_(needsSingletonType)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(NewCallObject)
 
-    static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType)
-    {
-        return new(alloc) MNewCallObject(templateObj, needsSingletonType);
-    }
-
+    static MNewCallObject *New(TempAllocator &alloc, JSObject *templateObj, bool needsSingletonType,
+                               MDefinition *slots)
+    {
+        return new(alloc) MNewCallObject(templateObj, needsSingletonType, slots);
+    }
+
+    MDefinition *slots() {
+        return getOperand(0);
+    }
     JSObject *templateObject() {
         return templateObj_;
     }
     bool needsSingletonType() const {
         return needsSingletonType_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MNewCallObjectPar : public MUnaryInstruction
+class MNewCallObjectPar : public MBinaryInstruction
 {
     CompilerRootObject templateObj_;
 
-    MNewCallObjectPar(MDefinition *cx, JSObject *templateObj)
-        : MUnaryInstruction(cx),
+    MNewCallObjectPar(MDefinition *cx, JSObject *templateObj, MDefinition *slots)
+        : MBinaryInstruction(cx, slots),
           templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
     }
 
   public:
     INSTRUCTION_HEADER(NewCallObjectPar);
 
     static MNewCallObjectPar *New(TempAllocator &alloc, MDefinition *cx, MNewCallObject *callObj) {
-        return new(alloc) MNewCallObjectPar(cx, callObj->templateObject());
+        return new(alloc) MNewCallObjectPar(cx, callObj->templateObject(), callObj->slots());
     }
 
     MDefinition *forkJoinContext() const {
         return getOperand(0);
     }
 
+    MDefinition *slots() const {
+        return getOperand(1);
+    }
+
     JSObject *templateObj() const {
         return templateObj_;
     }
 
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -80,16 +80,17 @@ namespace jit {
     _(GuardObject)                                                          \
     _(GuardString)                                                          \
     _(AssertRange)                                                          \
     _(ToDouble)                                                             \
     _(ToFloat32)                                                            \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
     _(ToString)                                                             \
+    _(NewSlots)                                                             \
     _(NewArray)                                                             \
     _(NewObject)                                                            \
     _(NewDeclEnvObject)                                                     \
     _(NewCallObject)                                                        \
     _(NewStringObject)                                                      \
     _(InitElem)                                                             \
     _(InitElemGetterSetter)                                                 \
     _(MutateProto)                                                          \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -174,16 +174,17 @@ class ParallelSafetyVisitor : public MIn
     SAFE_OP(Unbox)
     SAFE_OP(GuardObject)
     SAFE_OP(ToDouble)
     SAFE_OP(ToFloat32)
     SAFE_OP(ToInt32)
     SAFE_OP(TruncateToInt32)
     SAFE_OP(MaybeToDoubleElement)
     CUSTOM_OP(ToString)
+    SAFE_OP(NewSlots)
     CUSTOM_OP(NewArray)
     CUSTOM_OP(NewObject)
     CUSTOM_OP(NewCallObject)
     UNSAFE_OP(NewDerivedTypedObject)
     UNSAFE_OP(InitElem)
     UNSAFE_OP(InitElemGetterSetter)
     UNSAFE_OP(MutateProto)
     UNSAFE_OP(InitProp)
@@ -520,20 +521,16 @@ bool
 ParallelSafetyVisitor::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
 {
     return replaceWithNewPar(ins, ins->templateObject());
 }
 
 bool
 ParallelSafetyVisitor::visitNewCallObject(MNewCallObject *ins)
 {
-    if (ins->templateObject()->hasDynamicSlots()) {
-        SpewMIR(ins, "call with dynamic slots");
-        return markUnsafe();
-    }
     replace(ins, MNewCallObjectPar::New(alloc(), ForkJoinContext(), ins));
     return true;
 }
 
 bool
 ParallelSafetyVisitor::visitLambda(MLambda *ins)
 {
     if (ins->info().singletonType || ins->info().useNewTypeForClone) {
@@ -638,16 +635,21 @@ ParallelSafetyVisitor::insertWriteGuard(
         break;
 
       case MIRType_Slots:
         switch (valueBeingWritten->op()) {
           case MDefinition::Op_Slots:
             object = valueBeingWritten->toSlots()->object();
             break;
 
+          case MDefinition::Op_NewSlots:
+            // Values produced by new slots will ALWAYS be
+            // thread-local.
+            return true;
+
           default:
             SpewMIR(writeInstruction, "cannot insert write guard for %s",
                     valueBeingWritten->opName());
             return markUnsafe();
         }
         break;
 
       case MIRType_Elements:
--- a/js/src/jit/VMFunctions.cpp
+++ b/js/src/jit/VMFunctions.cpp
@@ -504,26 +504,36 @@ InterruptCheck(JSContext *cx)
     // afterwards which point to the interrupt handler, the next time they are
     // taken the backedges will just be reset again.
     cx->runtime()->jitRuntime()->patchIonBackedges(cx->runtime(),
                                                    JitRuntime::BackedgeLoopHeader);
 
     return CheckForInterrupt(cx);
 }
 
-void *
-MallocWrapper(JSRuntime *rt, size_t nbytes)
+HeapSlot *
+NewSlots(JSRuntime *rt, unsigned nslots)
 {
-    return rt->pod_malloc<uint8_t>(nbytes);
+    JS_STATIC_ASSERT(sizeof(Value) == sizeof(HeapSlot));
+
+    Value *slots = reinterpret_cast<Value *>(rt->malloc_(nslots * sizeof(Value)));
+    if (!slots)
+        return nullptr;
+
+    for (unsigned i = 0; i < nslots; i++)
+        slots[i] = UndefinedValue();
+
+    return reinterpret_cast<HeapSlot *>(slots);
 }
 
 JSObject *
-NewCallObject(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
+NewCallObject(JSContext *cx, HandleScript script,
+              HandleShape shape, HandleTypeObject type, HeapSlot *slots)
 {
-    JSObject *obj = CallObject::create(cx, script, shape, type);
+    JSObject *obj = CallObject::create(cx, script, shape, type, slots);
     if (!obj)
         return nullptr;
 
 #ifdef JSGC_GENERATIONAL
     // The JIT creates call objects in the nursery, so elides barriers for
     // the initializing writes. The interpreter, however, may have allocated
     // the call object tenured, so barrier as needed before re-entering.
     if (!IsInsideNursery(cx->runtime(), obj))
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -612,19 +612,19 @@ JSObject *ArrayConcatDense(JSContext *cx
 bool CharCodeAt(JSContext *cx, HandleString str, int32_t index, uint32_t *code);
 JSFlatString *StringFromCharCode(JSContext *cx, int32_t code);
 
 bool SetProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
                  bool strict, jsbytecode *pc);
 
 bool InterruptCheck(JSContext *cx);
 
-void *MallocWrapper(JSRuntime *rt, size_t nbytes);
+HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
 JSObject *NewCallObject(JSContext *cx, HandleScript script,
-                        HandleShape shape, HandleTypeObject type);
+                        HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 JSObject *NewStringObject(JSContext *cx, HandleString str);
 
 bool SPSEnter(JSContext *cx, HandleScript script);
 bool SPSExit(JSContext *cx, HandleScript script);
 
 bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, bool *out);
 bool OperatorInI(JSContext *cx, uint32_t index, HandleObject obj, bool *out);
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -247,17 +247,18 @@ class JSObject : public js::ObjectImpl
     /*
      * Make a non-array object with the specified initial state. This method
      * takes ownership of any extantSlots it is passed.
      */
     static inline JSObject *create(js::ExclusiveContext *cx,
                                    js::gc::AllocKind kind,
                                    js::gc::InitialHeap heap,
                                    js::HandleShape shape,
-                                   js::HandleTypeObject type);
+                                   js::HandleTypeObject type,
+                                   js::HeapSlot *extantSlots = nullptr);
 
     /* Make an array object with the specified initial state. */
     static inline js::ArrayObject *createArray(js::ExclusiveContext *cx,
                                                js::gc::AllocKind kind,
                                                js::gc::InitialHeap heap,
                                                js::HandleShape shape,
                                                js::HandleTypeObject type,
                                                uint32_t length);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -492,40 +492,51 @@ inline bool JSObject::isVarObj()
 {
     if (is<js::DebugScopeObject>())
         return as<js::DebugScopeObject>().scope().isVarObj();
     return lastProperty()->hasObjectFlag(js::BaseShape::VAROBJ);
 }
 
 /* static */ inline JSObject *
 JSObject::create(js::ExclusiveContext *cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
-                 js::HandleShape shape, js::HandleTypeObject type)
+                 js::HandleShape shape, js::HandleTypeObject type,
+                 js::HeapSlot *extantSlots /* = nullptr */)
 {
     /*
      * Callers must use dynamicSlotsCount to size the initial slot array of the
      * object. We can't check the allocated capacity of the dynamic slots, but
      * make sure their presence is consistent with the shape.
      */
     JS_ASSERT(shape && type);
     JS_ASSERT(type->clasp() == shape->getObjectClass());
     JS_ASSERT(type->clasp() != &js::ArrayObject::class_);
     JS_ASSERT(js::gc::GetGCKindSlots(kind, type->clasp()) == shape->numFixedSlots());
     JS_ASSERT_IF(type->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind));
     JS_ASSERT_IF(type->clasp()->finalize, heap == js::gc::TenuredHeap);
+    JS_ASSERT_IF(extantSlots, dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(),
+                                                type->clasp()));
 
     const js::Class *clasp = type->clasp();
-    size_t nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
+    size_t nDynamicSlots = 0;
+    if (!extantSlots)
+        nDynamicSlots = dynamicSlotsCount(shape->numFixedSlots(), shape->slotSpan(), clasp);
 
     JSObject *obj = js::NewGCObject<js::CanGC>(cx, kind, nDynamicSlots, heap);
     if (!obj)
         return nullptr;
 
     obj->shape_.init(shape);
     obj->type_.init(type);
-    // Note: slots are created and assigned internally by NewGCObject.
+    if (extantSlots) {
+#ifdef JSGC_GENERATIONAL
+        if (cx->isJSContext())
+            cx->asJSContext()->runtime()->gcNursery.notifyInitialSlots(obj, extantSlots);
+#endif
+        obj->slots = extantSlots;
+    }
     obj->elements = js::emptyObjectElements;
 
     if (clasp->hasPrivate())
         obj->privateRef(shape->numFixedSlots()) = nullptr;
 
     size_t span = shape->slotSpan();
     if (span && clasp != &js::ArrayBufferObject::class_)
         obj->initializeSlotRange(0, span);
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -136,24 +136,24 @@ ScopeObject::setEnclosingScope(HandleObj
     setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
 }
 
 /*
  * Construct a bare-bones call object given a shape, type, and slots pointer.
  * The call object must be further initialized to be usable.
  */
 CallObject *
-CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type)
+CallObject::create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     JS_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     gc::InitialHeap heap = script->treatAsRunOnce() ? gc::TenuredHeap : gc::DefaultHeap;
-    JSObject *obj = JSObject::create(cx, kind, heap, shape, type);
+    JSObject *obj = JSObject::create(cx, kind, heap, shape, type, slots);
     if (!obj)
         return nullptr;
 
     if (script->treatAsRunOnce()) {
         RootedObject nobj(cx, obj);
         if (!JSObject::setSingletonType(cx, nobj))
             return nullptr;
         return &nobj->as<CallObject>();
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -232,17 +232,17 @@ class CallObject : public ScopeObject
     static CallObject *
     create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
 
   public:
     static const Class class_;
 
     /* These functions are internal and are exposed only for JITs. */
     static CallObject *
-    create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type);
+    create(JSContext *cx, HandleScript script, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 
     static CallObject *
     createTemplateObject(JSContext *cx, HandleScript script, gc::InitialHeap heap);
 
     static const uint32_t RESERVED_SLOTS = 2;
 
     static CallObject *createForFunction(JSContext *cx, HandleObject enclosing, HandleFunction callee);