mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-06 15:58:39 +09:00
Remove Unboxed Object code from jit, Part 2.
This commit is contained in:
parent
bd6c34b56a
commit
3e1ffa6cf6
10 changed files with 9 additions and 1048 deletions
|
|
@ -16,7 +16,7 @@ using namespace js;
|
|||
using namespace js::jit;
|
||||
|
||||
// OperandLocation represents the location of an OperandId. The operand is
|
||||
// either in a register or on the stack, and is either boxed or unboxed.
|
||||
// either in a register or on the stack.
|
||||
class OperandLocation
|
||||
{
|
||||
public:
|
||||
|
|
@ -814,36 +814,6 @@ BaselineCacheIRCompiler::emitGuardSpecificObject()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardNoUnboxedExpando()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando());
|
||||
masm.branchPtr(Assembler::NotEqual, expandoAddr, ImmWord(0), failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardAndLoadUnboxedExpando()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
Register output = allocator.defineRegister(masm, reader.objOperandId());
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
Address expandoAddr(obj, UnboxedPlainObject::offsetOfExpando());
|
||||
masm.loadPtr(expandoAddr, output);
|
||||
masm.branchTestPtr(Assembler::Zero, output, output, failure->label());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadFixedSlotResult()
|
||||
{
|
||||
|
|
@ -870,26 +840,6 @@ BaselineCacheIRCompiler::emitLoadDynamicSlotResult()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitLoadUnboxedPropertyResult()
|
||||
{
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
JSValueType fieldType = reader.valueType();
|
||||
|
||||
Address fieldOffset(stubAddress(reader.stubOffset()));
|
||||
masm.load32(fieldOffset, scratch);
|
||||
masm.loadUnboxedProperty(BaseIndex(obj, scratch, TimesOne), fieldType, R0);
|
||||
|
||||
if (fieldType == JSVAL_TYPE_OBJECT)
|
||||
emitEnterTypeMonitorIC();
|
||||
else
|
||||
emitReturnFromIC();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardNoDetachedTypedObjects()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1920,13 +1920,6 @@ ICGetElemNativeCompiler<T>::generateStubCode(MacroAssembler& masm)
|
|||
if (popR1)
|
||||
masm.addToStackPtr(ImmWord(sizeof(size_t)));
|
||||
|
||||
} else if (acctype_ == ICGetElemNativeStub::UnboxedProperty) {
|
||||
masm.load32(Address(ICStubReg, ICGetElemNativeSlotStub<T>::offsetOfOffset()),
|
||||
scratchReg);
|
||||
masm.loadUnboxedProperty(BaseIndex(objReg, scratchReg, TimesOne), unboxedType_,
|
||||
TypedOrValueRegister(R0));
|
||||
if (popR1)
|
||||
masm.addToStackPtr(ImmWord(sizeof(size_t)));
|
||||
} else {
|
||||
MOZ_ASSERT(acctype_ == ICGetElemNativeStub::NativeGetter ||
|
||||
acctype_ == ICGetElemNativeStub::ScriptedGetter);
|
||||
|
|
@ -4292,40 +4285,6 @@ TryAttachSetAccessorPropStub(JSContext* cx, HandleScript script, jsbytecode* pc,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachUnboxedSetPropStub(JSContext* cx, HandleScript script,
|
||||
ICSetProp_Fallback* stub, HandleId id,
|
||||
HandleObject obj, HandleValue rhs, bool* attached)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint)
|
||||
return true;
|
||||
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return true;
|
||||
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(id);
|
||||
if (!property)
|
||||
return true;
|
||||
|
||||
ICSetProp_Unboxed::Compiler compiler(cx, obj->group(),
|
||||
property->offset + UnboxedPlainObject::offsetOfData(),
|
||||
property->type);
|
||||
ICUpdatedStub* newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
if (compiler.needsUpdateStubs() && !newStub->addUpdateStubForValue(cx, script, obj, id, rhs))
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
|
||||
StripPreliminaryObjectStubs(cx, stub);
|
||||
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachTypedObjectSetPropStub(JSContext* cx, HandleScript script,
|
||||
ICSetProp_Fallback* stub, HandleId id,
|
||||
|
|
@ -4485,15 +4444,6 @@ DoSetPropFallback(JSContext* cx, BaselineFrame* frame, ICSetProp_Fallback* stub_
|
|||
if (attached)
|
||||
return true;
|
||||
|
||||
if (!attached &&
|
||||
lhs.isObject() &&
|
||||
!TryAttachUnboxedSetPropStub(cx, script, stub, id, obj, rhs, &attached))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (attached)
|
||||
return true;
|
||||
|
||||
if (!attached &&
|
||||
lhs.isObject() &&
|
||||
!TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
|
||||
|
|
@ -4828,70 +4778,6 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler& masm)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetProp_Unboxed::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
MOZ_ASSERT(engine_ == Engine::Baseline);
|
||||
|
||||
Label failure;
|
||||
|
||||
// Guard input is an object.
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratch = regs.takeAny();
|
||||
|
||||
// Unbox and group guard.
|
||||
Register object = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(ICStubReg, ICSetProp_Unboxed::offsetOfGroup()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfGroup()), scratch,
|
||||
&failure);
|
||||
|
||||
if (needsUpdateStubs()) {
|
||||
// Stow both R0 and R1 (object and value).
|
||||
EmitStowICValues(masm, 2);
|
||||
|
||||
// Move RHS into R0 for TypeUpdate check.
|
||||
masm.moveValue(R1, R0);
|
||||
|
||||
// Call the type update stub.
|
||||
if (!callTypeUpdateIC(masm, sizeof(Value)))
|
||||
return false;
|
||||
|
||||
// Unstow R0 and R1 (object and key)
|
||||
EmitUnstowICValues(masm, 2);
|
||||
|
||||
// The TypeUpdate IC may have smashed object. Rederive it.
|
||||
masm.unboxObject(R0, object);
|
||||
|
||||
// Trigger post barriers here on the values being written. Fields which
|
||||
// objects can be written to also need update stubs.
|
||||
LiveGeneralRegisterSet saveRegs;
|
||||
saveRegs.add(R0);
|
||||
saveRegs.add(R1);
|
||||
saveRegs.addUnchecked(object);
|
||||
saveRegs.add(ICStubReg);
|
||||
emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs);
|
||||
}
|
||||
|
||||
// Compute the address being written to.
|
||||
masm.load32(Address(ICStubReg, ICSetProp_Unboxed::offsetOfFieldOffset()), scratch);
|
||||
BaseIndex address(object, scratch, TimesOne);
|
||||
|
||||
EmitUnboxedPreBarrierForBaseline(masm, address, fieldType_);
|
||||
masm.storeUnboxedProperty(address, fieldType_,
|
||||
ConstantOrRegister(TypedOrValueRegister(R1)), &failure);
|
||||
|
||||
// The RHS has to be in R0.
|
||||
masm.moveValue(R1, R0);
|
||||
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -104,19 +104,11 @@ AddReceiver(const ReceiverGuard& receiver,
|
|||
static bool
|
||||
GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
|
||||
{
|
||||
// We match either:
|
||||
// We match:
|
||||
//
|
||||
// GuardIsObject 0
|
||||
// GuardShape 0
|
||||
// LoadFixedSlotResult 0 or LoadDynamicSlotResult 0
|
||||
//
|
||||
// or
|
||||
//
|
||||
// GuardIsObject 0
|
||||
// GuardGroup 0
|
||||
// 1: GuardAndLoadUnboxedExpando 0
|
||||
// GuardShape 1
|
||||
// LoadFixedSlotResult 1 or LoadDynamicSlotResult 1
|
||||
|
||||
*receiver = ReceiverGuard();
|
||||
CacheIRReader reader(stub->stubInfo());
|
||||
|
|
@ -125,14 +117,6 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re
|
|||
if (!reader.matchOp(CacheOp::GuardIsObject, objId))
|
||||
return false;
|
||||
|
||||
if (reader.matchOp(CacheOp::GuardGroup, objId)) {
|
||||
receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
|
||||
|
||||
if (!reader.matchOp(CacheOp::GuardAndLoadUnboxedExpando, objId))
|
||||
return false;
|
||||
objId = reader.objOperandId();
|
||||
}
|
||||
|
||||
if (reader.matchOp(CacheOp::GuardShape, objId)) {
|
||||
receiver->shape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());
|
||||
return reader.matchOpEither(CacheOp::LoadFixedSlotResult, CacheOp::LoadDynamicSlotResult);
|
||||
|
|
@ -141,29 +125,6 @@ GetCacheIRReceiverForNativeReadSlot(ICCacheIR_Monitored* stub, ReceiverGuard* re
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetCacheIRReceiverForUnboxedProperty(ICCacheIR_Monitored* stub, ReceiverGuard* receiver)
|
||||
{
|
||||
// We match:
|
||||
//
|
||||
// GuardIsObject 0
|
||||
// GuardGroup 0
|
||||
// LoadUnboxedPropertyResult 0 ..
|
||||
|
||||
*receiver = ReceiverGuard();
|
||||
CacheIRReader reader(stub->stubInfo());
|
||||
|
||||
ObjOperandId objId = ObjOperandId(0);
|
||||
if (!reader.matchOp(CacheOp::GuardIsObject, objId))
|
||||
return false;
|
||||
|
||||
if (!reader.matchOp(CacheOp::GuardGroup, objId))
|
||||
return false;
|
||||
receiver->group = stub->stubInfo()->getStubField<ObjectGroup*>(stub, reader.stubOffset());
|
||||
|
||||
return reader.matchOp(CacheOp::LoadUnboxedPropertyResult, objId);
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receivers)
|
||||
{
|
||||
|
|
@ -182,8 +143,7 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
|||
while (stub->next()) {
|
||||
ReceiverGuard receiver;
|
||||
if (stub->isCacheIR_Monitored()) {
|
||||
if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver) &&
|
||||
!GetCacheIRReceiverForUnboxedProperty(stub->toCacheIR_Monitored(), &receiver))
|
||||
if (!GetCacheIRReceiverForNativeReadSlot(stub->toCacheIR_Monitored(), &receiver))
|
||||
{
|
||||
receivers.clear();
|
||||
return true;
|
||||
|
|
@ -191,8 +151,6 @@ BaselineInspector::maybeInfoForPropertyOp(jsbytecode* pc, ReceiverVector& receiv
|
|||
} else if (stub->isSetProp_Native()) {
|
||||
receiver = ReceiverGuard(stub->toSetProp_Native()->group(),
|
||||
stub->toSetProp_Native()->shape());
|
||||
} else if (stub->isSetProp_Unboxed()) {
|
||||
receiver = ReceiverGuard(stub->toSetProp_Unboxed()->group(), nullptr);
|
||||
} else {
|
||||
receivers.clear();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,7 @@
|
|||
#include "jit/IonCaches.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "vm/UnboxedObject-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
|
@ -60,10 +59,6 @@ GetPropIRGenerator::tryAttachStub(Maybe<CacheIRWriter>& writer)
|
|||
return false;
|
||||
if (!emitted_ && !tryAttachNative(*writer, obj, objId))
|
||||
return false;
|
||||
if (!emitted_ && !tryAttachUnboxed(*writer, obj, objId))
|
||||
return false;
|
||||
if (!emitted_ && !tryAttachUnboxedExpando(*writer, obj, objId))
|
||||
return false;
|
||||
if (!emitted_ && !tryAttachTypedObject(*writer, obj, objId))
|
||||
return false;
|
||||
if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId))
|
||||
|
|
@ -163,19 +158,9 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
|
|||
}
|
||||
|
||||
static void
|
||||
TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId,
|
||||
Maybe<ObjOperandId>* expandoId)
|
||||
TestMatchingReceiver(CacheIRWriter& writer, JSObject* obj, Shape* shape, ObjOperandId objId)
|
||||
{
|
||||
if (obj->is<UnboxedPlainObject>()) {
|
||||
writer.guardGroup(objId, obj->group());
|
||||
|
||||
if (UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando()) {
|
||||
expandoId->emplace(writer.guardAndLoadUnboxedExpando(objId));
|
||||
writer.guardShape(expandoId->ref(), expando->lastProperty());
|
||||
} else {
|
||||
writer.guardNoUnboxedExpando(objId);
|
||||
}
|
||||
} else if (obj->is<TypedObject>()) {
|
||||
if (obj->is<TypedObject>()) {
|
||||
writer.guardGroup(objId, obj->group());
|
||||
} else {
|
||||
Shape* shape = obj->maybeShape();
|
||||
|
|
@ -188,8 +173,7 @@ static void
|
|||
EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
|
||||
Shape* shape, ObjOperandId objId)
|
||||
{
|
||||
Maybe<ObjOperandId> expandoId;
|
||||
TestMatchingReceiver(writer, obj, shape, objId, &expandoId);
|
||||
TestMatchingReceiver(writer, obj, shape, objId);
|
||||
|
||||
ObjOperandId holderId;
|
||||
if (obj != holder) {
|
||||
|
|
@ -212,9 +196,6 @@ EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
|
|||
lastObjId = protoId;
|
||||
}
|
||||
}
|
||||
} else if (obj->is<UnboxedPlainObject>()) {
|
||||
holder = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
holderId = *expandoId;
|
||||
} else {
|
||||
holderId = objId;
|
||||
}
|
||||
|
|
@ -265,51 +246,6 @@ GetPropIRGenerator::tryAttachNative(CacheIRWriter& writer, HandleObject obj, Obj
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
|
||||
{
|
||||
MOZ_ASSERT(!emitted_);
|
||||
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return true;
|
||||
|
||||
const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(name_);
|
||||
if (!property)
|
||||
return true;
|
||||
|
||||
if (!cx_->runtime()->jitSupportsFloatingPoint)
|
||||
return true;
|
||||
|
||||
writer.guardGroup(objId, obj->group());
|
||||
writer.loadUnboxedPropertyResult(objId, property->type,
|
||||
UnboxedPlainObject::offsetOfData() + property->offset);
|
||||
emitted_ = true;
|
||||
preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
|
||||
{
|
||||
MOZ_ASSERT(!emitted_);
|
||||
|
||||
if (!obj->is<UnboxedPlainObject>())
|
||||
return true;
|
||||
|
||||
UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
|
||||
if (!expando)
|
||||
return true;
|
||||
|
||||
Shape* shape = expando->lookup(cx_, NameToId(name_));
|
||||
if (!shape || !shape->hasDefaultGetter() || !shape->hasSlot())
|
||||
return true;
|
||||
|
||||
emitted_ = true;
|
||||
|
||||
EmitReadSlotResult(writer, obj, obj, shape, objId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -87,13 +87,10 @@ class ObjOperandId : public OperandId
|
|||
_(GuardClass) \
|
||||
_(GuardSpecificObject) \
|
||||
_(GuardNoDetachedTypedObjects) \
|
||||
_(GuardNoUnboxedExpando) \
|
||||
_(GuardAndLoadUnboxedExpando) \
|
||||
_(LoadObject) \
|
||||
_(LoadProto) \
|
||||
_(LoadFixedSlotResult) \
|
||||
_(LoadDynamicSlotResult) \
|
||||
_(LoadUnboxedPropertyResult) \
|
||||
_(LoadTypedObjectResult) \
|
||||
_(LoadInt32ArrayLengthResult) \
|
||||
_(LoadArgumentsObjectLengthResult) \
|
||||
|
|
@ -274,15 +271,6 @@ class MOZ_RAII CacheIRWriter
|
|||
void guardNoDetachedTypedObjects() {
|
||||
writeOp(CacheOp::GuardNoDetachedTypedObjects);
|
||||
}
|
||||
void guardNoUnboxedExpando(ObjOperandId obj) {
|
||||
writeOpWithOperandId(CacheOp::GuardNoUnboxedExpando, obj);
|
||||
}
|
||||
ObjOperandId guardAndLoadUnboxedExpando(ObjOperandId obj) {
|
||||
ObjOperandId res(nextOperandId_++);
|
||||
writeOpWithOperandId(CacheOp::GuardAndLoadUnboxedExpando, obj);
|
||||
writeOperandId(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
ObjOperandId loadObject(JSObject* obj) {
|
||||
ObjOperandId res(nextOperandId_++);
|
||||
|
|
@ -308,11 +296,6 @@ class MOZ_RAII CacheIRWriter
|
|||
writeOpWithOperandId(CacheOp::LoadDynamicSlotResult, obj);
|
||||
addStubWord(offset, StubField::GCType::NoGCThing);
|
||||
}
|
||||
void loadUnboxedPropertyResult(ObjOperandId obj, JSValueType type, size_t offset) {
|
||||
writeOpWithOperandId(CacheOp::LoadUnboxedPropertyResult, obj);
|
||||
buffer_.writeByte(uint32_t(type));
|
||||
addStubWord(offset, StubField::GCType::NoGCThing);
|
||||
}
|
||||
void loadTypedObjectResult(ObjOperandId obj, uint32_t offset, TypedThingLayout layout,
|
||||
uint32_t typeDescr) {
|
||||
MOZ_ASSERT(uint32_t(layout) <= UINT8_MAX);
|
||||
|
|
@ -406,9 +389,6 @@ class MOZ_RAII GetPropIRGenerator
|
|||
PreliminaryObjectAction preliminaryObjectAction_;
|
||||
|
||||
MOZ_MUST_USE bool tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
|
||||
MOZ_MUST_USE bool tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
|
||||
MOZ_MUST_USE bool tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj,
|
||||
ObjOperandId objId);
|
||||
MOZ_MUST_USE bool tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj,
|
||||
ObjOperandId objId);
|
||||
MOZ_MUST_USE bool tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj,
|
||||
|
|
|
|||
|
|
@ -867,30 +867,6 @@ 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,
|
||||
|
|
@ -1497,67 +1473,6 @@ 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)
|
||||
|
|
@ -2127,12 +2042,6 @@ 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;
|
||||
}
|
||||
|
|
@ -3298,141 +3207,6 @@ 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)
|
||||
|
|
@ -3513,26 +3287,6 @@ 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,
|
||||
|
|
@ -3558,12 +3312,6 @@ 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()) {
|
||||
|
|
@ -3615,16 +3363,6 @@ 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -529,18 +529,6 @@ class GetPropertyIC : public IonCache
|
|||
HandleObject obj, HandleId id, void* returnAddr,
|
||||
bool* emitted);
|
||||
|
||||
MOZ_MUST_USE bool tryAttachUnboxed(JSContext* cx, HandleScript outerScript, IonScript* ion,
|
||||
HandleObject obj, HandleId id, void* returnAddr,
|
||||
bool* emitted);
|
||||
|
||||
MOZ_MUST_USE bool tryAttachUnboxedExpando(JSContext* cx, HandleScript outerScript,
|
||||
IonScript* ion, HandleObject obj, HandleId id,
|
||||
void* returnAddr, bool* emitted);
|
||||
|
||||
MOZ_MUST_USE bool tryAttachUnboxedArrayLength(JSContext* cx, HandleScript outerScript,
|
||||
IonScript* ion, HandleObject obj, HandleId id,
|
||||
void* returnAddr, bool* emitted);
|
||||
|
||||
MOZ_MUST_USE bool tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript,
|
||||
IonScript* ion, HandleObject obj, HandleId id,
|
||||
bool* emitted);
|
||||
|
|
|
|||
|
|
@ -468,243 +468,6 @@ template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const A
|
|||
template void MacroAssembler::loadFromTypedArray(Scalar::Type arrayType, const BaseIndex& src, const ValueOperand& dest,
|
||||
bool allowDouble, Register temp, Label* fail);
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_INT32: {
|
||||
// Handle loading an int32 into a double reg.
|
||||
if (output.type() == MIRType::Double) {
|
||||
convertInt32ToDouble(address, output.typedReg().fpu());
|
||||
break;
|
||||
}
|
||||
MOZ_FALLTHROUGH;
|
||||
}
|
||||
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
case JSVAL_TYPE_STRING: {
|
||||
Register outReg;
|
||||
if (output.hasValue()) {
|
||||
outReg = output.valueReg().scratchReg();
|
||||
} else {
|
||||
MOZ_ASSERT(output.type() == MIRTypeFromValueType(type));
|
||||
outReg = output.typedReg().gpr();
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
load8ZeroExtend(address, outReg);
|
||||
break;
|
||||
case JSVAL_TYPE_INT32:
|
||||
load32(address, outReg);
|
||||
break;
|
||||
case JSVAL_TYPE_STRING:
|
||||
loadPtr(address, outReg);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
if (output.hasValue())
|
||||
tagValue(type, outReg, output.valueReg());
|
||||
break;
|
||||
}
|
||||
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
if (output.hasValue()) {
|
||||
Register scratch = output.valueReg().scratchReg();
|
||||
loadPtr(address, scratch);
|
||||
|
||||
Label notNull, done;
|
||||
branchPtr(Assembler::NotEqual, scratch, ImmWord(0), ¬Null);
|
||||
|
||||
moveValue(NullValue(), output.valueReg());
|
||||
jump(&done);
|
||||
|
||||
bind(¬Null);
|
||||
tagValue(JSVAL_TYPE_OBJECT, scratch, output.valueReg());
|
||||
|
||||
bind(&done);
|
||||
} else {
|
||||
// Reading null can't be possible here, as otherwise the result
|
||||
// would be a value (either because null has been read before or
|
||||
// because there is a barrier).
|
||||
Register reg = output.typedReg().gpr();
|
||||
loadPtr(address, reg);
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
branchTestPtr(Assembler::NonZero, reg, reg, &ok);
|
||||
assumeUnreachable("Null not possible");
|
||||
bind(&ok);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
// Note: doubles in unboxed objects are not accessed through other
|
||||
// views and do not need canonicalization.
|
||||
if (output.hasValue())
|
||||
loadValue(address, output.valueReg());
|
||||
else
|
||||
loadDouble(address, output.typedReg().fpu());
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
template void
|
||||
MacroAssembler::loadUnboxedProperty(Address address, JSValueType type,
|
||||
TypedOrValueRegister output);
|
||||
|
||||
template void
|
||||
MacroAssembler::loadUnboxedProperty(BaseIndex address, JSValueType type,
|
||||
TypedOrValueRegister output);
|
||||
|
||||
static void
|
||||
StoreUnboxedFailure(MacroAssembler& masm, Label* failure)
|
||||
{
|
||||
// Storing a value to an unboxed property is a fallible operation and
|
||||
// the caller must provide a failure label if a particular unboxed store
|
||||
// might fail. Sometimes, however, a store that cannot succeed (such as
|
||||
// storing a string to an int32 property) will be marked as infallible.
|
||||
// This can only happen if the code involved is unreachable.
|
||||
if (failure)
|
||||
masm.jump(failure);
|
||||
else
|
||||
masm.assumeUnreachable("Incompatible write to unboxed property");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
MacroAssembler::storeUnboxedProperty(T address, JSValueType type,
|
||||
const ConstantOrRegister& value, Label* failure)
|
||||
{
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
if (value.constant()) {
|
||||
if (value.value().isBoolean())
|
||||
store8(Imm32(value.value().toBoolean()), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else if (value.reg().hasTyped()) {
|
||||
if (value.reg().type() == MIRType::Boolean)
|
||||
store8(value.reg().typedReg().gpr(), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else {
|
||||
if (failure)
|
||||
branchTestBoolean(Assembler::NotEqual, value.reg().valueReg(), failure);
|
||||
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case JSVAL_TYPE_INT32:
|
||||
if (value.constant()) {
|
||||
if (value.value().isInt32())
|
||||
store32(Imm32(value.value().toInt32()), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else if (value.reg().hasTyped()) {
|
||||
if (value.reg().type() == MIRType::Int32)
|
||||
store32(value.reg().typedReg().gpr(), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else {
|
||||
if (failure)
|
||||
branchTestInt32(Assembler::NotEqual, value.reg().valueReg(), failure);
|
||||
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ 4);
|
||||
}
|
||||
break;
|
||||
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
if (value.constant()) {
|
||||
if (value.value().isNumber()) {
|
||||
loadConstantDouble(value.value().toNumber(), ScratchDoubleReg);
|
||||
storeDouble(ScratchDoubleReg, address);
|
||||
} else {
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
}
|
||||
} else if (value.reg().hasTyped()) {
|
||||
if (value.reg().type() == MIRType::Int32) {
|
||||
convertInt32ToDouble(value.reg().typedReg().gpr(), ScratchDoubleReg);
|
||||
storeDouble(ScratchDoubleReg, address);
|
||||
} else if (value.reg().type() == MIRType::Double) {
|
||||
storeDouble(value.reg().typedReg().fpu(), address);
|
||||
} else {
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
}
|
||||
} else {
|
||||
ValueOperand reg = value.reg().valueReg();
|
||||
Label notInt32, end;
|
||||
branchTestInt32(Assembler::NotEqual, reg, ¬Int32);
|
||||
int32ValueToDouble(reg, ScratchDoubleReg);
|
||||
storeDouble(ScratchDoubleReg, address);
|
||||
jump(&end);
|
||||
bind(¬Int32);
|
||||
if (failure)
|
||||
branchTestDouble(Assembler::NotEqual, reg, failure);
|
||||
storeValue(reg, address);
|
||||
bind(&end);
|
||||
}
|
||||
break;
|
||||
|
||||
case JSVAL_TYPE_OBJECT:
|
||||
if (value.constant()) {
|
||||
if (value.value().isObjectOrNull())
|
||||
storePtr(ImmGCPtr(value.value().toObjectOrNull()), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else if (value.reg().hasTyped()) {
|
||||
MOZ_ASSERT(value.reg().type() != MIRType::Null);
|
||||
if (value.reg().type() == MIRType::Object)
|
||||
storePtr(value.reg().typedReg().gpr(), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else {
|
||||
if (failure) {
|
||||
Label ok;
|
||||
branchTestNull(Assembler::Equal, value.reg().valueReg(), &ok);
|
||||
branchTestObject(Assembler::NotEqual, value.reg().valueReg(), failure);
|
||||
bind(&ok);
|
||||
}
|
||||
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
|
||||
}
|
||||
break;
|
||||
|
||||
case JSVAL_TYPE_STRING:
|
||||
if (value.constant()) {
|
||||
if (value.value().isString())
|
||||
storePtr(ImmGCPtr(value.value().toString()), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else if (value.reg().hasTyped()) {
|
||||
if (value.reg().type() == MIRType::String)
|
||||
storePtr(value.reg().typedReg().gpr(), address);
|
||||
else
|
||||
StoreUnboxedFailure(*this, failure);
|
||||
} else {
|
||||
if (failure)
|
||||
branchTestString(Assembler::NotEqual, value.reg().valueReg(), failure);
|
||||
storeUnboxedPayload(value.reg().valueReg(), address, /* width = */ sizeof(uintptr_t));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
template void
|
||||
MacroAssembler::storeUnboxedProperty(Address address, JSValueType type,
|
||||
const ConstantOrRegister& value, Label* failure);
|
||||
|
||||
template void
|
||||
MacroAssembler::storeUnboxedProperty(BaseIndex address, JSValueType type,
|
||||
const ConstantOrRegister& value, Label* failure);
|
||||
|
||||
// Inlined version of gc::CheckAllocatorState that checks the bare essentials
|
||||
// and bails for anything that cannot be handled with our jit allocators.
|
||||
void
|
||||
|
|
@ -1252,10 +1015,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
|
|||
nbytes = (nbytes < sizeof(uintptr_t)) ? 0 : nbytes - sizeof(uintptr_t);
|
||||
offset += sizeof(uintptr_t);
|
||||
}
|
||||
} else if (templateObj->is<UnboxedPlainObject>()) {
|
||||
storePtr(ImmWord(0), Address(obj, UnboxedPlainObject::offsetOfExpando()));
|
||||
if (initContents)
|
||||
initUnboxedObjectContents(obj, &templateObj->as<UnboxedPlainObject>());
|
||||
} else {
|
||||
MOZ_CRASH("Unknown object");
|
||||
}
|
||||
|
|
@ -1276,29 +1035,6 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
|
|||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject)
|
||||
{
|
||||
const UnboxedLayout& layout = templateObject->layoutDontCheckGeneration();
|
||||
|
||||
// Initialize reference fields of the object, per UnboxedPlainObject::create.
|
||||
if (const int32_t* list = layout.traceList()) {
|
||||
while (*list != -1) {
|
||||
storePtr(ImmGCPtr(GetJitContext()->runtime->names().empty),
|
||||
Address(object, UnboxedPlainObject::offsetOfData() + *list));
|
||||
list++;
|
||||
}
|
||||
list++;
|
||||
while (*list != -1) {
|
||||
storePtr(ImmWord(0),
|
||||
Address(object, UnboxedPlainObject::offsetOfData() + *list));
|
||||
list++;
|
||||
}
|
||||
// Unboxed objects don't have Values to initialize.
|
||||
MOZ_ASSERT(*(list + 1) == -1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::compareStrings(JSOp op, Register left, Register right, Register result,
|
||||
Label* fail)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@
|
|||
#include "vm/ProxyObject.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "vm/TypedArrayObject.h"
|
||||
#include "vm/UnboxedObject.h"
|
||||
|
||||
using mozilla::FloatingPoint;
|
||||
|
||||
|
|
@ -1626,17 +1625,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
void storeToTypedFloatArray(Scalar::Type arrayType, FloatRegister value, const Address& dest,
|
||||
unsigned numElems = 0);
|
||||
|
||||
// Load a property from an UnboxedPlainObject.
|
||||
template <typename T>
|
||||
void loadUnboxedProperty(T address, JSValueType type, TypedOrValueRegister output);
|
||||
|
||||
// Store a property to an UnboxedPlainObject, without triggering barriers.
|
||||
// If failure is null, the value definitely has a type suitable for storing
|
||||
// in the property.
|
||||
template <typename T>
|
||||
void storeUnboxedProperty(T address, JSValueType type,
|
||||
const ConstantOrRegister& value, Label* failure);
|
||||
|
||||
Register extractString(const Address& address, Register scratch) {
|
||||
return extractObject(address, scratch);
|
||||
}
|
||||
|
|
@ -1713,8 +1701,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
|||
LiveRegisterSet liveRegs, Label* fail,
|
||||
TypedArrayObject* templateObj, TypedArrayLength lengthKind);
|
||||
|
||||
void initUnboxedObjectContents(Register object, UnboxedPlainObject* templateObject);
|
||||
|
||||
void newGCString(Register result, Register temp, Label* fail);
|
||||
void newGCFatInlineString(Register result, Register temp, Label* fail);
|
||||
|
||||
|
|
|
|||
|
|
@ -67,205 +67,8 @@ static const uintptr_t CLEAR_CONSTRUCTOR_CODE_TOKEN = 0x1;
|
|||
/* static */ bool
|
||||
UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
|
||||
{
|
||||
gc::AutoSuppressGC suppress(cx);
|
||||
|
||||
using namespace jit;
|
||||
|
||||
if (!cx->compartment()->ensureJitCompartmentExists(cx))
|
||||
return false;
|
||||
|
||||
UnboxedLayout& layout = group->unboxedLayout();
|
||||
MOZ_ASSERT(!layout.constructorCode());
|
||||
|
||||
UnboxedPlainObject* templateObject = UnboxedPlainObject::create(cx, group, TenuredObject);
|
||||
if (!templateObject)
|
||||
return false;
|
||||
|
||||
JitContext jitContext(cx, nullptr);
|
||||
|
||||
MacroAssembler masm;
|
||||
|
||||
Register propertiesReg, newKindReg;
|
||||
#ifdef JS_CODEGEN_X86
|
||||
propertiesReg = eax;
|
||||
newKindReg = ecx;
|
||||
masm.loadPtr(Address(masm.getStackPointer(), sizeof(void*)), propertiesReg);
|
||||
masm.loadPtr(Address(masm.getStackPointer(), 2 * sizeof(void*)), newKindReg);
|
||||
#else
|
||||
propertiesReg = IntArgReg0;
|
||||
newKindReg = IntArgReg1;
|
||||
#endif
|
||||
|
||||
#ifdef JS_CODEGEN_ARM64
|
||||
// ARM64 communicates stack address via sp, but uses a pseudo-sp for addressing.
|
||||
masm.initStackPtr();
|
||||
#endif
|
||||
|
||||
MOZ_ASSERT(propertiesReg.volatile_());
|
||||
MOZ_ASSERT(newKindReg.volatile_());
|
||||
|
||||
AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
|
||||
regs.take(propertiesReg);
|
||||
regs.take(newKindReg);
|
||||
Register object = regs.takeAny(), scratch1 = regs.takeAny(), scratch2 = regs.takeAny();
|
||||
|
||||
LiveGeneralRegisterSet savedNonVolatileRegisters = SavedNonVolatileRegisters(regs);
|
||||
masm.PushRegsInMask(savedNonVolatileRegisters);
|
||||
|
||||
// The scratch double register might be used by MacroAssembler methods.
|
||||
if (ScratchDoubleReg.volatile_())
|
||||
masm.push(ScratchDoubleReg);
|
||||
|
||||
Label failure, tenuredObject, allocated;
|
||||
masm.branch32(Assembler::NotEqual, newKindReg, Imm32(GenericObject), &tenuredObject);
|
||||
masm.branchTest32(Assembler::NonZero, AbsoluteAddress(group->addressOfFlags()),
|
||||
Imm32(OBJECT_FLAG_PRE_TENURE), &tenuredObject);
|
||||
|
||||
// Allocate an object in the nursery
|
||||
masm.createGCObject(object, scratch1, templateObject, gc::DefaultHeap, &failure,
|
||||
/* initFixedSlots = */ false);
|
||||
|
||||
masm.jump(&allocated);
|
||||
masm.bind(&tenuredObject);
|
||||
|
||||
// Allocate an object in the tenured heap.
|
||||
masm.createGCObject(object, scratch1, templateObject, gc::TenuredHeap, &failure,
|
||||
/* initFixedSlots = */ false);
|
||||
|
||||
// If any of the properties being stored are in the nursery, add a store
|
||||
// buffer entry for the new object.
|
||||
Label postBarrier;
|
||||
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||
const UnboxedLayout::Property& property = layout.properties()[i];
|
||||
if (property.type == JSVAL_TYPE_OBJECT) {
|
||||
Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
|
||||
Label notObject;
|
||||
masm.branchTestObject(Assembler::NotEqual, valueAddress, ¬Object);
|
||||
Register valueObject = masm.extractObject(valueAddress, scratch1);
|
||||
masm.branchPtrInNurseryChunk(Assembler::Equal, valueObject, scratch2, &postBarrier);
|
||||
masm.bind(¬Object);
|
||||
}
|
||||
}
|
||||
|
||||
masm.jump(&allocated);
|
||||
masm.bind(&postBarrier);
|
||||
|
||||
LiveGeneralRegisterSet liveVolatileRegisters;
|
||||
liveVolatileRegisters.add(propertiesReg);
|
||||
if (object.volatile_())
|
||||
liveVolatileRegisters.add(object);
|
||||
masm.PushRegsInMask(liveVolatileRegisters);
|
||||
|
||||
masm.mov(ImmPtr(cx->runtime()), scratch1);
|
||||
masm.setupUnalignedABICall(scratch2);
|
||||
masm.passABIArg(scratch1);
|
||||
masm.passABIArg(object);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
|
||||
|
||||
masm.PopRegsInMask(liveVolatileRegisters);
|
||||
|
||||
masm.bind(&allocated);
|
||||
|
||||
ValueOperand valueOperand;
|
||||
#ifdef JS_NUNBOX32
|
||||
valueOperand = ValueOperand(scratch1, scratch2);
|
||||
#else
|
||||
valueOperand = ValueOperand(scratch1);
|
||||
#endif
|
||||
|
||||
Label failureStoreOther, failureStoreObject;
|
||||
|
||||
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||
const UnboxedLayout::Property& property = layout.properties()[i];
|
||||
Address valueAddress(propertiesReg, i * sizeof(IdValuePair) + offsetof(IdValuePair, value));
|
||||
Address targetAddress(object, UnboxedPlainObject::offsetOfData() + property.offset);
|
||||
|
||||
masm.loadValue(valueAddress, valueOperand);
|
||||
|
||||
if (property.type == JSVAL_TYPE_OBJECT) {
|
||||
HeapTypeSet* types = group->maybeGetProperty(IdToTypeId(NameToId(property.name)));
|
||||
|
||||
Label notObject;
|
||||
masm.branchTestObject(Assembler::NotEqual, valueOperand,
|
||||
types->mightBeMIRType(MIRType::Null) ? ¬Object : &failureStoreObject);
|
||||
|
||||
Register payloadReg = masm.extractObject(valueOperand, scratch1);
|
||||
|
||||
if (!types->hasType(TypeSet::AnyObjectType())) {
|
||||
Register scratch = (payloadReg == scratch1) ? scratch2 : scratch1;
|
||||
masm.guardObjectType(payloadReg, types, scratch, &failureStoreObject);
|
||||
}
|
||||
|
||||
masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT,
|
||||
TypedOrValueRegister(MIRType::Object,
|
||||
AnyRegister(payloadReg)), nullptr);
|
||||
|
||||
if (notObject.used()) {
|
||||
Label done;
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Object);
|
||||
masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
|
||||
masm.storeUnboxedProperty(targetAddress, JSVAL_TYPE_OBJECT, NullValue(), nullptr);
|
||||
masm.bind(&done);
|
||||
}
|
||||
} else {
|
||||
masm.storeUnboxedProperty(targetAddress, property.type,
|
||||
ConstantOrRegister(valueOperand), &failureStoreOther);
|
||||
}
|
||||
}
|
||||
|
||||
Label done;
|
||||
masm.bind(&done);
|
||||
|
||||
if (object != ReturnReg)
|
||||
masm.movePtr(object, ReturnReg);
|
||||
|
||||
// Restore non-volatile registers which were saved on entry.
|
||||
if (ScratchDoubleReg.volatile_())
|
||||
masm.pop(ScratchDoubleReg);
|
||||
masm.PopRegsInMask(savedNonVolatileRegisters);
|
||||
|
||||
masm.abiret();
|
||||
|
||||
masm.bind(&failureStoreOther);
|
||||
|
||||
// There was a failure while storing a value which cannot be stored at all
|
||||
// in the unboxed object. Initialize the object so it is safe for GC and
|
||||
// return null.
|
||||
masm.initUnboxedObjectContents(object, templateObject);
|
||||
|
||||
masm.bind(&failure);
|
||||
|
||||
masm.movePtr(ImmWord(0), object);
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&failureStoreObject);
|
||||
|
||||
// There was a failure while storing a value to an object slot of the
|
||||
// unboxed object. If the value is storable, the failure occurred due to
|
||||
// incomplete type information in the object, so return a token to trigger
|
||||
// regeneration of the jitcode after a new object is created in the VM.
|
||||
{
|
||||
Label isObject;
|
||||
masm.branchTestObject(Assembler::Equal, valueOperand, &isObject);
|
||||
masm.branchTestNull(Assembler::NotEqual, valueOperand, &failureStoreOther);
|
||||
masm.bind(&isObject);
|
||||
}
|
||||
|
||||
// Initialize the object so it is safe for GC.
|
||||
masm.initUnboxedObjectContents(object, templateObject);
|
||||
|
||||
masm.movePtr(ImmWord(CLEAR_CONSTRUCTOR_CODE_TOKEN), object);
|
||||
masm.jump(&done);
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("UnboxedObject");
|
||||
JitCode* code = linker.newCode<NoGC>(cx, OTHER_CODE);
|
||||
if (!code)
|
||||
return false;
|
||||
|
||||
layout.setConstructorCode(code);
|
||||
return true;
|
||||
// *** STUB ***
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue