Bug 1279992 - Inline constructor of typed arrays with non-compile-time known size. r=jandem, r=Waldo
☠☠ backed out by 5910a5ced959 ☠ ☠
authorSander Mathijs van Veen <smvv@kompiler.org>
Thu, 21 Jul 2016 07:57:00 -0400
changeset 346225 8f3feee738430140a75e80c725af121fbc42ed3e
parent 346224 1fd18c03c696d8c7789851b61844219fae3b8e95
child 346226 e4c2198977499384eec51031f1001f62d913f3e6
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem, Waldo
bugs1279992
milestone50.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 1279992 - Inline constructor of typed arrays with non-compile-time known size. r=jandem, r=Waldo
js/src/jit/BaselineIC.cpp
js/src/jit/CodeGenerator.cpp
js/src/jit/CodeGenerator.h
js/src/jit/Lowering.cpp
js/src/jit/Lowering.h
js/src/jit/MCallOptimize.cpp
js/src/jit/MIR.h
js/src/jit/MOpcodes.h
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
js/src/jit/shared/LIR-shared.h
js/src/jit/shared/LOpcodes-shared.h
js/src/vm/TypedArrayObject.cpp
js/src/vm/TypedArrayObject.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -5497,18 +5497,22 @@ GetTemplateObjectForNative(JSContext* cx
             // don't end up with a template whose structure might change later.
             res.set(NewFullyAllocatedArrayForCallingAllocationSite(cx, count, TenuredObject));
             if (!res)
                 return false;
             return true;
         }
     }
 
-    if (args.length() == 1 && args[0].isInt32() && args[0].toInt32() >= 0) {
-        uint32_t len = args[0].toInt32();
+    if (args.length() == 1) {
+        size_t len = 0;
+
+        if (args[0].isInt32() && args[0].toInt32() >= 0)
+            len = args[0].toInt32();
+
         if (TypedArrayObject::GetTemplateObjectForNative(cx, native, len, res))
             return !!res;
     }
 
     if (native == js::array_slice) {
         if (args.thisv().isObject()) {
             JSObject* obj = &args.thisv().toObject();
             if (!obj->isSingleton()) {
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -5435,17 +5435,44 @@ CodeGenerator::visitNewTypedArray(LNewTy
 
     OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
                                    ArgList(ImmGCPtr(templateObject), Imm32(n)),
                                    StoreRegisterTo(objReg));
 
     masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
                         ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
 
-    masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(), ttemplate);
+    masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
+                             ttemplate, TypedArrayLength::Fixed);
+
+    masm.bind(ool->rejoin());
+}
+
+void
+CodeGenerator::visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir)
+{
+    Register lengthReg = ToRegister(lir->length());
+    Register objReg = ToRegister(lir->output());
+    Register tempReg = ToRegister(lir->temp());
+    LiveRegisterSet liveRegs = lir->safepoint()->liveRegs();
+
+    JSObject* templateObject = lir->mir()->templateObject();
+    gc::InitialHeap initialHeap = lir->mir()->initialHeap();
+
+    TypedArrayObject* ttemplate = &templateObject->as<TypedArrayObject>();
+
+    OutOfLineCode* ool = oolCallVM(TypedArrayConstructorOneArgInfo, lir,
+                                   ArgList(ImmGCPtr(templateObject), lengthReg),
+                                   StoreRegisterTo(objReg));
+
+    masm.createGCObject(objReg, tempReg, templateObject, initialHeap,
+                        ool->entry(), /*initContents*/true, /*convertDoubleElements*/false);
+
+    masm.initTypedArraySlots(objReg, tempReg, lengthReg, liveRegs, ool->entry(),
+                             ttemplate, TypedArrayLength::Dynamic);
 
     masm.bind(ool->rejoin());
 }
 
 // Out-of-line object allocation for JSOP_NEWOBJECT.
 class OutOfLineNewObject : public OutOfLineCodeBase<CodeGenerator>
 {
     LNewObject* lir_;
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -190,16 +190,17 @@ class CodeGenerator final : public CodeG
     void visitDoubleToInt32(LDoubleToInt32* lir);
     void visitFloat32ToInt32(LFloat32ToInt32* lir);
     void visitNewArrayCallVM(LNewArray* lir);
     void visitNewArray(LNewArray* lir);
     void visitOutOfLineNewArray(OutOfLineNewArray* ool);
     void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir);
     void visitNewArrayDynamicLength(LNewArrayDynamicLength* lir);
     void visitNewTypedArray(LNewTypedArray* lir);
+    void visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir);
     void visitNewObjectVMCall(LNewObject* lir);
     void visitNewObject(LNewObject* lir);
     void visitOutOfLineNewObject(OutOfLineNewObject* ool);
     void visitNewTypedObject(LNewTypedObject* lir);
     void visitSimdBox(LSimdBox* lir);
     void visitSimdUnbox(LSimdUnbox* lir);
     void visitNewDeclEnvObject(LNewDeclEnvObject* lir);
     void visitNewCallObject(LNewCallObject* lir);
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -243,16 +243,27 @@ void
 LIRGenerator::visitNewTypedArray(MNewTypedArray* ins)
 {
     LNewTypedArray* lir = new(alloc()) LNewTypedArray(temp(), temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
+LIRGenerator::visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins)
+{
+    MDefinition* length = ins->length();
+    MOZ_ASSERT(length->type() == MIRType::Int32);
+
+    LNewTypedArrayDynamicLength* lir = new(alloc()) LNewTypedArrayDynamicLength(useRegister(length), temp());
+    define(lir, ins);
+    assignSafepoint(lir, ins);
+}
+
+void
 LIRGenerator::visitNewObject(MNewObject* ins)
 {
     LNewObject* lir = new(alloc()) LNewObject(temp());
     define(lir, ins);
     assignSafepoint(lir, ins);
 }
 
 void
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -70,16 +70,17 @@ class LIRGenerator : public LIRGenerator
     void visitCallee(MCallee* callee);
     void visitIsConstructing(MIsConstructing* ins);
     void visitGoto(MGoto* ins);
     void visitTableSwitch(MTableSwitch* tableswitch);
     void visitNewArray(MNewArray* ins);
     void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
     void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
     void visitNewTypedArray(MNewTypedArray* ins);
+    void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins);
     void visitNewObject(MNewObject* ins);
     void visitNewTypedObject(MNewTypedObject* ins);
     void visitNewDeclEnvObject(MNewDeclEnvObject* ins);
     void visitNewCallObject(MNewCallObject* ins);
     void visitNewSingletonCallObject(MNewSingletonCallObject* ins);
     void visitNewStringObject(MNewStringObject* ins);
     void visitNewDerivedTypedObject(MNewDerivedTypedObject* ins);
     void visitInitElem(MInitElem* ins);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -2297,50 +2297,55 @@ IonBuilder::inlineTypedArray(CallInfo& c
     if (callInfo.argc() != 1)
         return InliningStatus_NotInlined;
 
     MDefinition* arg = callInfo.getArg(0);
 
     if (arg->type() != MIRType::Int32)
         return InliningStatus_NotInlined;
 
-    if (!arg->maybeConstantValue())
-        return InliningStatus_NotInlined;
-
     JSObject* templateObject = inspector->getTemplateObjectForNative(pc, native);
 
     if (!templateObject) {
         trackOptimizationOutcome(TrackedOutcome::CantInlineNativeNoTemplateObj);
         return InliningStatus_NotInlined;
     }
 
     MOZ_ASSERT(templateObject->is<TypedArrayObject>());
     TypedArrayObject* obj = &templateObject->as<TypedArrayObject>();
 
     // Do not optimize when we see a template object with a singleton type,
     // since it hits at most once.
     if (templateObject->isSingleton())
         return InliningStatus_NotInlined;
 
-    // Negative lengths must throw a RangeError.  (We don't track that this
-    // might have previously thrown, when determining whether to inline, so we
-    // have to deal with this error case when inlining.)
-    int32_t providedLen = arg->maybeConstantValue()->toInt32();
-    if (providedLen < 0)
-        return InliningStatus_NotInlined;
-
-    uint32_t len = AssertedCast<uint32_t>(providedLen);
-
-    if (obj->length() != len)
-        return InliningStatus_NotInlined;
-
-    callInfo.setImplicitlyUsedUnchecked();
-
-    MInstruction* ins = MNewTypedArray::New(alloc(), constraints(), obj,
-                                            obj->group()->initialHeap(constraints()));
+    MInstruction* ins = nullptr;
+
+    if (!arg->isConstant()) {
+        callInfo.setImplicitlyUsedUnchecked();
+        ins = MNewTypedArrayDynamicLength::New(alloc(), constraints(), templateObject,
+                                               templateObject->group()->initialHeap(constraints()),
+                                               arg);
+    } else {
+        // Negative lengths must throw a RangeError.  (We don't track that this
+        // might have previously thrown, when determining whether to inline, so we
+        // have to deal with this error case when inlining.)
+        int32_t providedLen = arg->maybeConstantValue()->toInt32();
+        if (providedLen < 0)
+            return InliningStatus_NotInlined;
+
+        uint32_t len = AssertedCast<uint32_t>(providedLen);
+
+        if (obj->length() != len)
+            return InliningStatus_NotInlined;
+
+        callInfo.setImplicitlyUsedUnchecked();
+        ins = MNewTypedArray::New(alloc(), constraints(), obj,
+                                  obj->group()->initialHeap(constraints()));
+    }
 
     current->add(ins);
     current->push(ins);
     if (!resumeAfter(ins))
         return InliningStatus_Error;
 
     return InliningStatus_Inlined;
 }
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -3328,16 +3328,60 @@ class MNewTypedArray : public MNullaryIn
         return initialHeap_;
     }
 
     virtual AliasSet getAliasSet() const override {
         return AliasSet::None();
     }
 };
 
