mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-29 03:47:31 +09:00
Revert #1142 - Remove unboxed objects
- accounting for removal of watch()/unwatch()
This commit is contained in:
parent
90e01a7329
commit
47781d6165
48 changed files with 3400 additions and 75 deletions
|
|
@ -31,6 +31,7 @@
|
|||
#include "jit/shared/Lowering-shared-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
|
@ -619,7 +620,26 @@ TestMatchingReceiver(MacroAssembler& masm, IonCache::StubAttacher& attacher,
|
|||
Register object, JSObject* obj, Label* failure,
|
||||
bool alwaysCheckGroup = false)
|
||||
{
|
||||
if (obj->is<TypedObject>()) {
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
MOZ_ASSERT(failure);
|
||||
|
||||
masm.branchTestObjGroup(Assembler::NotEqual, object, obj->group(), failure);
|
||||
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
|
||||
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failure);
|
||||
Label success;
|
||||
masm.push(object);
|
||||
masm.loadPtr(expandoAddress, object);
|
||||
masm.branchTestObjShape(Assembler::Equal, object, expando->lastProperty(),
|
||||
&success);
|
||||
masm.pop(object);
|
||||
masm.jump(failure);
|
||||
masm.bind(&success);
|
||||
masm.pop(object);
|
||||
} else {
|
||||
masm.branchPtr(Assembler::NotEqual, expandoAddress, ImmWord(0), failure);
|
||||
}
|
||||
} else if (obj->is<TypedObject>()) {
|
||||
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
|
||||
Address(object, JSObject::offsetOfGroup()),
|
||||
ImmGCPtr(obj->group()), failure);
|
||||
|
|
@ -736,6 +756,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
// jump directly. Otherwise, jump to the end of the stub, so there's a
|
||||
// common point to patch.
|
||||
bool multipleFailureJumps = (obj != holder)
|
||||
|| obj->is<UnboxedPlainObject>()
|
||||
|| (checkTDZ && output.hasValue())
|
||||
|| (failures != nullptr && failures->used());
|
||||
|
||||
|
|
@ -754,6 +775,7 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
Register scratchReg = Register::FromCode(0); // Quell compiler warning.
|
||||
|
||||
if (obj != holder ||
|
||||
obj->is<UnboxedPlainObject>() ||
|
||||
!holder->as<NativeObject>().isFixedSlot(shape->slot()))
|
||||
{
|
||||
if (output.hasValue()) {
|
||||
|
|
@ -814,6 +836,10 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
|
||||
holderReg = InvalidReg;
|
||||
}
|
||||
} else if (obj->is<UnboxedPlainObject>()) {
|
||||
holder = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
holderReg = scratchReg;
|
||||
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), holderReg);
|
||||
} else {
|
||||
holderReg = object;
|
||||
}
|
||||
|
|
@ -841,6 +867,30 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
|||
attacher.jumpNextStub(masm);
|
||||
}
|
||||
|
||||
static void
|
||||
GenerateReadUnboxed(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
IonCache::StubAttacher& attacher, JSObject* obj,
|
||||
const UnboxedLayout::Property* property,
|
||||
Register object, TypedOrValueRegister output,
|
||||
Label* failures = nullptr)
|
||||
{
|
||||
// Guard on the group of the object.
|
||||
attacher.branchNextStubOrLabel(masm, Assembler::NotEqual,
|
||||
Address(object, JSObject::offsetOfGroup()),
|
||||
ImmGCPtr(obj->group()), failures);
|
||||
|
||||
Address address(object, UnboxedPlainObject::offsetOfData() + property->offset);
|
||||
|
||||
masm.loadUnboxedProperty(address, property->type, output);
|
||||
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
if (failures) {
|
||||
masm.bind(failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitGetterCall(JSContext* cx, MacroAssembler& masm,
|
||||
IonCache::StubAttacher& attacher, JSObject* obj,
|
||||
|
|
@ -1447,6 +1497,67 @@ GetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
|
|||
return linkAndAttachStub(cx, masm, attacher, ion, attachKind, outcome);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, void* returnAddr, bool* emitted)
|
||||
{
|
||||
MOZ_ASSERT(canAttachStub());
|
||||
MOZ_ASSERT(!*emitted);
|
||||
MOZ_ASSERT(outerScript->ionScript() == ion);
|
||||
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return true;
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
|
||||
if (!property)
|
||||
return true;
|
||||
|
||||
*emitted = true;
|
||||
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
|
||||
Label failures;
|
||||
emitIdGuard(masm, id, &failures);
|
||||
Label* maybeFailures = failures.used() ? &failures : nullptr;
|
||||
|
||||
StubAttacher attacher(*this);
|
||||
GenerateReadUnboxed(cx, ion, masm, attacher, obj, property, object(), output(), maybeFailures);
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed",
|
||||
JS::TrackedOutcome::ICGetPropStub_UnboxedRead);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, void* returnAddr, bool* emitted)
|
||||
{
|
||||
MOZ_ASSERT(canAttachStub());
|
||||
MOZ_ASSERT(!*emitted);
|
||||
MOZ_ASSERT(outerScript->ionScript() == ion);
|
||||
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return true;
|
||||
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
|
||||
if (!expando)
|
||||
return true;
|
||||
|
||||
Shape* shape = expando->lookup(cx, id);
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return true;
|
||||
|
||||
*emitted = true;
|
||||
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
|
||||
Label failures;
|
||||
emitIdGuard(masm, id, &failures);
|
||||
Label* maybeFailures = failures.used() ? &failures : nullptr;
|
||||
|
||||
StubAttacher attacher(*this);
|
||||
GenerateReadSlot(cx, ion, masm, attacher, DontCheckTDZ, obj, obj,
|
||||
shape, object(), output(), maybeFailures);
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "read unboxed expando",
|
||||
JS::TrackedOutcome::ICGetPropStub_UnboxedReadExpando);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, bool* emitted)
|
||||
|
|
@ -2016,6 +2127,12 @@ GetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
|
|||
if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, returnAddr, emitted))
|
||||
return false;
|
||||
|
||||
if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, returnAddr, emitted))
|
||||
return false;
|
||||
|
||||
if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, returnAddr, emitted))
|
||||
return false;
|
||||
|
||||
if (!*emitted && !tryAttachTypedArrayLength(cx, outerScript, ion, obj, id, emitted))
|
||||
return false;
|
||||
}
|
||||
|
|
@ -2194,6 +2311,12 @@ GenerateSetSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
|
||||
NativeObject::slotsSizeMustNotOverflow();
|
||||
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
obj = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), tempReg);
|
||||
object = tempReg;
|
||||
}
|
||||
|
||||
if (obj->as<NativeObject>().isFixedSlot(shape->slot())) {
|
||||
Address addr(object, NativeObject::getFixedSlotOffset(shape->slot()));
|
||||
|
||||
|
|
@ -2831,13 +2954,23 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
masm.branchTestObjGroup(Assembler::NotEqual, object, oldGroup, failures);
|
||||
if (obj->maybeShape()) {
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, oldShape, failures);
|
||||
} else {
|
||||
MOZ_ASSERT(obj->is<UnboxedPlainObject>());
|
||||
|
||||
Address expandoAddress(object, UnboxedPlainObject::offsetOfExpando());
|
||||
masm.branchPtr(Assembler::Equal, expandoAddress, ImmWord(0), failures);
|
||||
|
||||
masm.loadPtr(expandoAddress, tempReg);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, tempReg, oldShape, failures);
|
||||
}
|
||||
|
||||
Shape* newShape = obj->maybeShape();
|
||||
if (!newShape)
|
||||
newShape = obj->as<UnboxedPlainObject>().maybeExpando()->lastProperty();
|
||||
|
||||
// Guard that the incoming value is in the type set for the property
|
||||
// if a type barrier is required.
|
||||
if (newShape && checkTypeset)
|
||||
if (checkTypeset)
|
||||
CheckTypeSetForWrite(masm, obj, newShape->propid(), tempReg, value, failures);
|
||||
|
||||
// Guard shapes along prototype chain.
|
||||
|
|
@ -2858,7 +2991,9 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
}
|
||||
|
||||
// Call a stub to (re)allocate dynamic slots, if necessary.
|
||||
uint32_t newNumDynamicSlots = obj->as<NativeObject>().numDynamicSlots();
|
||||
uint32_t newNumDynamicSlots = obj->is<UnboxedPlainObject>()
|
||||
? obj->as<UnboxedPlainObject>().maybeExpando()->numDynamicSlots()
|
||||
: obj->as<NativeObject>().numDynamicSlots();
|
||||
if (NativeObject::dynamicSlotsCount(oldShape) != newNumDynamicSlots) {
|
||||
AllocatableRegisterSet regs(RegisterSet::Volatile());
|
||||
LiveRegisterSet save(regs.asLiveSet());
|
||||
|
|
@ -2869,6 +3004,12 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
Register temp1 = regs.takeAnyGeneral();
|
||||
Register temp2 = regs.takeAnyGeneral();
|
||||
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
// Pass the expando object to the stub.
|
||||
masm.Push(object);
|
||||
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object);
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(temp1);
|
||||
masm.loadJSContext(temp1);
|
||||
masm.passABIArg(temp1);
|
||||
|
|
@ -2885,16 +3026,27 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
masm.jump(&allocDone);
|
||||
|
||||
masm.bind(&allocFailed);
|
||||
if (obj->is<UnboxedPlainObject>())
|
||||
masm.Pop(object);
|
||||
masm.PopRegsInMask(save);
|
||||
masm.jump(failures);
|
||||
|
||||
masm.bind(&allocDone);
|
||||
masm.setFramePushed(framePushedAfterCall);
|
||||
if (obj->is<UnboxedPlainObject>())
|
||||
masm.Pop(object);
|
||||
masm.PopRegsInMask(save);
|
||||
}
|
||||
|
||||
bool popObject = false;
|
||||
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
masm.push(object);
|
||||
popObject = true;
|
||||
obj = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object);
|
||||
}
|
||||
|
||||
// Write the object or expando object's new shape.
|
||||
Address shapeAddr(object, ShapedObject::offsetOfShape());
|
||||
if (cx->zone()->needsIncrementalBarrier())
|
||||
|
|
@ -2902,6 +3054,8 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
|||
masm.storePtr(ImmGCPtr(newShape), shapeAddr);
|
||||
|
||||
if (oldGroup != obj->group()) {
|
||||
MOZ_ASSERT(!obj->is<UnboxedPlainObject>());
|
||||
|
||||
// Changing object's group from a partially to fully initialized group,
|
||||
// per the acquired properties analysis. Only change the group if the
|
||||
// old group still has a newScript.
|
||||
|
|
@ -3144,6 +3298,141 @@ CanAttachNativeSetProp(JSContext* cx, HandleObject obj, HandleId id, const Const
|
|||
return SetPropertyIC::CanAttachNone;
|
||||
}
|
||||
|
||||
static void
|
||||
GenerateSetUnboxed(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& attacher,
|
||||
JSObject* obj, jsid id, uint32_t unboxedOffset, JSValueType unboxedType,
|
||||
Register object, Register tempReg, const ConstantOrRegister& value,
|
||||
bool checkTypeset, Label* failures)
|
||||
{
|
||||
// Guard on the type of the object.
|
||||
masm.branchPtr(Assembler::NotEqual,
|
||||
Address(object, JSObject::offsetOfGroup()),
|
||||
ImmGCPtr(obj->group()), failures);
|
||||
|
||||
if (checkTypeset)
|
||||
CheckTypeSetForWrite(masm, obj, id, tempReg, value, failures);
|
||||
|
||||
Address address(object, UnboxedPlainObject::offsetOfData() + unboxedOffset);
|
||||
|
||||
if (cx->zone()->needsIncrementalBarrier()) {
|
||||
if (unboxedType == JSVAL_TYPE_OBJECT)
|
||||
masm.callPreBarrier(address, MIRType::Object);
|
||||
else if (unboxedType == JSVAL_TYPE_STRING)
|
||||
masm.callPreBarrier(address, MIRType::String);
|
||||
else
|
||||
MOZ_ASSERT(!UnboxedTypeNeedsPreBarrier(unboxedType));
|
||||
}
|
||||
|
||||
masm.storeUnboxedProperty(address, unboxedType, value, failures);
|
||||
|
||||
attacher.jumpRejoin(masm);
|
||||
|
||||
masm.bind(failures);
|
||||
attacher.jumpNextStub(masm);
|
||||
}
|
||||
|
||||
static bool
|
||||
CanAttachSetUnboxed(JSContext* cx, HandleObject obj, HandleId id, const ConstantOrRegister& val,
|
||||
bool needsTypeBarrier, bool* checkTypeset,
|
||||
uint32_t* unboxedOffset, JSValueType* unboxedType)
|
||||
{
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
|
||||
if (property) {
|
||||
*checkTypeset = false;
|
||||
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
|
||||
return false;
|
||||
*unboxedOffset = property->offset;
|
||||
*unboxedType = property->type;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
CanAttachSetUnboxedExpando(JSContext* cx, HandleObject obj, HandleId id,
|
||||
const ConstantOrRegister& val,
|
||||
bool needsTypeBarrier, bool* checkTypeset, Shape** pshape)
|
||||
{
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
|
||||
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
|
||||
if (!expando)
|
||||
return false;
|
||||
|
||||
Shape* shape = expando->lookupPure(id);
|
||||
if (!shape || !shape->hasDefaultSetter() || !shape->hasSlot() || !shape->writable())
|
||||
return false;
|
||||
|
||||
*checkTypeset = false;
|
||||
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
|
||||
return false;
|
||||
|
||||
*pshape = shape;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CanAttachAddUnboxedExpando(JSContext* cx, HandleObject obj, HandleShape oldShape,
|
||||
HandleId id, const ConstantOrRegister& val,
|
||||
bool needsTypeBarrier, bool* checkTypeset)
|
||||
{
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return false;
|
||||
|
||||
Rooted<UnboxedExpandoObject*> expando(cx, obj->as<UnboxedPlainObject>().maybeExpando());
|
||||
if (!expando || expando->inDictionaryMode())
|
||||
return false;
|
||||
|
||||
Shape* newShape = expando->lastProperty();
|
||||
if (newShape->isEmptyShape() || newShape->propid() != id || newShape->previous() != oldShape)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(newShape->hasDefaultSetter() && newShape->hasSlot() && newShape->writable());
|
||||
|
||||
if (PrototypeChainShadowsPropertyAdd(cx, obj, id))
|
||||
return false;
|
||||
|
||||
*checkTypeset = false;
|
||||
if (needsTypeBarrier && !CanInlineSetPropTypeCheck(obj, id, val, checkTypeset))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetPropertyIC::tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, bool* emitted)
|
||||
{
|
||||
MOZ_ASSERT(!*emitted);
|
||||
|
||||
bool checkTypeset = false;
|
||||
uint32_t unboxedOffset;
|
||||
JSValueType unboxedType;
|
||||
if (!CanAttachSetUnboxed(cx, obj, id, value(), needsTypeBarrier(), &checkTypeset,
|
||||
&unboxedOffset, &unboxedType))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
*emitted = true;
|
||||
|
||||
MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_);
|
||||
StubAttacher attacher(*this);
|
||||
|
||||
Label failures;
|
||||
emitIdGuard(masm, id, &failures);
|
||||
|
||||
GenerateSetUnboxed(cx, masm, attacher, obj, id, unboxedOffset, unboxedType,
|
||||
object(), temp(), value(), checkTypeset, &failures);
|
||||
return linkAndAttachStub(cx, masm, attacher, ion, "set_unboxed",
|
||||
JS::TrackedOutcome::ICSetPropStub_SetUnboxed);
|
||||
}
|
||||
|
||||
bool
|
||||
SetPropertyIC::tryAttachProxy(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, bool* emitted)
|
||||
|
|
@ -3224,6 +3513,26 @@ SetPropertyIC::tryAttachNative(JSContext* cx, HandleScript outerScript, IonScrip
|
|||
MOZ_CRASH("Unreachable");
|
||||
}
|
||||
|
||||
bool
|
||||
SetPropertyIC::tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, bool* emitted)
|
||||
{
|
||||
MOZ_ASSERT(!*emitted);
|
||||
|
||||
RootedShape shape(cx);
|
||||
bool checkTypeset = false;
|
||||
if (!CanAttachSetUnboxedExpando(cx, obj, id, value(), needsTypeBarrier(),
|
||||
&checkTypeset, shape.address()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!attachSetSlot(cx, outerScript, ion, obj, shape, checkTypeset))
|
||||
return false;
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleValue idval, HandleValue value,
|
||||
|
|
@ -3249,6 +3558,12 @@ SetPropertyIC::tryAttachStub(JSContext* cx, HandleScript outerScript, IonScript*
|
|||
|
||||
if (!*emitted && !tryAttachNative(cx, outerScript, ion, obj, id, emitted, tryNativeAddSlot))
|
||||
return false;
|
||||
|
||||
if (!*emitted && !tryAttachUnboxed(cx, outerScript, ion, obj, id, emitted))
|
||||
return false;
|
||||
|
||||
if (!*emitted && !tryAttachUnboxedExpando(cx, outerScript, ion, obj, id, emitted))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (idval.isInt32()) {
|
||||
|
|
@ -3300,6 +3615,16 @@ SetPropertyIC::tryAttachAddSlot(JSContext* cx, HandleScript outerScript, IonScri
|
|||
return true;
|
||||
}
|
||||
|
||||
checkTypeset = false;
|
||||
if (CanAttachAddUnboxedExpando(cx, obj, oldShape, id, value(), needsTypeBarrier(),
|
||||
&checkTypeset))
|
||||
{
|
||||
if (!attachAddSlot(cx, outerScript, ion, obj, id, oldShape, oldGroup, checkTypeset))
|
||||
return false;
|
||||
*emitted = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -3321,6 +3646,11 @@ SetPropertyIC::update(JSContext* cx, HandleScript outerScript, size_t cacheIndex
|
|||
return false;
|
||||
|
||||
oldShape = obj->maybeShape();
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
MOZ_ASSERT(!oldShape);
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando())
|
||||
oldShape = expando->lastProperty();
|
||||
}
|
||||
}
|
||||
|
||||
RootedId id(cx);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue