Bug 922270 - Don't construct template objects during IonBuilder, r=jandem.
☠☠ backed out by af90be985882 ☠ ☠
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 16 Oct 2013 12:34:37 -0600
changeset 165833 b4ebfef56feecc150a0252e4f5a3985501423d3b
parent 165832 d7fe1f3439e276a851a31ea1f499c0cd4a3f8e75
child 165834 bdcfcd904df05594733829643b9acd4d6040346d
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs922270
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 922270 - Don't construct template objects during IonBuilder, r=jandem.
js/src/gc/Marking.cpp
js/src/jit/BaselineCompiler.cpp
js/src/jit/BaselineIC.cpp
js/src/jit/BaselineIC.h
js/src/jit/BaselineInspector.cpp
js/src/jit/BaselineInspector.h
js/src/jit/IonBuilder.cpp
js/src/jit/IonBuilder.h
js/src/jit/MCallOptimize.cpp
js/src/jsinfer.cpp
js/src/jsinfer.h
js/src/jsinferinlines.h
js/src/jsobj.cpp
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -1135,17 +1135,17 @@ ScanTypeObject(GCMarker *gcmarker, types
 
     if (type->singleton && !type->lazy())
         PushMarkStack(gcmarker, type->singleton);
 
     if (type->addendum) {
         switch (type->addendum->kind) {
           case types::TypeObjectAddendum::NewScript:
             PushMarkStack(gcmarker, type->newScript()->fun);
-            PushMarkStack(gcmarker, type->newScript()->shape.get());
+            PushMarkStack(gcmarker, type->newScript()->templateObject);
             break;
 
           case types::TypeObjectAddendum::TypedObject:
             PushMarkStack(gcmarker, type->typedObject()->typeRepr->ownerObject());
             break;
         }
     }
 
@@ -1168,17 +1168,17 @@ gc::MarkChildren(JSTracer *trc, types::T
 
     if (type->singleton && !type->lazy())
         MarkObject(trc, &type->singleton, "type_singleton");
 
     if (type->addendum) {
         switch (type->addendum->kind) {
           case types::TypeObjectAddendum::NewScript:
             MarkObject(trc, &type->newScript()->fun, "type_new_function");
-            MarkShape(trc, &type->newScript()->shape, "type_new_shape");
+            MarkObject(trc, &type->newScript()->templateObject, "type_new_template");
             break;
 
           case types::TypeObjectAddendum::TypedObject:
             type->typedObject()->typeRepr->mark(trc);
             break;
         }
     }
 
--- a/js/src/jit/BaselineCompiler.cpp
+++ b/js/src/jit/BaselineCompiler.cpp
@@ -1388,17 +1388,22 @@ BaselineCompiler::emit_JSOP_NEWARRAY()
         if (!type)
             return false;
     }
 
     // Pass length in R0, type in R1.
     masm.move32(Imm32(length), R0.scratchReg());
     masm.movePtr(ImmGCPtr(type), R1.scratchReg());
 
-    ICNewArray_Fallback::Compiler stubCompiler(cx);
+    JSObject *templateObject = NewDenseUnallocatedArray(cx, length);
+    if (!templateObject)
+        return false;
+    templateObject->setType(type);
+
+    ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.push(R0);
     return true;
 }
 
 bool
@@ -1440,20 +1445,17 @@ BaselineCompiler::emit_JSOP_NEWOBJECT()
 
     if (type) {
         templateObject->setType(type);
     } else {
         if (!JSObject::setSingletonType(cx, templateObject))
             return false;
     }
 
-    // Pass base object in R0.
-    masm.movePtr(ImmGCPtr(templateObject), R0.scratchReg());
-
-    ICNewObject_Fallback::Compiler stubCompiler(cx);
+    ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
     if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
         return false;
 
     frame.push(R0);
     return true;
 }
 
 bool
@@ -1469,17 +1471,22 @@ BaselineCompiler::emit_JSOP_NEWINIT()
             return false;
     }
 
     if (key == JSProto_Array) {
         // Pass length in R0, type in R1.
         masm.move32(Imm32(0), R0.scratchReg());
         masm.movePtr(ImmGCPtr(type), R1.scratchReg());
 
-        ICNewArray_Fallback::Compiler stubCompiler(cx);
+        JSObject *templateObject = NewDenseUnallocatedArray(cx, 0);
+        if (!templateObject)
+            return false;
+        templateObject->setType(type);
+
+        ICNewArray_Fallback::Compiler stubCompiler(cx, templateObject);
         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
             return false;
     } else {
         JS_ASSERT(key == JSProto_Object);
 
         RootedObject templateObject(cx);
         templateObject = NewBuiltinClassInstance(cx, &JSObject::class_, TenuredObject);
         if (!templateObject)
@@ -1487,20 +1494,17 @@ BaselineCompiler::emit_JSOP_NEWINIT()
 
         if (type) {
             templateObject->setType(type);
         } else {
             if (!JSObject::setSingletonType(cx, templateObject))
                 return false;
         }
 
-        // Pass base object in R0.
-        masm.movePtr(ImmGCPtr(templateObject), R0.scratchReg());
-
-        ICNewObject_Fallback::Compiler stubCompiler(cx);
+        ICNewObject_Fallback::Compiler stubCompiler(cx, templateObject);
         if (!emitOpIC(stubCompiler.getStub(&stubSpace_)))
             return false;
     }
 
     frame.push(R0);
     return true;
 }
 
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -24,16 +24,17 @@
 #include "jit/VMFunctions.h"
 
 #include "jsboolinlines.h"
 #include "jsscriptinlines.h"
 
 #include "jit/IonFrames-inl.h"
 #include "vm/Interpreter-inl.h"
 #include "vm/ScopeObject-inl.h"
+#include "vm/StringObject-inl.h"
 
 namespace js {
 namespace jit {
 
 #ifdef DEBUG
 void
 FallbackICSpew(JSContext *cx, ICFallbackStub *stub, const char *fmt, ...)
 {
@@ -178,21 +179,25 @@ ICStub::trace(JSTracer *trc)
             iter->markCode(trc, "baseline-update-stub-ioncode");
         }
     }
 
     switch (kind()) {
       case ICStub::Call_Scripted: {
         ICCall_Scripted *callStub = toCall_Scripted();
         MarkScript(trc, &callStub->calleeScript(), "baseline-callscripted-callee");
+        if (callStub->templateObject())
+            MarkObject(trc, &callStub->templateObject(), "baseline-callscripted-template");
         break;
       }
       case ICStub::Call_Native: {
         ICCall_Native *callStub = toCall_Native();
         MarkObject(trc, &callStub->callee(), "baseline-callnative-callee");
+        if (callStub->templateObject())
+            MarkObject(trc, &callStub->templateObject(), "baseline-callnative-template");
         break;
       }
       case ICStub::GetElem_NativeSlot: {
         ICGetElem_NativeSlot *getElemStub = toGetElem_NativeSlot();
         MarkShape(trc, &getElemStub->shape(), "baseline-getelem-native-shape");
         MarkString(trc, &getElemStub->name(), "baseline-getelem-native-name");
         break;
       }
@@ -396,16 +401,26 @@ ICStub::trace(JSTracer *trc)
       case ICStub::SetProp_CallNative: {
         ICSetProp_CallNative *callStub = toSetProp_CallNative();
         MarkShape(trc, &callStub->shape(), "baseline-setpropcallnative-stub-shape");
         MarkObject(trc, &callStub->holder(), "baseline-setpropcallnative-stub-holder");
         MarkShape(trc, &callStub->holderShape(), "baseline-setpropcallnative-stub-holdershape");
         MarkObject(trc, &callStub->setter(), "baseline-setpropcallnative-stub-setter");
         break;
       }
+      case ICStub::NewArray_Fallback: {
+        ICNewArray_Fallback *stub = toNewArray_Fallback();
+        MarkObject(trc, &stub->templateObject(), "baseline-newarray-template");
+        break;
+      }
+      case ICStub::NewObject_Fallback: {
+        ICNewObject_Fallback *stub = toNewObject_Fallback();
+        MarkObject(trc, &stub->templateObject(), "baseline-newobject-template");
+        break;
+      }
       default:
         break;
     }
 }
 
 void
 ICFallbackStub::unlinkStub(Zone *zone, ICStub *prev, ICStub *stub)
 {
@@ -1678,39 +1693,37 @@ ICNewArray_Fallback::Compiler::generateS
     return tailCallVM(DoNewArrayInfo, masm);
 }
 
 //
 // NewObject_Fallback
 //
 
 static bool
-DoNewObject(JSContext *cx, ICNewObject_Fallback *stub, HandleObject templateObject,
-            MutableHandleValue res)
+DoNewObject(JSContext *cx, ICNewObject_Fallback *stub, MutableHandleValue res)
 {
     FallbackICSpew(cx, stub, "NewObject");
 
+    RootedObject templateObject(cx, stub->templateObject());
     JSObject *obj = NewInitObject(cx, templateObject);
     if (!obj)
         return false;
 
     res.setObject(*obj);
     return true;
 }
 
-typedef bool(*DoNewObjectFn)(JSContext *, ICNewObject_Fallback *, HandleObject,
-                             MutableHandleValue);
+typedef bool(*DoNewObjectFn)(JSContext *, ICNewObject_Fallback *, MutableHandleValue);
 static const VMFunction DoNewObjectInfo = FunctionInfo<DoNewObjectFn>(DoNewObject);
 
 bool
 ICNewObject_Fallback::Compiler::generateStubCode(MacroAssembler &masm)
 {
     EmitRestoreTailCallReg(masm);
 
-    masm.push(R0.scratchReg()); // template
     masm.push(BaselineStubReg); // stub.
 
     return tailCallVM(DoNewObjectInfo, masm);
 }
 
 //
 // Compare_Fallback
 //
@@ -7412,16 +7425,61 @@ TryAttachFunApplyStub(JSContext *cx, ICC
             stub->addNewStub(newStub);
             return true;
         }
     }
     return true;
 }
 
 static bool
+GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
+                           Native native, const CallArgs &args, MutableHandleObject res)
+{
+    // Check for natives to which template objects can be attached. This is
+    // done to provide templates to Ion for inlining these natives later on.
+
+    if (native == js_Array) {
+        size_t count = 0;
+        if (args.hasDefined(1))
+            count = args.length();
+        else if (args.hasDefined(0) && args[0].isInt32() && args[0].toInt32() > 0)
+            count = args[0].toInt32();
+        res.set(NewDenseUnallocatedArray(cx, count, nullptr, TenuredObject));
+        if (!res)
+            return false;
+
+        types::TypeObject *type = types::TypeScript::InitObject(cx, script, pc, JSProto_Array);
+        if (!type)
+            return false;
+        res->setType(type);
+        return true;
+    }
+
+    if (native == js::array_concat) {
+        if (args.thisv().isObject() && args.thisv().toObject().is<ArrayObject>()) {
+            res.set(NewDenseEmptyArray(cx, args.thisv().toObject().getProto(), TenuredObject));
+            if (!res)
+                return false;
+            res->setType(args.thisv().toObject().type());
+            return true;
+        }
+    }
+
+    if (native == js_String) {
+        RootedString emptyString(cx, cx->runtime()->emptyString);
+        res.set(StringObject::create(cx, emptyString, TenuredObject));
+        if (!res)
+            return false;
+        return true;
+    }
+
+    return true;
+}
+
+static bool
 TryAttachCallStub(JSContext *cx, ICCall_Fallback *stub, HandleScript script, jsbytecode *pc,
                   JSOp op, uint32_t argc, Value *vp, bool constructing, bool useNewType)
 {
     if (useNewType || op == JSOP_EVAL)
         return true;
 
     if (stub->numOptimizedStubs() >= ICCall_Fallback::MAX_OPTIMIZED_STUBS) {
         // TODO: Discard all stubs in this IC and replace with inert megamorphic stub.
@@ -7483,54 +7541,70 @@ TryAttachCallStub(JSContext *cx, ICCall_
             return true;
         }
 
         // Keep track of the function's |prototype| property in type
         // information, for use during Ion compilation.
         if (IsIonEnabled(cx))
             types::EnsureTrackPropertyTypes(cx, fun, NameToId(cx->names().prototype));
 
+        // Remember the template object associated with any script being called
+        // as a constructor, for later use during Ion compilation.
+        RootedObject templateObject(cx);
+        if (constructing) {
+            if (!fun->hasLazyType() && fun->type()->hasNewScript())
+                templateObject = fun->type()->newScript()->templateObject;
+            else
+                templateObject = CreateThisForFunction(cx, fun, /* newType = */ false);
+        }
+
         IonSpew(IonSpew_BaselineIC,
                 "  Generating Call_Scripted stub (fun=%p, %s:%d, cons=%s)",
                 fun.get(), fun->nonLazyScript()->filename(), fun->nonLazyScript()->lineno,
                 constructing ? "yes" : "no");
         ICCallScriptedCompiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
-                                        calleeScript, constructing, pc - script->code);
+                                        calleeScript, templateObject,
+                                        constructing, pc - script->code);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         return true;
     }
 
     if (fun->isNative() && (!constructing || (constructing && fun->isNativeConstructor()))) {
-        // Generalied native call stubs are not here yet!
+        // Generalized native call stubs are not here yet!
         JS_ASSERT(!stub->nativeStubsAreGeneralized());
 
         // Check for JSOP_FUNAPPLY
         if (op == JSOP_FUNAPPLY) {
-            if (fun->maybeNative() == js_fun_apply)
+            if (fun->native() == js_fun_apply)
                 return TryAttachFunApplyStub(cx, stub, script, pc, thisv, argc, vp + 2);
 
             // Don't try to attach a "regular" optimized call stubs for FUNAPPLY ops,
             // since MagicArguments may escape through them.
             return true;
         }
 
         if (stub->nativeStubCount() >= ICCall_Fallback::MAX_NATIVE_STUBS) {
             IonSpew(IonSpew_BaselineIC,
                     "  Too many Call_Native stubs. TODO: add Call_AnyNative!");
             return true;
         }
 
+        CallArgs args = CallArgsFromVp(argc, vp);
+        RootedObject templateObject(cx);
+        if (!GetTemplateObjectForNative(cx, script, pc, fun->native(), args, &templateObject))
+            return false;
+
         IonSpew(IonSpew_BaselineIC, "  Generating Call_Native stub (fun=%p, cons=%s)",
                 fun.get(), constructing ? "yes" : "no");
         ICCall_Native::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
-                                         fun, constructing, pc - script->code);
+                                         fun, templateObject, constructing, pc - script->code);
         ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
         if (!newStub)
             return false;
 
         stub->addNewStub(newStub);
         return true;
     }
 