+class MNewTypedArrayDynamicLength
+  : public MUnaryInstruction,
+    public IntPolicy<0>::Data
+{
+    CompilerObject templateObject_;
+    gc::InitialHeap initialHeap_;
+
+    MNewTypedArrayDynamicLength(CompilerConstraintList* constraints, JSObject* templateObject,
+                           gc::InitialHeap initialHeap, MDefinition* length)
+      : MUnaryInstruction(length),
+        templateObject_(templateObject),
+        initialHeap_(initialHeap)
+    {
+        setGuard(); // Need to throw if length is negative.
+        setResultType(MIRType::Object);
+        if (!templateObject->isSingleton())
+            setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject));
+    }
+
+  public:
+    INSTRUCTION_HEADER(NewTypedArrayDynamicLength)
+
+    static MNewTypedArrayDynamicLength* New(TempAllocator& alloc, CompilerConstraintList* constraints,
+                                            JSObject* templateObject, gc::InitialHeap initialHeap,
+                                            MDefinition* length)
+    {
+        return new(alloc) MNewTypedArrayDynamicLength(constraints, templateObject, initialHeap, length);
+    }
+
+    MDefinition* length() const {
+        return getOperand(0);
+    }
+    JSObject* templateObject() const {
+        return templateObject_;
+    }
+    gc::InitialHeap initialHeap() const {
+        return initialHeap_;
+    }
+
+    virtual AliasSet getAliasSet() const override {
+        return AliasSet::None();
+    }
+};
+
 class MNewObject
   : public MUnaryInstruction,
     public NoTypePolicy::Data
 {
   public:
     enum Mode { ObjectLiteral, ObjectCreate };
 
   private:
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -125,16 +125,17 @@ namespace jit {
     _(ExtendInt32ToInt64)                                                   \
     _(Int64ToFloatingPoint)                                                 \
     _(ToString)                                                             \
     _(ToObjectOrNull)                                                       \
     _(NewArray)                                                             \
     _(NewArrayCopyOnWrite)                                                  \
     _(NewArrayDynamicLength)                                                \
     _(NewTypedArray)                                                        \
+    _(NewTypedArrayDynamicLength)                                           \
     _(NewObject)                                                            \
     _(NewTypedObject)                                                       \
     _(NewDeclEnvObject)                                                     \
     _(NewCallObject)                                                        \
     _(NewSingletonCallObject)                                               \
     _(NewStringObject)                                                      \
     _(ObjectState)                                                          \
     _(ArrayState)                                                           \
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -1054,32 +1054,32 @@ JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARR
         obj->initPrivate(buf);
         memset(buf, 0, nbytes);
     }
 }
 
 void
 MacroAssembler::initTypedArraySlots(Register obj, Register temp, Register lengthReg,
                                     LiveRegisterSet liveRegs, Label* fail,
-                                    TypedArrayObject* templateObj)
+                                    TypedArrayObject* templateObj, TypedArrayLength lengthKind)
 {
     MOZ_ASSERT(templateObj->hasPrivate());
     MOZ_ASSERT(!templateObj->hasBuffer());
 
     size_t dataSlotOffset = TypedArrayObject::dataOffset();
     size_t dataOffset = TypedArrayObject::dataOffset() + sizeof(HeapSlot);
 
     static_assert(TypedArrayObject::FIXED_DATA_START == TypedArrayObject::DATA_SLOT + 1,
                     "fixed inline element data assumed to begin after the data slot");
 
     // Initialise data elements to zero.
     int32_t length = templateObj->length();
     size_t nbytes = length * templateObj->bytesPerElement();
 
-    if (dataOffset + nbytes <= JSObject::MAX_BYTE_SIZE) {
+    if (lengthKind == TypedArrayLength::Fixed && dataOffset + nbytes <= JSObject::MAX_BYTE_SIZE) {
         MOZ_ASSERT(dataOffset + nbytes <= templateObj->tenuredSizeOfThis());
 
         // Store data elements inside the remaining JSObject slots.
         computeEffectiveAddress(Address(obj, dataOffset), temp);
         storePtr(temp, Address(obj, dataSlotOffset));
 
         // Write enough zero pointers into fixed data to zero every
         // element.  (This zeroes past the end of a byte count that's
@@ -1088,17 +1088,18 @@ MacroAssembler::initTypedArraySlots(Regi
         // and we won't inline unless the desired memory fits in that
         // space.)
         static_assert(sizeof(HeapSlot) == 8, "Assumed 8 bytes alignment");
 
         size_t numZeroPointers = ((nbytes + 7) & ~0x7) / sizeof(char *);
         for (size_t i = 0; i < numZeroPointers; i++)
             storePtr(ImmWord(0), Address(obj, dataOffset + i * sizeof(char *)));
     } else {
-        move32(Imm32(length), lengthReg);
+        if (lengthKind == TypedArrayLength::Fixed)
+            move32(Imm32(length), lengthReg);
 
         // Allocate a buffer on the heap to store the data elements.
         liveRegs.addUnchecked(temp);
         liveRegs.addUnchecked(obj);
         liveRegs.addUnchecked(lengthReg);
         PushRegsInMask(liveRegs);
         setupUnalignedABICall(temp);
         loadJSContext(temp);
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -30,16 +30,17 @@
 # error "Unknown architecture!"
 #endif
 #include "jit/AtomicOp.h"
 #include "jit/IonInstrumentation.h"
 #include "jit/JitCompartment.h"
 #include "jit/VMFunctions.h"
 #include "vm/ProxyObject.h"
 #include "vm/Shape.h"
+#include "vm/TypedArrayObject.h"
 #include "vm/UnboxedObject.h"
 
 // * How to read/write MacroAssembler method declarations:
 //
 // The following macros are made to avoid #ifdef around each method declarations
 // of the Macro Assembler, and they are also used as an hint on the location of
 // the implementations of each method.  For example, the following declaration
 //
@@ -1523,17 +1524,17 @@ class MacroAssembler : public MacroAssem
     void createGCObject(Register result, Register temp, JSObject* templateObj,
                         gc::InitialHeap initialHeap, Label* fail, bool initContents = true,
                         bool convertDoubleElements = false);
 
     void initGCThing(Register obj, Register temp, JSObject* templateObj,
                      bool initContents = true, bool convertDoubleElements = false);
     void initTypedArraySlots(Register obj, Register temp, Register lengthReg,
                              LiveRegisterSet liveRegs, Label* fail,
-                             TypedArrayObject* templateObj);
+                             TypedArrayObject* templateObj, TypedArrayLength lengthKind);
 
     void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject);
 
     void newGCString(Register result, Register temp, Label* fail);
     void newGCFatInlineString(Register result, Register temp, Label* fail);
 
     // Compares two strings for equality based on the JSOP.
     // This checks for identical pointers, atoms and length and fails for everything else.
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -1079,16 +1079,38 @@ class LNewTypedArray : public LInstructi
         return getTemp(1);
     }
 
     MNewTypedArray* mir() const {
         return mir_->toNewTypedArray();
     }
 };
 
