mirror of
https://github.com/roytam1/UXP.git
synced 2026-05-26 14:54:25 +00:00
Guard typed array JIT paths for resizable buffers
This commit is contained in:
@@ -1464,6 +1464,12 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
|
||||
res.isNumber() &&
|
||||
!TypedArrayGetElemStubExists(stub, obj))
|
||||
{
|
||||
if (obj->is<TypedArrayObject>() &&
|
||||
obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
|
||||
{
|
||||
@@ -2154,6 +2160,8 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||
if (layout_ == Layout_TypedArray)
|
||||
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
|
||||
|
||||
// Ensure the index is an integer.
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
@@ -2625,6 +2633,9 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
|
||||
bool expectOutOfBounds;
|
||||
double idx = index.toNumber();
|
||||
if (obj->is<TypedArrayObject>()) {
|
||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
||||
return true;
|
||||
|
||||
expectOutOfBounds = (idx < 0 || idx >= double(obj->as<TypedArrayObject>().length()));
|
||||
} else {
|
||||
// Typed objects throw on out of bounds accesses. Don't attach
|
||||
@@ -3215,6 +3226,8 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
Register obj = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure);
|
||||
if (layout_ == Layout_TypedArray)
|
||||
GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure);
|
||||
|
||||
// Ensure the index is an integer.
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
|
||||
@@ -8889,9 +8889,17 @@ CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target)
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElements),
|
||||
&emptyObj);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
masm.branchPtr(Assembler::Equal,
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElementsShared),
|
||||
&emptyObj);
|
||||
masm.branchPtr(Assembler::Equal,
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElementsResizableOrGrowable),
|
||||
&emptyObj);
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(obj, NativeObject::offsetOfElements()),
|
||||
ImmPtr(js::emptyObjectElementsSharedResizableOrGrowable),
|
||||
target);
|
||||
masm.bind(&emptyObj);
|
||||
}
|
||||
|
||||
@@ -535,8 +535,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||
Label* ifDoesntEmulateUndefined,
|
||||
Register scratch, OutOfLineTestObject* ool);
|
||||
|
||||
// Branch to target unless obj has an emptyObjectElements or emptyObjectElementsShared
|
||||
// elements pointer.
|
||||
// Branch to target unless obj has one of the empty elements pointers.
|
||||
void branchIfNotEmptyObjectElements(Register obj, Label* target);
|
||||
|
||||
void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType,
|
||||
|
||||
@@ -1245,6 +1245,7 @@ GenerateTypedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta
|
||||
masm.branchPtr(Assembler::AboveOrEqual, tmpReg,
|
||||
ImmPtr(&TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]),
|
||||
failures);
|
||||
GuardResizableOrGrowableTypedArray(masm, object, tmpReg, failures);
|
||||
|
||||
// Load length.
|
||||
masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output);
|
||||
@@ -1644,6 +1645,9 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript
|
||||
if (!JSID_IS_ATOM(id, cx->names().length))
|
||||
return true;
|
||||
|
||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
||||
return true;
|
||||
|
||||
if (hasTypedArrayLengthStub(obj))
|
||||
return true;
|
||||
|
||||
@@ -4038,6 +4042,12 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i
|
||||
if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
|
||||
return false;
|
||||
|
||||
if (obj->is<TypedArrayObject>() &&
|
||||
obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(idval.isInt32() || idval.isString());
|
||||
|
||||
// Don't emit a stub if the access is out of bounds. We make to make
|
||||
@@ -4092,6 +4102,9 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
|
||||
// Decide to what type index the stub should be optimized
|
||||
Register tmpReg = output.scratchReg().gpr();
|
||||
MOZ_ASSERT(tmpReg != InvalidReg);
|
||||
if (array->is<TypedArrayObject>())
|
||||
GuardResizableOrGrowableTypedArray(masm, object, tmpReg, &failures);
|
||||
|
||||
Register indexReg = tmpReg;
|
||||
if (idval.isString()) {
|
||||
MOZ_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX);
|
||||
@@ -4575,6 +4588,7 @@ GenerateSetTypedArrayElement(JSContext* cx, MacroAssembler& masm, IonCache::Stub
|
||||
if (!shape)
|
||||
return false;
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures);
|
||||
GuardResizableOrGrowableTypedArray(masm, object, temp, &failures);
|
||||
|
||||
// Ensure the index is an int32.
|
||||
Register indexReg;
|
||||
@@ -4661,6 +4675,9 @@ SetPropertyIC::tryAttachTypedArrayElement(JSContext* cx, HandleScript outerScrip
|
||||
if (!IsTypedArrayElementSetInlineable(obj, idval, val))
|
||||
return true;
|
||||
|
||||
if (obj->as<TypedArrayObject>().hasResizableOrGrowableBuffer())
|
||||
return true;
|
||||
|
||||
*emitted = true;
|
||||
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
|
||||
@@ -365,13 +365,9 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target)
|
||||
|
||||
// Try to optimize typed array lengths.
|
||||
if (TypedArrayObject::isOriginalLengthGetter(native)) {
|
||||
Scalar::Type type = thisTypes->getTypedArrayType(constraints());
|
||||
if (type == Scalar::MaxTypedArrayViewType)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MInstruction* length = addTypedArrayLength(thisArg);
|
||||
current->push(length);
|
||||
return InliningStatus_Inlined;
|
||||
// RAB/GSAB views can have dynamic length or temporarily become
|
||||
// out-of-bounds. Let the property IC/VM path handle the getter.
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Try to optimize RegExp getters.
|
||||
@@ -2480,21 +2476,10 @@ IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def)
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo)
|
||||
{
|
||||
MOZ_ASSERT(!callInfo.constructing());
|
||||
MOZ_ASSERT(callInfo.argc() == 1);
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (getInlineReturnType() != MIRType::Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
(void) callInfo;
|
||||
|
||||
if (!IsTypedArrayObject(constraints(), callInfo.getArg(0)))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MInstruction* length = addTypedArrayLength(callInfo.getArg(0));
|
||||
current->push(length);
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
return InliningStatus_Inlined;
|
||||
// RAB/GSAB views require dynamic length semantics.
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
@@ -3251,45 +3236,14 @@ bool
|
||||
IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType,
|
||||
bool* requiresTagCheck, AtomicCheckResult checkResult)
|
||||
{
|
||||
if (!JitSupportsAtomics())
|
||||
return false;
|
||||
(void) callInfo;
|
||||
(void) arrayType;
|
||||
(void) requiresTagCheck;
|
||||
(void) checkResult;
|
||||
|
||||
if (callInfo.getArg(0)->type() != MIRType::Object)
|
||||
return false;
|
||||
|
||||
if (callInfo.getArg(1)->type() != MIRType::Int32)
|
||||
return false;
|
||||
|
||||
// Ensure that the first argument is a TypedArray that maps shared
|
||||
// memory.
|
||||
//
|
||||
// Then check both that the element type is something we can
|
||||
// optimize and that the return type is suitable for that element
|
||||
// type.
|
||||
|
||||
TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet();
|
||||
if (!arg0Types)
|
||||
return false;
|
||||
|
||||
TemporaryTypeSet::TypedArraySharedness sharedness;
|
||||
*arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness);
|
||||
*requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared;
|
||||
switch (*arrayType) {
|
||||
case Scalar::Int8:
|
||||
case Scalar::Uint8:
|
||||
case Scalar::Int16:
|
||||
case Scalar::Uint16:
|
||||
case Scalar::Int32:
|
||||
return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32;
|
||||
case Scalar::Uint32:
|
||||
// Bug 1077305: it would be attractive to allow inlining even
|
||||
// if the inline return type is Int32, which it will frequently
|
||||
// be.
|
||||
return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double;
|
||||
default:
|
||||
// Excludes floating types and Uint8Clamped.
|
||||
return false;
|
||||
}
|
||||
// Atomics bounds checks through addTypedArrayLengthAndData assume stable
|
||||
// SharedArrayBuffer lengths. Avoid this path now that growable SAB exists.
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+8
-18
@@ -5505,25 +5505,15 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints,
|
||||
MDefinition* obj, MDefinition* id,
|
||||
Scalar::Type* arrayType)
|
||||
{
|
||||
if (obj->mightBeType(MIRType::String))
|
||||
return false;
|
||||
(void) constraints;
|
||||
(void) obj;
|
||||
(void) id;
|
||||
(void) arrayType;
|
||||
|
||||
if (id->type() != MIRType::Int32 && id->type() != MIRType::Double)
|
||||
return false;
|
||||
|
||||
TemporaryTypeSet* types = obj->resultTypeSet();
|
||||
if (!types)
|
||||
return false;
|
||||
|
||||
*arrayType = types->getTypedArrayType(constraints);
|
||||
|
||||
// FIXME: https://bugzil.la/1536699
|
||||
if (*arrayType == Scalar::MaxTypedArrayViewType ||
|
||||
Scalar::isBigIntType(*arrayType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Resizable ArrayBuffer and growable SharedArrayBuffer views need dynamic
|
||||
// length/out-of-bounds handling. This older MIR path assumes stable
|
||||
// typed-array length/data slots, so keep element accesses on IC/VM paths.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -3608,6 +3608,17 @@ CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Labe
|
||||
masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure);
|
||||
}
|
||||
|
||||
void
|
||||
GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch,
|
||||
Label* failure)
|
||||
{
|
||||
masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch);
|
||||
masm.branchTest32(Assembler::NonZero,
|
||||
Address(scratch, ObjectElements::offsetOfFlags()),
|
||||
Imm32(ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER),
|
||||
failure);
|
||||
}
|
||||
|
||||
void
|
||||
LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result)
|
||||
{
|
||||
|
||||
@@ -2302,6 +2302,10 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register
|
||||
void
|
||||
CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure);
|
||||
|
||||
void
|
||||
GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch,
|
||||
Label* failure);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
|
||||
MutableHandleValue result);
|
||||
|
||||
@@ -1748,6 +1748,9 @@ JS_IsFloat64Array(JSObject* obj);
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_GetTypedArraySharedness(JSObject* obj);
|
||||
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_GetTypedArrayLength(JSObject* obj);
|
||||
|
||||
/*
|
||||
* Test for specific typed array types (ArrayBufferView subtypes) and return
|
||||
* the unwrapped object if so, else nullptr. Never throws.
|
||||
@@ -1814,8 +1817,7 @@ inline void \
|
||||
Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \
|
||||
{ \
|
||||
MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \
|
||||
const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
|
||||
*length = mozilla::AssertedCast<uint32_t>(lenSlot.toInt32()); \
|
||||
*length = JS_GetTypedArrayLength(obj); \
|
||||
*isSharedMemory = JS_GetTypedArraySharedness(obj); \
|
||||
*data = static_cast<type*>(GetObjectPrivate(obj)); \
|
||||
}
|
||||
|
||||
@@ -66,5 +66,58 @@ assertEq(sharedTracking.length, 8);
|
||||
sharedTracking[6] = 33;
|
||||
assertEq(new Uint8Array(gsab)[6], 33);
|
||||
|
||||
function readLength(view) {
|
||||
return view.length;
|
||||
}
|
||||
|
||||
function readElement(view, index) {
|
||||
return view[index];
|
||||
}
|
||||
|
||||
function writeElement(view, index, value) {
|
||||
view[index] = value;
|
||||
}
|
||||
|
||||
var normal = new Uint8Array(4);
|
||||
normal[0] = 7;
|
||||
for (var i = 0; i < 2000; i++) {
|
||||
assertEq(readLength(normal), 4);
|
||||
assertEq(readElement(normal, 0), 7);
|
||||
writeElement(normal, 1, 8);
|
||||
}
|
||||
|
||||
var icRab = new ArrayBuffer(4, { maxByteLength: 8 });
|
||||
var icTracking = new Uint8Array(icRab);
|
||||
icTracking[0] = 9;
|
||||
assertEq(readLength(icTracking), 4);
|
||||
assertEq(readElement(icTracking, 0), 9);
|
||||
icRab.resize(0);
|
||||
assertEq(readLength(icTracking), 0);
|
||||
assertEq(readElement(icTracking, 0), undefined);
|
||||
writeElement(icTracking, 0, 1);
|
||||
icRab.resize(4);
|
||||
assertEq(readLength(icTracking), 4);
|
||||
assertEq(readElement(icTracking, 0), 0);
|
||||
writeElement(icTracking, 0, 12);
|
||||
assertEq(readElement(icTracking, 0), 12);
|
||||
|
||||
var icFixed = new Uint8Array(icRab, 1, 2);
|
||||
assertEq(readLength(icFixed), 2);
|
||||
icRab.resize(2);
|
||||
assertEq(readLength(icFixed), 0);
|
||||
assertEq(readElement(icFixed, 0), undefined);
|
||||
writeElement(icFixed, 0, 55);
|
||||
icRab.resize(4);
|
||||
assertEq(readLength(icFixed), 2);
|
||||
assertEq(readElement(icFixed, 0), 0);
|
||||
|
||||
var icGsab = new SharedArrayBuffer(4, { maxByteLength: 8 });
|
||||
var icSharedTracking = new Uint8Array(icGsab);
|
||||
assertEq(readLength(icSharedTracking), 4);
|
||||
icGsab.grow(8);
|
||||
assertEq(readLength(icSharedTracking), 8);
|
||||
writeElement(icSharedTracking, 5, 77);
|
||||
assertEq(readElement(icSharedTracking, 5), 77);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
||||
|
||||
@@ -43,6 +43,22 @@ static const ObjectElements emptyElementsHeaderShared(0, 0, ObjectElements::Shar
|
||||
HeapSlot* const js::emptyObjectElementsShared =
|
||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements));
|
||||
|
||||
static const ObjectElements emptyElementsHeaderResizableOrGrowable(
|
||||
0, 0, ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
|
||||
|
||||
/* Objects with no elements share one empty set of elements. */
|
||||
HeapSlot* const js::emptyObjectElementsResizableOrGrowable =
|
||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderResizableOrGrowable) +
|
||||
sizeof(ObjectElements));
|
||||
|
||||
static const ObjectElements emptyElementsHeaderSharedResizableOrGrowable(
|
||||
0, 0, ObjectElements::SHARED_MEMORY | ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER);
|
||||
|
||||
/* Objects with no elements share one empty set of elements. */
|
||||
HeapSlot* const js::emptyObjectElementsSharedResizableOrGrowable =
|
||||
reinterpret_cast<HeapSlot*>(uintptr_t(&emptyElementsHeaderSharedResizableOrGrowable) +
|
||||
sizeof(ObjectElements));
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
@@ -61,10 +77,12 @@ ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr)
|
||||
* This function is infallible, but has a fallible interface so that it can
|
||||
* be called directly from Ion code. Only arrays can have their dense
|
||||
* elements converted to doubles, and arrays never have empty elements.
|
||||
*/
|
||||
*/
|
||||
HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr;
|
||||
MOZ_ASSERT(elementsHeapPtr != emptyObjectElements &&
|
||||
elementsHeapPtr != emptyObjectElementsShared);
|
||||
elementsHeapPtr != emptyObjectElementsShared &&
|
||||
elementsHeapPtr != emptyObjectElementsResizableOrGrowable &&
|
||||
elementsHeapPtr != emptyObjectElementsSharedResizableOrGrowable);
|
||||
|
||||
ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr);
|
||||
MOZ_ASSERT(!header->shouldConvertDoubleElements());
|
||||
|
||||
@@ -185,6 +185,11 @@ class ObjectElements
|
||||
|
||||
// These elements are set to integrity level "frozen".
|
||||
FROZEN = 0x10,
|
||||
|
||||
// For TypedArrays only: this TypedArray views a resizable
|
||||
// ArrayBuffer or growable SharedArrayBuffer. JIT fast paths with
|
||||
// cached length/data assumptions must fall back for these objects.
|
||||
RESIZABLE_OR_GROWABLE_BUFFER = 0x20,
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -255,6 +260,10 @@ class ObjectElements
|
||||
: flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length)
|
||||
{}
|
||||
|
||||
constexpr ObjectElements(uint32_t capacity, uint32_t length, uint32_t flags)
|
||||
: flags(flags), initializedLength(0), capacity(capacity), length(length)
|
||||
{}
|
||||
|
||||
HeapSlot* elements() {
|
||||
return reinterpret_cast<HeapSlot*>(uintptr_t(this) + sizeof(ObjectElements));
|
||||
}
|
||||
@@ -269,6 +278,10 @@ class ObjectElements
|
||||
return flags & SHARED_MEMORY;
|
||||
}
|
||||
|
||||
bool hasResizableOrGrowableBuffer() const {
|
||||
return flags & RESIZABLE_OR_GROWABLE_BUFFER;
|
||||
}
|
||||
|
||||
GCPtrNativeObject& ownerObject() const {
|
||||
MOZ_ASSERT(isCopyOnWrite());
|
||||
return *(GCPtrNativeObject*)(&elements()[initializedLength]);
|
||||
@@ -326,6 +339,8 @@ static_assert(ObjectElements::VALUES_PER_HEADER * sizeof(HeapSlot) == sizeof(Obj
|
||||
*/
|
||||
extern HeapSlot* const emptyObjectElements;
|
||||
extern HeapSlot* const emptyObjectElementsShared;
|
||||
extern HeapSlot* const emptyObjectElementsResizableOrGrowable;
|
||||
extern HeapSlot* const emptyObjectElementsSharedResizableOrGrowable;
|
||||
|
||||
struct Class;
|
||||
class GCMarker;
|
||||
@@ -480,6 +495,12 @@ class NativeObject : public ShapedObject
|
||||
elements_ = emptyObjectElementsShared;
|
||||
}
|
||||
|
||||
void setHasResizableOrGrowableBuffer() {
|
||||
MOZ_ASSERT(elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared);
|
||||
elements_ = isSharedMemory() ? emptyObjectElementsSharedResizableOrGrowable
|
||||
: emptyObjectElementsResizableOrGrowable;
|
||||
}
|
||||
|
||||
bool isInWholeCellBuffer() const {
|
||||
const gc::TenuredCell* cell = &asTenured();
|
||||
gc::ArenaCellSet* cells = cell->arena()->bufferedCells;
|
||||
@@ -1254,7 +1275,10 @@ class NativeObject : public ShapedObject
|
||||
}
|
||||
|
||||
inline bool hasEmptyElements() const {
|
||||
return elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared;
|
||||
return elements_ == emptyObjectElements ||
|
||||
elements_ == emptyObjectElementsShared ||
|
||||
elements_ == emptyObjectElementsResizableOrGrowable ||
|
||||
elements_ == emptyObjectElementsSharedResizableOrGrowable;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -509,12 +509,19 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
||||
return nullptr;
|
||||
|
||||
bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get());
|
||||
bool hasResizableOrGrowableBuffer =
|
||||
buffer &&
|
||||
((buffer->is<ArrayBufferObject>() && buffer->as<ArrayBufferObject>().isResizable()) ||
|
||||
(buffer->is<SharedArrayBufferObject>() &&
|
||||
buffer->as<SharedArrayBufferObject>().isGrowable()));
|
||||
|
||||
obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer));
|
||||
// This is invariant. Self-hosting code that sets BUFFER_SLOT
|
||||
// (if it does) must maintain it, should it need to.
|
||||
if (isSharedMemory)
|
||||
obj->setIsSharedMemory();
|
||||
if (hasResizableOrGrowableBuffer)
|
||||
obj->setHasResizableOrGrowableBuffer();
|
||||
|
||||
if (buffer) {
|
||||
obj->initViewData(buffer->dataPointerEither() + byteOffset);
|
||||
|
||||
Reference in New Issue
Block a user