From 091336138ac4993d6b7912ed2c5f256544e84090 Mon Sep 17 00:00:00 2001 From: Sander Mathijs van Veen Date: Tue, 28 Jun 2016 04:28:00 +0200 Subject: [PATCH] Bug 1248163 - Inline typed array constructors r=jandem r=Waldo --HG-- extra : rebase_source : 7cdd013ce65bb30ccc97ae4f16cb0925ec8118a0 --- .../jit-test/tests/ion/recover-typed-array.js | 13 ++ js/src/jit/BaselineIC.cpp | 7 + js/src/jit/CodeGenerator.cpp | 23 ++- js/src/jit/InlinableNatives.h | 1 + js/src/jit/IonBuilder.h | 1 + js/src/jit/MCallOptimize.cpp | 78 ++++++++++ js/src/jit/MIR.h | 2 +- js/src/jit/MacroAssembler.cpp | 43 +++++- js/src/jit/Recover.cpp | 11 +- js/src/jit/VMFunctions.h | 2 + js/src/vm/TypedArrayObject.cpp | 144 ++++++++++++++++-- js/src/vm/TypedArrayObject.h | 7 + 12 files changed, 304 insertions(+), 28 deletions(-) create mode 100644 js/src/jit-test/tests/ion/recover-typed-array.js diff --git a/js/src/jit-test/tests/ion/recover-typed-array.js b/js/src/jit-test/tests/ion/recover-typed-array.js new file mode 100644 index 000000000000..9a48a2018a9c --- /dev/null +++ b/js/src/jit-test/tests/ion/recover-typed-array.js @@ -0,0 +1,13 @@ +function f () { + var x = new Uint8Array(4); + empty(); + assertRecoveredOnBailout(x, true); + var res = inIon(); + bailout(); + return res; +} + +function empty() { +} + +while(!f()); diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 307abeef3a55..0b55eabb5c31 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -32,6 +32,7 @@ #include "vm/Opcodes.h" #include "vm/SelfHosting.h" #include "vm/TypedArrayCommon.h" +#include "vm/TypedArrayObject.h" #include "jsboolinlines.h" #include "jsscriptinlines.h" @@ -5501,6 +5502,12 @@ GetTemplateObjectForNative(JSContext* cx, JSFunction* target, const CallArgs& ar } } + if (args.length() == 1 && args[0].isInt32() && args[0].toInt32() >= 0) { + uint32_t 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(); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index cc6713fd8d87..b612f4a921bb 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -5446,6 +5446,12 @@ typedef PlainObject* (*ObjectCreateWithTemplateFn)(JSContext*, HandlePlainObject static const VMFunction ObjectCreateWithTemplateInfo = FunctionInfo(ObjectCreateWithTemplate, "ObjectCreateWithTemplate"); +typedef TypedArrayObject* (*TypedArrayCreateWithTemplateFn)(JSContext*, HandleObject); +static const VMFunction TypedArrayCreateWithTemplateInfo = + FunctionInfo(TypedArrayCreateWithTemplate, + "TypedArrayCreateWithTemplate"); + + void CodeGenerator::visitNewObjectVMCall(LNewObject* lir) { @@ -5456,11 +5462,17 @@ CodeGenerator::visitNewObjectVMCall(LNewObject* lir) JSObject* templateObject = lir->mir()->templateObject(); + MNewObject::Mode mode_ = lir->mir()->mode(); + + MOZ_ASSERT_IF(mode_ != MNewObject::TypedArray && templateObject, + !templateObject->is()); + // If we're making a new object with a class prototype (that is, an object // that derives its class from its prototype instead of being // PlainObject::class_'d) from self-hosted code, we need a different init // function. - if (lir->mir()->mode() == MNewObject::ObjectLiteral) { + switch (mode_) { + case MNewObject::ObjectLiteral: if (templateObject) { pushArg(ImmGCPtr(templateObject)); callVM(NewInitObjectWithTemplateInfo, lir); @@ -5470,10 +5482,15 @@ CodeGenerator::visitNewObjectVMCall(LNewObject* lir) pushArg(ImmGCPtr(lir->mir()->block()->info().script())); callVM(NewInitObjectInfo, lir); } - } else { - MOZ_ASSERT(lir->mir()->mode() == MNewObject::ObjectCreate); + break; + case MNewObject::ObjectCreate: pushArg(ImmGCPtr(templateObject)); callVM(ObjectCreateWithTemplateInfo, lir); + break; + case MNewObject::TypedArray: + pushArg(ImmGCPtr(templateObject)); + callVM(TypedArrayCreateWithTemplateInfo, lir); + break; } if (ReturnReg != objReg) diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index a4a87a3deaee..e90e6ea90549 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -126,6 +126,7 @@ _(IntrinsicArrayBufferByteLength) \ _(IntrinsicPossiblyWrappedArrayBufferByteLength) \ \ + _(TypedArrayConstructor) \ _(IntrinsicIsTypedArray) \ _(IntrinsicIsPossiblyWrappedTypedArray) \ _(IntrinsicTypedArrayLength) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 65da67fc54c0..318c3b8831d6 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -890,6 +890,7 @@ class IonBuilder // TypedArray intrinsics. enum WrappingBehavior { AllowWrappedTypedArrays, RejectWrappedTypedArrays }; + InliningStatus inlineTypedArray(CallInfo& callInfo, Native native); InliningStatus inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior); InliningStatus inlineIsTypedArray(CallInfo& callInfo); InliningStatus inlineIsPossiblyWrappedTypedArray(CallInfo& callInfo); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 43eddecfbc50..886d4109f513 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -4,6 +4,8 @@ * 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 "mozilla/Casting.h" + #include "jsmath.h" #include "jsobj.h" #include "jsstr.h" @@ -21,6 +23,7 @@ #include "vm/ArgumentsObject.h" #include "vm/ProxyObject.h" #include "vm/SelfHosting.h" +#include "vm/TypedArrayObject.h" #include "jsscriptinlines.h" @@ -30,6 +33,7 @@ #include "vm/UnboxedObject-inl.h" using mozilla::ArrayLength; +using mozilla::AssertedCast; using JS::DoubleNaNValue; using JS::TrackedOutcome; @@ -298,6 +302,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlinePossiblyWrappedArrayBufferByteLength(callInfo); // TypedArray intrinsics. + case InlinableNative::TypedArrayConstructor: + return inlineTypedArray(callInfo, target->native()); case InlinableNative::IntrinsicIsTypedArray: return inlineIsTypedArray(callInfo); case InlinableNative::IntrinsicIsPossiblyWrappedTypedArray: @@ -2275,6 +2281,78 @@ IonBuilder::inlinePossiblyWrappedArrayBufferByteLength(CallInfo& callInfo) return InliningStatus_Inlined; } +IonBuilder::InliningStatus +IonBuilder::inlineTypedArray(CallInfo& callInfo, Native native) +{ + if (!callInfo.constructing()) { + trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); + return InliningStatus_NotInlined; + } + + if (getInlineReturnType() != MIRType::Object) + return InliningStatus_NotInlined; + 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* obj = &templateObject->as(); + + // 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(providedLen); + + if (obj->length() != len) + return InliningStatus_NotInlined; + + // Large typed arrays have a separate buffer object, while small arrays + // have their values stored inline. + bool createBuffer = len > TypedArrayObject::INLINE_BUFFER_LIMIT / obj->bytesPerElement(); + + // Buffers are not supported yet! + if (createBuffer) + return InliningStatus_NotInlined; + + callInfo.setImplicitlyUsedUnchecked(); + + MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), obj); + current->add(templateConst); + + MNewObject* ins = MNewObject::New(alloc(), constraints(), templateConst, + obj->group()->initialHeap(constraints()), + MNewObject::TypedArray); + current->add(ins); + current->push(ins); + if (!resumeAfter(ins)) + return InliningStatus_Error; + + return InliningStatus_Inlined; +} + IonBuilder::InliningStatus IonBuilder::inlineIsTypedArrayHelper(CallInfo& callInfo, WrappingBehavior wrappingBehavior) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 8ac4e553eca0..3c67a1abf4d7 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -3279,7 +3279,7 @@ class MNewObject public NoTypePolicy::Data { public: - enum Mode { ObjectLiteral, ObjectCreate }; + enum Mode { ObjectLiteral, ObjectCreate, TypedArray }; private: gc::InitialHeap initialHeap_; diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index 4883b89bdb15..44bdbccc879e 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -1128,16 +1128,47 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj, } else { // If the target type could be a TypedArray that maps shared memory // then this would need to store emptyObjectElementsShared in that case. - // That cannot happen at present; TypedArray allocation is always - // a VM call. + MOZ_ASSERT(!ntemplate->isSharedMemory()); + storePtr(ImmPtr(emptyObjectElements), Address(obj, NativeObject::offsetOfElements())); initGCSlots(obj, temp, ntemplate, initContents); - if (ntemplate->hasPrivate()) { - uint32_t nfixed = ntemplate->numFixedSlots(); - storePtr(ImmPtr(ntemplate->getPrivate()), - Address(obj, NativeObject::getPrivateDataOffset(nfixed))); + if (ntemplate->is()) { + TypedArrayObject* ttemplate = &ntemplate->as(); + MOZ_ASSERT(ntemplate->hasPrivate()); + MOZ_ASSERT(!ttemplate->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"); + + computeEffectiveAddress(Address(obj, dataOffset), temp); + storePtr(temp, Address(obj, dataSlotOffset)); + + // Initialise inline data elements to zero. + size_t n = ttemplate->length() * ttemplate->bytesPerElement(); + MOZ_ASSERT(dataOffset + n <= JSObject::MAX_BYTE_SIZE); + + // Write enough zero pointers into fixed data to zero every + // element. (This zeroes past the end of a byte count that's + // not a multiple of pointer size. That's okay, because fixed + // data is a count of 8-byte HeapSlots (i.e. <= pointer size), + // 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 = ((n + 7) & ~0x7) / sizeof(char *); + for (size_t i = 0; i < numZeroPointers; i++) + storePtr(ImmWord(0), Address(obj, dataOffset + i * sizeof(char *))); + } else { + if (ntemplate->hasPrivate()) { + uint32_t nfixed = ntemplate->numFixedSlots(); + storePtr(ImmPtr(ntemplate->getPrivate()), + Address(obj, NativeObject::getPrivateDataOffset(nfixed))); + } } } } else if (templateObj->is()) { diff --git a/js/src/jit/Recover.cpp b/js/src/jit/Recover.cpp index 1bcc739257f0..e7ea510cf213 100644 --- a/js/src/jit/Recover.cpp +++ b/js/src/jit/Recover.cpp @@ -1202,11 +1202,16 @@ RNewObject::recover(JSContext* cx, SnapshotIterator& iter) const JSObject* resultObject = nullptr; // See CodeGenerator::visitNewObjectVMCall - if (mode_ == MNewObject::ObjectLiteral) { + switch (mode_) { + case MNewObject::ObjectLiteral: resultObject = NewObjectOperationWithTemplate(cx, templateObject); - } else { - MOZ_ASSERT(mode_ == MNewObject::ObjectCreate); + break; + case MNewObject::ObjectCreate: resultObject = ObjectCreateWithTemplate(cx, templateObject.as()); + break; + case MNewObject::TypedArray: + resultObject = TypedArrayCreateWithTemplate(cx, templateObject.as()); + break; } if (!resultObject) diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index a778cc197112..ce30a9257d0c 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -20,6 +20,7 @@ class DeclEnvObject; class StaticWithScope; class InlineTypedObject; class GeneratorObject; +class TypedArrayObject; namespace jit { @@ -281,6 +282,7 @@ template <> struct TypeToDataType { static const DataType result = template <> struct TypeToDataType { static const DataType result = Type_Object; }; template <> struct TypeToDataType { static const DataType result = Type_Object; }; template <> struct TypeToDataType { static const DataType result = Type_Object; }; +template <> struct TypeToDataType { static const DataType result = Type_Object; }; template <> struct TypeToDataType { static const DataType result = Type_Object; }; template <> struct TypeToDataType { static const DataType result = Type_Object; }; template <> struct TypeToDataType { static const DataType result = Type_Handle; }; diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 87821eda4fdd..3f271fe7a357 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -7,6 +7,7 @@ #include "vm/TypedArrayObject.h" #include "mozilla/Alignment.h" +#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/PodOperations.h" @@ -31,6 +32,7 @@ #include "builtin/TypedObjectConstants.h" #include "gc/Barrier.h" #include "gc/Marking.h" +#include "jit/InlinableNatives.h" #include "js/Conversions.h" #include "vm/ArrayBufferObject.h" #include "vm/GlobalObject.h" @@ -49,6 +51,7 @@ using namespace js; using namespace js::gc; +using mozilla::AssertedCast; using JS::CanonicalizeNaN; using JS::ToInt32; using JS::ToUint32; @@ -175,6 +178,17 @@ template static inline JSObject* NewArray(JSContext* cx, uint32_t nelements); +#define JS_FOR_EACH_TYPED_ARRAY(macro) \ + macro(int8_t, Int8) \ + macro(uint8_t, Uint8) \ + macro(int16_t, Int16) \ + macro(uint16_t, Uint16) \ + macro(int32_t, Int32) \ + macro(uint32_t, Uint32) \ + macro(float, Float32) \ + macro(double, Float64) \ + macro(uint8_clamped, Uint8Clamped) + namespace { // We allow nullptr for newTarget for all the creation methods, to allow for @@ -225,11 +239,16 @@ class TypedArrayObjectTemplate : public TypedArrayObject if (!ctorProto) return nullptr; - return NewFunctionWithProto(cx, class_constructor, 3, - JSFunction::NATIVE_CTOR, nullptr, - ClassName(key, cx), - ctorProto, gc::AllocKind::FUNCTION, - SingletonObject); + JSFunction* fun = NewFunctionWithProto(cx, class_constructor, 3, + JSFunction::NATIVE_CTOR, nullptr, + ClassName(key, cx), + ctorProto, gc::AllocKind::FUNCTION, + SingletonObject); + + if (fun) + fun->setJitInfo(&jit::JitInfo_TypedArrayConstructor); + + return fun; } static bool @@ -438,6 +457,45 @@ class TypedArrayObjectTemplate : public TypedArrayObject return makeInstance(cx, buffer, byteOffset, len, proto); } + static TypedArrayObject* + makeTemplateObject(JSContext* cx, uint32_t len, NewObjectKind newKind) + { + MOZ_ASSERT(len <= TypedArrayObject::INLINE_BUFFER_LIMIT / sizeof(NativeType)); + gc::AllocKind allocKind = AllocKindForLazyBuffer(len * sizeof(NativeType)); + + AutoSetNewObjectMetadata metadata(cx); + MOZ_ASSERT(len * sizeof(NativeType) < TypedArrayObject::SINGLETON_BYTE_LENGTH); + + const Class* clasp = instanceClass(); + jsbytecode* pc; + RootedScript script(cx, cx->currentScript(&pc)); + if (script && ObjectGroup::useSingletonForAllocationSite(script, pc, clasp)) + newKind = SingletonObject; + RootedObject tmp(cx, NewBuiltinClassInstance(cx, clasp, allocKind, newKind)); + if (!tmp) + return nullptr; + if (script && !ObjectGroup::setAllocationSiteObjectGroup(cx, script, pc, tmp, + newKind == SingletonObject)) + { + return nullptr; + } + + TypedArrayObject* tarray = &tmp->as(); + + void* data = tarray->fixedData(FIXED_DATA_START); + tarray->initPrivate(data); + memset(data, 0, len * sizeof(NativeType)); + + tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT, NullValue()); + tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(AssertedCast(len))); + tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(0)); + + // Verify that the private slot is at the expected place. + MOZ_ASSERT(tarray->numFixedSlots() == TypedArrayObject::DATA_SLOT); + + return tarray; + } + /* * new [Type]Array(length) * new [Type]Array(otherTypedArray) @@ -728,18 +786,52 @@ class TypedArrayObjectTemplate : public TypedArrayObject static Value getIndexValue(JSObject* tarray, uint32_t index); }; -typedef TypedArrayObjectTemplate Int8Array; -typedef TypedArrayObjectTemplate Uint8Array; -typedef TypedArrayObjectTemplate Int16Array; -typedef TypedArrayObjectTemplate Uint16Array; -typedef TypedArrayObjectTemplate Int32Array; -typedef TypedArrayObjectTemplate Uint32Array; -typedef TypedArrayObjectTemplate Float32Array; -typedef TypedArrayObjectTemplate Float64Array; -typedef TypedArrayObjectTemplate Uint8ClampedArray; +#define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \ + typedef TypedArrayObjectTemplate N##Array; +JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPE_FOR_TYPED_ARRAY) +#undef CREATE_TYPE_FOR_TYPED_ARRAY } /* anonymous namespace */ +static void +UpdateTypedArrayAfterMove(JSObject* obj, const JSObject* old) +{ + MOZ_ASSERT(obj->is()); + MOZ_ASSERT(old->is()); + TypedArrayObject* newObj = &obj->as(); + const TypedArrayObject* oldObj = &old->as(); + + // Typed arrays with a buffer or small typed arrays with a *shared* buffer object are not + // supported yet! + if (oldObj->hasBuffer()) + return; + + // Update the data slot pointer if it points to the old JSObject. + void* oldData = newObj->fixedData(TypedArrayObject::FIXED_DATA_START); + if (oldData == ((char *)oldObj) + oldObj->dataOffset()) { + void* newData = newObj->fixedData(TypedArrayObject::FIXED_DATA_START); + *(void **)((((char *)newObj) + newObj->dataOffset())) = newData; + } +} + +TypedArrayObject* +js::TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj) +{ + MOZ_ASSERT(templateObj->is()); + TypedArrayObject* obj = &templateObj->as(); + size_t len = obj->length(); + + switch (obj->type()) { +#define CREATE_TYPED_ARRAY(T, N) \ + case Scalar::N: \ + return TypedArrayObjectTemplate::makeTemplateObject(cx, len, GenericObject); +JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY) +#undef CREATE_TYPED_ARRAY + default: + MOZ_CRASH("Unsupported TypedArray type"); + } +} + template struct TypedArrayObject::OfType { @@ -1021,6 +1113,22 @@ TypedArrayConstructor(JSContext* cx, unsigned argc, Value* vp) return false; } +/* static */ bool +TypedArrayObject::GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len, + MutableHandleObject res) +{ +#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \ + if (native == &TypedArrayObjectTemplate::class_constructor && \ + len <= TypedArrayObject::INLINE_BUFFER_LIMIT / sizeof(T)) \ + { \ + res.set(TypedArrayObjectTemplate::makeTemplateObject(cx, len, TenuredObject)); \ + return true; \ + } +JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR) +#undef CHECK_TYPED_ARRAY_CONSTRUCTOR + return false; +} + /* * These next 3 functions are brought to you by the buggy GCC we use to build * B2G ICS. Older GCC versions have a bug in which they fail to compile @@ -2196,6 +2304,11 @@ static const ClassOps TypedArrayClassOps = { TypedArrayObject::trace, /* trace */ }; +static const ClassExtension TypedArrayClassExtension = { + nullptr, + UpdateTypedArrayAfterMove, +}; + #define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \ { \ _type##Array::createConstructor, \ @@ -2228,7 +2341,8 @@ static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \ JSCLASS_DELAY_METADATA_BUILDER, \ &TypedArrayClassOps, \ - &TypedArrayObjectClassSpecs[Scalar::Type::_type] \ + &TypedArrayObjectClassSpecs[Scalar::Type::_type], \ + &TypedArrayClassExtension \ } const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = { diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 9e5b5c2d2fe6..136522cd4b61 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -155,6 +155,10 @@ class TypedArrayObject : public NativeObject void notifyBufferDetached(void* newData); + static bool + GetTemplateObjectForNative(JSContext* cx, Native native, uint32_t len, + MutableHandleObject res); + /* * Byte length above which created typed arrays and data views will have * singleton types regardless of the context in which they are created. @@ -267,6 +271,9 @@ class TypedArrayObject : public NativeObject static bool set(JSContext* cx, unsigned argc, Value* vp); }; +extern TypedArrayObject* +TypedArrayCreateWithTemplate(JSContext* cx, HandleObject templateObj); + inline bool IsTypedArrayClass(const Class* clasp) {