+class LNewTypedArrayDynamicLength : public LInstructionHelper<1, 1, 1>
+{
+  public:
+    LIR_HEADER(NewTypedArrayDynamicLength)
+
+    explicit LNewTypedArrayDynamicLength(const LAllocation& length, const LDefinition& temp) {
+        setOperand(0, length);
+        setTemp(0, temp);
+    }
+
+    const LAllocation* length() {
+        return getOperand(0);
+    }
+    const LDefinition* temp() {
+        return getTemp(0);
+    }
+
+    MNewTypedArrayDynamicLength* mir() const {
+        return mir_->toNewTypedArrayDynamicLength();
+    }
+};
+
 class LNewObject : public LInstructionHelper<1, 0, 1>
 {
   public:
     LIR_HEADER(NewObject)
 
     explicit LNewObject(const LDefinition& temp) {
         setTemp(0, temp);
     }
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -63,16 +63,17 @@
     _(IsConstructing)               \
     _(TableSwitch)                  \
     _(TableSwitchV)                 \
     _(Goto)                         \
     _(NewArray)                     \
     _(NewArrayCopyOnWrite)          \
     _(NewArrayDynamicLength)        \
     _(NewTypedArray)                \
+    _(NewTypedArrayDynamicLength)   \
     _(ArraySplice)                  \
     _(NewObject)                    \
     _(NewTypedObject)               \
     _(NewDeclEnvObject)             \
     _(NewCallObject)                \
     _(NewSingletonCallObject)       \
     _(NewStringObject)              \
     _(NewDerivedTypedObject)        \
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -38,16 +38,17 @@
 #include "vm/GlobalObject.h"
 #include "vm/Interpreter.h"
 #include "vm/SelfHosting.h"
 #include "vm/TypedArrayCommon.h"
 #include "vm/WrapperObject.h"
 
 #include "jsatominlines.h"
 
+#include "gc/Nursery-inl.h"
 #include "gc/StoreBuffer-inl.h"
 #include "vm/ArrayBufferObject-inl.h"
 #include "vm/NativeObject-inl.h"
 #include "vm/Shape-inl.h"
 
 using namespace js;
 using namespace js::gc;
 
@@ -101,16 +102,23 @@ TypedArrayObject::ensureHasBuffer(JSCont
     if (!buffer)
         return false;
 
     if (!buffer->addView(cx, tarray))
         return false;
 
     // tarray is not shared, because if it were it would have a buffer.
     memcpy(buffer->dataPointer(), tarray->viewDataUnshared(), tarray->byteLength());
+
+    // Free the data slot pointer if has no inline data
+    if (!tarray->hasInlineElements() && !cx->runtime()->gc.nursery.isInside(tarray->elements())) {
+        js_free(tarray->elements());
+        tarray->setInlineElements();
+    }
+
     tarray->setPrivate(buffer->dataPointer());
 
     tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*buffer));
 
     // Notify compiled jit code that the base pointer has moved.
     MarkObjectStateChange(cx, tarray);
 
     return true;