@@ -9324,26 +9398,30 @@ ICSetPropCallSetter::ICSetPropCallSetter
     holderShape_(holderShape),
     setter_(setter),
     pcOffset_(pcOffset)
 {
     JS_ASSERT(kind == ICStub::SetProp_CallScripted || kind == ICStub::SetProp_CallNative);
 }
 
 ICCall_Scripted::ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub,
-                                 HandleScript calleeScript, uint32_t pcOffset)
+                                 HandleScript calleeScript, HandleObject templateObject,
+                                 uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Scripted, stubCode, firstMonitorStub),
     calleeScript_(calleeScript),
+    templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
 
-ICCall_Native::ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee,
+ICCall_Native::ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub,
+                             HandleFunction callee, HandleObject templateObject,
                              uint32_t pcOffset)
   : ICMonitoredStub(ICStub::Call_Native, stubCode, firstMonitorStub),
     callee_(callee),
+    templateObject_(templateObject),
     pcOffset_(pcOffset)
 { }
 
 ICGetPropCallDOMProxyNativeStub::ICGetPropCallDOMProxyNativeStub(Kind kind, IonCode *stubCode,
                                                                  ICStub *firstMonitorStub,
                                                                  HandleShape shape,
                                                                  BaseProxyHandler *proxyHandler,
                                                                  HandleShape expandoShape,
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1791,68 +1791,86 @@ class ICThis_Fallback : public ICFallbac
         }
     };
 };
 
 class ICNewArray_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
-    ICNewArray_Fallback(IonCode *stubCode)
-      : ICFallbackStub(ICStub::NewArray_Fallback, stubCode)
+    HeapPtrObject templateObject_;
+
+    ICNewArray_Fallback(IonCode *stubCode, JSObject *templateObject)
+      : ICFallbackStub(ICStub::NewArray_Fallback, stubCode), templateObject_(templateObject)
     {}
 
   public:
-    static inline ICNewArray_Fallback *New(ICStubSpace *space, IonCode *code) {
+    static inline ICNewArray_Fallback *New(ICStubSpace *space, IonCode *code,
+                                           JSObject *templateObject) {
         if (!code)
             return nullptr;
-        return space->allocate<ICNewArray_Fallback>(code);
+        return space->allocate<ICNewArray_Fallback>(code, templateObject);
     }
 
     class Compiler : public ICStubCompiler {
+        RootedObject templateObject;
         bool generateStubCode(MacroAssembler &masm);
 
       public:
-        Compiler(JSContext *cx)
-          : ICStubCompiler(cx, ICStub::NewArray_Fallback)
+        Compiler(JSContext *cx, JSObject *templateObject)
+          : ICStubCompiler(cx, ICStub::NewArray_Fallback),
+            templateObject(cx, templateObject)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
-            return ICNewArray_Fallback::New(space, getStubCode());
+            return ICNewArray_Fallback::New(space, getStubCode(), templateObject);
         }
     };
