mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 15:23:51 +00:00
Bug 1248163 - Inline typed array constructors r=jandem r=Waldo
This commit is contained in:
parent
677cf917fd
commit
8988e365a7
13
js/src/jit-test/tests/ion/recover-typed-array.js
Normal file
13
js/src/jit-test/tests/ion/recover-typed-array.js
Normal file
@ -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());
|
@ -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"
|
||||
@ -5465,7 +5466,7 @@ GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject
|
||||
}
|
||||
|
||||
static bool
|
||||
GetTemplateObjectForNative(JSContext* cx, JSFunction* target, const CallArgs& args,
|
||||
GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs& args,
|
||||
MutableHandleObject res, bool* skipAttach)
|
||||
{
|
||||
Native native = target->native();
|
||||
@ -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();
|
||||
|
@ -5446,6 +5446,12 @@ typedef PlainObject* (*ObjectCreateWithTemplateFn)(JSContext*, HandlePlainObject
|
||||
static const VMFunction ObjectCreateWithTemplateInfo =
|
||||
FunctionInfo<ObjectCreateWithTemplateFn>(ObjectCreateWithTemplate, "ObjectCreateWithTemplate");
|
||||
|
||||
typedef TypedArrayObject* (*TypedArrayCreateWithTemplateFn)(JSContext*, HandleObject);
|
||||
static const VMFunction TypedArrayCreateWithTemplateInfo =
|
||||
FunctionInfo<TypedArrayCreateWithTemplateFn>(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<TypedArrayObject>());
|
||||
|
||||
// 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)
|
||||
|
@ -126,6 +126,7 @@
|
||||
_(IntrinsicArrayBufferByteLength) \
|
||||
_(IntrinsicPossiblyWrappedArrayBufferByteLength) \
|
||||
\
|
||||
_(TypedArrayConstructor) \
|
||||
_(IntrinsicIsTypedArray) \
|
||||
_(IntrinsicIsPossiblyWrappedTypedArray) \
|
||||
_(IntrinsicTypedArrayLength) \
|
||||
|
@ -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);
|
||||
|
@ -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>());
|
||||
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;
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -3279,7 +3279,7 @@ class MNewObject
|
||||
public NoTypePolicy::Data
|
||||
{
|
||||
public:
|
||||
enum Mode { ObjectLiteral, ObjectCreate };
|
||||
enum Mode { ObjectLiteral, ObjectCreate, TypedArray };
|
||||
|
||||
private:
|
||||
gc::InitialHeap initialHeap_;
|
||||
|
@ -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>()) {
|
||||
TypedArrayObject* ttemplate = &ntemplate->as<TypedArrayObject>();
|
||||
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<InlineTypedObject>()) {
|
||||
|
@ -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<PlainObject>());
|
||||
break;
|
||||
case MNewObject::TypedArray:
|
||||
resultObject = TypedArrayCreateWithTemplate(cx, templateObject.as<TypedArrayObject>());
|
||||
break;
|
||||
}
|
||||
|
||||
if (!resultObject)
|
||||
|
@ -20,6 +20,7 @@ class DeclEnvObject;
|
||||
class StaticWithScope;
|
||||
class InlineTypedObject;
|
||||
class GeneratorObject;
|
||||
class TypedArrayObject;
|
||||
|
||||
namespace jit {
|
||||
|
||||
@ -281,6 +282,7 @@ template <> struct TypeToDataType<PlainObject*> { static const DataType result =
|
||||
template <> struct TypeToDataType<InlineTypedObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<DeclEnvObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<ArrayObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<TypedArrayObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<JSString*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<JSFlatString*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
|
||||
|
@ -205,18 +205,15 @@ ObjectGroup::useSingletonForAllocationSite(JSScript* script, jsbytecode* pc, JSP
|
||||
|
||||
/*
|
||||
* Objects created outside loops in global and eval scripts should have
|
||||
* singleton types. For now this is only done for plain objects and typed
|
||||
* arrays, but not normal arrays.
|
||||
* singleton types. For now this is only done for plain objects, but not
|
||||
* typed arrays or normal arrays.
|
||||
*/
|
||||
|
||||
if (script->functionNonDelazifying() && !script->treatAsRunOnce())
|
||||
return GenericObject;
|
||||
|
||||
if (key != JSProto_Object &&
|
||||
!(key >= JSProto_Int8Array && key <= JSProto_Uint8ClampedArray))
|
||||
{
|
||||
if (key != JSProto_Object)
|
||||
return GenericObject;
|
||||
}
|
||||
|
||||
// All loops in the script will have a try note indicating their boundary.
|
||||
|
||||
|
@ -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<typename ElementType>
|
||||
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<TypedArrayObject>();
|
||||
|
||||
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<int32_t>(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<int8_t> Int8Array;
|
||||
typedef TypedArrayObjectTemplate<uint8_t> Uint8Array;
|
||||
typedef TypedArrayObjectTemplate<int16_t> Int16Array;
|
||||
typedef TypedArrayObjectTemplate<uint16_t> Uint16Array;
|
||||
typedef TypedArrayObjectTemplate<int32_t> Int32Array;
|
||||
typedef TypedArrayObjectTemplate<uint32_t> Uint32Array;
|
||||
typedef TypedArrayObjectTemplate<float> Float32Array;
|
||||
typedef TypedArrayObjectTemplate<double> Float64Array;
|
||||
typedef TypedArrayObjectTemplate<uint8_clamped> Uint8ClampedArray;
|
||||
#define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \
|
||||
typedef TypedArrayObjectTemplate<T> 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<TypedArrayObject>());
|
||||
MOZ_ASSERT(old->is<TypedArrayObject>());
|
||||
TypedArrayObject* newObj = &obj->as<TypedArrayObject>();
|
||||
const TypedArrayObject* oldObj = &old->as<TypedArrayObject>();
|
||||
|
||||
// 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>());
|
||||
TypedArrayObject* obj = &templateObj->as<TypedArrayObject>();
|
||||
size_t len = obj->length();
|
||||
|
||||
switch (obj->type()) {
|
||||
#define CREATE_TYPED_ARRAY(T, N) \
|
||||
case Scalar::N: \
|
||||
return TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len, GenericObject);
|
||||
JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)
|
||||
#undef CREATE_TYPED_ARRAY
|
||||
default:
|
||||
MOZ_CRASH("Unsupported TypedArray type");
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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<T>::class_constructor && \
|
||||
len <= TypedArrayObject::INLINE_BUFFER_LIMIT / sizeof(T)) \
|
||||
{ \
|
||||
res.set(TypedArrayObjectTemplate<T>::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] = {
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user