Backed out 2 changesets (bug 969012) for gc bustage
authorWes Kocher <wkocher@mozilla.com>
Thu, 08 May 2014 16:30:52 -0700
changeset 182277 4e33e9729ab697044b31283bbb2d7455de3c1eca
parent 182276 f5421fcfb39c75d22d17b92a3b4b4e662ae3c562
child 182278 21332f87ca195f11c024b003f6b049d46289b957
push id26755
push usercbook@mozilla.com
push dateFri, 09 May 2014 11:54:47 +0000
treeherdermozilla-central@5700a88f895f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs969012
milestone32.0a1
backs out01f27ad85b1bae4b6b8f8b4acebd8623684d2cc1
f844291b895bd36b104f6d00e8e16af4ec4722b7
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
Backed out 2 changesets (bug 969012) for gc bustage Backed out changeset 01f27ad85b1b (bug 969012) Backed out changeset f844291b895b (bug 969012)
js/src/jit-test/tests/gc/bug-969012.js
js/src/jit-test/tests/gc/bug-985732.js
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/jit/shared/IonAssemblerBuffer.h
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/vm/ScopeObject.cpp
js/src/vm/ScopeObject.h
deleted file mode 100644
--- a/js/src/jit-test/tests/gc/bug-969012.js
+++ /dev/null
@@ -1,60 +0,0 @@
-function testClosureCreationAndInvocation() {
-    var a = 'foobar';
-    function makeaddv(vvvv) {
-        var z = -4 * vvvv;
-        var y = -3 * vvvv;
-        var x = -2 * vvvv;
-        var w = -1 * vvvv;
-        var v = 0 * vvvv;
-        var u = 1 * vvvv;
-        var t = 2 * vvvv;
-        var s = 3 * vvvv;
-        var r = 4 * vvvv;
-        var q = 5 * vvvv;
-        var p = 6 * vvvv;
-        var o = 7 * vvvv;
-        var n = 8 * vvvv;
-        var m = 9 * vvvv;
-        var l = 10 * vvvv;
-        var k = 11 * vvvv;
-        var j = 12 * vvvv;
-        var i = 13 * vvvv;
-        var h = 14 * vvvv;
-        var g = 15 * vvvv;
-        var f = 16 * vvvv;
-        var e = 17 * vvvv;
-        var d = 18 * vvvv;
-        var c = 19 * vvvv;
-        var b = 20 * vvvv;
-        var a = 21 * vvvv;
-        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; case 21: return v;
-                  case 22: return w; case 23: return x;
-                  case 24: return y; case 25: return z;
-                  }
-                };
-    }
-    var a = Array();
-    for (var i = 0; i < 26; ++i) {
-        a.push(makeaddv(Math.random()));
-    }
-    return a;
-}
-
-var a = testClosureCreationAndInvocation();
-for (var i = 0; i < 26; ++i) {
-    print(a[i](i));
-}
-
-
deleted file mode 100644
--- a/js/src/jit-test/tests/gc/bug-985732.js
+++ /dev/null
@@ -1,83 +0,0 @@
-function testx() {
-function compareArray(aExpected, aActual) {}
-    for (var i = 0; i < expected.length; i++) {}
-var supportsArrayIndexGettersOnArrays = undefined;
-function fnSupportsArrayIndexGettersOnArrays() {}
-var supportsArrayIndexGettersOnObjects = undefined;
-function fnSupportsArrayIndexGettersOnObjects() {}
-function ConvertToFileUrl(pathStr) {
-}
-function fnExists() {}
-var __globalObject = Function("return this;")();
-function fnGlobalObject() {}
-function fnSupportsStrict() {
-        eval('with ({}) {}');
-}
-function dataPropertyAttributesAreCorrect(obj, configurable) {}
-function accessorPropertyAttributesAreCorrect(obj, configurable) {}
-var NotEarlyErrorString = "NotEarlyError";
-var EarlyErrorRePat = "^((?!" + NotEarlyErrorString + ").)*$";
-var NotEarlyError = new Error(NotEarlyErrorString);
-function Test262Error(message) {};
-function testFailed(message) {}
-function testPrint(message) {}
-function $PRINT(message) {}
-function $INCLUDE(message) { }
-function $ERROR(message) {}
-function $FAIL(message) {}
-function getPrecision(num) {}
-var prec;
-function isEqual(num1, num2) {}
-function ToInteger(p) {}
-var HoursPerDay = 24;
-var MinutesPerHour = 60;
-var SecondsPerMinute = 60;
-var msPerDay = 86400000;
-var msPerSecond = 1000;
-var msPerMinute = 60000;
-var msPerHour = 3600000;
-var date_1899_end = -2208988800001;
-var date_1900_start = -2208988800000;
-var date_1969_end = -1;
-var date_1970_start = 0;
-var date_1999_end = 946684799999;
-var date_2000_start = 946684800000;
-var date_2099_end = 4102444799999;
-var date_2100_start = 4102444800000;
-var $LocalTZ,
-    $DST_start_month,
-    $DST_start_sunday,
-    $DST_start_hour,
-    $DST_start_minutes,
-    $DST_end_month,
-    $DST_end_sunday,
-    $DST_end_hour,
-    $DST_end_minutes;
-function Day(t) {}
-function TimeWithinDay(t) {}
-function DaysInYear(y){}
-function DayFromYear(y) {}
-function TimeFromYear(y){}
-function YearFromTime(t) {}
-function InLeapYear(t){}
-function DayWithinYear(t) {}
-function MonthFromTime(t){}
-function DateFromTime(t) {}
-function WeekDay(t) {}
-var LocalTZA = $LocalTZ*msPerHour;
-function DaysInMonth(m, leap) {}
-function GetSundayInMonth(t, m, count){}
-function DaylightSavingTA(t) {}
-function LocalTime(t){}
-function UTC(t) {}
-function HourFromTime(t){}
-function MinFromTime(t){}
-function SecFromTime(t){}
-function msFromTime(t){}
-function MakeTime(hour, min, sec, ms){}
-function MakeDay(year, month, date) {}
-function MakeDate( day, time ) {}
-function TimeClip(time) {}
-function ConstructDate(year, month, date, hours, minutes, seconds, ms){}
-function runTestCase(testcase) {}
-} testx();
--- 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
@@ -1039,17 +1039,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;
 }
 
 typedef JSObject *(*LambdaArrowFn)(JSContext *, HandleFunction, HandleObject, HandleValue);