+
+    HeapPtrObject &templateObject() {
+        return templateObject_;
+    }
 };
 
 class ICNewObject_Fallback : public ICFallbackStub
 {
     friend class ICStubSpace;
 
-    ICNewObject_Fallback(IonCode *stubCode)
-      : ICFallbackStub(ICStub::NewObject_Fallback, stubCode)
+    HeapPtrObject templateObject_;
+
+    ICNewObject_Fallback(IonCode *stubCode, JSObject *templateObject)
+      : ICFallbackStub(ICStub::NewObject_Fallback, stubCode), templateObject_(templateObject)
     {}
 
   public:
-    static inline ICNewObject_Fallback *New(ICStubSpace *space, IonCode *code) {
+    static inline ICNewObject_Fallback *New(ICStubSpace *space, IonCode *code,
+                                            JSObject *templateObject) {
         if (!code)
             return nullptr;
-        return space->allocate<ICNewObject_Fallback>(code);
+        return space->allocate<ICNewObject_Fallback>(code, templateObject);
     }
 
     class Compiler : public ICStubCompiler {
+        RootedObject templateObject;
         bool generateStubCode(MacroAssembler &masm);
 
       public:
-        Compiler(JSContext *cx)
-          : ICStubCompiler(cx, ICStub::NewObject_Fallback)
+        Compiler(JSContext *cx, JSObject *templateObject)
+          : ICStubCompiler(cx, ICStub::NewObject_Fallback),
+            templateObject(cx, templateObject)
         {}
 
         ICStub *getStub(ICStubSpace *space) {
-            return ICNewObject_Fallback::New(space, getStubCode());
+            return ICNewObject_Fallback::New(space, getStubCode(), templateObject);
         }
     };
+
+    HeapPtrObject &templateObject() {
+        return templateObject_;
+    }
 };
 
 // Compare
 //      JSOP_LT
 //      JSOP_GT
 
 class ICCompare_Fallback : public ICFallbackStub
 {
@@ -5199,34 +5217,41 @@ class ICCall_Fallback : public ICMonitor
 };
 
 class ICCall_Scripted : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected:
     HeapPtrScript calleeScript_;
+    HeapPtrObject templateObject_;
     uint32_t pcOffset_;
 
-    ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub, HandleScript calleeScript,
+    ICCall_Scripted(IonCode *stubCode, ICStub *firstMonitorStub,
+                    HandleScript calleeScript, HandleObject templateObject,
                     uint32_t pcOffset);
 
   public:
     static inline ICCall_Scripted *New(
-            ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub, HandleScript calleeScript,
+            ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
+            HandleScript calleeScript, HandleObject templateObject,
             uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
-        return space->allocate<ICCall_Scripted>(code, firstMonitorStub, calleeScript, pcOffset);
+        return space->allocate<ICCall_Scripted>(code, firstMonitorStub,
+                                                calleeScript, templateObject, pcOffset);
     }
 
     HeapPtrScript &calleeScript() {
         return calleeScript_;
     }
+    HeapPtrObject &templateObject() {
+        return templateObject_;
+    }
 
     static size_t offsetOfCalleeScript() {
         return offsetof(ICCall_Scripted, calleeScript_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Scripted, pcOffset_);
     }
 };
@@ -5258,107 +5283,123 @@ class ICCall_AnyScripted : public ICMoni
 };
 
 // Compiler for Call_Scripted and Call_AnyScripted stubs.
 class ICCallScriptedCompiler : public ICCallStubCompiler {
   protected:
     ICStub *firstMonitorStub_;
     bool isConstructing_;
     RootedScript calleeScript_;
+    RootedObject templateObject_;
     uint32_t pcOffset_;
     bool generateStubCode(MacroAssembler &masm);
 
     virtual int32_t getKey() const {
         return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16);
     }
 
   public:
-    ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, HandleScript calleeScript,
-                            bool isConstructing, uint32_t pcOffset)
+    ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub,
+                           HandleScript calleeScript, HandleObject templateObject,
+                           bool isConstructing, uint32_t pcOffset)
       : ICCallStubCompiler(cx, ICStub::Call_Scripted),
         firstMonitorStub_(firstMonitorStub),
         isConstructing_(isConstructing),
         calleeScript_(cx, calleeScript),
+        templateObject_(cx, templateObject),
         pcOffset_(pcOffset)
     { }
 
     ICCallScriptedCompiler(JSContext *cx, ICStub *firstMonitorStub, bool isConstructing,
                            uint32_t pcOffset)
       : ICCallStubCompiler(cx, ICStub::Call_AnyScripted),
         firstMonitorStub_(firstMonitorStub),
         isConstructing_(isConstructing),
         calleeScript_(cx, nullptr),
+        templateObject_(cx, nullptr),
         pcOffset_(pcOffset)
     { }
 
     ICStub *getStub(ICStubSpace *space) {
         if (calleeScript_) {
-            return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_, calleeScript_,
+            return ICCall_Scripted::New(space, getStubCode(), firstMonitorStub_,
+                                        calleeScript_, templateObject_,
                                         pcOffset_);
         }
         return ICCall_AnyScripted::New(space, getStubCode(), firstMonitorStub_, pcOffset_);
     }
 };
 
 class ICCall_Native : public ICMonitoredStub
 {
     friend class ICStubSpace;
 
   protected:
     HeapPtrFunction callee_;
+    HeapPtrObject templateObject_;
     uint32_t pcOffset_;
 
-    ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub, HandleFunction callee,
+    ICCall_Native(IonCode *stubCode, ICStub *firstMonitorStub,
+                  HandleFunction callee, HandleObject templateObject,
                   uint32_t pcOffset);
 
   public:
     static inline ICCall_Native *New(ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
-                                     HandleFunction callee, uint32_t pcOffset)
+                                     HandleFunction callee, HandleObject templateObject,
+                                     uint32_t pcOffset)
     {
         if (!code)
             return nullptr;
-        return space->allocate<ICCall_Native>(code, firstMonitorStub, callee, pcOffset);
+        return space->allocate<ICCall_Native>(code, firstMonitorStub,
+                                              callee, templateObject, pcOffset);
     }
 
     HeapPtrFunction &callee() {
         return callee_;
     }