@@ -157,16 +165,17 @@ TypedArrayObject::objectMoved(JSObject* 
 
 /* static */ size_t
 TypedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* obj, const JSObject* old,
                                            gc::AllocKind newAllocKind)
 {
     TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
     const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
     MOZ_ASSERT(newObj->elements() == oldObj->elements());
+    MOZ_ASSERT(obj->isTenured());
 
     // Typed arrays with a buffer object do not need an update.
     if (oldObj->hasBuffer())
         return 0;
 
     Nursery& nursery = trc->runtime()->gc.nursery;
     void* buf = oldObj->elements();
 
@@ -590,30 +599,16 @@ class TypedArrayObjectTemplate : public 
 #endif
 
             void* data = tarray->fixedData(FIXED_DATA_START);
             tarray->initPrivate(data);
             memset(data, 0, nbytes);
         }
     }
 
-    static void*
-    allocateTypedArrayElementsBuffer(JSContext* cx, uint32_t len)
-    {
-        if (len == 0)
-            return nullptr;
-
-        void* buf = cx->runtime()->pod_callocCanGC<HeapSlot>(len);
-        if (!buf) {
-            ReportOutOfMemory(cx);
-            return nullptr;
-        }
-        return buf;
-    }
-
     static TypedArrayObject*
     makeTypedArrayWithTemplate(JSContext* cx, TypedArrayObject* templateObj, uint32_t len)
     {
         size_t nbytes;
         if (!js::CalculateAllocSize<NativeType>(len, &nbytes))
             return nullptr;
 
         MOZ_ASSERT(nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH);
@@ -626,27 +621,36 @@ class TypedArrayObjectTemplate : public 
                                   ? GetGCObjectKind(clasp)
                                   : AllocKindForLazyBuffer(len * sizeof(NativeType));
         MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, clasp));
         allocKind = GetBackgroundAllocKind(allocKind);
         RootedObjectGroup group(cx, templateObj->group());
 
         NewObjectKind newKind = GenericObject;
 