@@ -1075,17 +1076,18 @@ CodeGenerator::visitLambdaArrow(LLambdaA
     if (info.singletonType) {
         // If the function has a singleton type, this instruction will only be
         // executed once so we don't bother inlining it.
         masm.jump(ool->entry());
         masm.bind(ool->rejoin());
         return true;
     }
 
-    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);
 
     // Initialize extended slots. Lexical |this| is stored in the first one.
     MOZ_ASSERT(info.flags & JSFunction::EXTENDED);
     static_assert(FunctionExtended::NUM_EXTENDED_SLOTS == 2, "All slots must be initialized");
     static_assert(FunctionExtended::ARROW_THIS_SLOT == 0, "|this| must be stored in first slot");
     masm.storeValue(thisv, Address(output, FunctionExtended::offsetOfExtendedSlot(0)));
@@ -3499,16 +3501,38 @@ 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));
+
+    if (!bailoutTestPtr(Assembler::Zero, output, output, 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);
@@ -3547,17 +3571,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)
 {
@@ -3633,17 +3658,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)
 {
@@ -3668,63 +3694,94 @@ 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 *, HandleShape, HandleTypeObject);
+typedef JSObject *(*NewCallObjectFn)(JSContext *, 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();
 
-    OutOfLineCode *ool = oolCallVM(NewCallObjectInfo, lir,
-                                   (ArgList(), ImmGCPtr(templateObj->lastProperty()),
-                                               ImmGCPtr(templateObj->type())),
-                                   StoreRegisterTo(objReg));
+    OutOfLineCode *ool;
+    if (lir->slots()->isRegister()) {
+        ool = oolCallVM(NewCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(templateObj->lastProperty()),
+                                    ImmGCPtr(templateObj->type()),
+                                    ToRegister(lir->slots())),
+                        StoreRegisterTo(objReg));
+    } else {
+        ool = oolCallVM(NewCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(templateObj->lastProperty()),
+                                    ImmGCPtr(templateObj->type()),
+                                    ImmPtr(nullptr)),
+                        StoreRegisterTo(objReg));
+    }
     if (!ool)
         return false;
 