+    HeapPtrObject &templateObject() {
+        return templateObject_;
+    }
 
     static size_t offsetOfCallee() {
         return offsetof(ICCall_Native, callee_);
     }
     static size_t offsetOfPCOffset() {
         return offsetof(ICCall_Native, pcOffset_);
     }
 
     // Compiler for this stub kind.
     class Compiler : public ICCallStubCompiler {
       protected:
         ICStub *firstMonitorStub_;
         bool isConstructing_;
         RootedFunction callee_;
+        RootedObject templateObject_;
         uint32_t pcOffset_;
         bool generateStubCode(MacroAssembler &masm);
 
         virtual int32_t getKey() const {
             return static_cast<int32_t>(kind) | (static_cast<int32_t>(isConstructing_) << 16);
         }
 
       public:
-        Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleFunction callee,
+        Compiler(JSContext *cx, ICStub *firstMonitorStub,
+                 HandleFunction callee, HandleObject templateObject,
                  bool isConstructing, uint32_t pcOffset)
           : ICCallStubCompiler(cx, ICStub::Call_Native),
             firstMonitorStub_(firstMonitorStub),
             isConstructing_(isConstructing),
             callee_(cx, callee),
+            templateObject_(cx, templateObject),
             pcOffset_(pcOffset)
         { }
 
         ICStub *getStub(ICStubSpace *space) {
-            return ICCall_Native::New(space, getStubCode(), firstMonitorStub_, callee_, pcOffset_);
+            return ICCall_Native::New(space, getStubCode(), firstMonitorStub_,
+                                      callee_, templateObject_, pcOffset_);
         }
     };
 };
 
 class ICCall_ScriptedApplyArray : public ICMonitoredStub
 {
     friend class ICStubSpace;
   public:
--- a/js/src/jit/BaselineInspector.cpp
+++ b/js/src/jit/BaselineInspector.cpp
@@ -378,8 +378,48 @@ BaselineInspector::hasSeenDoubleResult(j
 
     if (stub->isUnaryArith_Fallback())
         return stub->toUnaryArith_Fallback()->sawDoubleResult();
     else
         return stub->toBinaryArith_Fallback()->sawDoubleResult();
 
     return false;
 }
+
+JSObject *
+BaselineInspector::getTemplateObject(jsbytecode *pc)
+{
+    if (!hasBaselineScript())
+        return NULL;
+
+    const ICEntry &entry = icEntryFromPC(pc);
+    for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
+        switch (stub->kind()) {
+          case ICStub::NewArray_Fallback:
+            return stub->toNewArray_Fallback()->templateObject();
+          case ICStub::NewObject_Fallback:
+            return stub->toNewObject_Fallback()->templateObject();
+          case ICStub::Call_Scripted:
+            if (JSObject *obj = stub->toCall_Scripted()->templateObject())
+                return obj;
+            break;
+          default:
+            break;
+        }
+    }
+
+    return NULL;
+}
+
+JSObject *
+BaselineInspector::getTemplateObjectForNative(jsbytecode *pc, Native native)
+{
+    if (!hasBaselineScript())
+        return NULL;
+
+    const ICEntry &entry = icEntryFromPC(pc);
+    for (ICStub *stub = entry.firstStub(); stub; stub = stub->next()) {
+        if (stub->isCall_Native() && stub->toCall_Native()->callee()->native() == native)
+            return stub->toCall_Native()->templateObject();
+    }
+
+    return NULL;
+}
--- a/js/src/jit/BaselineInspector.h
+++ b/js/src/jit/BaselineInspector.h
@@ -105,16 +105,19 @@ class BaselineInspector
     MCompare::CompareType expectedCompareType(jsbytecode *pc);
     MIRType expectedBinaryArithSpecialization(jsbytecode *pc);
 
     bool hasSeenNonNativeGetElement(jsbytecode *pc);
     bool hasSeenNegativeIndexGetElement(jsbytecode *pc);
     bool hasSeenAccessedGetter(jsbytecode *pc);
     bool hasSeenDoubleResult(jsbytecode *pc);
     bool hasSeenNonStringIterNext(jsbytecode *pc);
+
+    JSObject *getTemplateObject(jsbytecode *pc);
+    JSObject *getTemplateObjectForNative(jsbytecode *pc, Native native);
 };
 
 } // namespace jit
 } // namespace js
 
 #endif // JS_ION
 
 #endif /* jit_BaselineInspector_h */
--- a/js/src/jit/IonBuilder.cpp
+++ b/js/src/jit/IonBuilder.cpp
@@ -1429,23 +1429,23 @@ IonBuilder::inspectOpcode(JSOp op)
       case JSOP_POPN:
         for (uint32_t i = 0, n = GET_UINT16(pc); i < n; i++)
             current->pop();
         return true;
 
       case JSOP_NEWINIT:
         if (GET_UINT8(pc) == JSProto_Array)
             return jsop_newarray(0);
-        return jsop_newobject(nullptr);
+        return jsop_newobject();
 
       case JSOP_NEWARRAY:
         return jsop_newarray(GET_UINT24(pc));
 
       case JSOP_NEWOBJECT:
-        return jsop_newobject(info().getObject(pc));
+        return jsop_newobject();
 
       case JSOP_INITELEM:
         return jsop_initelem();
 
       case JSOP_INITELEM_ARRAY:
         return jsop_initelem_array();
 
       case JSOP_INITPROP:
@@ -4629,34 +4629,40 @@ IonBuilder::createThisScriptedSingleton(
     // Get the singleton prototype (if exists)
     JSObject *proto = getSingletonPrototype(target);
     if (!proto)
         return nullptr;
 
     if (!target->nonLazyScript()->types)
         return nullptr;
 
+    JSObject *templateObject = inspector->getTemplateObject(pc);
+    if (!templateObject || !templateObject->is<JSObject>())
+        return nullptr;
+    if (templateObject->getProto() != proto)
+        return nullptr;
+
+    if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(templateObject)))
+        return nullptr;
+
+    // For template objects with NewScript info, the appropriate allocation
+    // kind to use may change due to dynamic property adds. In these cases
+    // calling Ion code will be invalidated, but any baseline template object
+    // may be stale. Update to the correct template object in this case.
+    types::TypeObject *templateType = templateObject->type();
+    if (templateType->hasNewScript()) {
+        templateObject = templateType->newScript()->templateObject;
+        JS_ASSERT(templateObject->type() == templateType);
+
+        // Trigger recompilation if the templateObject changes.
+        types::TypeObjectKey::get(templateType)->watchStateChangeForNewScriptTemplate(constraints());
+    }
+
     // Generate an inline path to create a new |this| object with
     // the given singleton prototype.
-    types::TypeObject *type = cx->getNewType(&JSObject::class_, proto, target);
-    if (!type)
-        return nullptr;
-    if (!types::TypeScript::ThisTypes(target->nonLazyScript())->hasType(types::Type::ObjectType(type)))
-        return nullptr;
-
-    RootedObject targetRoot(cx, target);
-    JSObject *templateObject = CreateThisForFunctionWithProto(cx, targetRoot, proto, TenuredObject);
-    if (!templateObject)
-        return nullptr;
-
-    // Trigger recompilation if the templateObject changes.
-    types::TypeObjectKey *templateType = types::TypeObjectKey::get(templateObject);
-    if (templateType->newScript())
-        templateType->watchStateChangeForNewScriptTemplate(constraints());
-
     MCreateThisWithTemplate *createThis = MCreateThisWithTemplate::New(templateObject);
     current->add(createThis);
 
     return createThis;
 }
 
 MDefinition *
 IonBuilder::createThis(JSFunction *target, MDefinition *callee)
@@ -5329,48 +5335,26 @@ IonBuilder::jsop_compare(JSOp op)
 
     ins->infer(inspector, pc);
 
     if (ins->isEffectful() && !resumeAfter(ins))
         return false;
     return true;
 }
 
