summaryrefslogtreecommitdiffstats
path: root/js/src/jit/CodeGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit/CodeGenerator.cpp')
-rw-r--r--js/src/jit/CodeGenerator.cpp381
1 files changed, 293 insertions, 88 deletions
diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp
index 901e9ea93..c3e242991 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3184,7 +3184,9 @@ CodeGenerator::visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins)
void
CodeGenerator::visitElements(LElements* lir)
{
- Address elements(ToRegister(lir->object()), NativeObject::offsetOfElements());
+ Address elements(ToRegister(lir->object()),
+ lir->mir()->unboxed() ? UnboxedArrayObject::offsetOfElements()
+ : NativeObject::offsetOfElements());
masm.loadPtr(elements, ToRegister(lir->output()));
}
@@ -5169,11 +5171,11 @@ static JSObject*
NewArrayWithGroup(JSContext* cx, uint32_t length, HandleObjectGroup group,
bool convertDoubleElements)
{
- ArrayObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
+ JSObject* res = NewFullyAllocatedArrayTryUseGroup(cx, group, length);
if (!res)
return nullptr;
if (convertDoubleElements)
- res->setShouldConvertDoubleElements();
+ res->as<ArrayObject>().setShouldConvertDoubleElements();
return res;
}
@@ -5319,7 +5321,7 @@ CodeGenerator::visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir)
masm.bind(ool->rejoin());
}
-typedef ArrayObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
+typedef JSObject* (*ArrayConstructorOneArgFn)(JSContext*, HandleObjectGroup, int32_t length);
static const VMFunction ArrayConstructorOneArgInfo =
FunctionInfo<ArrayConstructorOneArgFn>(ArrayConstructorOneArg, "ArrayConstructorOneArg");
@@ -5339,11 +5341,21 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
bool canInline = true;
size_t inlineLength = 0;
- if (templateObject->as<ArrayObject>().hasFixedElements()) {
- size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
- inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
+ if (templateObject->is<ArrayObject>()) {
+ if (templateObject->as<ArrayObject>().hasFixedElements()) {
+ size_t numSlots = gc::GetGCKindSlots(templateObject->asTenured().getAllocKind());
+ inlineLength = numSlots - ObjectElements::VALUES_PER_HEADER;
+ } else {
+ canInline = false;
+ }
} else {
- canInline = false;
+ if (templateObject->as<UnboxedArrayObject>().hasInlineElements()) {
+ size_t nbytes =
+ templateObject->tenuredSizeOfThis() - UnboxedArrayObject::offsetOfInlineElements();
+ inlineLength = nbytes / templateObject->as<UnboxedArrayObject>().elementSize();
+ } else {
+ canInline = false;
+ }
}
if (canInline) {
@@ -7765,7 +7777,7 @@ CodeGenerator::visitSinCos(LSinCos *lir)
masm.freeStack(sizeof(double) * 2);
}
-typedef ArrayObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
+typedef JSObject* (*StringSplitFn)(JSContext*, HandleObjectGroup, HandleString, HandleString, uint32_t);
static const VMFunction StringSplitInfo =
FunctionInfo<StringSplitFn>(js::str_split_string, "str_split_string");
@@ -7800,6 +7812,49 @@ 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);
+}
+
+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);
+}
+
+void
+CodeGenerator::visitIncrementUnboxedArrayInitializedLength(LIncrementUnboxedArrayInitializedLength* lir)
+{
+ Register obj = ToRegister(lir->object());
+ masm.add32(Imm32(1), Address(obj, UnboxedArrayObject::offsetOfCapacityIndexAndInitializedLength()));
+}
+
+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);
+}
+
+void
CodeGenerator::visitNotO(LNotO* lir)
{
MOZ_ASSERT(lir->mir()->operandMightEmulateUndefined(),
@@ -8095,19 +8150,46 @@ CodeGenerator::emitStoreElementHoleT(T* lir)
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
addOutOfLineCode(ool, lir->mir());
+ Register obj = ToRegister(lir->object());
Register elements = ToRegister(lir->elements());
const LAllocation* index = lir->index();
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
- Address initLength(elements, ObjectElements::offsetOfInitializedLength());
- masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
+ JSValueType unboxedType = lir->mir()->unboxedType();
+ if (unboxedType == JSVAL_TYPE_MAGIC) {
+ Address initLength(elements, ObjectElements::offsetOfInitializedLength());
+ masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
- if (lir->mir()->needsBarrier())
- emitPreBarrier(elements, index, 0);
+ if (lir->mir()->needsBarrier())
+ emitPreBarrier(elements, index, 0);
+
+ masm.bind(ool->rejoinStore());
+ 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());
- masm.bind(ool->rejoinStore());
- emitStoreElementTyped(lir->value(), lir->mir()->value()->type(), lir->mir()->elementType(),
- elements, index, 0);
+ 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);
+ }
+ }
masm.bind(ool->rejoin());
}
@@ -8127,22 +8209,47 @@ CodeGenerator::emitStoreElementHoleV(T* lir)
OutOfLineStoreElementHole* ool = new(alloc()) OutOfLineStoreElementHole(lir);
addOutOfLineCode(ool, lir->mir());
+ Register obj = ToRegister(lir->object());
Register elements = ToRegister(lir->elements());
const LAllocation* index = lir->index();
const ValueOperand value = ToValue(lir, T::Value);
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
- Address initLength(elements, ObjectElements::offsetOfInitializedLength());
- masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
+ JSValueType unboxedType = lir->mir()->unboxedType();
+ if (unboxedType == JSVAL_TYPE_MAGIC) {
+ Address initLength(elements, ObjectElements::offsetOfInitializedLength());
+ masm.branch32(Assembler::BelowOrEqual, initLength, key, ool->entry());
- if (lir->mir()->needsBarrier())
- emitPreBarrier(elements, index, 0);
+ if (lir->mir()->needsBarrier())
+ emitPreBarrier(elements, index, 0);
- masm.bind(ool->rejoinStore());
- if (index->isConstant())
- masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
- else
- masm.storeValue(value, BaseIndex(elements, ToRegister(index), TimesEight));
+ masm.bind(ool->rejoinStore());
+ if (index->isConstant())
+ masm.storeValue(value, Address(elements, ToInt32(index) * sizeof(js::Value)));
+ 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);
+ }
+ }
masm.bind(ool->rejoin());
}
@@ -8213,10 +8320,11 @@ CodeGenerator::visitFallibleStoreElementV(LFallibleStoreElementV* lir)
masm.bind(&isFrozen);
}
-typedef bool (*SetDenseElementFn)(JSContext*, HandleNativeObject, int32_t, HandleValue,
- bool strict);
-static const VMFunction SetDenseElementInfo =
- FunctionInfo<SetDenseElementFn>(jit::SetDenseElement, "SetDenseElement");
+typedef bool (*SetDenseOrUnboxedArrayElementFn)(JSContext*, HandleObject, int32_t,
+ HandleValue, bool strict);
+static const VMFunction SetDenseOrUnboxedArrayElementInfo =
+ FunctionInfo<SetDenseOrUnboxedArrayElementFn>(SetDenseOrUnboxedArrayElement,
+ "SetDenseOrUnboxedArrayElement");
void
CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
@@ -8226,6 +8334,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
const LAllocation* index;
MIRType valueType;
ConstantOrRegister value;
+ JSValueType unboxedType;
+ LDefinition *temp = nullptr;
if (ins->isStoreElementHoleV()) {
LStoreElementHoleV* store = ins->toStoreElementHoleV();
@@ -8234,6 +8344,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
index = store->index();
valueType = store->mir()->value()->type();
value = TypedOrValueRegister(ToValue(store, LStoreElementHoleV::Value));
+ unboxedType = store->mir()->unboxedType();
+ temp = store->getTemp(0);
} else if (ins->isFallibleStoreElementV()) {
LFallibleStoreElementV* store = ins->toFallibleStoreElementV();
object = ToRegister(store->object());
@@ -8241,6 +8353,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
index = store->index();
valueType = store->mir()->value()->type();
value = TypedOrValueRegister(ToValue(store, LFallibleStoreElementV::Value));
+ unboxedType = store->mir()->unboxedType();
+ temp = store->getTemp(0);
} else if (ins->isStoreElementHoleT()) {
LStoreElementHoleT* store = ins->toStoreElementHoleT();
object = ToRegister(store->object());
@@ -8251,6 +8365,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
else
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
+ unboxedType = store->mir()->unboxedType();
+ temp = store->getTemp(0);
} else { // ins->isFallibleStoreElementT()
LFallibleStoreElementT* store = ins->toFallibleStoreElementT();
object = ToRegister(store->object());
@@ -8261,6 +8377,8 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
value = ConstantOrRegister(store->value()->toConstant()->toJSValue());
else
value = TypedOrValueRegister(valueType, ToAnyRegister(store->value()));
+ unboxedType = store->mir()->unboxedType();
+ temp = store->getTemp(0);
}
RegisterOrInt32Constant key = ToRegisterOrInt32Constant(index);
@@ -8271,32 +8389,54 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
Label callStub;
#if defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
// Had to reimplement for MIPS because there are no flags.
- Address initLength(elements, ObjectElements::offsetOfInitializedLength());
- masm.branch32(Assembler::NotEqual, initLength, key, &callStub);
+ if (unboxedType == JSVAL_TYPE_MAGIC) {
+ 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);
+ }
#else
masm.j(Assembler::NotEqual, &callStub);
#endif
- // Check array capacity.
- masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
- key, &callStub);
+ if (unboxedType == JSVAL_TYPE_MAGIC) {
+ // Check array capacity.
+ masm.branch32(Assembler::BelowOrEqual, Address(elements, ObjectElements::offsetOfCapacity()),
+ key, &callStub);
- // Update initialized length. The capacity guard above ensures this won't overflow,
- // due to MAX_DENSE_ELEMENTS_COUNT.
- masm.inc32(&key);
- masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
+ // Update initialized length. The capacity guard above ensures this won't overflow,
+ // due to MAX_DENSE_ELEMENTS_COUNT.
+ masm.inc32(&key);
+ masm.store32(key, Address(elements, ObjectElements::offsetOfInitializedLength()));
- // Update length if length < initializedLength.
- Label dontUpdate;
- masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
- key, &dontUpdate);
- masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
- masm.bind(&dontUpdate);
+ // Update length if length < initializedLength.
+ Label dontUpdate;
+ masm.branch32(Assembler::AboveOrEqual, Address(elements, ObjectElements::offsetOfLength()),
+ key, &dontUpdate);
+ masm.store32(key, Address(elements, ObjectElements::offsetOfLength()));
+ masm.bind(&dontUpdate);
- masm.dec32(&key);
+ 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);
+ }
if ((ins->isStoreElementHoleT() || ins->isFallibleStoreElementT()) &&
- valueType != MIRType::Double)
+ unboxedType == JSVAL_TYPE_MAGIC && valueType != MIRType::Double)
{
// The inline path for StoreElementHoleT and FallibleStoreElementT does not always store
// the type tag, so we do the store on the OOL path. We use MIRType::None for the element
@@ -8325,7 +8465,7 @@ CodeGenerator::visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool)
else
pushArg(ToRegister(index));
pushArg(object);
- callVM(SetDenseElementInfo, ins);
+ callVM(SetDenseOrUnboxedArrayElementInfo, ins);
restoreLive(ins);
masm.jump(ool->rejoin());
@@ -8386,6 +8526,9 @@ 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");
typedef bool (*ArrayPopShiftFn)(JSContext*, HandleObject, MutableHandleValue);
static const VMFunction ArrayPopDenseInfo =
@@ -8411,11 +8554,20 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
// Load elements and length, and VM call if length != initializedLength.
RegisterOrInt32Constant key = RegisterOrInt32Constant(lengthTemp);
- masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
- masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
+ masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), lengthTemp);
- Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
- masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
+ 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());
+ }
// Test for length != 0. On zero length either take a VM call or generate
// an undefined value, depending on whether the call is known to produce
@@ -8427,10 +8579,13 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
// According to the spec we need to set the length 0 (which is already 0).
// This is observable when the array length is made non-writable.
- // Handle this case in the OOL.
- Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
- Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
- masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
+ // Handle this case in the OOL. When freezing an unboxed array it is converted
+ // to an normal array.
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
+ Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
+ masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
+ }
masm.moveValue(UndefinedValue(), out.valueReg());
masm.jump(&done);
@@ -8442,25 +8597,41 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
masm.dec32(&key);
if (mir->mode() == MArrayPopShift::Pop) {
- BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
- masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ BaseIndex addr(elementsTemp, lengthTemp, TimesEight);
+ masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
+ } else {
+ size_t elemSize = UnboxedTypeSize(mir->unboxedType());
+ BaseIndex addr(elementsTemp, lengthTemp, ScaleFromElemWidth(elemSize));
+ masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
+ }
} else {
MOZ_ASSERT(mir->mode() == MArrayPopShift::Shift);
Address addr(elementsTemp, 0);
- masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC)
+ masm.loadElementTypedOrValue(addr, out, mir->needsHoleCheck(), ool->entry());
+ else
+ masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
}
- // Handle the failure case when the array length is non-writable in the
- // OOL path. (Unlike in the adding-an-element cases, we can't rely on the
- // capacity <= length invariant for such arrays to avoid an explicit
- // check.)
- Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
- Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
- masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ // Handle the failure case when the array length is non-writable in the
+ // OOL path. (Unlike in the adding-an-element cases, we can't rely on the
+ // capacity <= length invariant for such arrays to avoid an explicit
+ // check.)
+ Address elementFlags(elementsTemp, ObjectElements::offsetOfFlags());
+ Imm32 bit(ObjectElements::NONWRITABLE_ARRAY_LENGTH);
+ masm.branchTest32(Assembler::NonZero, elementFlags, bit, ool->entry());
- // Now adjust length and initializedLength.
- masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfLength()));
- masm.store32(lengthTemp, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
+ // Now adjust length and initializedLength.
+ 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()));
+ }
if (mir->mode() == MArrayPopShift::Shift) {
// Don't save the temp registers.
@@ -8499,7 +8670,7 @@ CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir)
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
}
-typedef bool (*ArrayPushDenseFn)(JSContext*, HandleArrayObject, HandleValue, uint32_t*);
+typedef bool (*ArrayPushDenseFn)(JSContext*, HandleObject, HandleValue, uint32_t*);
static const VMFunction ArrayPushDenseInfo =
FunctionInfo<ArrayPushDenseFn>(jit::ArrayPushDense, "ArrayPushDense");
@@ -8510,27 +8681,50 @@ CodeGenerator::emitArrayPush(LInstruction* lir, const MArrayPush* mir, Register
OutOfLineCode* ool = oolCallVM(ArrayPushDenseInfo, lir, ArgList(obj, value), StoreRegisterTo(length));
RegisterOrInt32Constant key = RegisterOrInt32Constant(length);
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ // Load elements and length.
+ masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
+ masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
+
+ // Guard length == initializedLength.
+ Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
+ masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
- // Load elements and length.
- masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), elementsTemp);
- masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), length);
+ // Guard length < capacity.
+ Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
+ masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
- // Guard length == initializedLength.
- Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
- masm.branch32(Assembler::NotEqual, initLength, key, ool->entry());
+ // 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 < capacity.
- Address capacity(elementsTemp, ObjectElements::offsetOfCapacity());
- masm.branch32(Assembler::BelowOrEqual, capacity, key, ool->entry());
+ // Guard length == initializedLength.
+ Address lengthAddr(obj, UnboxedArrayObject::offsetOfLength());
+ masm.branch32(Assembler::NotEqual, lengthAddr, key, ool->entry());
- // Do the store.
- masm.storeConstantOrRegister(value, BaseIndex(elementsTemp, length, TimesEight));
+ // 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);
+ }
masm.inc32(&key);
// Update length and initialized length.
- masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfLength()));
- masm.store32(length, Address(elementsTemp, ObjectElements::offsetOfInitializedLength()));
+ if (mir->unboxedType() == JSVAL_TYPE_MAGIC) {
+ 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()));
+ }
masm.bind(ool->rejoin());
}
@@ -10357,11 +10551,22 @@ CodeGenerator::visitLoadElementHole(LLoadElementHole* lir)
else
masm.branch32(Assembler::BelowOrEqual, initLength, ToRegister(lir->index()), &undefined);
- if (lir->index()->isConstant()) {
- NativeObject::elementsSizeMustNotOverflow();
- masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
+ if (mir->unboxedType() != JSVAL_TYPE_MAGIC) {
+ size_t width = UnboxedTypeSize(mir->unboxedType());
+ if (lir->index()->isConstant()) {
+ Address addr(elements, ToInt32(lir->index()) * width);
+ masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
+ } else {
+ BaseIndex addr(elements, ToRegister(lir->index()), ScaleFromElemWidth(width));
+ masm.loadUnboxedProperty(addr, mir->unboxedType(), out);
+ }
} else {
- masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
+ if (lir->index()->isConstant()) {
+ NativeObject::elementsSizeMustNotOverflow();
+ masm.loadValue(Address(elements, ToInt32(lir->index()) * sizeof(Value)), out);
+ } else {
+ masm.loadValue(BaseObjectElementIndex(elements, ToRegister(lir->index())), out);
+ }
}
// If a hole check is needed, and the value wasn't a hole, we're done.
@@ -10739,7 +10944,7 @@ CodeGenerator::visitInArray(LInArray* lir)
}
masm.branch32(Assembler::BelowOrEqual, initLength, Imm32(index), failedInitLength);
- if (mir->needsHoleCheck()) {
+ if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
NativeObject::elementsSizeMustNotOverflow();
Address address = Address(elements, index * sizeof(Value));
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
@@ -10752,7 +10957,7 @@ CodeGenerator::visitInArray(LInArray* lir)
failedInitLength = &negativeIntCheck;
masm.branch32(Assembler::BelowOrEqual, initLength, index, failedInitLength);
- if (mir->needsHoleCheck()) {
+ if (mir->needsHoleCheck() && mir->unboxedType() == JSVAL_TYPE_MAGIC) {
BaseIndex address = BaseIndex(elements, ToRegister(lir->index()), TimesEight);
masm.branchTestMagic(Assembler::Equal, address, &falseBranch);
}