-    // Inline call object creation, using the OOL path only for tricky cases.
-    masm.createGCObject(objReg, tempReg, templateObj, gc::DefaultHeap, ool->entry());
+#ifdef JSGC_GENERATIONAL
+    if (templateObj->hasDynamicSlots()) {
+        // Slot initialization is unbarriered in this case, so we must either
+        // allocate in the nursery or bail if that is not possible.
+        masm.jump(ool->entry());
+    } else
+#endif
+    {
+        // Inline call object creation, using the OOL path only for tricky cases.
+        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;
 }
 
-typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape);
+typedef JSObject *(*NewSingletonCallObjectFn)(JSContext *, HandleShape, HeapSlot *);
 static const VMFunction NewSingletonCallObjectInfo =
     FunctionInfo<NewSingletonCallObjectFn>(NewSingletonCallObject);
 
 bool
 CodeGenerator::visitNewSingletonCallObject(LNewSingletonCallObject *lir)
 {
     Register objReg = ToRegister(lir->output());
 
     JSObject *templateObj = lir->mir()->templateObject();
 
     OutOfLineCode *ool;
-    ool = oolCallVM(NewSingletonCallObjectInfo, lir,
-                    (ArgList(), ImmGCPtr(templateObj->lastProperty())),
-                    StoreRegisterTo(objReg));
+    if (lir->slots()->isRegister()) {
+        ool = oolCallVM(NewSingletonCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(templateObj->lastProperty()),
+                                    ToRegister(lir->slots())),
+                        StoreRegisterTo(objReg));
+    } else {
+        ool = oolCallVM(NewSingletonCallObjectInfo, lir,
+                        (ArgList(), ImmGCPtr(templateObj->lastProperty()),
+                                    ImmPtr(nullptr)),
+                        StoreRegisterTo(objReg));
+    }
     if (!ool)
         return false;
 
     // Objects can only be given singleton types in VM calls.  We make the call
     // out of line to not bloat inline code, even if (naively) this seems like
     // extra work.
     masm.jump(ool->entry());
     masm.bind(ool->rejoin());
@@ -3737,16 +3794,27 @@ CodeGenerator::visitNewCallObjectPar(LNe
 {
     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());
@@ -3795,17 +3863,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;
@@ -4040,17 +4109,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;
 }
 
@@ -5169,80 +5238,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());
@@ -5904,17 +5909,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);
@@ -6275,17 +6282,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
@@ -130,16 +130,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
@@ -265,26 +265,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
@@ -4733,45 +4733,53 @@ 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.
-    MNullaryInstruction *callObj;
+    // 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.
+    MUnaryInstruction *callObj;
     if (script()->treatAsRunOnce())
-        callObj = MNewRunOnceCallObject::New(alloc(), templateObj);
+        callObj = MNewRunOnceCallObject::New(alloc(), templateObj, slots);
     else
-        callObj = MNewCallObject::New(alloc(), templateObj);
+        callObj = MNewCallObject::New(alloc(), templateObj, 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)
 {
@@ -7735,20 +7743,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
@@ -420,213 +420,84 @@ MacroAssembler::loadFromTypedArray(int a
     }
 }
 
 template void MacroAssembler::loadFromTypedArray(int arrayType, const Address &src, const ValueOperand &dest,
                                                  bool allowDouble, Register temp, Label *fail);
 template void MacroAssembler::loadFromTypedArray(int arrayType, const BaseIndex &src, const ValueOperand &dest,
                                                  bool allowDouble, Register temp, Label *fail);
 