-JSObject *
-IonBuilder::getNewArrayTemplateObject(uint32_t count)
-{
-    NewObjectKind newKind = types::UseNewTypeForInitializer(script(), pc, JSProto_Array);
-
-    // Do not allocate template objects in the nursery.
-    if (newKind == GenericObject)
-        newKind = TenuredObject;
-
-    JSObject *templateObject = NewDenseUnallocatedArray(cx, count, nullptr, newKind);
-    if (!templateObject)
-        return nullptr;
-
-    if (newKind != SingletonObject) {
-        types::TypeObject *type = types::TypeScript::InitObject(cx, script(), pc, JSProto_Array);
-        if (!type)
-            return nullptr;
-        templateObject->setType(type);
-    }
-
-    return templateObject;
-}
-
 bool
 IonBuilder::jsop_newarray(uint32_t count)
 {
     JS_ASSERT(script()->compileAndGo);
 
-    JSObject *templateObject = getNewArrayTemplateObject(count);
+    JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject)
-        return false;
-
+        return abort("No template object for NEWARRAY");
+
+    JS_ASSERT(templateObject->is<ArrayObject>());
     if (templateObject->type()->unknownProperties()) {
         // We will get confused in jsop_initelem_array if we can't find the
         // type object being initialized.
         return abort("New array has unknown properties");
     }
 
     types::TemporaryTypeSet::DoubleConversion conversion =
         bytecodeTypes(pc)->convertDoubleElements(constraints());
@@ -5381,46 +5365,26 @@ IonBuilder::jsop_newarray(uint32_t count
 
     current->add(ins);
     current->push(ins);
 
     return true;
 }
 
 bool
-IonBuilder::jsop_newobject(JSObject *baseObj)
+IonBuilder::jsop_newobject()
 {
     // Don't bake in the TypeObject for non-CNG scripts.
     JS_ASSERT(script()->compileAndGo);
 
-    NewObjectKind newKind = types::UseNewTypeForInitializer(script(), pc, JSProto_Object);
-
-    // Do not allocate template objects in the nursery.
-    if (newKind == GenericObject)
-        newKind = TenuredObject;
-
-    JSObject *templateObject;
-    if (baseObj) {
-        RootedObject baseObjRoot(cx, baseObj);
-        templateObject = CopyInitializerObject(cx, baseObjRoot, newKind);
-    } else {
-        gc::AllocKind allocKind = GuessObjectGCKind(0);
-        templateObject = NewBuiltinClassInstance(cx, &JSObject::class_, allocKind, newKind);
-    }
-
+    JSObject *templateObject = inspector->getTemplateObject(pc);
     if (!templateObject)
-        return false;
-
-    if (newKind != SingletonObject) {
-        types::TypeObject *type = types::TypeScript::InitObject(cx, script(), pc, JSProto_Object);
-        if (!type)
-            return false;
-        templateObject->setType(type);
-    }
-
+        return abort("No template object for NEWOBJECT");
+
+    JS_ASSERT(templateObject->is<JSObject>());
     MNewObject *ins = MNewObject::New(templateObject,
                                       /* templateObjectIsClassPrototype = */ false);
 
     current->add(ins);
     current->push(ins);
 
     return resumeAfter(ins);
 }
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -340,17 +340,16 @@ class IonBuilder : public MIRGenerator
     MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj);
 
     MDefinition *walkScopeChain(unsigned hops);
 
     MInstruction *addConvertElementsToDoubles(MDefinition *elements);
     MInstruction *addBoundsCheck(MDefinition *index, MDefinition *length);
     MInstruction *addShapeGuard(MDefinition *obj, Shape *const shape, BailoutKind bailoutKind);
 
-    JSObject *getNewArrayTemplateObject(uint32_t count);
     MDefinition *convertShiftToMaskForStaticTypedArray(MDefinition *id,
                                                        ArrayBufferView::ViewType viewType);
 
     bool invalidatedIdempotentCache();
 
     bool hasStaticScopeObject(ScopeCoordinate sc, JSObject **pcall);
     bool loadSlot(MDefinition *obj, Shape *shape, MIRType rvalType,
                   bool barrier, types::TemporaryTypeSet *types);
@@ -488,17 +487,17 @@ class IonBuilder : public MIRGenerator
     bool jsop_runonce();
     bool jsop_rest();
     bool jsop_not();
     bool jsop_getprop(PropertyName *name);
     bool jsop_setprop(PropertyName *name);
     bool jsop_delprop(PropertyName *name);
     bool jsop_delelem();
     bool jsop_newarray(uint32_t count);
-    bool jsop_newobject(JSObject *baseObj);
+    bool jsop_newobject();
     bool jsop_initelem();
     bool jsop_initelem_array();
     bool jsop_initelem_getter_setter();
     bool jsop_initprop(PropertyName *name);
     bool jsop_initprop_getter_setter(PropertyName *name);
     bool jsop_regexp(RegExpObject *reobj);
     bool jsop_object(JSObject *obj);
     bool jsop_lambda(JSFunction *fun);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -3,16 +3,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "jsmath.h"
 
 #include "builtin/ParallelArray.h"
 #include "builtin/TestingFunctions.h"
+#include "jit/BaselineInspector.h"
 #include "jit/IonBuilder.h"
 #include "jit/Lowering.h"
 #include "jit/MIR.h"
 #include "jit/MIRGraph.h"
 
 #include "jsscriptinlines.h"
 
 #include "vm/StringObject-inl.h"
