Compare commits

...
5 Commits
Author SHA1 Message Date
Moonchild f23478616c Issue #1459 - De-templatize array accessor methods. 2020-06-23 09:48:58 +00:00
Moonchild adbec0c69b Issue #1459 - Inline rest of Combined methods for NativeObject and UnboxedArrayObject accesses. 2020-06-22 19:59:41 +00:00
Moonchild b791b67121 Issue #1459 - Inline a number of helper functions. 2020-06-22 12:52:03 +00:00
Moonchild c15bc7d3dd Issue #1459 - Remove unboxed array enabling options. 2020-06-20 13:13:55 +00:00
Moonchild 33b7d3e638 Issue #1459 - Remove UnboxedArrayObject
This removes the main class and functions for unboxed arrays.
For debugging caller purposes, a number of implementation
blocks have been replaced with MOZ_CRASH() calls.
Without using Unboxed Arrays, these should never be hit,
and if they do that's a bug.
2020-06-19 23:01:22 +00:00
34 changed files with 212 additions and 2183 deletions

No files matched your search

+1 -1
View File
@@ -927,7 +927,7 @@ ModuleObject::evaluate(JSContext* cx, HandleModuleObject self, MutableHandleValu
ModuleObject::createNamespace(JSContext* cx, HandleModuleObject self, HandleObject exports)
{
MOZ_ASSERT(!self->namespace_());
MOZ_ASSERT(exports->is<ArrayObject>() || exports->is<UnboxedArrayObject>());
MOZ_ASSERT(exports->is<ArrayObject>());
RootedModuleNamespaceObject ns(cx, ModuleNamespaceObject::create(cx, self));
if (!ns)
-2
View File
@@ -2548,8 +2548,6 @@ js::TenuringTracer::moveObjectToTenured(JSObject* dst, JSObject* src, AllocKind
InlineTypedObject::objectMovedDuringMinorGC(this, dst, src);
} else if (src->is<TypedArrayObject>()) {
tenuredSize += TypedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
} else if (src->is<UnboxedArrayObject>()) {
tenuredSize += UnboxedArrayObject::objectMovedDuringMinorGC(this, dst, src, dstKind);
} else if (src->is<ArgumentsObject>()) {
tenuredSize += ArgumentsObject::objectMovedDuringMinorGC(this, dst, src);
} else if (src->is<ProxyObject>()) {
+5 -2
View File
@@ -787,8 +787,8 @@ BaselineCacheIRCompiler::emitGuardClass()
case GuardClassKind::Array:
clasp = &ArrayObject::class_;
break;
case GuardClassKind::UnboxedArray:
clasp = &UnboxedArrayObject::class_;
case GuardClassKind::UnboxedArray: // XXX Remove
clasp = &ArrayObject::class_;
break;
case GuardClassKind::MappedArguments:
clasp = &MappedArgumentsObject::class_;
@@ -1006,6 +1006,8 @@ BaselineCacheIRCompiler::emitLoadInt32ArrayLengthResult()
bool
BaselineCacheIRCompiler::emitLoadUnboxedArrayLengthResult()
{
MOZ_CRASH("Not implemented");
/*
Register obj = allocator.useRegister(masm, reader.objOperandId());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), R0.scratchReg());
masm.tagValue(JSVAL_TYPE_INT32, R0.scratchReg(), R0);
@@ -1014,6 +1016,7 @@ BaselineCacheIRCompiler::emitLoadUnboxedArrayLengthResult()
// just return.
emitReturnFromIC();
return true;
*/
}
bool
+15 -152
View File
@@ -1375,7 +1375,7 @@ IsNativeDenseElementAccess(HandleObject obj, HandleValue key)
static bool
IsNativeOrUnboxedDenseElementAccess(HandleObject obj, HandleValue key)
{
if (!obj->isNative() && !obj->is<UnboxedArrayObject>())
if (!obj->isNative())
return false;
if (key.isInt32() && key.toInt32() >= 0 && !obj->is<TypedArrayObject>())
return true;
@@ -1479,20 +1479,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_
script = rootedScript;
}
// Check for UnboxedArray[int] accesses.
if (obj->is<UnboxedArrayObject>() && rhs.isInt32() && rhs.toInt32() >= 0) {
JitSpew(JitSpew_BaselineIC, " Generating GetElem(UnboxedArray[Int32]) stub");
ICGetElem_UnboxedArray::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
obj->group());
ICStub* unboxedStub = compiler.getStub(compiler.getStubSpace(script));
if (!unboxedStub)
return false;
stub->addNewStub(unboxedStub);
*attached = true;
return true;
}
// Check for TypedArray[int] => Number and TypedObject[int] => Number accesses.
if ((obj->is<TypedArrayObject>() || IsPrimitiveArrayTypedObject(obj)) &&
rhs.isNumber() &&
@@ -2098,56 +2084,6 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler& masm)
return true;
}
//
// GetElem_UnboxedArray
//
bool
ICGetElem_UnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
{
MOZ_ASSERT(engine_ == Engine::Baseline);
Label failure;
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
Register scratchReg = regs.takeAny();
// Unbox R0 and group guard.
Register obj = masm.extractObject(R0, ExtractTemp0);
masm.loadPtr(Address(ICStubReg, ICGetElem_UnboxedArray::offsetOfGroup()), scratchReg);
masm.branchTestObjGroup(Assembler::NotEqual, obj, scratchReg, &failure);
// Unbox key.
Register key = masm.extractInt32(R1, ExtractTemp1);
// Bounds check.
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()),
scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Load value.
size_t width = UnboxedTypeSize(elementType_);
BaseIndex addr(scratchReg, key, ScaleFromElemWidth(width));
masm.loadUnboxedProperty(addr, elementType_, R0);
// Only monitor the result if its type might change.
if (elementType_ == JSVAL_TYPE_OBJECT)
EmitEnterTypeMonitorIC(masm);
else
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
//
// GetElem_TypedArray
//
@@ -2452,8 +2388,12 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index,
Shape* oldShape, uint32_t oldCapacity, uint32_t oldInitLength,
bool* isAddingCaseOut, size_t* protoDepthOut)
{
uint32_t initLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
uint32_t capacity = GetAnyBoxedOrUnboxedCapacity(obj);
uint32_t initLength = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
uint32_t capacity = obj->isNative() ?
obj->as<NativeObject>().getDenseCapacity() :
0;
*isAddingCaseOut = false;
*protoDepthOut = 0;
@@ -2462,10 +2402,6 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index,
if (initLength < oldInitLength || capacity < oldCapacity)
return false;
// Unboxed arrays need to be able to emit floating point code.
if (obj->is<UnboxedArrayObject>() && !obj->runtimeFromMainThread()->jitSupportsFloatingPoint)
return false;
Shape* shape = obj->maybeShape();
// Cannot optimize if the shape changed.
@@ -2546,9 +2482,9 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_
// Check the old capacity
uint32_t oldCapacity = 0;
uint32_t oldInitLength = 0;
if (index.isInt32() && index.toInt32() >= 0) {
oldCapacity = GetAnyBoxedOrUnboxedCapacity(obj);
oldInitLength = GetAnyBoxedOrUnboxedInitializedLength(obj);
if (index.isInt32() && index.toInt32() >= 0 && obj->isNative()) {
oldCapacity = obj->as<NativeObject>().getDenseCapacity();
oldInitLength = obj->as<NativeObject>().getDenseInitializedLength();
}
if (op == JSOP_INITELEM || op == JSOP_INITHIDDENELEM) {
@@ -2886,29 +2822,6 @@ ICSetElem_DenseOrUnboxedArray::Compiler::generateStubCode(MacroAssembler& masm)
masm.loadValue(valueAddr, tmpVal);
EmitPreBarrier(masm, element, MIRType::Value);
masm.storeValue(tmpVal, element);
} else {
// Set element on an unboxed array.
// Bounds check.
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Compute the address being written to.
BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_)));
EmitUnboxedPreBarrierForBaseline(masm, address, unboxedType_);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.Push(R0);
masm.loadValue(valueAddr, R0);
masm.storeUnboxedProperty(address, unboxedType_,
ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0);
masm.Pop(R0);
}
EmitReturnFromIC(masm);
@@ -3102,40 +3015,6 @@ ICSetElemDenseOrUnboxedArrayAddCompiler::generateStubCode(MacroAssembler& masm)
BaseIndex element(scratchReg, key, TimesEight);
masm.loadValue(valueAddr, tmpVal);
masm.storeValue(tmpVal, element);
} else {
// Adding element to an unboxed array.
// Bounds check (key == initLength)
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLengthAddr, scratchReg);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), scratchReg);
masm.branch32(Assembler::NotEqual, scratchReg, key, &failure);
// Capacity check.
masm.checkUnboxedArrayCapacity(obj, RegisterOrInt32Constant(key), scratchReg, &failure);
// Load obj->elements.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), scratchReg);
// Write the value first, since this can fail. No need for pre-barrier
// since we're not overwriting an old value.
masm.Push(R0);
Address valueAddr(masm.getStackPointer(), ICStackValueOffset + sizeof(Value));
masm.loadValue(valueAddr, R0);
BaseIndex address(scratchReg, key, ScaleFromElemWidth(UnboxedTypeSize(unboxedType_)));
masm.storeUnboxedProperty(address, unboxedType_,
ConstantOrRegister(TypedOrValueRegister(R0)), &failurePopR0);
masm.Pop(R0);
// Increment initialized length.
masm.add32(Imm32(1), initLengthAddr);
// If length is now <= key, increment length.
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
Label skipIncrementLength;
masm.branch32(Assembler::Above, lengthAddr, key, &skipIncrementLength);
masm.add32(Imm32(1), lengthAddr);
masm.bind(&skipIncrementLength);
}
EmitReturnFromIC(masm);
@@ -5903,12 +5782,12 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb
static bool
CopyArray(JSContext* cx, HandleObject obj, MutableHandleValue result)
{
uint32_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
uint32_t length = obj->as<ArrayObject>().length();
JSObject* nobj = NewFullyAllocatedArrayTryReuseGroup(cx, obj, length, TenuredObject);
if (!nobj)
return false;
EnsureArrayGroupAnalyzed(cx, nobj);
CopyAnyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length);
CopyBoxedOrUnboxedDenseElements(cx, nobj, obj, 0, 0, length);
result.setObject(*nobj);
return true;
@@ -5945,16 +5824,13 @@ TryAttachStringSplit(JSContext* cx, ICCall_Fallback* stub, HandleScript script,
// Atomize all elements of the array.
RootedObject arrObj(cx, &arr.toObject());
uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(arrObj);
uint32_t initLength = arrObj->as<ArrayObject>().length();
for (uint32_t i = 0; i < initLength; i++) {
JSAtom* str = js::AtomizeString(cx, GetAnyBoxedOrUnboxedDenseElement(arrObj, i).toString());
JSAtom* str = js::AtomizeString(cx, arrObj->as<NativeObject>().getDenseElement(i).toString());
if (!str)
return false;
if (!SetAnyBoxedOrUnboxedDenseElement(cx, arrObj, i, StringValue(str))) {
// The value could not be stored to an unboxed dense element.
return true;
}
arrObj->as<NativeObject>().setDenseElementWithType(cx, i, StringValue(str));
}
ICCall_StringSplit::Compiler compiler(cx, stub->fallbackMonitorStub()->firstMonitorStub(),
@@ -8324,19 +8200,6 @@ ICGetElem_Dense::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorSt
return New<ICGetElem_Dense>(cx, space, other.jitCode(), firstMonitorStub, other.shape_);
}
ICGetElem_UnboxedArray::ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub,
ObjectGroup *group)
: ICMonitoredStub(GetElem_UnboxedArray, stubCode, firstMonitorStub),
group_(group)
{ }
/* static */ ICGetElem_UnboxedArray*
ICGetElem_UnboxedArray::Clone(JSContext* cx, ICStubSpace* space, ICStub* firstMonitorStub,
ICGetElem_UnboxedArray& other)
{
return New<ICGetElem_UnboxedArray>(cx, space, other.jitCode(), firstMonitorStub, other.group_);
}
ICGetElem_TypedArray::ICGetElem_TypedArray(JitCode* stubCode, Shape* shape, Scalar::Type type)
: ICStub(GetElem_TypedArray, stubCode),
shape_(shape)
+1 -51
View File
@@ -892,54 +892,6 @@ class ICGetElem_Dense : public ICMonitoredStub
};
};
class ICGetElem_UnboxedArray : public ICMonitoredStub
{
friend class ICStubSpace;
GCPtrObjectGroup group_;
ICGetElem_UnboxedArray(JitCode* stubCode, ICStub* firstMonitorStub, ObjectGroup* group);
public:
static ICGetElem_UnboxedArray* Clone(JSContext* cx, ICStubSpace* space,
ICStub* firstMonitorStub, ICGetElem_UnboxedArray& other);
static size_t offsetOfGroup() {
return offsetof(ICGetElem_UnboxedArray, group_);
}
GCPtrObjectGroup& group() {
return group_;
}
class Compiler : public ICStubCompiler {
ICStub* firstMonitorStub_;
RootedObjectGroup group_;
JSValueType elementType_;
protected:
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
virtual int32_t getKey() const {
return static_cast<int32_t>(engine_) |
(static_cast<int32_t>(kind) << 1) |
(static_cast<int32_t>(elementType_) << 17);
}
public:
Compiler(JSContext* cx, ICStub* firstMonitorStub, ObjectGroup* group)
: ICStubCompiler(cx, ICStub::GetElem_UnboxedArray, Engine::Baseline),
firstMonitorStub_(firstMonitorStub),
group_(cx, group),
elementType_(group->unboxedLayoutDontCheckGeneration().elementType())
{}
ICStub* getStub(ICStubSpace* space) {
return newStub<ICGetElem_UnboxedArray>(space, getStubCode(), firstMonitorStub_, group_);
}
};
};
// Accesses scalar elements of a typed array or typed object.
class ICGetElem_TypedArray : public ICStub
{
@@ -1225,9 +1177,7 @@ class ICSetElemDenseOrUnboxedArrayAddCompiler : public ICStubCompiler {
: ICStubCompiler(cx, ICStub::SetElem_DenseOrUnboxedArrayAdd, Engine::Baseline),
obj_(cx, obj),
protoChainDepth_(protoChainDepth),
unboxedType_(obj->is<UnboxedArrayObject>()
? obj->as<UnboxedArrayObject>().elementType()
: JSVAL_TYPE_MAGIC)
unboxedType_(JSVAL_TYPE_MAGIC)
{}
template <size_t ProtoChainDepth>
-1
View File
@@ -60,7 +60,6 @@ namespace jit {
_(GetElem_UnboxedPropertyName) \
_(GetElem_String) \
_(GetElem_Dense) \
_(GetElem_UnboxedArray) \
_(GetElem_TypedArray) \
_(GetElem_Arguments) \
\
-1
View File
@@ -864,7 +864,6 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
case ICStub::GetElem_String:
case ICStub::GetElem_Dense:
case ICStub::GetElem_TypedArray:
case ICStub::GetElem_UnboxedArray:
stubType = MIRType::Object;
break;
+1 -8
View File
@@ -175,7 +175,7 @@ TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOper
} else {
writer.guardNoUnboxedExpando(objId);
}
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
} else if (obj->is<TypedObject>()) {
writer.guardGroup(objId, obj->group());
} else {
Shape* shape = obj->maybeShape();
@@ -368,13 +368,6 @@ GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject ob
return true;
}
if (obj->is<UnboxedArrayObject>()) {
writer.guardClass(objId, GuardClassKind::UnboxedArray);
writer.loadUnboxedArrayLengthResult(objId);
emitted_ = true;
return true;
}
if (obj->is<ArgumentsObject>() && !obj->as<ArgumentsObject>().hasOverriddenLength()) {
if (obj->is<MappedArgumentsObject>()) {
writer.guardClass(objId, GuardClassKind::MappedArguments);
+15 -125
View File
@@ -3209,9 +3209,7 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
void
CodeGenerator::visitElements(LElements* lir)
{
Address elements(ToRegister(lir->object()),
lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
: NativeObject::offsetOfElements());
Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
masm.loadPtr(elements, ToRegister(lir->output()));
}
@@ -5395,13 +5393,7 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
canInline = false;
}
} else {
if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
size_t nbytes =
templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
} else {
canInline = false;
}
MOZ_CRASH("UnboxedArrayObject -- should not get here");
}
if (canInline) {
@@ -7860,44 +7852,25 @@ CodeGenerator::visitSetInitializedLength(LSetInitializedLength* lir)
void
CodeGenerator::visitUnboxedArrayLength(LUnboxedArrayLength* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->output());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfLength()), result);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
void
CodeGenerator::visitUnboxedArrayInitializedLength(LUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
Register result = ToRegister(lir->output());
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), result);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), result);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
void
CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
void
CodeGenerator::visitSetUnboxedArrayInitializedLength(LSetUnboxedArrayInitializedLength* lir)
{
Register obj = ToRegister(lir->object());
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(lir->length());
Register temp = ToRegister(lir->temp());
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLengthAddr, temp);
masm.and32(Imm32(UnboxedArrayObject::CapacityMask), temp);
if (key.isRegister())
masm.or32(key.reg(), temp);
else
masm.or32(Imm32(key.constant()), temp);
masm.store32(temp, initLengthAddr);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
void
@@ -8213,28 +8186,7 @@ CodeGenerator::emitStoreElementHoleT(T* lir)
emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
elements, index, 0);
} else {
Register temp = ToRegister(lir->getTemp(0));
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, temp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
ConstantOrRegister v = ToConstantOrRegister(lir->value(), lir->mir()->value()->type());
if (index->isConstant()) {
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
} else {
BaseIndex address(elements, ToRegister(index),
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, v, nullptr);
}
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
masm.bind(ool->rejoin());
@@ -8275,26 +8227,7 @@ CodeGenerator::emitStoreElementHoleV(T* lir)
else
masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
} else {
Register temp = ToRegister(lir->getTemp(0));
Address initLength(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, temp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), temp);
masm.branch32(Assembler::BelowOrEqual, temp, key, ool->entry());
if (index->isConstant()) {
Address address(elements, ToInt32(index) * UnboxedTypeSize(unboxedType));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
} else {
BaseIndex address(elements, ToRegister(index),
ScaleFromElemWidth(UnboxedTypeSize(unboxedType)));
EmitUnboxedPreBarrier(masm, address, unboxedType);
masm.bind(ool->rejoinStore());
masm.storeUnboxedProperty(address, unboxedType, ConstantOrRegister(value), nullptr);
}
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
masm.bind(ool->rejoin());
@@ -8439,10 +8372,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
Address initLength(elements, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
} else {
Address initLength(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
masm.load32(initLength, ToRegister(temp));
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), ToRegister(temp));
masm.branch32(Assembler::NotEqual, ToRegister(temp), key, &callStub);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
#else
masm.j(Assembler::NotEqual, &callStub);
@@ -8467,18 +8397,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
masm.dec32(&key);
} else {
// Check array capacity.
masm.checkUnboxedArrayCapacity(object, key, ToRegister(temp), &callStub);
// Update initialized length.
masm.add32(Imm32(1), Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
// Update length if length < initializedLength.
Address lengthAddr(object, UnboxedArrayObject::offsetOfLength());
Label dontUpdate;
masm.branch32(Assembler::Above, lengthAddr, key, &dontUpdate);
masm.add32(Imm32(1), lengthAddr);
masm.bind(&dontUpdate);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
@@ -8572,18 +8491,13 @@ typedef bool (*ConvertUnboxedObjectToNativeFn)(JSContext*, JSObject*);
static const VMFunction ConvertUnboxedPlainObjectToNativeInfo =
FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedPlainObject::convertToNative,
"UnboxedPlainObject::convertToNative");
static const VMFunction ConvertUnboxedArrayObjectToNativeInfo =
FunctionInfo<ConvertUnboxedObjectToNativeFn>(UnboxedArrayObject::convertToNative,
"UnboxedArrayObject::convertToNative");
void
CodeGenerator::visitConvertUnboxedObjectToNative(LConvertUnboxedObjectToNative* lir)
{
Register object = ToRegister(lir->getOperand(0));
OutOfLineCode* ool = oolCallVM(lir->mir()->group()->unboxedLayoutDontCheckGeneration().isArray()
? ConvertUnboxedArrayObjectToNativeInfo
: ConvertUnboxedPlainObjectToNativeInfo,
OutOfLineCode* ool = oolCallVM(ConvertUnboxedPlainObjectToNativeInfo,
lir, ArgList(object), StoreNothing());
masm.branchPtr(Assembler::Equal, Address(object, JSObject::offsetOfGroup()),
@@ -8622,12 +8536,7 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
} else {
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), lengthTemp);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), lengthTemp);
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
// Test for length != 0. On zero length either take a VM call or generate
@@ -8688,10 +8597,7 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
} else {
// Unboxed arrays always have writable lengths. Adjust length and
// initializedLength.
masm.store32(lengthTemp, Address(obj, UnboxedArrayObject::offsetOfLength()));
masm.add32(Imm32(-1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
if (mir->mode() == MArrayPopShift::Shift) {
@@ -8758,22 +8664,7 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register
// Do the store.
masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
} else {
// Load initialized length.
masm.load32(Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), length);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), length);
// Guard length == initializedLength.
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
// Guard length < capacity.
masm.checkUnboxedArrayCapacity(obj, key, elementsTemp, ool->entry());
// Load elements and do the store.
masm.loadPtr(Address(obj, UnboxedArrayObject::offsetOfElements()), elementsTemp);
size_t elemSize = UnboxedTypeSize(mir->unboxedType());
BaseIndex addr(elementsTemp, length, ScaleFromElemWidth(elemSize));
masm.storeUnboxedProperty(addr, mir->unboxedType(), value, nullptr);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
masm.inc32(&key);
@@ -8783,8 +8674,7 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
} else {
masm.store32(length, Address(obj, UnboxedArrayObject::offsetOfLength()));
masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
masm.bind(ool->rejoin());
-13
View File
@@ -7354,12 +7354,6 @@ IonBuilder::newArrayTryTemplateObject(bool* emitted, JSObject* templateObject, u
if (!templateObject)
return true;
if (templateObject->is<UnboxedArrayObject>()) {
MOZ_ASSERT(templateObject->as<UnboxedArrayObject>().capacity() >= length);
if (!templateObject->as<UnboxedArrayObject>().hasInlineElements())
return true;
}
MOZ_ASSERT(length <= NativeObject::MAX_DENSE_ELEMENTS_COUNT);
size_t arraySlots =
@@ -7626,12 +7620,6 @@ IonBuilder::jsop_initelem_array()
} else {
MOZ_ASSERT(obj->resultTypeSet()->getObjectCount() == 1);
TypeSet::ObjectKey* initializer = obj->resultTypeSet()->getObject(0);
if (initializer->clasp() == &UnboxedArrayObject::class_) {
if (initializer->group()->unboxedLayout().nativeGroup())
needStub = true;
else
unboxedType = initializer->group()->unboxedLayout().elementType();
}
if (value->type() == MIRType::MagicHole) {
if (!initializer->hasFlags(constraints(), OBJECT_FLAG_NON_PACKED))
needStub = true;
@@ -8196,7 +8184,6 @@ static bool
ClassHasEffectlessLookup(const Class* clasp)
{
return (clasp == &UnboxedPlainObject::class_) ||
(clasp == &UnboxedArrayObject::class_) ||
IsTypedObjectClass(clasp) ||
(clasp->isNative() && !clasp->getOpsLookupProperty());
}
+8 -88
View File
@@ -639,9 +639,6 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher,
} else {
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure);
}
} else if (obj->is<UnboxedArrayObject>()) {
MOZ_ASSERT(failure);
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure);
} else if (obj->is<TypedObject>()) {
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
Address(object, JSObject::offsetOfGroup()),
@@ -1193,31 +1190,7 @@ GenerateUnboxedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAt
JSObject* array, Register object, TypedOrValueRegister output,
Label* failures)
{
Register outReg;
if (output.hasValue()) {
outReg = output.valueReg().scratchReg();
} else {
MOZ_ASSERT(output.type() == MIRType::Int32);
outReg = output.typedReg().gpr();
}
MOZ_ASSERT(object != outReg);
TestMatchingReceiver(masm, attacher, object, array, failures);
// Load length.
masm.load32(Address(object, UnboxedArrayObject::offsetOfLength()), outReg);
// Check for a length that fits in an int32.
masm.branchTest32(Assembler::Signed, outReg, outReg, failures);
if (output.hasValue())
masm.tagValue(JSVAL_TYPE_INT32, outReg, output.valueReg());
// Success.
attacher.jumpRejoin(masm);
// Failure.
masm.bind(failures);
attacher.jumpNextStub(masm);
}
@@ -1599,33 +1572,8 @@ GetPropertyIC::tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScri
HandleObject obj, HandleId id, void* returnAddr,
bool* emitted)
{
MOZ_ASSERT(canAttachStub());
MOZ_ASSERT(!*emitted);
MOZ_ASSERT(outerScript->ionScript() == ion);
if (!obj->is<UnboxedArrayObject>())
return true;
if (!JSID_IS_ATOM(id, cx->names().length))
return true;
if (obj->as<UnboxedArrayObject>().length() > INT32_MAX)
return true;
if (!allowArrayLength(cx))
return true;
*emitted = true;
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
Label failures;
emitIdGuard(masm, id, &failures);
StubAttacher attacher(*this);
GenerateUnboxedArrayLength(cx, masm, attacher, obj, object(), output(), &failures);
return linkAndAttachStub(cx, masm, attacher, ion, "unboxed array length",
JS::TrackedOutcome::ICGetPropStub_UnboxedArrayLength);
// Stub UnboxedArrayObject
return true;
}
bool
@@ -4026,7 +3974,7 @@ GetPropertyIC::tryAttachDenseElementHole(JSContext* cx, HandleScript outerScript
GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& idval,
TypedOrValueRegister output)
{
if (!obj->is<TypedArrayObject>() && !obj->is<UnboxedArrayObject>())
if (!obj->is<TypedArrayObject>())
return false;
MOZ_ASSERT(idval.isInt32() || idval.isString());
@@ -4044,24 +3992,13 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i
return false;
}
if (obj->is<TypedArrayObject>()) {
if (index >= obj->as<TypedArrayObject>().length())
return false;
// The output register is not yet specialized as a float register, the only
// way to accept float typed arrays for now is to return a Value type.
uint32_t arrayType = obj->as<TypedArrayObject>().type();
if (arrayType == Scalar::Float32 || arrayType == Scalar::Float64)
return output.hasValue();
return output.hasValue() || !output.typedReg().isFloat();
}
if (index >= obj->as<UnboxedArrayObject>().initializedLength())
if (index >= obj->as<TypedArrayObject>().length())
return false;
JSValueType elementType = obj->as<UnboxedArrayObject>().elementType();
if (elementType == JSVAL_TYPE_DOUBLE)
// The output register is not yet specialized as a float register, the only
// way to accept float typed arrays for now is to return a Value type.
uint32_t arrayType = obj->as<TypedArrayObject>().type();
if (arrayType == Scalar::Float32 || arrayType == Scalar::Float64)
return output.hasValue();
return output.hasValue() || !output.typedReg().isFloat();
@@ -4163,23 +4100,6 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
} else {
masm.loadFromTypedArray(arrayType, source, output.typedReg(), elementReg, &popObjectAndFail);
}
} else {
// Save the object register on the stack in case of failure.
masm.push(object);
// Guard on the initialized length.
masm.load32(Address(object, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()), object);
masm.and32(Imm32(UnboxedArrayObject::InitializedLengthMask), object);
masm.branch32(Assembler::BelowOrEqual, object, indexReg, &popObjectAndFail);
// Load elements vector.
Register elementReg = object;
masm.loadPtr(Address(masm.getStackPointer(), 0), object);
masm.loadPtr(Address(object, UnboxedArrayObject::offsetOfElements()), elementReg);
JSValueType elementType = array->as<UnboxedArrayObject>().elementType();
BaseIndex source(elementReg, indexReg, ScaleFromElemWidth(UnboxedTypeSize(elementType)));
masm.loadUnboxedProperty(source, elementType, output);
}
masm.pop(object);
+13 -33
View File
@@ -471,11 +471,6 @@ IonBuilder::inlineArray(CallInfo& callInfo)
return InliningStatus_NotInlined;
}
if (templateObject->is<UnboxedArrayObject>()) {
if (templateObject->group()->unboxedLayout().nativeGroup())
return InliningStatus_NotInlined;
}
// Multiple arguments imply array initialization, not just construction.
if (callInfo.argc() >= 2) {
initLength = callInfo.argc();
@@ -523,7 +518,7 @@ IonBuilder::inlineArray(CallInfo& callInfo)
// Make sure initLength matches the template object's length. This is
// not guaranteed to be the case, for instance if we're inlining the
// MConstant may come from an outer script.
if (initLength != GetAnyBoxedOrUnboxedArrayLength(templateObject))
if (initLength != templateObject->as<ArrayObject>().length())
return InliningStatus_NotInlined;
// Don't inline large allocations.
@@ -538,7 +533,7 @@ IonBuilder::inlineArray(CallInfo& callInfo)
MDefinition* array = current->peek(-1);
if (callInfo.argc() >= 2) {
JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
for (uint32_t i = 0; i < initLength; i++) {
if (!alloc().ensureBallast())
return InliningStatus_Error;
@@ -580,7 +575,7 @@ IonBuilder::inlineArrayIsArray(CallInfo& callInfo)
if (!clasp || clasp->isProxy())
return InliningStatus_NotInlined;
isArray = (clasp == &ArrayObject::class_ || clasp == &UnboxedArrayObject::class_);
isArray = (clasp == &ArrayObject::class_);
}
pushConstant(BooleanValue(isArray));
@@ -616,7 +611,7 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
if (!thisTypes)
return InliningStatus_NotInlined;
const Class* clasp = thisTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
if (thisTypes->hasObjectFlags(constraints(), unhandledFlags)) {
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
@@ -630,11 +625,6 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
}
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@@ -734,11 +724,6 @@ IonBuilder::inlineArrayPush(CallInfo& callInfo)
}
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@@ -797,15 +782,10 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
return InliningStatus_NotInlined;
const Class* clasp = thisTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_ && clasp != &UnboxedArrayObject::class_)
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
if (clasp == &UnboxedArrayObject::class_) {
unboxedType = UnboxedArrayElementType(constraints(), obj, nullptr);
if (unboxedType == JSVAL_TYPE_MAGIC)
return InliningStatus_NotInlined;
}
// Watch out for indexed properties on the object or its prototype.
if (ElementAccessHasExtraIndexedProperty(this, obj)) {
@@ -831,10 +811,7 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
if (!templateObj->is<ArrayObject>())
return InliningStatus_NotInlined;
} else {
if (!templateObj->is<UnboxedArrayObject>())
return InliningStatus_NotInlined;
if (templateObj->as<UnboxedArrayObject>().elementType() != unboxedType)
return InliningStatus_NotInlined;
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
@@ -1408,13 +1385,16 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
if (!key.maybeTypes()->hasType(TypeSet::StringType()))
return InliningStatus_NotInlined;
uint32_t initLength = GetAnyBoxedOrUnboxedArrayLength(templateObject);
if (GetAnyBoxedOrUnboxedInitializedLength(templateObject) != initLength)
uint32_t arrayLength = templateObject->as<ArrayObject>().length();
uint32_t initLength = templateObject->isNative() ?
templateObject->as<NativeObject>().getDenseInitializedLength() :
0;
if (arrayLength != initLength)
return InliningStatus_NotInlined;
Vector<MConstant*, 0, SystemAllocPolicy> arrayValues;
for (uint32_t i = 0; i < initLength; i++) {
Value str = GetAnyBoxedOrUnboxedDenseElement(templateObject, i);
Value str = templateObject->as<NativeObject>().getDenseElement(i);
MOZ_ASSERT(str.toString()->isAtom());
MConstant* value = MConstant::New(alloc().fallible(), str, constraints());
if (!value)
@@ -1445,7 +1425,7 @@ IonBuilder::inlineConstantStringSplitString(CallInfo& callInfo)
return InliningStatus_Inlined;
}
JSValueType unboxedType = GetBoxedOrUnboxedType(templateObject);
JSValueType unboxedType = JSVAL_TYPE_MAGIC;
// Store all values, no need to initialize the length after each as
// jsop_initelem_array is doing because we do not expect to bailout
+1 -41
View File
@@ -5914,42 +5914,7 @@ JSValueType
jit::UnboxedArrayElementType(CompilerConstraintList* constraints, MDefinition* obj,
MDefinition* id)
{
if (obj->mightBeType(MIRType::String))
return JSVAL_TYPE_MAGIC;
if (id && id->type() != MIRType::Int32 && id->type() != MIRType::Double)
return JSVAL_TYPE_MAGIC;
TemporaryTypeSet* types = obj->resultTypeSet();
if (!types || types->unknownObject())
return JSVAL_TYPE_MAGIC;
JSValueType elementType = JSVAL_TYPE_MAGIC;
for (unsigned i = 0; i < types->getObjectCount(); i++) {
TypeSet::ObjectKey* key = types->getObject(i);
if (!key)
continue;
if (key->unknownProperties() || !key->isGroup())
return JSVAL_TYPE_MAGIC;
if (key->clasp() != &UnboxedArrayObject::class_)
return JSVAL_TYPE_MAGIC;
const UnboxedLayout &layout = key->group()->unboxedLayout();
if (layout.nativeGroup())
return JSVAL_TYPE_MAGIC;
if (elementType == layout.elementType() || elementType == JSVAL_TYPE_MAGIC)
elementType = layout.elementType();
else
return JSVAL_TYPE_MAGIC;
key->watchStateChangeForUnboxedConvertedToNative(constraints);
}
return elementType;
return JSVAL_TYPE_MAGIC;
}
bool
@@ -6111,11 +6076,6 @@ ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
firstElements.maybeTypes()->equals(secondElements.maybeTypes());
}
if (first->clasp() == &UnboxedArrayObject::class_) {
return first->group()->unboxedLayout().elementType() ==
second->group()->unboxedLayout().elementType();
}
return false;
}
+1 -29
View File
@@ -709,25 +709,7 @@ void
MacroAssembler::checkUnboxedArrayCapacity(Register obj, const RegisterOrInt32Constant& index,
Register temp, Label* failure)
{
Address initLengthAddr(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength());
Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
Label capacityIsIndex, done;
load32(initLengthAddr, temp);
branchTest32(Assembler::NonZero, temp, Imm32(UnboxedArrayObject::CapacityMask), &capacityIsIndex);
branch32(Assembler::BelowOrEqual, lengthAddr, index, failure);
jump(&done);
bind(&capacityIsIndex);
// Do a partial shift so that we can get an absolute offset from the base
// of CapacityArray to use.
JS_STATIC_ASSERT(sizeof(UnboxedArrayObject::CapacityArray[0]) == 4);
rshiftPtr(Imm32(UnboxedArrayObject::CapacityShift - 2), temp);
and32(Imm32(~0x3), temp);
addPtr(ImmPtr(&UnboxedArrayObject::CapacityArray), temp);
branch32(Assembler::BelowOrEqual, Address(temp, 0), index, failure);
bind(&done);
// Stub
}
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
@@ -1281,16 +1263,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
if (initContents)
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
} else if (templateObj->is<UnboxedArrayObject>()) {
MOZ_ASSERT(templateObj->as<UnboxedArrayObject>().hasInlineElements());
int elementsOffset = UnboxedArrayObject::offsetOfInlineElements();
computeEffectiveAddress(Address(obj, elementsOffset), temp);
storePtr(temp, Address(obj, UnboxedArrayObject::offsetOfElements()));
store32(Imm32(templateObj->as<UnboxedArrayObject>().length()),
Address(obj, UnboxedArrayObject::offsetOfLength()));
uint32_t capacityIndex = templateObj->as<UnboxedArrayObject>().capacityIndex();
store32(Imm32(capacityIndex << UnboxedArrayObject::CapacityShift),
Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
} else {
MOZ_CRASH("Unknown object");
}
+1 -1
View File
@@ -1626,7 +1626,7 @@ class MacroAssembler : public MacroAssemblerSpecific
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,
unsigned numElems = 0);
// Load a property from an UnboxedPlainObject or UnboxedArrayObject.
// Load a property from an Unboxed Object.
template <typename T>
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
-5
View File
@@ -907,11 +907,6 @@ IsArrayEscaped(MInstruction* ins)
return true;
}
if (obj->is<UnboxedArrayObject>()) {
JitSpew(JitSpew_Escape, "Template object is an unboxed plain object.");
return true;
}
if (length >= 16) {
JitSpew(JitSpew_Escape, "Array has too many elements");
return true;
-9
View File
@@ -285,11 +285,6 @@ ICStub::trace(JSTracer* trc)
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-dense-shape");
break;
}
case ICStub::GetElem_UnboxedArray: {
ICGetElem_UnboxedArray* getElemStub = toGetElem_UnboxedArray();
TraceEdge(trc, &getElemStub->group(), "baseline-getelem-unboxed-array-group");
break;
}
case ICStub::GetElem_TypedArray: {
ICGetElem_TypedArray* getElemStub = toGetElem_TypedArray();
TraceEdge(trc, &getElemStub->shape(), "baseline-getelem-typedarray-shape");
@@ -2249,7 +2244,6 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy)
if (obj == holder)
return false;
if (!obj->is<UnboxedPlainObject>() &&
!obj->is<UnboxedArrayObject>() &&
!obj->is<TypedObject>())
{
return false;
@@ -2581,9 +2575,6 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
} else if (curObj->is<UnboxedPlainObject>()) {
if (curObj->as<UnboxedPlainObject>().containsUnboxedOrExpandoProperty(cx, NameToId(name)))
return false;
} else if (curObj->is<UnboxedArrayObject>()) {
if (name == cx->names().length)
return false;
} else if (curObj->is<TypedObject>()) {
if (curObj->as<TypedObject>().typeDescr().hasProperty(cx->names(), NameToId(name)))
return false;
+7 -7
View File
@@ -306,7 +306,7 @@ template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString
bool
ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
AutoDetectInvalidation adi(cx, rval);
@@ -327,10 +327,10 @@ ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
bool
ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
{
*length = GetAnyBoxedOrUnboxedArrayLength(obj);
*length = obj->as<ArrayObject>().length();
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1,
ShouldUpdateTypes::DontUpdate);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, *length, v.address(), 1,
ShouldUpdateTypes::DontUpdate);
if (result != DenseElementResult::Incomplete) {
(*length)++;
return result == DenseElementResult::Success;
@@ -350,7 +350,7 @@ ArrayPushDense(JSContext* cx, HandleObject obj, HandleValue v, uint32_t* length)
bool
ArrayShiftDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
{
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
AutoDetectInvalidation adi(cx, rval);
@@ -1139,8 +1139,8 @@ SetDenseOrUnboxedArrayElement(JSContext* cx, HandleObject obj, int32_t index,
// no type changes are needed.
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1,
ShouldUpdateTypes::DontUpdate);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, index, value.address(), 1,
ShouldUpdateTypes::DontUpdate);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
-6
View File
@@ -1173,12 +1173,6 @@ class JS_PUBLIC_API(ContextOptions) {
return *this;
}
bool unboxedArrays() const { return unboxedArrays_; }
ContextOptions& setUnboxedArrays(bool flag) {
unboxedArrays_ = flag;
return *this;
}
bool asyncStack() const { return asyncStack_; }
ContextOptions& setAsyncStack(bool flag) {
asyncStack_ = flag;
+71 -85
View File
@@ -64,7 +64,7 @@ using JS::ToUint32;
bool
JS::IsArray(JSContext* cx, HandleObject obj, IsArrayAnswer* answer)
{
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
if (obj->is<ArrayObject>()) {
*answer = IsArrayAnswer::Array;
return true;
}
@@ -100,11 +100,6 @@ js::GetLengthProperty(JSContext* cx, HandleObject obj, uint32_t* lengthp)
return true;
}
if (obj->is<UnboxedArrayObject>()) {
*lengthp = obj->as<UnboxedArrayObject>().length();
return true;
}
if (obj->is<ArgumentsObject>()) {
ArgumentsObject& argsobj = obj->as<ArgumentsObject>();
if (!argsobj.hasOverriddenLength()) {
@@ -254,8 +249,11 @@ GetElement(JSContext* cx, HandleObject obj, HandleObject receiver,
uint32_t index, bool* hole, MutableHandleValue vp)
{
AssertGreaterThanZero(index);
if (index < GetAnyBoxedOrUnboxedInitializedLength(obj)) {
vp.set(GetAnyBoxedOrUnboxedDenseElement(obj, uint32_t(index)));
uint32_t initLength = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
if (index < initLength) {
vp.set(obj->as<NativeObject>().getDenseElement(index));
if (!vp.isMagic(JS_ELEMENTS_HOLE)) {
*hole = false;
return true;
@@ -284,7 +282,7 @@ ElementAdder::append(JSContext* cx, HandleValue v)
MOZ_ASSERT(index_ < length_);
if (resObj_) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1);
SetOrExtendBoxedOrUnboxedDenseElements(cx, resObj_, index_, v.address(), 1);
if (result == DenseElementResult::Failure)
return false;
if (result == DenseElementResult::Incomplete) {
@@ -342,11 +340,11 @@ GetBoxedOrUnboxedDenseElements(JSObject* aobj, uint32_t length, Value* vp)
{
MOZ_ASSERT(!ObjectMayHaveExtraIndexedProperties(aobj));
if (length > GetBoxedOrUnboxedInitializedLength<Type>(aobj))
if (length > GetBoxedOrUnboxedInitializedLength(aobj))
return DenseElementResult::Incomplete;
for (size_t i = 0; i < length; i++) {
vp[i] = GetBoxedOrUnboxedDenseElement<Type>(aobj, i);
vp[i] = GetBoxedOrUnboxedDenseElement(aobj, i);
// No other indexed properties so hole => undefined.
if (vp[i].isMagic(JS_ELEMENTS_HOLE))
@@ -398,9 +396,9 @@ SetArrayElement(JSContext* cx, HandleObject obj, double index, HandleValue v)
{
MOZ_ASSERT(index >= 0);
if ((obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) && !obj->isIndexed() && index <= UINT32_MAX) {
if (obj->is<ArrayObject>() && !obj->isIndexed() && index <= UINT32_MAX) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, uint32_t(index), v.address(), 1);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
}
@@ -823,7 +821,7 @@ array_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v)
static inline bool
ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj)
{
return (!obj->isNative() && !obj->is<UnboxedArrayObject>()) ||
return !obj->isNative() ||
obj->isIndexed() ||
obj->is<TypedArrayObject>() ||
ClassMayResolveId(*obj->runtimeFromAnyThread()->commonNames,
@@ -854,7 +852,10 @@ js::ObjectMayHaveExtraIndexedProperties(JSObject* obj)
if (ObjectMayHaveExtraIndexedOwnProperties(obj))
return true;
if (GetAnyBoxedOrUnboxedInitializedLength(obj) != 0)
uint32_t initLength = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
if (initLength != 0)
return true;
} while (true);
}
@@ -1073,7 +1074,7 @@ ArrayJoinDenseKernel(JSContext* cx, SeparatorOp sepOp, HandleObject obj, uint32_
// length > initLength we rely on the second loop to add the
// other elements.
MOZ_ASSERT(*numProcessed == 0);
uint32_t initLength = Min<uint32_t>(GetBoxedOrUnboxedInitializedLength<Type>(obj),
uint32_t initLength = Min<uint32_t>(GetBoxedOrUnboxedInitializedLength(obj),
length);
while (*numProcessed < initLength) {
if (!CheckForInterrupt(cx))
@@ -1213,8 +1214,11 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
// An optimized version of a special case of steps 7-11: when length==1 and
// the 0th element is a string, ToString() of that element is a no-op and
// so it can be immediately returned as the result.
if (length == 1 && GetAnyBoxedOrUnboxedInitializedLength(obj) == 1) {
Value elem0 = GetAnyBoxedOrUnboxedDenseElement(obj, 0);
uint32_t initLength = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
if (length == 1 && initLength == 1) {
Value elem0 = obj->as<NativeObject>().getDenseElement(0);
if (elem0.isString()) {
args.rval().set(elem0);
return true;
@@ -1289,10 +1293,6 @@ array_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
args.rval().setString(cx->names().empty);
return true;
}
if (obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().length() == 0) {
args.rval().setString(cx->names().empty);
return true;
}
AutoCycleDetector detector(cx, obj);
if (!detector.init())
@@ -1330,7 +1330,7 @@ InitArrayElements(JSContext* cx, HandleObject obj, uint32_t start,
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, start, vector, count, updateTypes);
if (result != DenseElementResult::Incomplete)
return result == DenseElementResult::Success;
}
@@ -1369,7 +1369,7 @@ DenseElementResult
ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
{
/* An empty array or an array with no elements is already reversed. */
if (length == 0 || GetBoxedOrUnboxedInitializedLength<Type>(obj) == 0)
if (length == 0 || GetBoxedOrUnboxedInitializedLength(obj) == 0)
return DenseElementResult::Success;
if (Type == JSVAL_TYPE_MAGIC) {
@@ -1392,26 +1392,22 @@ ArrayReverseDenseKernel(JSContext* cx, HandleObject obj, uint32_t length)
/* Fill out the array's initialized length to its proper length. */
obj->as<NativeObject>().ensureDenseInitializedLength(cx, length, 0);
} else {
// Unboxed arrays can only be reversed here if their initialized length
// matches their actual length. Otherwise the reversal will place holes
// at the beginning of the array, which we don't support.
if (length != obj->as<UnboxedArrayObject>().initializedLength())
return DenseElementResult::Incomplete;
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
RootedValue origlo(cx), orighi(cx);
uint32_t lo = 0, hi = length - 1;
for (; lo < hi; lo++, hi--) {
origlo = GetBoxedOrUnboxedDenseElement<Type>(obj, lo);
orighi = GetBoxedOrUnboxedDenseElement<Type>(obj, hi);
SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, lo, orighi);
origlo = GetBoxedOrUnboxedDenseElement(obj, lo);
orighi = GetBoxedOrUnboxedDenseElement(obj, hi);
SetBoxedOrUnboxedDenseElementNoTypeChange(obj, lo, orighi);
if (orighi.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(lo)))
{
return DenseElementResult::Failure;
}
SetBoxedOrUnboxedDenseElementNoTypeChange<Type>(obj, hi, origlo);
SetBoxedOrUnboxedDenseElementNoTypeChange(obj, hi, origlo);
if (origlo.isMagic(JS_ELEMENTS_HOLE) &&
!SuppressDeletedProperty(cx, obj, INT_TO_JSID(hi)))
{
@@ -2083,8 +2079,8 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp)
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, length,
args.array(), args.length());
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, length,
args.array(), args.length());
if (result != DenseElementResult::Incomplete) {
if (result == DenseElementResult::Failure)
return false;
@@ -2092,7 +2088,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp)
uint32_t newlength = length + args.length();
args.rval().setNumber(newlength);
// SetOrExtendAnyBoxedOrUnboxedDenseElements takes care of updating the
// SetOrExtendBoxedOrUnboxedDenseElements takes care of updating the
// length for boxed and unboxed arrays. Handle updates to the length of
// non-arrays here.
bool isArray;
@@ -2159,20 +2155,18 @@ template <JSValueType Type>
static inline DenseElementResult
ShiftMoveBoxedOrUnboxedDenseElements(JSObject* obj)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj));
/*
* At this point the length and initialized length have already been
* decremented and the result fetched, so just shift the array elements
* themselves.
*/
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
size_t initlen = GetBoxedOrUnboxedInitializedLength(obj);
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().moveDenseElementsNoPreBarrier(0, 1, initlen);
} else {
uint8_t* data = obj->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(Type);
memmove(data, data + elementSize, initlen * elementSize);
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
return DenseElementResult::Success;
@@ -2203,19 +2197,19 @@ ArrayShiftDenseKernel(JSContext* cx, HandleObject obj, MutableHandleValue rval)
if (MOZ_UNLIKELY(group->hasAllFlags(OBJECT_FLAG_ITERATED)))
return DenseElementResult::Incomplete;
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
size_t initlen = GetBoxedOrUnboxedInitializedLength(obj);
if (initlen == 0)
return DenseElementResult::Incomplete;
rval.set(GetBoxedOrUnboxedDenseElement<Type>(obj, 0));
rval.set(GetBoxedOrUnboxedDenseElement(obj, 0));
if (rval.isMagic(JS_ELEMENTS_HOLE))
rval.setUndefined();
DenseElementResult result = MoveBoxedOrUnboxedDenseElements<Type>(cx, obj, 0, 1, initlen - 1);
DenseElementResult result = MoveBoxedOrUnboxedDenseElements(cx, obj, 0, 1, initlen - 1);
if (result != DenseElementResult::Success)
return result;
SetBoxedOrUnboxedInitializedLength<Type>(cx, obj, initlen - 1);
SetBoxedOrUnboxedInitializedLength(cx, obj, initlen - 1);
return DenseElementResult::Success;
}
@@ -2384,7 +2378,7 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
return false;
/* There's no optimizing possible if it's not an array. */
if (!arr->is<ArrayObject>() && !arr->is<UnboxedArrayObject>())
if (!arr->is<ArrayObject>())
return false;
/* If it's a frozen array, always pick the slow path */
@@ -2419,8 +2413,11 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
* other indexed properties on the object. (Note that non-writable length
* is subsumed by the initializedLength comparison.)
*/
uint32_t initLength = arr->isNative() ?
arr->as<NativeObject>().getDenseInitializedLength() :
0;
return !ObjectMayHaveExtraIndexedProperties(arr) &&
startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
startingIndex + count <= initLength;
}
static inline bool
@@ -2514,7 +2511,7 @@ array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUse
/* Steps 10-11. */
DebugOnly<DenseElementResult> result =
CopyAnyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount);
CopyBoxedOrUnboxedDenseElements(cx, arr, obj, 0, actualStart, actualDeleteCount);
MOZ_ASSERT(result.value == DenseElementResult::Success);
/* Step 12 (implicit). */
@@ -2551,14 +2548,14 @@ array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUse
if (CanOptimizeForDenseStorage(obj, 0, len, cx)) {
/* Steps 15.a-b. */
DenseElementResult result =
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex,
len - sourceIndex);
MoveBoxedOrUnboxedDenseElements(cx, obj, targetIndex, sourceIndex,
len - sourceIndex);
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return false;
/* Steps 15.c-d. */
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, finalLength);
SetBoxedOrUnboxedInitializedLength(cx, obj, finalLength);
} else {
/*
* This is all very slow if the length is very large. We don't yet
@@ -2638,15 +2635,15 @@ array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUse
if (CanOptimizeForDenseStorage(obj, len, itemCount - actualDeleteCount, cx)) {
DenseElementResult result =
MoveAnyBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount,
actualStart + actualDeleteCount,
len - (actualStart + actualDeleteCount));
MoveBoxedOrUnboxedDenseElements(cx, obj, actualStart + itemCount,
actualStart + actualDeleteCount,
len - (actualStart + actualDeleteCount));
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return false;
/* Steps 16.a-b. */
SetAnyBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount);
SetBoxedOrUnboxedInitializedLength(cx, obj, len + itemCount - actualDeleteCount);
} else {
RootedValue fromValue(cx);
for (double k = len - actualDeleteCount; k > actualStart; k--) {
@@ -2881,7 +2878,9 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be
begin = end;
if (!ObjectMayHaveExtraIndexedProperties(obj)) {
size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
size_t initlen = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
size_t count = 0;
if (initlen > begin)
count = Min<size_t>(initlen - begin, end - begin);
@@ -2889,11 +2888,12 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint32_t length, uint32_t be
RootedObject narr(cx, NewFullyAllocatedArrayTryReuseGroup(cx, obj, count));
if (!narr)
return false;
SetAnyBoxedOrUnboxedArrayLength(cx, narr, end - begin);
MOZ_ASSERT((end - begin) >= narr->as<ArrayObject>().length());
narr->as<ArrayObject>().setLength(cx, end - begin);
if (count) {
DebugOnly<DenseElementResult> result =
CopyAnyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count);
CopyBoxedOrUnboxedDenseElements(cx, narr, obj, 0, begin, count);
MOZ_ASSERT(result.value == DenseElementResult::Success);
}
arr.set(narr);
@@ -3021,7 +3021,7 @@ template <JSValueType Type>
DenseElementResult
ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t endArg, JSObject* result)
{
int32_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
int32_t length = obj->as<ArrayObject>().length();
uint32_t begin = NormalizeSliceTerm(beginArg, length);
uint32_t end = NormalizeSliceTerm(endArg, length);
@@ -3029,18 +3029,19 @@ ArraySliceDenseKernel(JSContext* cx, JSObject* obj, int32_t beginArg, int32_t en
if (begin > end)
begin = end;
size_t initlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
size_t initlen = GetBoxedOrUnboxedInitializedLength(obj);
if (initlen > begin) {
size_t count = Min<size_t>(initlen - begin, end - begin);
if (count) {
DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements<Type>(cx, result, count);
DenseElementResult rv = EnsureBoxedOrUnboxedDenseElements(cx, result, count);
if (rv != DenseElementResult::Success)
return rv;
CopyBoxedOrUnboxedDenseElements<Type, Type>(cx, result, obj, 0, begin, count);
CopyBoxedOrUnboxedDenseElements(cx, result, obj, 0, begin, count);
}
}
SetAnyBoxedOrUnboxedArrayLength(cx, result, end - begin);
MOZ_ASSERT((end - begin) >= result->as<ArrayObject>().length());
result->as<ArrayObject>().setLength(cx, end - begin);
return DenseElementResult::Success;
}
@@ -3612,11 +3613,6 @@ NewArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group, size_t length
newKind = TenuredObject;
RootedObject proto(cx, group->proto().toObject());
if (group->maybeUnboxedLayout()) {
if (length > UnboxedArrayObject::MaximumCapacity)
return NewArray<maxLength>(cx, length, proto, newKind);
return UnboxedArrayObject::create(cx, group, length, newKind, maxLength);
}
ArrayObject* res = NewArray<maxLength>(cx, length, proto, newKind);
if (!res)
@@ -3653,14 +3649,13 @@ js::NewPartlyAllocatedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup g
// object. The resulting array will either reuse the input object's group or
// will have unknown property types. Additionally, the result will have the
// same boxed/unboxed elements representation as the input object, unless
// |length| is larger than the input object's initialized length (in which case
// UnboxedArrayObject::MaximumCapacity might be exceeded).
// |length| is larger than the input object's initialized length.
template <uint32_t maxLength>
static inline JSObject*
NewArrayTryReuseGroup(JSContext* cx, HandleObject obj, size_t length,
NewObjectKind newKind = GenericObject)
{
if (!obj->is<ArrayObject>() && !obj->is<UnboxedArrayObject>())
if (!obj->is<ArrayObject>())
return NewArray<maxLength>(cx, length, nullptr, newKind);
if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype())
@@ -3724,8 +3719,8 @@ js::MaybeAnalyzeBeforeCreatingLargeArray(ExclusiveContext* cx, HandleObjectGroup
if (!obj)
return false;
DebugOnly<DenseElementResult> result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength,
ShouldUpdateTypes::Update);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, nlength,
ShouldUpdateTypes::Update);
MOZ_ASSERT(result.value == DenseElementResult::Success);
}
objects->maybeAnalyze(cx, group, /* forceAnalyze = */ true);
@@ -3747,23 +3742,14 @@ js::NewCopiedArrayTryUseGroup(ExclusiveContext* cx, HandleObjectGroup group,
return nullptr;
DenseElementResult result =
SetOrExtendAnyBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes);
SetOrExtendBoxedOrUnboxedDenseElements(cx, obj, 0, vp, length, updateTypes);
if (result == DenseElementResult::Failure)
return nullptr;
if (result == DenseElementResult::Success)
return obj;
MOZ_ASSERT(obj->is<UnboxedArrayObject>());
if (!UnboxedArrayObject::convertToNative(cx->asJSContext(), obj))
return nullptr;
result = SetOrExtendBoxedOrUnboxedDenseElements<JSVAL_TYPE_MAGIC>(cx, obj, 0, vp, length,
updateTypes);
MOZ_ASSERT(result != DenseElementResult::Incomplete);
if (result == DenseElementResult::Failure)
return nullptr;
return obj;
// if we get here it was unboxed
MOZ_CRASH("UnboxedArrayObject -- Should not get here");
}
JSObject*
+1 -1
View File
@@ -270,7 +270,7 @@ js::GetBuiltinClass(JSContext* cx, HandleObject obj, ESClass* cls)
if (obj->is<PlainObject>() || obj->is<UnboxedPlainObject>())
*cls = ESClass::Object;
else if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>())
else if (obj->is<ArrayObject>())
*cls = ESClass::Array;
else if (obj->is<NumberObject>())
*cls = ESClass::Number;
+10 -24
View File
@@ -1141,16 +1141,18 @@ static bool
GetScriptArrayObjectElements(JSContext* cx, HandleObject obj, MutableHandle<GCVector<Value>> values)
{
MOZ_ASSERT(!obj->isSingleton());
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
MOZ_ASSERT(!obj->isIndexed());
size_t length = GetAnyBoxedOrUnboxedArrayLength(obj);
size_t length = obj->as<ArrayObject>().length();
if (!values.appendN(MagicValue(JS_ELEMENTS_HOLE), length))
return false;
size_t initlen = GetAnyBoxedOrUnboxedInitializedLength(obj);
size_t initlen = obj->isNative() ?
obj->as<NativeObject>().getDenseInitializedLength() :
0;
for (size_t i = 0; i < initlen; i++)
values[i].set(GetAnyBoxedOrUnboxedDenseElement(obj, i));
values[i].set(obj->as<NativeObject>().getDenseElement(i));
return true;
}
@@ -1221,10 +1223,10 @@ js::DeepCloneObjectLiteral(JSContext* cx, HandleObject obj, NewObjectKind newKin
MOZ_ASSERT_IF(obj->isSingleton(),
cx->compartment()->behaviors().getSingletonsAsTemplates());
MOZ_ASSERT(obj->is<PlainObject>() || obj->is<UnboxedPlainObject>() ||
obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
obj->is<ArrayObject>());
MOZ_ASSERT(newKind != SingletonObject);
if (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) {
if (obj->is<ArrayObject>()) {
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
if (!GetScriptArrayObjectElements(cx, obj, &values))
return nullptr;
@@ -1341,9 +1343,8 @@ js::XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj)
if (mode == XDR_ENCODE) {
MOZ_ASSERT(obj->is<PlainObject>() ||
obj->is<UnboxedPlainObject>() ||
obj->is<ArrayObject>() ||
obj->is<UnboxedArrayObject>());
isArray = (obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>()) ? 1 : 0;
obj->is<ArrayObject>());
isArray = (obj->is<ArrayObject>()) ? 1 : 0;
}
if (!xdr->codeUint32(&isArray))
@@ -2341,11 +2342,6 @@ js::LookupOwnPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, Shape**
MarkNonNativePropertyFound<NoGC>(propp);
return true;
}
} else if (obj->is<UnboxedArrayObject>()) {
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
MarkNonNativePropertyFound<NoGC>(propp);
return true;
}
} else if (obj->is<TypedObject>()) {
if (obj->as<TypedObject>().typeDescr().hasProperty(cx->names(), id)) {
MarkNonNativePropertyFound<NoGC>(propp);
@@ -3651,16 +3647,6 @@ JSObject::allocKindForTenure(const js::Nursery& nursery) const
return GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + nbytes);
}
// Unboxed arrays use inline data if their size is small enough.
if (is<UnboxedArrayObject>()) {
const UnboxedArrayObject* nobj = &as<UnboxedArrayObject>();
size_t nbytes = UnboxedArrayObject::offsetOfInlineElements() +
nobj->capacity() * nobj->elementSize();
if (nbytes <= JSObject::MAX_BYTE_SIZE)
return GetGCObjectKindForBytes(nbytes);
return AllocKind::OBJECT0;
}
// Inlined typed objects are followed by their data, so make sure we copy
// it all over to the new object.
if (is<InlineTypedObject>()) {
-2
View File
@@ -40,8 +40,6 @@ MaybeConvertUnboxedObjectToNative(ExclusiveContext* cx, JSObject* obj)
{
if (obj->is<UnboxedPlainObject>())
return UnboxedPlainObject::convertToNative(cx->asJSContext(), obj);
if (obj->is<UnboxedArrayObject>())
return UnboxedArrayObject::convertToNative(cx->asJSContext(), obj);
return true;
}
-5
View File
@@ -317,7 +317,6 @@ static bool enableIon = false;
static bool enableAsmJS = false;
static bool enableWasm = false;
static bool enableNativeRegExp = false;
static bool enableUnboxedArrays = false;
static bool enableSharedMemory = SHARED_MEMORY_DEFAULT;
static bool enableWasmAlwaysBaseline = false;
static bool enableArrayProtoValues = true;
@@ -7263,7 +7262,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
enableAsmJS = !op.getBoolOption("no-asmjs");
enableWasm = !op.getBoolOption("no-wasm");
enableNativeRegExp = !op.getBoolOption("no-native-regexp");
enableUnboxedArrays = op.getBoolOption("unboxed-arrays");
enableWasmAlwaysBaseline = op.getBoolOption("wasm-always-baseline");
enableArrayProtoValues = !op.getBoolOption("no-array-proto-values");
@@ -7273,7 +7271,6 @@ SetContextOptions(JSContext* cx, const OptionParser& op)
.setWasm(enableWasm)
.setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays)
.setArrayProtoValues(enableArrayProtoValues);
if (op.getBoolOption("wasm-check-bce"))
@@ -7545,7 +7542,6 @@ SetWorkerContextOptions(JSContext* cx)
.setWasm(enableWasm)
.setWasmAlwaysBaseline(enableWasmAlwaysBaseline)
.setNativeRegExp(enableNativeRegExp)
.setUnboxedArrays(enableUnboxedArrays)
.setArrayProtoValues(enableArrayProtoValues);
cx->setOffthreadIonCompilationEnabled(offthreadCompilation);
cx->profilingScripts = enableCodeCoverage || enableDisassemblyDumps;
@@ -7716,7 +7712,6 @@ main(int argc, char** argv, char** envp)
|| !op.addBoolOption('\0', "no-wasm", "Disable WebAssembly compilation")
|| !op.addBoolOption('\0', "no-native-regexp", "Disable native regexp compilation")
|| !op.addBoolOption('\0', "no-unboxed-objects", "Disable creating unboxed plain objects")
|| !op.addBoolOption('\0', "unboxed-arrays", "Allow creating unboxed arrays")
|| !op.addBoolOption('\0', "wasm-always-baseline", "Enable wasm baseline compiler when possible")
|| !op.addBoolOption('\0', "wasm-check-bce", "Always generate wasm bounds check, even redundant ones.")
|| !op.addBoolOption('\0', "no-array-proto-values", "Remove Array.prototype.values")
+1 -1
View File
@@ -598,7 +598,7 @@ InitArrayElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, uint32_t
JSOp op = JSOp(*pc);
MOZ_ASSERT(op == JSOP_INITELEM_ARRAY || op == JSOP_INITELEM_INC);
MOZ_ASSERT(obj->is<ArrayObject>() || obj->is<UnboxedArrayObject>());
MOZ_ASSERT(obj->is<ArrayObject>());
if (op == JSOP_INITELEM_INC && index == INT32_MAX) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SPREAD_TOO_LARGE);
-9
View File
@@ -5052,9 +5052,6 @@ js::NewArrayOperation(JSContext* cx, HandleScript script, jsbytecode* pc, uint32
if (group->shouldPreTenure() || group->maybePreliminaryObjects())
newKind = TenuredObject;
if (group->maybeUnboxedLayout())
return UnboxedArrayObject::create(cx, group, length, newKind);
}
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, length, nullptr, newKind);
@@ -5080,12 +5077,6 @@ js::NewArrayOperationWithTemplate(JSContext* cx, HandleObject templateObject)
NewObjectKind newKind = templateObject->group()->shouldPreTenure() ? TenuredObject : GenericObject;
if (templateObject->is<UnboxedArrayObject>()) {
uint32_t length = templateObject->as<UnboxedArrayObject>().length();
RootedObjectGroup group(cx, templateObject->group());
return UnboxedArrayObject::create(cx, group, length, newKind);
}
ArrayObject* obj = NewDenseFullyAllocatedArray(cx, templateObject->as<ArrayObject>().length(),
nullptr, newKind);
if (!obj)
-4
View File
@@ -734,10 +734,6 @@ NativeObject::maybeDensifySparseElements(js::ExclusiveContext* cx, HandleNativeO
// * minimize the number of unused elements beyond an array's length, and
// * provide at least SLOT_CAPACITY_MIN elements no matter what (so adding
// the first several elements to small arrays only needs one allocation).
//
// Note: the structure and behavior of this method follow along with
// UnboxedArrayObject::chooseCapacityIndex. Changes to the allocation strategy
// in one should generally be matched by the other.
/* static */ bool
NativeObject::goodElementsAllocationAmount(ExclusiveContext* cx, uint32_t reqCapacity,
uint32_t length, uint32_t* goodAmount)
+2 -29
View File
@@ -900,7 +900,7 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
{
MOZ_ASSERT(source->group() != target->group());
if (!target->is<ArrayObject>() && !target->is<UnboxedArrayObject>())
if (!target->is<ArrayObject>())
return true;
if (target->group()->maybePreliminaryObjects()) {
@@ -911,11 +911,7 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
if (target->is<ArrayObject>()) {
ObjectGroup* sourceGroup = source->group();
if (source->is<UnboxedArrayObject>()) {
Shape* shape = target->as<ArrayObject>().lastProperty();
if (!UnboxedArrayObject::convertToNativeWithGroup(cx, source, target->group(), shape))
return false;
} else if (source->is<ArrayObject>()) {
if (source->is<ArrayObject>()) {
source->setGroup(target->group());
} else {
return true;
@@ -934,17 +930,6 @@ GiveObjectGroup(ExclusiveContext* cx, JSObject* source, JSObject* target)
return true;
}
if (target->is<UnboxedArrayObject>()) {
if (!source->is<UnboxedArrayObject>())
return true;
if (source->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_INT32)
return true;
if (target->as<UnboxedArrayObject>().elementType() != JSVAL_TYPE_DOUBLE)
return true;
return source->as<UnboxedArrayObject>().convertInt32ToDouble(cx, target->group());
}
return true;
}
@@ -1506,18 +1491,6 @@ ObjectGroup::allocationSiteGroup(JSContext* cx, JSScript* scriptArg, jsbytecode*
}
}
if (kind == JSProto_Array &&
(JSOp(*pc) == JSOP_NEWARRAY || IsCallPC(pc)) &&
cx->options().unboxedArrays())
{
PreliminaryObjectArrayWithTemplate* preliminaryObjects =
cx->new_<PreliminaryObjectArrayWithTemplate>(nullptr);
if (preliminaryObjects)
res->setPreliminaryObjects(preliminaryObjects);
else
cx->recoverFromOutOfMemory();
}
if (!table->add(p, key, res)) {
ReportOutOfMemory(cx);
return nullptr;
+1 -1
View File
@@ -505,7 +505,7 @@ class ObjectGroup : public gc::TenuredCell
UnknownIndex // Make an array with an unknown element type.
};
// Create an ArrayObject or UnboxedArrayObject with the specified elements
// Create an ArrayObject with the specified elements
// and a group specialized for the elements.
static JSObject* newArrayObject(ExclusiveContext* cx, const Value* vp, size_t length,
NewObjectKind newKind,
+4 -4
View File
@@ -20,7 +20,7 @@ ReceiverGuard::ReceiverGuard(JSObject* obj)
group = obj->group();
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
shape = expando->lastProperty();
} else if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
} else if (obj->is<TypedObject>()) {
group = obj->group();
} else {
shape = obj->maybeShape();
@@ -35,7 +35,7 @@ ReceiverGuard::ReceiverGuard(ObjectGroup* group, Shape* shape)
const Class* clasp = group->clasp();
if (clasp == &UnboxedPlainObject::class_) {
// Keep both group and shape.
} else if (clasp == &UnboxedArrayObject::class_ || IsTypedObjectClass(clasp)) {
} else if (IsTypedObjectClass(clasp)) {
this->shape = nullptr;
} else {
this->group = nullptr;
@@ -50,8 +50,8 @@ HeapReceiverGuard::keyBits(JSObject* obj)
// Both the group and shape need to be guarded for unboxed plain objects.
return obj->as<UnboxedPlainObject>().maybeExpando() ? 0 : 1;
}
if (obj->is<UnboxedArrayObject>() || obj->is<TypedObject>()) {
// Only the group needs to be guarded for unboxed arrays and typed objects.
if (obj->is<TypedObject>()) {
// Only the group needs to be guarded for typed objects.
return 2;
}
// Other objects only need the shape to be guarded.
+1 -1
View File
@@ -2520,7 +2520,7 @@ TemporaryTypeSet::propertyNeedsBarrier(CompilerConstraintList* constraints, jsid
bool
js::ClassCanHaveExtraProperties(const Class* clasp)
{
if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_)
if (clasp == &UnboxedPlainObject::class_)
return false;
return clasp->getResolve()
|| clasp->getOpsLookupProperty()
+48 -475
View File
@@ -172,475 +172,129 @@ UnboxedPlainObject::layout() const
return group()->unboxedLayout();
}
/////////////////////////////////////////////////////////////////////
// UnboxedArrayObject
/////////////////////////////////////////////////////////////////////
inline const UnboxedLayout&
UnboxedArrayObject::layout() const
{
return group()->unboxedLayout();
}
inline void
UnboxedArrayObject::setLength(ExclusiveContext* cx, uint32_t length)
{
if (length > INT32_MAX) {
// Track objects with overflowing lengths in type information.
MarkObjectGroupFlags(cx, this, OBJECT_FLAG_LENGTH_OVERFLOW);
}
length_ = length;
}
inline void
UnboxedArrayObject::setInitializedLength(uint32_t initlen)
{
if (initlen < initializedLength()) {
switch (elementType()) {
case JSVAL_TYPE_STRING:
for (size_t i = initlen; i < initializedLength(); i++)
triggerPreBarrier<JSVAL_TYPE_STRING>(i);
break;
case JSVAL_TYPE_OBJECT:
for (size_t i = initlen; i < initializedLength(); i++)
triggerPreBarrier<JSVAL_TYPE_OBJECT>(i);
break;
default:
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(elementType()));
}
}
setInitializedLengthNoBarrier(initlen);
}
template <JSValueType Type>
inline bool
UnboxedArrayObject::setElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::setElementNoTypeChangeSpecific(size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ true);
}
template <JSValueType Type>
inline bool
UnboxedArrayObject::initElementSpecific(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::initElementNoTypeChangeSpecific(size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
}
template <JSValueType Type>
inline Value
UnboxedArrayObject::getElementSpecific(size_t index)
{
MOZ_ASSERT(index < initializedLength());
MOZ_ASSERT(Type == elementType());
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
return GetUnboxedValue(p, Type, /* maybeUninitialized = */ false);
}
template <JSValueType Type>
inline void
UnboxedArrayObject::triggerPreBarrier(size_t index)
{
MOZ_ASSERT(UnboxedTypeNeedsPreBarrier(Type));
uint8_t* p = elements() + index * UnboxedTypeSize(Type);
switch (Type) {
case JSVAL_TYPE_STRING: {
JSString** np = reinterpret_cast<JSString**>(p);
JSString::writeBarrierPre(*np);
break;
}
case JSVAL_TYPE_OBJECT: {
JSObject** np = reinterpret_cast<JSObject**>(p);
JSObject::writeBarrierPre(*np);
break;
}
default:
MOZ_CRASH("Bad type");
}
}
/////////////////////////////////////////////////////////////////////
// Combined methods for NativeObject and UnboxedArrayObject accesses.
/////////////////////////////////////////////////////////////////////
static inline bool
HasAnyBoxedOrUnboxedDenseElements(JSObject* obj)
{
return obj->isNative() || obj->is<UnboxedArrayObject>();
}
static inline size_t
GetAnyBoxedOrUnboxedInitializedLength(JSObject* obj)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseInitializedLength();
if (obj->is<UnboxedArrayObject>())
return obj->as<UnboxedArrayObject>().initializedLength();
return 0;
}
static inline size_t
GetAnyBoxedOrUnboxedCapacity(JSObject* obj)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseCapacity();
if (obj->is<UnboxedArrayObject>())
return obj->as<UnboxedArrayObject>().capacity();
return 0;
}
static inline Value
GetAnyBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
{
if (obj->isNative())
return obj->as<NativeObject>().getDenseElement(index);
return obj->as<UnboxedArrayObject>().getElement(index);
}
static inline size_t
GetAnyBoxedOrUnboxedArrayLength(JSObject* obj)
{
if (obj->is<ArrayObject>())
return obj->as<ArrayObject>().length();
return obj->as<UnboxedArrayObject>().length();
}
static inline void
SetAnyBoxedOrUnboxedArrayLength(JSContext* cx, JSObject* obj, size_t length)
{
if (obj->is<ArrayObject>()) {
MOZ_ASSERT(length >= obj->as<ArrayObject>().length());
obj->as<ArrayObject>().setLength(cx, length);
} else {
MOZ_ASSERT(length >= obj->as<UnboxedArrayObject>().length());
obj->as<UnboxedArrayObject>().setLength(cx, length);
}
}
static inline bool
SetAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (obj->isNative()) {
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().setElement(cx, index, value);
}
static inline bool
InitAnyBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (obj->isNative()) {
obj->as<NativeObject>().initDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().initElement(cx, index, value);
}
/////////////////////////////////////////////////////////////////////
// Template methods for NativeObject and UnboxedArrayObject accesses.
/////////////////////////////////////////////////////////////////////
static inline JSValueType
GetBoxedOrUnboxedType(JSObject* obj)
{
if (obj->isNative())
return JSVAL_TYPE_MAGIC;
return obj->as<UnboxedArrayObject>().elementType();
}
template <JSValueType Type>
static inline bool
HasBoxedOrUnboxedDenseElements(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->isNative();
return obj->is<UnboxedArrayObject>() && obj->as<UnboxedArrayObject>().elementType() == Type;
return obj->isNative();
}
template <JSValueType Type>
static inline size_t
GetBoxedOrUnboxedInitializedLength(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseInitializedLength();
return obj->as<UnboxedArrayObject>().initializedLength();
return obj->as<NativeObject>().getDenseInitializedLength();
}
template <JSValueType Type>
static inline DenseElementResult
SetBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
{
size_t oldInitlen = GetBoxedOrUnboxedInitializedLength<Type>(obj);
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().setDenseInitializedLength(initlen);
if (initlen < oldInitlen)
obj->as<NativeObject>().shrinkElements(cx, initlen);
} else {
obj->as<UnboxedArrayObject>().setInitializedLength(initlen);
if (initlen < oldInitlen)
obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen);
}
size_t oldInitlen = GetBoxedOrUnboxedInitializedLength(obj);
obj->as<NativeObject>().setDenseInitializedLength(initlen);
if (initlen < oldInitlen)
obj->as<NativeObject>().shrinkElements(cx, initlen);
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline size_t
GetBoxedOrUnboxedCapacity(JSObject* obj)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseCapacity();
return obj->as<UnboxedArrayObject>().capacity();
return obj->as<NativeObject>().getDenseCapacity();
}
template <JSValueType Type>
static inline Value
GetBoxedOrUnboxedDenseElement(JSObject* obj, size_t index)
{
if (Type == JSVAL_TYPE_MAGIC)
return obj->as<NativeObject>().getDenseElement(index);
return obj->as<UnboxedArrayObject>().getElementSpecific<Type>(index);
return obj->as<NativeObject>().getDenseElement(index);
}
template <JSValueType Type>
static inline void
SetBoxedOrUnboxedDenseElementNoTypeChange(JSObject* obj, size_t index, const Value& value)
{
if (Type == JSVAL_TYPE_MAGIC)
obj->as<NativeObject>().setDenseElement(index, value);
else
obj->as<UnboxedArrayObject>().setElementNoTypeChangeSpecific<Type>(index, value);
obj->as<NativeObject>().setDenseElement(index, value);
}
template <JSValueType Type>
static inline bool
SetBoxedOrUnboxedDenseElement(JSContext* cx, JSObject* obj, size_t index, const Value& value)
{
if (Type == JSVAL_TYPE_MAGIC) {
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
return true;
}
return obj->as<UnboxedArrayObject>().setElementSpecific<Type>(cx, index, value);
obj->as<NativeObject>().setDenseElementWithType(cx, index, value);
return true;
}
template <JSValueType Type>
static inline DenseElementResult
EnsureBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count)
{
if (Type == JSVAL_TYPE_MAGIC) {
if (!obj->as<ArrayObject>().ensureElements(cx, count))
return DenseElementResult::Failure;
} else {
if (obj->as<UnboxedArrayObject>().capacity() < count) {
if (!obj->as<UnboxedArrayObject>().growElements(cx, count))
return DenseElementResult::Failure;
}
}
if (!obj->as<ArrayObject>().ensureElements(cx, count))
return DenseElementResult::Failure;
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline DenseElementResult
SetOrExtendBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update)
{
if (Type == JSVAL_TYPE_MAGIC) {
NativeObject* nobj = &obj->as<NativeObject>();
NativeObject* nobj = &obj->as<NativeObject>();
if (nobj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (nobj->denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (obj->is<ArrayObject>() &&
!obj->as<ArrayObject>().lengthIsWritable() &&
start + count >= obj->as<ArrayObject>().length())
{
return DenseElementResult::Incomplete;
}
DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
if (result != DenseElementResult::Success)
return result;
if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
obj->as<ArrayObject>().setLengthInt32(start + count);
if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
nobj->copyDenseElements(start, vp, count);
} else {
for (size_t i = 0; i < count; i++)
nobj->setDenseElementWithType(cx, start + i, vp[i]);
}
return DenseElementResult::Success;
if (obj->is<ArrayObject>() &&
!obj->as<ArrayObject>().lengthIsWritable() &&
start + count >= obj->as<ArrayObject>().length())
{
return DenseElementResult::Incomplete;
}
UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
DenseElementResult result = nobj->ensureDenseElements(cx, start, count);
if (result != DenseElementResult::Success)
return result;
if (start > nobj->initializedLength())
return DenseElementResult::Incomplete;
if (obj->is<ArrayObject>() && start + count >= obj->as<ArrayObject>().length())
obj->as<ArrayObject>().setLengthInt32(start + count);
if (start + count >= UnboxedArrayObject::MaximumCapacity)
return DenseElementResult::Incomplete;
if (start + count > nobj->capacity() && !nobj->growElements(cx, start + count))
return DenseElementResult::Failure;
size_t oldInitlen = nobj->initializedLength();
// Overwrite any existing elements covered by the new range. If we fail
// after this point due to some incompatible type being written to the
// object's elements, afterwards the contents will be different from when
// we started. The caller must retry the operation using a generic path,
// which will overwrite the already-modified elements as well as the ones
// that were left alone.
size_t i = 0;
if (updateTypes == ShouldUpdateTypes::DontUpdate) {
for (size_t j = start; i < count && j < oldInitlen; i++, j++)
nobj->setElementNoTypeChangeSpecific<Type>(j, vp[i]);
if (updateTypes == ShouldUpdateTypes::DontUpdate && !nobj->shouldConvertDoubleElements()) {
nobj->copyDenseElements(start, vp, count);
} else {
for (size_t j = start; i < count && j < oldInitlen; i++, j++) {
if (!nobj->setElementSpecific<Type>(cx, j, vp[i]))
return DenseElementResult::Incomplete;
}
for (size_t i = 0; i < count; i++)
nobj->setDenseElementWithType(cx, start + i, vp[i]);
}
if (i != count) {
obj->as<UnboxedArrayObject>().setInitializedLength(start + count);
if (updateTypes == ShouldUpdateTypes::DontUpdate) {
for (; i < count; i++)
nobj->initElementNoTypeChangeSpecific<Type>(start + i, vp[i]);
} else {
for (; i < count; i++) {
if (!nobj->initElementSpecific<Type>(cx, start + i, vp[i])) {
nobj->setInitializedLengthNoBarrier(oldInitlen);
return DenseElementResult::Incomplete;
}
}
}
}
if (start + count >= nobj->length())
nobj->setLength(cx, start + count);
return DenseElementResult::Success;
}
template <JSValueType Type>
static inline DenseElementResult
MoveBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, uint32_t dstStart, uint32_t srcStart,
uint32_t length)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<Type>(obj));
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(obj));
if (Type == JSVAL_TYPE_MAGIC) {
if (obj->as<NativeObject>().denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (obj->as<NativeObject>().denseElementsAreFrozen())
return DenseElementResult::Incomplete;
if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
return DenseElementResult::Failure;
obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
} else {
uint8_t* data = obj->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(Type);
if (UnboxedTypeNeedsPreBarrier(Type) &&
JS::shadow::Zone::asShadowZone(obj->zone())->needsIncrementalBarrier())
{
// Trigger pre barriers on any elements we are overwriting. See
// NativeObject::moveDenseElements. No post barrier is needed as
// only whole cell post barriers are used with unboxed objects.
for (size_t i = 0; i < length; i++)
obj->as<UnboxedArrayObject>().triggerPreBarrier<Type>(dstStart + i);
}
memmove(data + dstStart * elementSize,
data + srcStart * elementSize,
length * elementSize);
}
if (!obj->as<NativeObject>().maybeCopyElementsForWrite(cx))
return DenseElementResult::Failure;
obj->as<NativeObject>().moveDenseElements(dstStart, srcStart, length);
return DenseElementResult::Success;
}
template <JSValueType DstType, JSValueType SrcType>
static inline DenseElementResult
CopyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length)
{
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<SrcType>(src));
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements<DstType>(dst));
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<DstType>(dst) == dstStart);
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength<SrcType>(src) >= srcStart + length);
MOZ_ASSERT(GetBoxedOrUnboxedCapacity<DstType>(dst) >= dstStart + length);
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(src));
MOZ_ASSERT(HasBoxedOrUnboxedDenseElements(dst));
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(dst) == dstStart);
MOZ_ASSERT(GetBoxedOrUnboxedInitializedLength(src) >= srcStart + length);
MOZ_ASSERT(GetBoxedOrUnboxedCapacity(dst) >= dstStart + length);
SetBoxedOrUnboxedInitializedLength<DstType>(cx, dst, dstStart + length);
SetBoxedOrUnboxedInitializedLength(cx, dst, dstStart + length);
if (DstType == JSVAL_TYPE_MAGIC) {
if (SrcType == JSVAL_TYPE_MAGIC) {
const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
} else {
for (size_t i = 0; i < length; i++) {
Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
dst->as<NativeObject>().initDenseElement(dstStart + i, v);
}
}
} else if (DstType == SrcType) {
uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
size_t elementSize = UnboxedTypeSize(DstType);
memcpy(dstData + dstStart * elementSize,
srcData + srcStart * elementSize,
length * elementSize);
// Add a store buffer entry if we might have copied a nursery pointer to dst.
if (UnboxedTypeNeedsPostBarrier(DstType) && !IsInsideNursery(dst))
dst->runtimeFromMainThread()->gc.storeBuffer.putWholeCell(dst);
} else if (DstType == JSVAL_TYPE_DOUBLE && SrcType == JSVAL_TYPE_INT32) {
uint8_t* dstData = dst->as<UnboxedArrayObject>().elements();
uint8_t* srcData = src->as<UnboxedArrayObject>().elements();
for (size_t i = 0; i < length; i++) {
int32_t v = *reinterpret_cast<int32_t*>(srcData + (srcStart + i) * sizeof(int32_t));
*reinterpret_cast<double*>(dstData + (dstStart + i) * sizeof(double)) = v;
}
} else {
for (size_t i = 0; i < length; i++) {
Value v = GetBoxedOrUnboxedDenseElement<SrcType>(src, srcStart + i);
dst->as<UnboxedArrayObject>().initElementNoTypeChangeSpecific<DstType>(dstStart + i, v);
}
}
const Value* vp = src->as<NativeObject>().getDenseElements() + srcStart;
dst->as<NativeObject>().initDenseElements(dstStart, vp, length);
return DenseElementResult::Success;
}
@@ -664,24 +318,9 @@ template <typename F>
DenseElementResult
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj)
{
if (!HasAnyBoxedOrUnboxedDenseElements(obj))
if (!obj->isNative())
return DenseElementResult::Incomplete;
switch (GetBoxedOrUnboxedType(obj)) {
case JSVAL_TYPE_MAGIC:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
case JSVAL_TYPE_BOOLEAN:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_BOOLEAN>();
case JSVAL_TYPE_INT32:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_INT32>();
case JSVAL_TYPE_DOUBLE:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_DOUBLE>();
case JSVAL_TYPE_STRING:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_STRING>();
case JSVAL_TYPE_OBJECT:
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_OBJECT>();
default:
MOZ_CRASH();
}
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC>();
}
// As above, except the specialization can reflect the unboxed type of two objects.
@@ -689,45 +328,10 @@ template <typename F>
DenseElementResult
CallBoxedOrUnboxedSpecialization(F f, JSObject* obj1, JSObject* obj2)
{
if (!HasAnyBoxedOrUnboxedDenseElements(obj1) || !HasAnyBoxedOrUnboxedDenseElements(obj2))
if (!obj1->isNative() || !obj2->isNative())
return DenseElementResult::Incomplete;
#define SPECIALIZE_OBJ2(TYPE) \
switch (GetBoxedOrUnboxedType(obj2)) { \
case JSVAL_TYPE_MAGIC: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_MAGIC>(); \
case JSVAL_TYPE_BOOLEAN: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_BOOLEAN>(); \
case JSVAL_TYPE_INT32: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_INT32>(); \
case JSVAL_TYPE_DOUBLE: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_DOUBLE>(); \
case JSVAL_TYPE_STRING: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_STRING>(); \
case JSVAL_TYPE_OBJECT: \
return f. DEPENDENT_TEMPLATE_HINT operator()<TYPE, JSVAL_TYPE_OBJECT>(); \
default: \
MOZ_CRASH(); \
}
switch (GetBoxedOrUnboxedType(obj1)) {
case JSVAL_TYPE_MAGIC:
SPECIALIZE_OBJ2(JSVAL_TYPE_MAGIC)
case JSVAL_TYPE_BOOLEAN:
SPECIALIZE_OBJ2(JSVAL_TYPE_BOOLEAN)
case JSVAL_TYPE_INT32:
SPECIALIZE_OBJ2(JSVAL_TYPE_INT32)
case JSVAL_TYPE_DOUBLE:
SPECIALIZE_OBJ2(JSVAL_TYPE_DOUBLE)
case JSVAL_TYPE_STRING:
SPECIALIZE_OBJ2(JSVAL_TYPE_STRING)
case JSVAL_TYPE_OBJECT:
SPECIALIZE_OBJ2(JSVAL_TYPE_OBJECT)
default:
MOZ_CRASH();
}
#undef SPECIALIZE_OBJ2
return f. DEPENDENT_TEMPLATE_HINT operator()<JSVAL_TYPE_MAGIC, JSVAL_TYPE_MAGIC>();
}
#undef DEPENDENT_TEMPLATE_HINT
@@ -792,18 +396,6 @@ struct Signature ## Functor { \
} \
}
#define DefineBoxedOrUnboxedFunctor6(Signature, A, B, C, D, E, F) \
struct Signature ## Functor { \
A a; B b; C c; D d; E e; F f; \
Signature ## Functor(A a, B b, C c, D d, E e, F f) \
: a(a), b(b), c(c), d(d), e(e), f(f) \
{} \
template <JSValueType Type> \
DenseElementResult operator()() { \
return Signature<Type>(a, b, c, d, e, f); \
} \
}
#define DefineBoxedOrUnboxedFunctorPair6(Signature, A, B, C, D, E, F) \
struct Signature ## Functor { \
A a; B b; C c; D d; E e; F f; \
@@ -816,25 +408,6 @@ struct Signature ## Functor { \
} \
}
DenseElementResult
SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes = ShouldUpdateTypes::Update);
DenseElementResult
MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
uint32_t dstStart, uint32_t srcStart, uint32_t length);
DenseElementResult
CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length);
void
SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen);
DenseElementResult
EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t count);
} // namespace js
#endif // vm_UnboxedObject_inl_h
+4 -780
View File
@@ -945,692 +945,6 @@ const Class UnboxedPlainObject::class_ = {
&UnboxedPlainObjectObjectOps
};
/////////////////////////////////////////////////////////////////////
// UnboxedArrayObject
/////////////////////////////////////////////////////////////////////
template <JSValueType Type>
DenseElementResult
AppendUnboxedDenseElements(UnboxedArrayObject* obj, uint32_t initlen,
MutableHandle<GCVector<Value>> values)
{
for (size_t i = 0; i < initlen; i++)
values.infallibleAppend(obj->getElementSpecific<Type>(i));
return DenseElementResult::Success;
}
DefineBoxedOrUnboxedFunctor3(AppendUnboxedDenseElements,
UnboxedArrayObject*, uint32_t, MutableHandle<GCVector<Value>>);
/* static */ bool
UnboxedArrayObject::convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
ObjectGroup* group, Shape* shape)
{
size_t length = obj->as<UnboxedArrayObject>().length();
size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
Rooted<GCVector<Value>> values(cx, GCVector<Value>(cx));
if (!values.reserve(initlen))
return false;
AppendUnboxedDenseElementsFunctor functor(&obj->as<UnboxedArrayObject>(), initlen, &values);
DebugOnly<DenseElementResult> result = CallBoxedOrUnboxedSpecialization(functor, obj);
MOZ_ASSERT(result.value == DenseElementResult::Success);
obj->setGroup(group);
ArrayObject* aobj = &obj->as<ArrayObject>();
aobj->setLastPropertyMakeNative(cx, shape);
// Make sure there is at least one element, so that this array does not
// use emptyObjectElements / emptyObjectElementsShared.
if (!aobj->ensureElements(cx, Max<size_t>(initlen, 1)))
return false;
MOZ_ASSERT(!aobj->getDenseInitializedLength());
aobj->setDenseInitializedLength(initlen);
aobj->initDenseElements(0, values.begin(), initlen);
aobj->setLengthInt32(length);
return true;
}
/* static */ bool
UnboxedArrayObject::convertToNative(JSContext* cx, JSObject* obj)
{
const UnboxedLayout& layout = obj->as<UnboxedArrayObject>().layout();
if (!layout.nativeGroup()) {
if (!UnboxedLayout::makeNativeGroup(cx, obj->group()))
return false;
}
return convertToNativeWithGroup(cx, obj, layout.nativeGroup(), layout.nativeShape());
}
bool
UnboxedArrayObject::convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group)
{
MOZ_ASSERT(elementType() == JSVAL_TYPE_INT32);
MOZ_ASSERT(group->unboxedLayout().elementType() == JSVAL_TYPE_DOUBLE);
Vector<int32_t> values(cx);
if (!values.reserve(initializedLength()))
return false;
for (size_t i = 0; i < initializedLength(); i++)
values.infallibleAppend(getElementSpecific<JSVAL_TYPE_INT32>(i).toInt32());
uint8_t* newElements;
if (hasInlineElements()) {
newElements = AllocateObjectBuffer<uint8_t>(cx, this, capacity() * sizeof(double));
} else {
newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
capacity() * sizeof(int32_t),
capacity() * sizeof(double));
}
if (!newElements)
return false;
setGroup(group);
elements_ = newElements;
for (size_t i = 0; i < initializedLength(); i++)
setElementNoTypeChangeSpecific<JSVAL_TYPE_DOUBLE>(i, DoubleValue(values[i]));
return true;
}
/* static */ UnboxedArrayObject*
UnboxedArrayObject::create(ExclusiveContext* cx, HandleObjectGroup group, uint32_t length,
NewObjectKind newKind, uint32_t maxLength)
{
MOZ_ASSERT(length <= MaximumCapacity);
MOZ_ASSERT(group->clasp() == &class_);
uint32_t elementSize = UnboxedTypeSize(group->unboxedLayout().elementType());
uint32_t capacity = Min(length, maxLength);
uint32_t nbytes = offsetOfInlineElements() + elementSize * capacity;
UnboxedArrayObject* res;
if (nbytes <= JSObject::MAX_BYTE_SIZE) {
gc::AllocKind allocKind = gc::GetGCObjectKindForBytes(nbytes);
// If there was no provided length information, pick an allocation kind
// to accommodate small arrays (as is done for normal native arrays).
if (capacity == 0)
allocKind = gc::AllocKind::OBJECT8;
res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, allocKind, newKind);
if (!res)
return nullptr;
res->setInitializedLengthNoBarrier(0);
res->setInlineElements();
size_t actualCapacity = (GetGCKindBytes(allocKind) - offsetOfInlineElements()) / elementSize;
MOZ_ASSERT(actualCapacity >= capacity);
res->setCapacityIndex(exactCapacityIndex(actualCapacity));
} else {
res = NewObjectWithGroup<UnboxedArrayObject>(cx, group, gc::AllocKind::OBJECT0, newKind);
if (!res)
return nullptr;
res->setInitializedLengthNoBarrier(0);
uint32_t capacityIndex = (capacity == length)
? CapacityMatchesLengthIndex
: chooseCapacityIndex(capacity, length);
uint32_t actualCapacity = computeCapacity(capacityIndex, length);
res->elements_ = AllocateObjectBuffer<uint8_t>(cx, res, actualCapacity * elementSize);
if (!res->elements_) {
// Make the object safe for GC.
res->setInlineElements();
return nullptr;
}
res->setCapacityIndex(capacityIndex);
}
res->setLength(cx, length);
return res;
}
bool
UnboxedArrayObject::setElement(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
uint8_t* p = elements() + index * elementSize();
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ true);
}
bool
UnboxedArrayObject::initElement(ExclusiveContext* cx, size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
uint8_t* p = elements() + index * elementSize();
return SetUnboxedValue(cx, this, JSID_VOID, p, elementType(), v, /* preBarrier = */ false);
}
void
UnboxedArrayObject::initElementNoTypeChange(size_t index, const Value& v)
{
MOZ_ASSERT(index < initializedLength());
uint8_t* p = elements() + index * elementSize();
if (UnboxedTypeNeedsPreBarrier(elementType()))
*reinterpret_cast<void**>(p) = nullptr;
SetUnboxedValueNoTypeChange(this, p, elementType(), v, /* preBarrier = */ false);
}
Value
UnboxedArrayObject::getElement(size_t index)
{
MOZ_ASSERT(index < initializedLength());
uint8_t* p = elements() + index * elementSize();
return GetUnboxedValue(p, elementType(), /* maybeUninitialized = */ false);
}
/* static */ void
UnboxedArrayObject::trace(JSTracer* trc, JSObject* obj)
{
JSValueType type = obj->as<UnboxedArrayObject>().elementType();
if (!UnboxedTypeNeedsPreBarrier(type))
return;
MOZ_ASSERT(obj->as<UnboxedArrayObject>().elementSize() == sizeof(uintptr_t));
size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
void** elements = reinterpret_cast<void**>(obj->as<UnboxedArrayObject>().elements());
switch (type) {
case JSVAL_TYPE_OBJECT:
for (size_t i = 0; i < initlen; i++) {
GCPtrObject* heap = reinterpret_cast<GCPtrObject*>(elements + i);
TraceNullableEdge(trc, heap, "unboxed_object");
}
break;
case JSVAL_TYPE_STRING:
for (size_t i = 0; i < initlen; i++) {
GCPtrString* heap = reinterpret_cast<GCPtrString*>(elements + i);
TraceEdge(trc, heap, "unboxed_string");
}
break;
default:
MOZ_CRASH();
}
}
/* static */ void
UnboxedArrayObject::objectMoved(JSObject* obj, const JSObject* old)
{
UnboxedArrayObject& dst = obj->as<UnboxedArrayObject>();
const UnboxedArrayObject& src = old->as<UnboxedArrayObject>();
// Fix up possible inline data pointer.
if (src.hasInlineElements())
dst.setInlineElements();
}
/* static */ void
UnboxedArrayObject::finalize(FreeOp* fop, JSObject* obj)
{
MOZ_ASSERT(!IsInsideNursery(obj));
if (!obj->as<UnboxedArrayObject>().hasInlineElements())
js_free(obj->as<UnboxedArrayObject>().elements());
}
/* static */ size_t
UnboxedArrayObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
gc::AllocKind allocKind)
{
UnboxedArrayObject* ndst = &dst->as<UnboxedArrayObject>();
UnboxedArrayObject* nsrc = &src->as<UnboxedArrayObject>();
MOZ_ASSERT(ndst->elements() == nsrc->elements());
Nursery& nursery = trc->runtime()->gc.nursery;
if (!nursery.isInside(nsrc->elements())) {
nursery.removeMallocedBuffer(nsrc->elements());
return 0;
}
// Determine if we can use inline data for the target array. If this is
// possible, the nursery will have picked an allocation size that is large
// enough.
size_t nbytes = nsrc->capacity() * nsrc->elementSize();
if (offsetOfInlineElements() + nbytes <= GetGCKindBytes(allocKind)) {
ndst->setInlineElements();
} else {
MOZ_ASSERT(allocKind == gc::AllocKind::OBJECT0);
AutoEnterOOMUnsafeRegion oomUnsafe;
uint8_t* data = nsrc->zone()->pod_malloc<uint8_t>(nbytes);
if (!data)
oomUnsafe.crash("Failed to allocate unboxed array elements while tenuring.");
ndst->elements_ = data;
}
PodCopy(ndst->elements(), nsrc->elements(), nsrc->initializedLength() * nsrc->elementSize());
// Set a forwarding pointer for the element buffers in case they were
// preserved on the stack by Ion.
bool direct = nsrc->capacity() * nsrc->elementSize() >= sizeof(uintptr_t);
nursery.maybeSetForwardingPointer(trc, nsrc->elements(), ndst->elements(), direct);
return ndst->hasInlineElements() ? 0 : nbytes;
}
// Possible capacities for unboxed arrays. Some of these capacities might seem
// a little weird, but were chosen to allow the inline data of objects of each
// size to be fully utilized for arrays of the various types on both 32 bit and
// 64 bit platforms.
//
// To find the possible inline capacities, the following script was used:
//
// var fixedSlotCapacities = [0, 2, 4, 8, 12, 16];
// var dataSizes = [1, 4, 8];
// var header32 = 4 * 2 + 4 * 2;
// var header64 = 8 * 2 + 4 * 2;
//
// for (var i = 0; i < fixedSlotCapacities.length; i++) {
// var nfixed = fixedSlotCapacities[i];
// var size32 = 4 * 4 + 8 * nfixed - header32;
// var size64 = 8 * 4 + 8 * nfixed - header64;
// for (var j = 0; j < dataSizes.length; j++) {
// print(size32 / dataSizes[j]);
// print(size64 / dataSizes[j]);
// }
// }
//
/* static */ const uint32_t
UnboxedArrayObject::CapacityArray[] = {
UINT32_MAX, // For CapacityMatchesLengthIndex.
0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 13, 16, 17, 18, 24, 26, 32, 34, 40, 64, 72, 96, 104, 128, 136,
256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288,
1048576, 2097152, 3145728, 4194304, 5242880, 6291456, 7340032, 8388608, 9437184, 11534336,
13631488, 15728640, 17825792, 20971520, 24117248, 27262976, 31457280, 35651584, 40894464,
46137344, 52428800, 59768832, MaximumCapacity
};
static const uint32_t
Pow2CapacityIndexes[] = {
2, // 1
3, // 2
5, // 4
8, // 8
13, // 16
18, // 32
21, // 64
25, // 128
27, // 256
28, // 512
29, // 1024
30, // 2048
31, // 4096
32, // 8192
33, // 16384
34, // 32768
35, // 65536
36, // 131072
37, // 262144
38, // 524288
39 // 1048576
};
static const uint32_t MebiCapacityIndex = 39;
/* static */ uint32_t
UnboxedArrayObject::chooseCapacityIndex(uint32_t capacity, uint32_t length)
{
// Note: the structure and behavior of this method follow along with
// NativeObject::goodAllocated. Changes to the allocation strategy in one
// should generally be matched by the other.
// Make sure we have enough space to store all possible values for the capacity index.
// This ought to be a static_assert, but MSVC doesn't like that.
MOZ_ASSERT(mozilla::ArrayLength(CapacityArray) - 1 <= (CapacityMask >> CapacityShift));
// The caller should have ensured the capacity is possible for an unboxed array.
MOZ_ASSERT(capacity <= MaximumCapacity);
static const uint32_t Mebi = 1024 * 1024;
if (capacity <= Mebi) {
capacity = mozilla::RoundUpPow2(capacity);
// When the required capacity is close to the array length, then round
// up to the array length itself, as for NativeObject.
if (length >= capacity && capacity > (length / 3) * 2)
return CapacityMatchesLengthIndex;
if (capacity < MinimumDynamicCapacity)
capacity = MinimumDynamicCapacity;
uint32_t bit = mozilla::FloorLog2Size(capacity);
MOZ_ASSERT(capacity == uint32_t(1 << bit));
MOZ_ASSERT(bit <= 20);
MOZ_ASSERT(mozilla::ArrayLength(Pow2CapacityIndexes) == 21);
uint32_t index = Pow2CapacityIndexes[bit];
MOZ_ASSERT(CapacityArray[index] == capacity);
return index;
}
MOZ_ASSERT(CapacityArray[MebiCapacityIndex] == Mebi);
for (uint32_t i = MebiCapacityIndex + 1;; i++) {
if (CapacityArray[i] >= capacity)
return i;
}
MOZ_CRASH("Invalid capacity");
}
/* static */ uint32_t
UnboxedArrayObject::exactCapacityIndex(uint32_t capacity)
{
for (size_t i = CapacityMatchesLengthIndex + 1; i < ArrayLength(CapacityArray); i++) {
if (CapacityArray[i] == capacity)
return i;
}
MOZ_CRASH();
}
bool
UnboxedArrayObject::growElements(ExclusiveContext* cx, size_t cap)
{
// The caller should have checked if this capacity is possible for an
// unboxed array, so the only way this call can fail is from OOM.
MOZ_ASSERT(cap <= MaximumCapacity);
uint32_t oldCapacity = capacity();
uint32_t newCapacityIndex = chooseCapacityIndex(cap, length());
uint32_t newCapacity = computeCapacity(newCapacityIndex, length());
MOZ_ASSERT(oldCapacity < cap);
MOZ_ASSERT(cap <= newCapacity);
// The allocation size computation below cannot have integer overflows.
JS_STATIC_ASSERT(MaximumCapacity < UINT32_MAX / sizeof(double));
uint8_t* newElements;
if (hasInlineElements()) {
newElements = AllocateObjectBuffer<uint8_t>(cx, this, newCapacity * elementSize());
if (!newElements)
return false;
js_memcpy(newElements, elements(), initializedLength() * elementSize());
} else {
newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
oldCapacity * elementSize(),
newCapacity * elementSize());
if (!newElements)
return false;
}
elements_ = newElements;
setCapacityIndex(newCapacityIndex);
return true;
}
void
UnboxedArrayObject::shrinkElements(ExclusiveContext* cx, size_t cap)
{
if (hasInlineElements())
return;
uint32_t oldCapacity = capacity();
uint32_t newCapacityIndex = chooseCapacityIndex(cap, 0);
uint32_t newCapacity = computeCapacity(newCapacityIndex, 0);
MOZ_ASSERT(cap < oldCapacity);
MOZ_ASSERT(cap <= newCapacity);
if (newCapacity >= oldCapacity)
return;
uint8_t* newElements = ReallocateObjectBuffer<uint8_t>(cx, this, elements(),
oldCapacity * elementSize(),
newCapacity * elementSize());
if (!newElements)
return;
elements_ = newElements;
setCapacityIndex(newCapacityIndex);
}
bool
UnboxedArrayObject::containsProperty(ExclusiveContext* cx, jsid id)
{
if (JSID_IS_INT(id) && uint32_t(JSID_TO_INT(id)) < initializedLength())
return true;
if (JSID_IS_ATOM(id) && JSID_TO_ATOM(id) == cx->names().length)
return true;
return false;
}
/* static */ bool
UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
MarkNonNativePropertyFound<CanGC>(propp);
objp.set(obj);
return true;
}
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
objp.set(nullptr);
propp.set(nullptr);
return true;
}
return LookupProperty(cx, proto, id, objp, propp);
}
/* static */ bool
UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
ObjectOpResult& result)
{
if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) {
UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
uint32_t index = JSID_TO_INT(id);
if (index < nobj->initializedLength()) {
if (nobj->setElement(cx, index, desc.value()))
return result.succeed();
} else if (index == nobj->initializedLength() && index < MaximumCapacity) {
if (nobj->initializedLength() == nobj->capacity()) {
if (!nobj->growElements(cx, index + 1))
return false;
}
nobj->setInitializedLength(index + 1);
if (nobj->initElement(cx, index, desc.value())) {
if (nobj->length() <= index)
nobj->setLengthInt32(index + 1);
return result.succeed();
}
nobj->setInitializedLengthNoBarrier(index);
}
}
if (!convertToNative(cx, obj))
return false;
return DefineProperty(cx, obj, id, desc, result);
}
/* static */ bool
UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
*foundp = true;
return true;
}
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
*foundp = false;
return true;
}
return HasProperty(cx, proto, id, foundp);
}
/* static */ bool
UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
if (JSID_IS_INT(id))
vp.set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
else
vp.set(Int32Value(obj->as<UnboxedArrayObject>().length()));
return true;
}
RootedObject proto(cx, obj->staticPrototype());
if (!proto) {
vp.setUndefined();
return true;
}
return GetProperty(cx, proto, receiver, id, vp);
}
/* static */ bool
UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
if (receiver.isObject() && obj == &receiver.toObject()) {
if (JSID_IS_INT(id)) {
if (obj->as<UnboxedArrayObject>().setElement(cx, JSID_TO_INT(id), v))
return result.succeed();
} else {
uint32_t len;
if (!CanonicalizeArrayLengthValue(cx, v, &len))
return false;
UnboxedArrayObject* nobj = &obj->as<UnboxedArrayObject>();
if (len < nobj->initializedLength()) {
nobj->setInitializedLength(len);
nobj->shrinkElements(cx, len);
}
nobj->setLength(cx, len);
return result.succeed();
}
if (!convertToNative(cx, obj))
return false;
return SetProperty(cx, obj, id, v, receiver, result);
}
return SetPropertyByDefining(cx, id, v, receiver, result);
}
return SetPropertyOnProto(cx, obj, id, v, receiver, result);
}
/* static */ bool
UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
if (JSID_IS_INT(id)) {
desc.value().set(obj->as<UnboxedArrayObject>().getElement(JSID_TO_INT(id)));
desc.setAttributes(JSPROP_ENUMERATE);
} else {
desc.value().set(Int32Value(obj->as<UnboxedArrayObject>().length()));
desc.setAttributes(JSPROP_PERMANENT);
}
desc.object().set(obj);
return true;
}
desc.object().set(nullptr);
return true;
}
/* static */ bool
UnboxedArrayObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
ObjectOpResult& result)
{
if (obj->as<UnboxedArrayObject>().containsProperty(cx, id)) {
size_t initlen = obj->as<UnboxedArrayObject>().initializedLength();
if (JSID_IS_INT(id) && JSID_TO_INT(id) == int32_t(initlen - 1)) {
obj->as<UnboxedArrayObject>().setInitializedLength(initlen - 1);
obj->as<UnboxedArrayObject>().shrinkElements(cx, initlen - 1);
return result.succeed();
}
}
if (!convertToNative(cx, obj))
return false;
return DeleteProperty(cx, obj, id, result);
}
/* static */ bool
UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly)
{
for (size_t i = 0; i < obj->as<UnboxedArrayObject>().initializedLength(); i++) {
if (!properties.append(INT_TO_JSID(i)))
return false;
}
if (!enumerableOnly && !properties.append(NameToId(cx->names().length)))
return false;
return true;
}
static const ClassOps UnboxedArrayObjectClassOps = {
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
UnboxedArrayObject::finalize,
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
UnboxedArrayObject::trace,
};
static const ClassExtension UnboxedArrayObjectClassExtension = {
nullptr, /* weakmapKeyDelegateOp */
UnboxedArrayObject::objectMoved
};
static const ObjectOps UnboxedArrayObjectObjectOps = {
UnboxedArrayObject::obj_lookupProperty,
UnboxedArrayObject::obj_defineProperty,
UnboxedArrayObject::obj_hasProperty,
UnboxedArrayObject::obj_getProperty,
UnboxedArrayObject::obj_setProperty,
UnboxedArrayObject::obj_getOwnPropertyDescriptor,
UnboxedArrayObject::obj_deleteProperty,
nullptr, /* getElements */
UnboxedArrayObject::obj_enumerate,
nullptr /* funToString */
};
const Class UnboxedArrayObject::class_ = {
"Array",
Class::NON_NATIVE |
JSCLASS_SKIP_NURSERY_FINALIZE |
JSCLASS_BACKGROUND_FINALIZE,
&UnboxedArrayObjectClassOps,
JS_NULL_CLASS_SPEC,
&UnboxedArrayObjectClassExtension,
&UnboxedArrayObjectObjectOps
};
/////////////////////////////////////////////////////////////////////
// API
/////////////////////////////////////////////////////////////////////
@@ -1856,31 +1170,6 @@ GetValuesFromPreliminaryArrayObject(ArrayObject* obj, MutableHandle<GCVector<Val
return true;
}
void
UnboxedArrayObject::fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor)
{
MOZ_ASSERT(CapacityArray[1] == 0);
setCapacityIndex(1);
setInitializedLengthNoBarrier(0);
setInlineElements();
setLength(cx, NextValue(values, valueCursor).toInt32());
int32_t initlen = NextValue(values, valueCursor).toInt32();
if (!initlen)
return;
AutoEnterOOMUnsafeRegion oomUnsafe;
if (!growElements(cx, initlen))
oomUnsafe.crash("UnboxedArrayObject::fillAfterConvert");
setInitializedLength(initlen);
for (size_t i = 0; i < size_t(initlen); i++)
JS_ALWAYS_TRUE(initElement(cx, i, NextValue(values, valueCursor)));
}
static bool
GetValuesFromPreliminaryPlainObject(PlainObject* obj, MutableHandle<GCVector<Value>> values)
{
@@ -1907,17 +1196,10 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Sh
{
bool isArray = !templateShape;
// Unboxed arrays are nightly only for now. The getenv() call will be
// removed when they are on by default. See bug 1153266.
if (isArray) {
#ifdef NIGHTLY_BUILD
if (!getenv("JS_OPTION_USE_UNBOXED_ARRAYS")) {
if (!cx->options().unboxedArrays())
return true;
}
#else
// Unboxed arrays are a NOP.
// All of this will go away so don't worry about removing unreachable code below.
return true;
#endif
} else {
if (jit::JitOptions.disableUnboxedObjects)
return true;
@@ -2022,7 +1304,7 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Sh
// fallible stuff first before modifying any objects.
// Get an empty shape which we can use for the preliminary objects.
const Class* clasp = isArray ? &UnboxedArrayObject::class_ : &UnboxedPlainObject::class_;
const Class* clasp = &UnboxedPlainObject::class_;
Shape* newShape = EmptyShape::getInitialShape(cx, clasp, group->proto(), 0);
if (!newShape) {
cx->recoverFromOutOfMemory();
@@ -2066,67 +1348,9 @@ js::TryConvertToUnboxedLayout(ExclusiveContext* cx, AutoEnterAnalysis& enter, Sh
if (!obj)
continue;
if (isArray)
obj->as<UnboxedArrayObject>().fillAfterConvert(cx, values, &valueCursor);
else
obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
obj->as<UnboxedPlainObject>().fillAfterConvert(cx, values, &valueCursor);
}
MOZ_ASSERT(valueCursor == values.length());
return true;
}
DefineBoxedOrUnboxedFunctor6(SetOrExtendBoxedOrUnboxedDenseElements,
ExclusiveContext*, JSObject*, uint32_t, const Value*, uint32_t,
ShouldUpdateTypes);
DenseElementResult
js::SetOrExtendAnyBoxedOrUnboxedDenseElements(ExclusiveContext* cx, JSObject* obj,
uint32_t start, const Value* vp, uint32_t count,
ShouldUpdateTypes updateTypes)
{
SetOrExtendBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, start, vp, count, updateTypes);
return CallBoxedOrUnboxedSpecialization(functor, obj);
};
DefineBoxedOrUnboxedFunctor5(MoveBoxedOrUnboxedDenseElements,
JSContext*, JSObject*, uint32_t, uint32_t, uint32_t);
DenseElementResult
js::MoveAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj,
uint32_t dstStart, uint32_t srcStart, uint32_t length)
{
MoveBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, dstStart, srcStart, length);
return CallBoxedOrUnboxedSpecialization(functor, obj);
}
DefineBoxedOrUnboxedFunctorPair6(CopyBoxedOrUnboxedDenseElements,
JSContext*, JSObject*, JSObject*, uint32_t, uint32_t, uint32_t);
DenseElementResult
js::CopyAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* dst, JSObject* src,
uint32_t dstStart, uint32_t srcStart, uint32_t length)
{
CopyBoxedOrUnboxedDenseElementsFunctor functor(cx, dst, src, dstStart, srcStart, length);
return CallBoxedOrUnboxedSpecialization(functor, dst, src);
}
DefineBoxedOrUnboxedFunctor3(SetBoxedOrUnboxedInitializedLength,
JSContext*, JSObject*, size_t);
void
js::SetAnyBoxedOrUnboxedInitializedLength(JSContext* cx, JSObject* obj, size_t initlen)
{
SetBoxedOrUnboxedInitializedLengthFunctor functor(cx, obj, initlen);
JS_ALWAYS_TRUE(CallBoxedOrUnboxedSpecialization(functor, obj) == DenseElementResult::Success);
}
DefineBoxedOrUnboxedFunctor3(EnsureBoxedOrUnboxedDenseElements,
JSContext*, JSObject*, size_t);
DenseElementResult
js::EnsureAnyBoxedOrUnboxedDenseElements(JSContext* cx, JSObject* obj, size_t initlen)
{
EnsureBoxedOrUnboxedDenseElementsFunctor functor(cx, obj, initlen);
return CallBoxedOrUnboxedSpecialization(functor, obj);
}
-187
View File
@@ -331,193 +331,6 @@ UnboxedLayout::getAllocKind() const
return gc::GetGCObjectKindForBytes(UnboxedPlainObject::offsetOfData() + size());
}
// Class for an array object using an unboxed representation.
class UnboxedArrayObject : public JSObject
{
// Elements pointer for the object.
uint8_t* elements_;
// The nominal array length. This always fits in an int32_t.
uint32_t length_;
// Value indicating the allocated capacity and initialized length of the
// array. The top CapacityBits bits are an index into CapacityArray, which
// indicates the elements capacity. The low InitializedLengthBits store the
// initialized length of the array.
uint32_t capacityIndexAndInitializedLength_;
// If the elements are inline, they will point here.
uint8_t inlineElements_[1];
public:
static const uint32_t CapacityBits = 6;
static const uint32_t CapacityShift = 26;
static const uint32_t CapacityMask = uint32_t(-1) << CapacityShift;
static const uint32_t InitializedLengthMask = (1 << CapacityShift) - 1;
static const uint32_t MaximumCapacity = InitializedLengthMask;
static const uint32_t MinimumDynamicCapacity = 8;
static const uint32_t CapacityArray[];
// Capacity index which indicates the array's length is also its capacity.
static const uint32_t CapacityMatchesLengthIndex = 0;
private:
static inline uint32_t computeCapacity(uint32_t index, uint32_t length) {
if (index == CapacityMatchesLengthIndex)
return length;
return CapacityArray[index];
}
static uint32_t chooseCapacityIndex(uint32_t capacity, uint32_t length);
static uint32_t exactCapacityIndex(uint32_t capacity);
public:
static const Class class_;
static bool obj_lookupProperty(JSContext* cx, HandleObject obj,
HandleId id, MutableHandleObject objp,
MutableHandleShape propp);
static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id,
Handle<PropertyDescriptor> desc,
ObjectOpResult& result);
static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp);
static bool obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiver,
HandleId id, MutableHandleValue vp);
static bool obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v,
HandleValue receiver, ObjectOpResult& result);
static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
MutableHandle<PropertyDescriptor> desc);
static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id,
ObjectOpResult& result);
static bool obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties,
bool enumerableOnly);
static bool obj_watch(JSContext* cx, HandleObject obj, HandleId id, HandleObject callable);
inline const UnboxedLayout& layout() const;
const UnboxedLayout& layoutDontCheckGeneration() const {
return group()->unboxedLayoutDontCheckGeneration();
}
JSValueType elementType() const {
return layoutDontCheckGeneration().elementType();
}
uint32_t elementSize() const {
return UnboxedTypeSize(elementType());
}
static bool convertToNative(JSContext* cx, JSObject* obj);
static UnboxedArrayObject* create(ExclusiveContext* cx, HandleObjectGroup group,
uint32_t length, NewObjectKind newKind,
uint32_t maxLength = MaximumCapacity);
static bool convertToNativeWithGroup(ExclusiveContext* cx, JSObject* obj,
ObjectGroup* group, Shape* shape);
bool convertInt32ToDouble(ExclusiveContext* cx, ObjectGroup* group);
void fillAfterConvert(ExclusiveContext* cx,
Handle<GCVector<Value>> values, size_t* valueCursor);
static void trace(JSTracer* trc, JSObject* object);
static void objectMoved(JSObject* obj, const JSObject* old);
static void finalize(FreeOp* fop, JSObject* obj);
static size_t objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject* src,
gc::AllocKind allocKind);
uint8_t* elements() {
return elements_;
}
bool hasInlineElements() const {
return elements_ == &inlineElements_[0];
}
uint32_t length() const {
return length_;
}
uint32_t initializedLength() const {
return capacityIndexAndInitializedLength_ & InitializedLengthMask;
}
uint32_t capacityIndex() const {
return (capacityIndexAndInitializedLength_ & CapacityMask) >> CapacityShift;
}
uint32_t capacity() const {
return computeCapacity(capacityIndex(), length());
}
bool containsProperty(ExclusiveContext* cx, jsid id);
bool setElement(ExclusiveContext* cx, size_t index, const Value& v);
bool initElement(ExclusiveContext* cx, size_t index, const Value& v);
void initElementNoTypeChange(size_t index, const Value& v);
Value getElement(size_t index);
template <JSValueType Type> inline bool setElementSpecific(ExclusiveContext* cx, size_t index,
const Value& v);
template <JSValueType Type> inline void setElementNoTypeChangeSpecific(size_t index, const Value& v);
template <JSValueType Type> inline bool initElementSpecific(ExclusiveContext* cx, size_t index,
const Value& v);
template <JSValueType Type> inline void initElementNoTypeChangeSpecific(size_t index, const Value& v);
template <JSValueType Type> inline Value getElementSpecific(size_t index);
template <JSValueType Type> inline void triggerPreBarrier(size_t index);
bool growElements(ExclusiveContext* cx, size_t cap);
void shrinkElements(ExclusiveContext* cx, size_t cap);
static uint32_t offsetOfElements() {
return offsetof(UnboxedArrayObject, elements_);
}
static uint32_t offsetOfLength() {
return offsetof(UnboxedArrayObject, length_);
}
static uint32_t offsetOfCapacityIndexAndInitializedLength() {
return offsetof(UnboxedArrayObject, capacityIndexAndInitializedLength_);
}
static uint32_t offsetOfInlineElements() {
return offsetof(UnboxedArrayObject, inlineElements_);
}
void setLengthInt32(uint32_t length) {
MOZ_ASSERT(length <= INT32_MAX);
length_ = length;
}
inline void setLength(ExclusiveContext* cx, uint32_t len);
inline void setInitializedLength(uint32_t initlen);
inline void setInitializedLengthNoBarrier(uint32_t initlen) {
MOZ_ASSERT(initlen <= InitializedLengthMask);
capacityIndexAndInitializedLength_ =
(capacityIndexAndInitializedLength_ & CapacityMask) | initlen;
}
private:
void setInlineElements() {
elements_ = &inlineElements_[0];
}
void setCapacityIndex(uint32_t index) {
MOZ_ASSERT(index <= (CapacityMask >> CapacityShift));
capacityIndexAndInitializedLength_ =
(index << CapacityShift) | initializedLength();
}
};
} // namespace js
namespace JS {