-        void* buf = nullptr;
-        if (!fitsInline) {
-            buf = allocateTypedArrayElementsBuffer(cx, len);
-            if (!buf)
-                return nullptr;
-        }
-
         RootedObject tmp(cx, NewObjectWithGroup<TypedArrayObject>(cx, group, allocKind, newKind));
         if (!tmp)
             return nullptr;
 
+        void* buf = nullptr;
+        if (!fitsInline && len > 0) {
+            buf = js::AllocateObjectBuffer<NativeType>(cx, len);
+            //buf = cx->runtime()->pod_callocCanGC<HeapSlot>(len);
+            if (!buf) {
+                ReportOutOfMemory(cx);
+                return nullptr;
+            }
+
+            memset(buf, 0, nbytes);
+
+            Nursery& nursery = cx->runtime()->gc.nursery;
+            if (!nursery.isInside(buf))
+                newKind = TenuredObject;
+        }
+
         TypedArrayObject* obj = &tmp->as<TypedArrayObject>();
         initTypedArraySlots(obj, len, buf, allocKind);
 
         return obj;
     }
 
     /*
      * new [Type]Array(length)
@@ -1246,21 +1250,21 @@ TypedArrayConstructor(JSContext* cx, uns
 /* static */ bool
 TypedArrayObject::GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len,
                                              MutableHandleObject res)
 {
 #define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \
     if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \
         size_t nbytes; \
         if (!js::CalculateAllocSize<T>(len, &nbytes)) \
-            return false; \
+            return true; \
         \
         if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \
             res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \
-            return !!res; \
+            return true; \
         } \
     }
 JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)
 #undef CHECK_TYPED_ARRAY_CONSTRUCTOR
     return false;
 }
 
 /*
--- a/js/src/vm/TypedArrayObject.h
+++ b/js/src/vm/TypedArrayObject.h
@@ -26,16 +26,18 @@
     macro(float, Float32) \
     macro(double, Float64) \
     macro(uint8_clamped, Uint8Clamped)
 
 typedef struct JSProperty JSProperty;
 
 namespace js {
 
+enum class TypedArrayLength { Fixed, Dynamic };
+
 /*
  * TypedArrayObject
  *
  * The non-templated base class for the specific typed implementations.
  * This class holds all the member variables that are used by
  * the subclasses.
  */