@@ -202,25 +203,27 @@ IonBuilder::inlineMathFunction(CallInfo 
 }
 
 IonBuilder::InliningStatus
 IonBuilder::inlineArray(CallInfo &callInfo)
 {
     uint32_t initLength = 0;
     MNewArray::AllocatingBehaviour allocating = MNewArray::NewArray_Unallocating;
 
+    JSObject *templateObject = inspector->getTemplateObjectForNative(pc, js_Array);
+    if (!templateObject)
+        return InliningStatus_NotInlined;
+    JS_ASSERT(templateObject->is<ArrayObject>());
+
     // Multiple arguments imply array initialization, not just construction.
     if (callInfo.argc() >= 2) {
         initLength = callInfo.argc();
         allocating = MNewArray::NewArray_Allocating;
 
-        types::TypeObject *baseType = types::TypeScript::InitObject(cx, script(), pc, JSProto_Array);
-        if (!baseType)
-            return InliningStatus_Error;
-        types::TypeObjectKey *type = types::TypeObjectKey::get(baseType);
+        types::TypeObjectKey *type = types::TypeObjectKey::get(templateObject);
         if (!type->unknownProperties()) {
             types::HeapTypeSetKey elemTypes = type->property(JSID_VOID);
 
             for (uint32_t i = 0; i < initLength; i++) {
                 MDefinition *value = callInfo.getArg(i);
                 if (!TypeSetIncludes(elemTypes.maybeTypes(), value->type(), value->resultTypeSet())) {
                     elemTypes.freeze(constraints());
                     return InliningStatus_NotInlined;
@@ -240,20 +243,16 @@ IonBuilder::inlineArray(CallInfo &callIn
         // Negative lengths generate a RangeError, unhandled by the inline path.
         initLength = arg->toConstant()->value().toInt32();
         if (initLength >= JSObject::NELEMENTS_LIMIT)
             return InliningStatus_NotInlined;
     }
 
     callInfo.unwrapArgs();
 
-    JSObject *templateObject = getNewArrayTemplateObject(initLength);
-    if (!templateObject)
-        return InliningStatus_Error;
-
     types::TemporaryTypeSet::DoubleConversion conversion =
         getInlineReturnTypeSet()->convertDoubleElements(constraints());
     if (conversion == types::TemporaryTypeSet::AlwaysConvertToDoubles)
         templateObject->setShouldConvertDoubleElements();
 
     MNewArray *ins = new MNewArray(initLength, templateObject, allocating);
     current->add(ins);
     current->push(ins);
@@ -495,20 +494,20 @@ IonBuilder::inlineArrayConcat(CallInfo &
             return InliningStatus_NotInlined;
 
         types::HeapTypeSetKey elemTypes = argType->property(JSID_VOID);
         if (!elemTypes.knownSubset(constraints(), thisElemTypes))
             return InliningStatus_NotInlined;
     }
 
     // Inline the call.
-    JSObject *templateObj = NewDenseEmptyArray(cx, thisType->proto().toObject(), TenuredObject);
-    if (!templateObj)
-        return InliningStatus_Error;
-    templateObj->setType(baseThisType);
+    JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js::array_concat);
+    if (!templateObj || templateObj->type() != baseThisType)
+        return InliningStatus_NotInlined;
+    JS_ASSERT(templateObj->is<ArrayObject>());
 
     callInfo.unwrapArgs();
 
     MArrayConcat *ins = MArrayConcat::New(callInfo.thisArg(), callInfo.getArg(0), templateObj);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
@@ -891,22 +890,22 @@ IonBuilder::inlineStringObject(CallInfo 
     if (callInfo.argc() != 1 || !callInfo.constructing())
         return InliningStatus_NotInlined;
 
     // MToString only supports int32 or string values.
     MIRType type = callInfo.getArg(0)->type();
     if (type != MIRType_Int32 && type != MIRType_String)
         return InliningStatus_NotInlined;
 
-    callInfo.unwrapArgs();
+    JSObject *templateObj = inspector->getTemplateObjectForNative(pc, js_String);
+    if (!templateObj)
+        return InliningStatus_NotInlined;
+    JS_ASSERT(templateObj->is<StringObject>());
 
-    RootedString emptyString(cx, cx->runtime()->emptyString);
-    JSObject *templateObj = StringObject::create(cx, emptyString, TenuredObject);
-    if (!templateObj)
-        return InliningStatus_Error;
+    callInfo.unwrapArgs();
 
     MNewStringObject *ins = MNewStringObject::New(callInfo.getArg(0), templateObj);
     current->add(ins);
     current->push(ins);
 
     if (!resumeAfter(ins))
         return InliningStatus_Error;
 
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1062,33 +1062,33 @@ class ConstraintDataFreezeObjectForInlin
 
     bool constraintHolds(JSContext *cx,
                          const HeapTypeSetKey &property, TemporaryTypeSet *expected)
     {
         return true;
     }
 };
 
-// Constraint which triggers recompilation when the allocation kind of the
-// template object for a type's new script changes.
+// Constraint which triggers recompilation when the template object for a
+// type's new script changes.
 class ConstraintDataFreezeObjectForNewScriptTemplate
 {
-    gc::AllocKind allocKind;
+    JSObject *templateObject;
 
   public:
-    ConstraintDataFreezeObjectForNewScriptTemplate(gc::AllocKind allocKind)
-      : allocKind(allocKind)
+    ConstraintDataFreezeObjectForNewScriptTemplate(JSObject *templateObject)
+      : templateObject(templateObject)
     {}
 
     const char *kind() { return "freezeObjectForNewScriptTemplate"; }
 
     bool invalidateOnNewType(Type type) { return false; }
     bool invalidateOnNewPropertyState(TypeSet *property) { return false; }
     bool invalidateOnNewObjectState(TypeObject *object) {
-        return !object->hasNewScript() || object->newScript()->allocKind != allocKind;
+        return !object->hasNewScript() || object->newScript()->templateObject != templateObject;
     }
 
     bool constraintHolds(JSContext *cx,
                          const HeapTypeSetKey &property, TemporaryTypeSet *expected)
     {
         return !invalidateOnNewObjectState(property.object()->maybeType());
     }
 };
@@ -1126,19 +1126,19 @@ TypeObjectKey::watchStateChangeForInline
 {
     HeapTypeSetKey objectProperty = property(JSID_EMPTY);
     constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForInlinedCall> >(objectProperty, ConstraintDataFreezeObjectForInlinedCall()));
 }
 
 void
 TypeObjectKey::watchStateChangeForNewScriptTemplate(CompilerConstraintList *constraints)
 {
-    gc::AllocKind kind = asTypeObject()->newScript()->allocKind;
+    JSObject *templateObject = asTypeObject()->newScript()->templateObject;
     HeapTypeSetKey objectProperty = property(JSID_EMPTY);
-    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForNewScriptTemplate> >(objectProperty, ConstraintDataFreezeObjectForNewScriptTemplate(kind)));
+    constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForNewScriptTemplate> >(objectProperty, ConstraintDataFreezeObjectForNewScriptTemplate(templateObject)));
 }
 
 void
 TypeObjectKey::watchStateChangeForTypedArrayBuffer(CompilerConstraintList *constraints)
 {
     void *viewData = asSingleObject()->as<TypedArrayObject>().viewData();
     HeapTypeSetKey objectProperty = property(JSID_EMPTY);
     constraints->add(IonAlloc()->new_<CompilerConstraintInstance<ConstraintDataFreezeObjectForTypedArrayBuffer> >(objectProperty, ConstraintDataFreezeObjectForTypedArrayBuffer(viewData)));
@@ -3125,18 +3125,17 @@ CheckNewScriptProperties(JSContext *cx, 
     type->addendum = newScript;
 
     if (!newScript) {
         cx->compartment()->types.setPendingNukeTypes(cx);
         return;
     }
 
     newScript->fun = fun;
-    newScript->allocKind = kind;
-    newScript->shape = baseobj->lastProperty();
+    newScript->templateObject = baseobj;
 
     newScript->initializerList = (TypeNewScript::Initializer *)
         ((char *) newScript + sizeof(TypeNewScript));
     PodCopy(newScript->initializerList,
             initializerList.begin(),
             initializerList.length());
 #endif // JS_ION
 }
--- a/js/src/jsinfer.h
+++ b/js/src/jsinfer.h
@@ -815,24 +815,25 @@ struct TypeObjectAddendum
  * constraints are violated.
  */
 struct TypeNewScript : public TypeObjectAddendum
 {
     TypeNewScript();
 
     HeapPtrFunction fun;
 
-    /* Allocation kind to use for newly constructed objects. */
-    gc::AllocKind allocKind;
-
     /*
-     * Shape to use for newly constructed objects. Reflects all definite
-     * properties the object will have.
+     * Template object to use for newly constructed objects. Reflects all
+     * definite properties the object will have and the allocation kind to use
+     * for the object. The allocation kind --- and template object itself ---
+     * is subject to change if objects allocated with this type are given
+     * dynamic slots later on due to new properties being added after the
+     * constructor function finishes.
      */
-    HeapPtrShape  shape;
+    HeapPtrObject templateObject;
 
     /*
      * Order in which properties become initialized. We need this in case a
      * scripted setter is added to one of the object's prototypes while it is
      * in the middle of being initialized, so we can walk the stack and fixup
      * any objects which look for in-progress objects which were prematurely
      * set with their final shape. Property assignments in inner frames are
      * preceded by a series of SETPROP_FRAME entries specifying the stack down
--- a/js/src/jsinferinlines.h
+++ b/js/src/jsinferinlines.h
@@ -1412,17 +1412,17 @@ TypeNewScript::writeBarrierPre(TypeNewSc
 {
 #ifdef JSGC_INCREMENTAL
     if (!newScript || !newScript->fun->runtimeFromAnyThread()->needsBarrier())
         return;
 
     JS::Zone *zone = newScript->fun->zoneFromAnyThread();
     if (zone->needsBarrier()) {
         MarkObject(zone->barrierTracer(), &newScript->fun, "write barrier");
-        MarkShape(zone->barrierTracer(), &newScript->shape, "write barrier");
+        MarkObject(zone->barrierTracer(), &newScript->templateObject, "write barrier");
     }
 #endif
 }
 
 // Allocate a CompilerOutput for a finished compilation and generate the type
 // constraints for the compilation. Returns whether the type constraints
 // still hold.
 bool
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1557,35 +1557,39 @@ CreateThisForFunctionWithType(JSContext 
                               NewObjectKind newKind)
 {
     if (type->hasNewScript()) {
         /*
          * Make an object with the type's associated finalize kind and shape,
          * which reflects any properties that will definitely be added to the
          * object before it is read from.
          */
-        gc::AllocKind kind = type->newScript()->allocKind;
-        RootedObject res(cx, NewObjectWithType(cx, type, parent, kind, newKind));
+        RootedObject templateObject(cx, type->newScript()->templateObject);
+        JS_ASSERT(templateObject->type() == type);
+
+        RootedObject res(cx, CopyInitializerObject(cx, templateObject, newKind));
         if (!res)
             return nullptr;
-        RootedObject metadata(cx, res->getMetadata());
-        RootedShape shape(cx, type->newScript()->shape);
-        JS_ALWAYS_TRUE(JSObject::setLastProperty(cx, res, shape));
-        if (metadata && !JSObject::setMetadata(cx, res, metadata))
-            return nullptr;
+        if (newKind == SingletonObject) {
+            Rooted<TaggedProto> proto(cx, templateObject->getProto());
+            if (!res->splicePrototype(cx, &JSObject::class_, proto))
+                return NULL;
+        } else {
+            res->setType(type);
+        }
         return res;
     }
 
     gc::AllocKind allocKind = NewObjectGCKind(&JSObject::class_);
     return NewObjectWithType(cx, type, parent, allocKind, newKind);
 }
 
 JSObject *
 js::CreateThisForFunctionWithProto(JSContext *cx, HandleObject callee, JSObject *proto,
-                                  NewObjectKind newKind /* = GenericObject */)
+                                   NewObjectKind newKind /* = GenericObject */)
 {
     RootedObject res(cx);
 
     if (proto) {
         RootedTypeObject type(cx, cx->getNewType(&JSObject::class_, proto, &callee->as<JSFunction>()));
         if (!type)
             return nullptr;
         res = CreateThisForFunctionWithType(cx, type, callee->getParent(), newKind);
@@ -2519,33 +2523,33 @@ JSObject::growSlots(ThreadSafeContext *c
 
     /*
      * If we are allocating slots for an object whose type is always created
      * by calling 'new' on a particular script, bump the GC kind for that
      * type to give these objects a larger number of fixed slots when future
      * objects are constructed.
      */
     if (!obj->hasLazyType() && !oldCount && obj->type()->hasNewScript()) {
-        gc::AllocKind kind = obj->type()->newScript()->allocKind;
+        JSObject *oldTemplate = obj->type()->newScript()->templateObject;
+        gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(oldTemplate->numFixedSlots());
         uint32_t newScriptSlots = gc::GetGCKindSlots(kind);
         if (newScriptSlots == obj->numFixedSlots() &&
             gc::TryIncrementAllocKind(&kind) &&
             cx->isJSContext())
         {
             JSContext *ncx = cx->asJSContext();
             AutoEnterAnalysis enter(ncx);
 
             Rooted<TypeObject*> typeObj(cx, obj->type());
-            RootedShape shape(cx, typeObj->newScript()->shape);
+            RootedShape shape(cx, oldTemplate->lastProperty());
             JSObject *reshapedObj = NewReshapedObject(ncx, typeObj, obj->getParent(), kind, shape);
             if (!reshapedObj)
                 return false;
 
-            typeObj->newScript()->allocKind = kind;
-            typeObj->newScript()->shape = reshapedObj->lastProperty();
+            typeObj->newScript()->templateObject = reshapedObj;
             typeObj->markStateChange(ncx);
         }
     }
 
     if (!oldCount) {
         obj->slots = AllocateSlots(cx, obj, newCount);
         if (!obj->slots)
             return false;