-// 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 known 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);
-
-    // We still need to allocate in the nursery, per the comment in
-    // shouldNurseryAllocate; however, we need to insert into hugeSlots, so
-    // bail to do the nursery allocation in the interpreter.
-    if (nDynamicSlots >= Nursery::MaxNurserySlots) {
-        jump(fail);
+    // 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
 
-    // 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()));
+    CompileZone *zone = GetIonContext()->compartment->zone();
 
-    if (nDynamicSlots)
-        computeEffectiveAddress(Address(result, thingSize), slots);
-#endif // JSGC_GENERATIONAL
-}
-
-// 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);
-
-    if (regNBytes != result)
-        push(regNBytes);
-    move32(Imm32(nbytes), regNBytes);
-    call(GetIonContext()->runtime->jitRuntime()->mallocStub());
-    if (regNBytes != result) {
-        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::newGCFatInlineString(Register result, Register temp, Label *fail)
 {
-    allocateNonObject(result, temp, js::gc::FINALIZE_FAT_INLINE_STRING, fail);
+    newGCThing(result, temp, js::gc::FINALIZE_FAT_INLINE_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
@@ -672,17 +543,16 @@ MacroAssembler::newGCThingPar(Register r
 }
 
 void
 MacroAssembler::newGCThingPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                               JSObject *templateObject, Label *fail)
 {
     gc::AllocKind allocKind = templateObject->tenuredGetAllocKind();
     JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
-    JS_ASSERT(!templateObject->numDynamicSlots());
 
     newGCThingPar(result, cx, tempReg1, tempReg2, allocKind, fail);
 }
 
 void
 MacroAssembler::newGCStringPar(Register result, Register cx, Register tempReg1, Register tempReg2,
                                Label *fail)
 {
@@ -692,115 +562,94 @@ MacroAssembler::newGCStringPar(Register 
 void
 MacroAssembler::newGCFatInlineStringPar(Register result, Register cx, Register tempReg1,
                                         Register tempReg2, Label *fail)
 {
     newGCThingPar(result, cx, tempReg1, tempReg2, js::gc::FINALIZE_FAT_INLINE_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.
@@ -813,17 +662,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
@@ -785,52 +785,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 newGCFatInlineString(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 newGCFatInlineStringPar(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_;
 
     // Thunk used to fix up on-stack recompile of baseline scripts.
     JitCode *baselineDebugModeOSRHandler_;
@@ -238,18 +234,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 *generateBaselineDebugModeOSRHandler(JSContext *cx, uint32_t *noFrameRegPopOffsetOut);
     JitCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
     JSC::ExecutableAllocator *createIonAlloc(JSContext *cx);
 
   public:
@@ -356,24 +350,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_;
     }
 
     bool hasIonReturnOverride() const {
         return !ionReturnOverride_.isMagic(JS_ARG_POISON);
     }
--- 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,89 +459,117 @@ class LNewDeclEnvObject : public LInstru
         return getTemp(0);
     }
 
     MNewDeclEnvObject *mir() const {
         return mir_->toNewDeclEnvObject();
     }
 };
 
-// Allocates a new CallObject.
-//
-// 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>
-{
-  public:
-    LIR_HEADER(NewCallObject)
-
-    LNewCallObject(const LDefinition &temp) {
-        setTemp(0, temp);
-    }
-
-    const LDefinition *temp() {
-        return getTemp(0);
-    }
-
-
-    MNewCallObject *mir() const {
-        return mir_->toNewCallObject();
-    }
-};
-
-// Allocates a new CallObject with singleton type.
+// 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 LNewSingletonCallObject : public LInstructionHelper<1, 0, 1>
-{
-  public:
-    LIR_HEADER(NewSingletonCallObject)
-
-    LNewSingletonCallObject(const LDefinition &temp) {
+class LNewCallObject : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(NewCallObject)
+
+    LNewCallObject(const LAllocation &slots, const LDefinition &temp) {
+        setOperand(0, slots);
         setTemp(0, temp);
     }
 
     const LDefinition *temp() {
         return getTemp(0);
     }
 
-    MNewCallObjectBase *mir() const {
+    const LAllocation *slots() {
+        return getOperand(0);
+    }
+
+    MNewCallObject *mir() const {
+        return mir_->toNewCallObject();
+    }
+};
+
+// Allocates a new CallObject with singleton type through an out-of-line VM
+// call. The inputs are:
+//      slots: either a reg representing a HeapSlot *, or a placeholder
+//             meaning that no slots pointer is needed.
+//
+class LNewSingletonCallObject : public LInstructionHelper<1, 1, 0>
+{
+  public:
+    LIR_HEADER(NewSingletonCallObject)
+
+    LNewSingletonCallObject(const LAllocation &slots) {
+        setOperand(0, slots);
+    }
+
+    const LAllocation *slots() {
+        return getOperand(0);
+    }
+
+    MNewCallObjectBase * mir() const {
         MOZ_ASSERT(mir_->isNewCallObject() || mir_->isNewRunOnceCallObject());
         return static_cast<MNewCallObjectBase *>(mir_);
     }
 };
 
-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
@@ -21,16 +21,17 @@
     _(Parameter)                    \
     _(Callee)                       \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(ArraySplice)                  \
     _(NewObject)                    \
+    _(NewSlots)                     \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewSingletonCallObject)       \
     _(NewStringObject)              \
     _(NewPar)                       \
     _(NewDenseArrayPar)             \
     _(NewCallObjectPar)             \
     _(NewDerivedTypedObject)        \
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -154,16 +154,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)
@@ -177,39 +188,51 @@ LIRGenerator::visitNewDeclEnvObject(MNew
 {
     LNewDeclEnvObject *lir = new(alloc()) LNewDeclEnvObject(temp());
     return define(lir, ins) && assignSafepoint(lir, ins);
 }
 
 bool
 LIRGenerator::visitNewCallObject(MNewCallObject *ins)
 {
+    LAllocation slots;
+    if (ins->slots()->type() == MIRType_Slots)
+        slots = useRegister(ins->slots());
+    else
+        slots = LConstantIndex::Bogus();
+
     LInstruction *lir;
     if (ins->templateObject()->hasSingletonType()) {
-        LNewSingletonCallObject *singletonLir = new(alloc()) LNewSingletonCallObject(temp());
+        LNewSingletonCallObject *singletonLir = new(alloc()) LNewSingletonCallObject(slots);
         if (!define(singletonLir, ins))
             return false;
         lir = singletonLir;
     } else {
-        LNewCallObject *normalLir = new(alloc()) LNewCallObject(temp());
+        LNewCallObject *normalLir = new(alloc()) LNewCallObject(slots, temp());
         if (!define(normalLir, ins))
             return false;
         lir = normalLir;
     }
 
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
 
 bool
 LIRGenerator::visitNewRunOnceCallObject(MNewRunOnceCallObject *ins)
 {
-    LNewSingletonCallObject *lir = new(alloc()) LNewSingletonCallObject(temp());
+    LAllocation slots;
+    if (ins->slots()->type() == MIRType_Slots)
+        slots = useRegister(ins->slots());
+    else
+        slots = LConstantIndex::Bogus();
+
+    LNewSingletonCallObject *lir = new(alloc()) LNewSingletonCallObject(slots);
     if (!define(lir, ins))
         return false;
 
     if (!assignSafepoint(lir, ins))
         return false;
 
     return true;
 }
@@ -223,17 +246,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
@@ -63,16 +63,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 visitNewRunOnceCallObject(MNewRunOnceCallObject *ins);
     bool visitNewStringObject(MNewStringObject *ins);
     bool visitNewDerivedTypedObject(MNewDerivedTypedObject *ins);
     bool visitNewPar(MNewPar *ins);
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -9314,16 +9314,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)
     {
@@ -9340,91 +9367,98 @@ class MNewDeclEnvObject : public MNullar
     JSObject *templateObj() {
         return templateObj_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
-class MNewCallObjectBase : public MNullaryInstruction
+class MNewCallObjectBase : public MUnaryInstruction
 {
     CompilerRootObject templateObj_;
 
   protected:
-    MNewCallObjectBase(JSObject *templateObj)
-      : MNullaryInstruction(),
+    MNewCallObjectBase(JSObject *templateObj, MDefinition *slots)
+      : MUnaryInstruction(slots),
         templateObj_(templateObj)
     {
         setResultType(MIRType_Object);
     }
 
   public:
+    MDefinition *slots() {
+        return getOperand(0);
+    }
     JSObject *templateObject() {
         return templateObj_;
     }
     AliasSet getAliasSet() const {
         return AliasSet::None();
     }
 };
 
 class MNewCallObject : public MNewCallObjectBase
 {
   public:
     INSTRUCTION_HEADER(NewCallObject)
 
-    MNewCallObject(JSObject *templateObj)
-      : MNewCallObjectBase(templateObj)
+    MNewCallObject(JSObject *templateObj, MDefinition *slots)
+      : MNewCallObjectBase(templateObj, slots)
     {}
 
     static MNewCallObject *
-    New(TempAllocator &alloc, JSObject *templateObj)
-    {
-        return new(alloc) MNewCallObject(templateObj);
+    New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
+    {
+        return new(alloc) MNewCallObject(templateObj, slots);
     }
 };
 
 class MNewRunOnceCallObject : public MNewCallObjectBase
 {
   public:
     INSTRUCTION_HEADER(NewRunOnceCallObject)
 
-    MNewRunOnceCallObject(JSObject *templateObj)
-      : MNewCallObjectBase(templateObj)
+    MNewRunOnceCallObject(JSObject *templateObj, MDefinition *slots)
+      : MNewCallObjectBase(templateObj, slots)
     {}
 
     static MNewRunOnceCallObject *
-    New(TempAllocator &alloc, JSObject *templateObj)
-    {
-        return new(alloc) MNewRunOnceCallObject(templateObj);
-    }
-};
-
-class MNewCallObjectPar : public MUnaryInstruction
+    New(TempAllocator &alloc, JSObject *templateObj, MDefinition *slots)
+    {
+        return new(alloc) MNewRunOnceCallObject(templateObj, slots);
+    }
+};
+
+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, MNewCallObjectBase *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
@@ -82,16 +82,17 @@ namespace jit {
     _(GuardObject)                                                          \
     _(GuardString)                                                          \
     _(AssertRange)                                                          \
     _(ToDouble)                                                             \
     _(ToFloat32)                                                            \
     _(ToInt32)                                                              \
     _(TruncateToInt32)                                                      \
     _(ToString)                                                             \
+    _(NewSlots)                                                             \
     _(NewArray)                                                             \
     _(NewObject)                                                            \
     _(NewDeclEnvObject)                                                     \
     _(NewCallObject)                                                        \
     _(NewRunOnceCallObject)                                                 \
     _(NewStringObject)                                                      \
     _(InitElem)                                                             \
     _(InitElemGetterSetter)                                                 \
--- a/js/src/jit/ParallelSafetyAnalysis.cpp
+++ b/js/src/jit/ParallelSafetyAnalysis.cpp
@@ -176,16 +176,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)
     CUSTOM_OP(NewRunOnceCallObject)
     CUSTOM_OP(NewDerivedTypedObject)
     UNSAFE_OP(InitElem)
     UNSAFE_OP(InitElemGetterSetter)
     UNSAFE_OP(MutateProto)
@@ -527,31 +528,23 @@ 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::visitNewRunOnceCallObject(MNewRunOnceCallObject *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) {
@@ -670,16 +663,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
@@ -520,44 +520,53 @@ 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, HandleShape shape, HandleTypeObject type)
+NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
 {
-    JSObject *obj = CallObject::create(cx, shape, type);
+    JSObject *obj = CallObject::create(cx, 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(obj))
         cx->runtime()->gc.storeBuffer.putWholeCellFromMainThread(obj);
 #endif
 
     return obj;
 }
 
 JSObject *
-NewSingletonCallObject(JSContext *cx, HandleShape shape)
+NewSingletonCallObject(JSContext *cx, HandleShape shape, HeapSlot *slots)
 {
-    JSObject *obj = CallObject::createSingleton(cx, shape);
+    JSObject *obj = CallObject::createSingleton(cx, shape, 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.
     MOZ_ASSERT(!IsInsideNursery(obj),
--- a/js/src/jit/VMFunctions.h
+++ b/js/src/jit/VMFunctions.h
@@ -614,19 +614,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);
-JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type);
-JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape);
+HeapSlot *NewSlots(JSRuntime *rt, unsigned nslots);
+JSObject *NewCallObject(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
+JSObject *NewSingletonCallObject(JSContext *cx, HandleShape shape, 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/jit/shared/IonAssemblerBuffer.h
+++ b/js/src/jit/shared/IonAssemblerBuffer.h
@@ -240,20 +240,18 @@ struct AssemblerBuffer
     }
     BufferOffset prevOffset() const {
         MOZ_ASSUME_UNREACHABLE("Don't current record lastInstSize");
     }
 
     // Break the instruction stream so we can go back and edit it at this point
     void perforate() {
         Slice *tmp = newSlice(LifoAlloc_);
-        if (!tmp) {
+        if (!tmp)
             m_oom = true;
-            return;
-        }
         bufferSize += tail->size();
         tail->setNext(tmp);
         tail = tmp;
     }
 
     class AssemblerBufferInstIterator {
       private:
         BufferOffset bo;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -231,17 +231,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
@@ -481,36 +481,52 @@ 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_IF(!ClassCanHaveFixedData(type->clasp()),
                  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()->gc.nursery.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)
         obj->initializeSlotRange(0, span);
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -132,43 +132,43 @@ void
 ScopeObject::setEnclosingScope(HandleObject obj)
 {
     JS_ASSERT_IF(obj->is<CallObject>() || obj->is<DeclEnvObject>() || obj->is<BlockObject>(),
                  obj->isDelegate());
     setFixedSlot(SCOPE_CHAIN_SLOT, ObjectValue(*obj));
 }
 
 CallObject *
-CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type)
+CallObject::create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots)
 {
     MOZ_ASSERT(!type->singleton(),
                "passed a singleton type to create() (use createSingleton() "
                "instead)");
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
-    JSObject *obj = JSObject::create(cx, kind, gc::DefaultHeap, shape, type);
+    JSObject *obj = JSObject::create(cx, kind, gc::DefaultHeap, shape, type, slots);
     if (!obj)
         return nullptr;
 
     return &obj->as<CallObject>();
 }
 
 CallObject *
-CallObject::createSingleton(JSContext *cx, HandleShape shape)
+CallObject::createSingleton(JSContext *cx, HandleShape shape, HeapSlot *slots)
 {
     gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
     MOZ_ASSERT(CanBeFinalizedInBackground(kind, &CallObject::class_));
     kind = gc::GetBackgroundAllocKind(kind);
 
     RootedTypeObject type(cx, cx->getSingletonType(&class_, nullptr));
     if (!type)
         return nullptr;
-    RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, type));
+    RootedObject obj(cx, JSObject::create(cx, kind, gc::TenuredHeap, shape, type, slots));
     if (!obj)
         return nullptr;
 
     MOZ_ASSERT(obj->hasSingletonType(),
                "type created inline above must be a singleton");
 
     return &obj->as<CallObject>();
 }
--- a/js/src/vm/ScopeObject.h
+++ b/js/src/vm/ScopeObject.h
@@ -233,28 +233,30 @@ class CallObject : public ScopeObject
     create(JSContext *cx, HandleScript script, HandleObject enclosing, HandleFunction callee);
 
   public:
     static const Class class_;
 
     /* These functions are internal and are exposed only for JITs. */
 
     /*
-     * Construct a bare-bones call object given a shape and a non-singleton
-     * type.  The call object must be further initialized to be usable.
+     * Construct a bare-bones call object given a shape, a non-singleton type,
+     * and slots pointer.  The call object must be further initialized to be
+     * usable.
      */
     static CallObject *
-    create(JSContext *cx, HandleShape shape, HandleTypeObject type);
+    create(JSContext *cx, HandleShape shape, HandleTypeObject type, HeapSlot *slots);
 
     /*
-     * Construct a bare-bones call object given a shape and make it have
-     * singleton type.  The call object must be initialized to be usable.
+     * Construct a bare-bones call object given a shape and slots pointer, and
+     * make it have singleton type.  The call object must be initialized to be
+     * usable.
      */
     static CallObject *
-    createSingleton(JSContext *cx, HandleShape shape);
+    createSingleton(JSContext *cx, HandleShape shape, 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);