mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1100173, bug 1102510 - Add baseline caches for typed object scalar element accesses and scalar/reference property accesses, r=jandem.
This commit is contained in:
parent
67bcbecc1c
commit
ee3a4f5001
@ -154,6 +154,10 @@ class TypedProto : public NativeObject
|
||||
}
|
||||
|
||||
inline type::Kind kind() const;
|
||||
|
||||
static int32_t offsetOfTypeDescr() {
|
||||
return getFixedSlotOffset(JS_TYPROTO_SLOT_DESCR);
|
||||
}
|
||||
};
|
||||
|
||||
class TypeDescr : public NativeObject
|
||||
@ -432,6 +436,10 @@ class ArrayTypeDescr : public ComplexTypeDescr
|
||||
int32_t length() const {
|
||||
return getReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH).toInt32();
|
||||
}
|
||||
|
||||
static int32_t offsetOfLength() {
|
||||
return getFixedSlotOffset(JS_DESCR_SLOT_ARRAY_LENGTH);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -366,6 +366,11 @@ ICStub::trace(JSTracer *trc)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::GetProp_TypedObject: {
|
||||
ICGetProp_TypedObject *propStub = toGetProp_TypedObject();
|
||||
MarkShape(trc, &propStub->shape(), "baseline-getprop-typedobject-stub-shape");
|
||||
break;
|
||||
}
|
||||
case ICStub::GetProp_CallDOMProxyNative:
|
||||
case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
|
||||
ICGetPropCallDOMProxyNativeStub *propStub;
|
||||
@ -435,6 +440,12 @@ ICStub::trace(JSTracer *trc)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICStub::SetProp_TypedObject: {
|
||||
ICSetProp_TypedObject *propStub = toSetProp_TypedObject();
|
||||
MarkShape(trc, &propStub->shape(), "baseline-setprop-typedobject-stub-shape");
|
||||
MarkTypeObject(trc, &propStub->type(), "baseline-setprop-typedobject-stub-type");
|
||||
break;
|
||||
}
|
||||
case ICStub::SetProp_CallScripted: {
|
||||
ICSetProp_CallScripted *callStub = toSetProp_CallScripted();
|
||||
MarkShape(trc, &callStub->shape(), "baseline-setpropcallscripted-stub-shape");
|
||||
@ -1545,6 +1556,25 @@ DoTypeUpdateFallback(JSContext *cx, BaselineFrame *frame, ICUpdatedStub *stub, H
|
||||
types::AddTypePropertyId(cx, obj, id, value);
|
||||
break;
|
||||
}
|
||||
case ICStub::SetProp_TypedObject: {
|
||||
MOZ_ASSERT(obj->is<TypedObject>());
|
||||
jsbytecode *pc = stub->getChainFallback()->icEntry()->pc(script);
|
||||
id = NameToId(script->getName(pc));
|
||||
if (stub->toSetProp_TypedObject()->isObjectReference()) {
|
||||
// Ignore all values being written except plain objects. Null
|
||||
// is included implicitly in type information for this property,
|
||||
// and non-object non-null values will cause the stub to fail to
|
||||
// match shortly and we will end up doing the assignment in the VM.
|
||||
if (value.isObject())
|
||||
types::AddTypePropertyId(cx, obj, id, value);
|
||||
} else {
|
||||
// Ignore undefined values, which are included implicitly in type
|
||||
// information for this property.
|
||||
if (!value.isUndefined())
|
||||
types::AddTypePropertyId(cx, obj, id, value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Invalid stub");
|
||||
}
|
||||
@ -3893,9 +3923,35 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
|
||||
}
|
||||
|
||||
static bool
|
||||
TypedArrayRequiresFloatingPoint(HandleObject obj)
|
||||
IsPrimitiveArrayTypedObject(JSObject *obj)
|
||||
{
|
||||
uint32_t type = AnyTypedArrayType(obj);
|
||||
if (!obj->is<TypedObject>())
|
||||
return false;
|
||||
TypeDescr &descr = obj->as<TypedObject>().typeDescr();
|
||||
return descr.is<ArrayTypeDescr>() &&
|
||||
descr.as<ArrayTypeDescr>().elementType().is<ScalarTypeDescr>();
|
||||
}
|
||||
|
||||
static Scalar::Type
|
||||
PrimitiveArrayTypedObjectType(JSObject *obj)
|
||||
{
|
||||
MOZ_ASSERT(IsPrimitiveArrayTypedObject(obj));
|
||||
TypeDescr &descr = obj->as<TypedObject>().typeDescr();
|
||||
return descr.as<ArrayTypeDescr>().elementType().as<ScalarTypeDescr>().type();
|
||||
}
|
||||
|
||||
static Scalar::Type
|
||||
TypedThingElementType(JSObject *obj)
|
||||
{
|
||||
return IsAnyTypedArray(obj)
|
||||
? AnyTypedArrayType(obj)
|
||||
: PrimitiveArrayTypedObjectType(obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
TypedThingRequiresFloatingPoint(JSObject *obj)
|
||||
{
|
||||
Scalar::Type type = TypedThingElementType(obj);
|
||||
return type == Scalar::Uint32 ||
|
||||
type == Scalar::Float32 ||
|
||||
type == Scalar::Float64;
|
||||
@ -3987,8 +4043,10 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
|
||||
}
|
||||
}
|
||||
|
||||
// Check for TypedArray[int] => Number accesses.
|
||||
if (IsAnyTypedArray(obj.get()) && rhs.isNumber() && res.isNumber() &&
|
||||
// Check for TypedArray[int] => Number and TypedObject[int] => Number accesses.
|
||||
if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
|
||||
rhs.isNumber() &&
|
||||
res.isNumber() &&
|
||||
!TypedArrayGetElemStubExists(stub, obj))
|
||||
{
|
||||
// Don't attach CALLELEM stubs for accesses on typed array expected to yield numbers.
|
||||
@ -3998,15 +4056,19 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
|
||||
#endif
|
||||
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||
(TypedArrayRequiresFloatingPoint(obj) || rhs.isDouble()))
|
||||
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't attach typed object stubs if they might be neutered, as the
|
||||
// stub will always bail out.
|
||||
if (IsPrimitiveArrayTypedObject(obj) && cx->compartment()->neuteredTypedObjects)
|
||||
return true;
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub");
|
||||
ICGetElem_TypedArray::Compiler compiler(cx,
|
||||
AnyTypedArrayShape(obj.get()),
|
||||
AnyTypedArrayType(obj.get()));
|
||||
ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(),
|
||||
TypedThingElementType(obj));
|
||||
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!typedArrayStub)
|
||||
return false;
|
||||
@ -4614,10 +4676,60 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
// GetElem_TypedArray
|
||||
//
|
||||
|
||||
static void
|
||||
LoadTypedThingLength(MacroAssembler &masm, TypedThingLayout layout, Register obj, Register result)
|
||||
{
|
||||
switch (layout) {
|
||||
case Layout_TypedArray:
|
||||
masm.unboxInt32(Address(obj, TypedArrayLayout::lengthOffset()), result);
|
||||
break;
|
||||
case Layout_OutlineTypedObject:
|
||||
case Layout_InlineTypedObject:
|
||||
masm.loadObjProto(obj, result);
|
||||
masm.unboxObject(Address(result, TypedProto::offsetOfTypeDescr()), result);
|
||||
masm.unboxInt32(Address(result, ArrayTypeDescr::offsetOfLength()), result);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
LoadTypedThingData(MacroAssembler &masm, TypedThingLayout layout, Register obj, Register result)
|
||||
{
|
||||
switch (layout) {
|
||||
case Layout_TypedArray:
|
||||
masm.loadPtr(Address(obj, TypedArrayLayout::dataOffset()), result);
|
||||
break;
|
||||
case Layout_OutlineTypedObject:
|
||||
masm.loadPtr(Address(obj, OutlineTypedObject::offsetOfData()), result);
|
||||
break;
|
||||
case Layout_InlineTypedObject:
|
||||
masm.computeEffectiveAddress(Address(obj, InlineTypedObject::offsetOfDataStart()), result);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
CheckForNeuteredTypedObject(JSContext *cx, MacroAssembler &masm, Label *failure)
|
||||
{
|
||||
// All stubs which manipulate typed objects need to check the compartment
|
||||
// wide flag indicating whether the objects are neutered, and bail out in
|
||||
// this case.
|
||||
int32_t *address = &cx->compartment()->neuteredTypedObjects;
|
||||
masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure);
|
||||
}
|
||||
|
||||
bool
|
||||
ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
Label failure;
|
||||
|
||||
if (layout_ != Layout_TypedArray)
|
||||
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
@ -4650,11 +4762,11 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
Register key = masm.extractInt32(R1, ExtractTemp1);
|
||||
|
||||
// Bounds check.
|
||||
masm.unboxInt32(Address(obj, TypedArrayLayout::lengthOffset()), scratchReg);
|
||||
LoadTypedThingLength(masm, layout_, obj, scratchReg);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
|
||||
|
||||
// Load the elements vector.
|
||||
masm.loadPtr(Address(obj, TypedArrayLayout::dataOffset()), scratchReg);
|
||||
LoadTypedThingData(masm, layout_, obj, scratchReg);
|
||||
|
||||
// Load the value.
|
||||
BaseIndex source(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
||||
@ -5112,31 +5224,45 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsAnyTypedArray(obj.get()) && index.isNumber() && rhs.isNumber()) {
|
||||
if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
|
||||
index.isNumber() &&
|
||||
rhs.isNumber())
|
||||
{
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||
(TypedArrayRequiresFloatingPoint(obj) || index.isDouble()))
|
||||
(TypedThingRequiresFloatingPoint(obj) || index.isDouble()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t len = AnyTypedArrayLength(obj.get());
|
||||
bool expectOutOfBounds;
|
||||
double idx = index.toNumber();
|
||||
bool expectOutOfBounds = (idx < 0 || idx >= double(len));
|
||||
if (IsAnyTypedArray(obj)) {
|
||||
expectOutOfBounds = (idx < 0 || idx >= double(AnyTypedArrayLength(obj)));
|
||||
} else {
|
||||
// Typed objects throw on out of bounds accesses. Don't attach
|
||||
// a stub in this case.
|
||||
if (idx < 0 || idx >= double(obj->as<TypedObject>().length()))
|
||||
return true;
|
||||
expectOutOfBounds = false;
|
||||
|
||||
// Don't attach stubs if typed objects in the compartment might be
|
||||
// neutered, as the stub will always bail out.
|
||||
if (cx->compartment()->neuteredTypedObjects)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TypedArraySetElemStubExists(stub, obj, expectOutOfBounds)) {
|
||||
// Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
|
||||
if (expectOutOfBounds)
|
||||
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
|
||||
|
||||
Shape *shape = obj->lastProperty();
|
||||
Scalar::Type type = TypedThingElementType(obj);
|
||||
|
||||
JitSpew(JitSpew_BaselineIC,
|
||||
" Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
|
||||
AnyTypedArrayShape(obj.get()),
|
||||
AnyTypedArrayType(obj.get()),
|
||||
expectOutOfBounds ? "yes" : "no");
|
||||
ICSetElem_TypedArray::Compiler compiler(cx,
|
||||
AnyTypedArrayShape(obj.get()),
|
||||
AnyTypedArrayType(obj.get()),
|
||||
expectOutOfBounds);
|
||||
shape, type, expectOutOfBounds ? "yes" : "no");
|
||||
ICSetElem_TypedArray::Compiler compiler(cx, shape, type, expectOutOfBounds);
|
||||
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!typedArrayStub)
|
||||
return false;
|
||||
@ -5520,10 +5646,81 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||
// SetElem_TypedArray
|
||||
//
|
||||
|
||||
// Write an arbitrary value to a typed array or typed object address at dest.
|
||||
// If the value could not be converted to the appropriate format, jump to
|
||||
// failure or failureModifiedScratch.
|
||||
template <typename T>
|
||||
static void
|
||||
StoreToTypedArray(JSContext *cx, MacroAssembler &masm, Scalar::Type type, Address value, T dest,
|
||||
Register scratch, Label *failure, Label *failureModifiedScratch)
|
||||
{
|
||||
Label done;
|
||||
|
||||
if (type == Scalar::Float32 || type == Scalar::Float64) {
|
||||
masm.ensureDouble(value, FloatReg0, failure);
|
||||
if (type == Scalar::Float32) {
|
||||
masm.convertDoubleToFloat32(FloatReg0, ScratchFloat32Reg);
|
||||
masm.storeToTypedFloatArray(type, ScratchFloat32Reg, dest);
|
||||
} else {
|
||||
masm.storeToTypedFloatArray(type, FloatReg0, dest);
|
||||
}
|
||||
} else if (type == Scalar::Uint8Clamped) {
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, value, ¬Int32);
|
||||
masm.unboxInt32(value, scratch);
|
||||
masm.clampIntToUint8(scratch);
|
||||
|
||||
Label clamped;
|
||||
masm.bind(&clamped);
|
||||
masm.storeToTypedIntArray(type, scratch, dest);
|
||||
masm.jump(&done);
|
||||
|
||||
// If the value is a double, clamp to uint8 and jump back.
|
||||
// Else, jump to failure.
|
||||
masm.bind(¬Int32);
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
masm.branchTestDouble(Assembler::NotEqual, value, failure);
|
||||
masm.unboxDouble(value, FloatReg0);
|
||||
masm.clampDoubleToUint8(FloatReg0, scratch);
|
||||
masm.jump(&clamped);
|
||||
} else {
|
||||
masm.jump(failure);
|
||||
}
|
||||
} else {
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, value, ¬Int32);
|
||||
masm.unboxInt32(value, scratch);
|
||||
|
||||
Label isInt32;
|
||||
masm.bind(&isInt32);
|
||||
masm.storeToTypedIntArray(type, scratch, dest);
|
||||
masm.jump(&done);
|
||||
|
||||
// If the value is a double, truncate and jump back.
|
||||
// Else, jump to failure.
|
||||
masm.bind(¬Int32);
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
masm.branchTestDouble(Assembler::NotEqual, value, failure);
|
||||
masm.unboxDouble(value, FloatReg0);
|
||||
masm.branchTruncateDouble(FloatReg0, scratch, failureModifiedScratch);
|
||||
masm.jump(&isInt32);
|
||||
} else {
|
||||
masm.jump(failure);
|
||||
}
|
||||
}
|
||||
|
||||
if (done.bound())
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
Label failure;
|
||||
|
||||
if (layout_ != Layout_TypedArray)
|
||||
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
@ -5557,12 +5754,12 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
|
||||
// Bounds check.
|
||||
Label oobWrite;
|
||||
masm.unboxInt32(Address(obj, TypedArrayLayout::lengthOffset()), scratchReg);
|
||||
LoadTypedThingLength(masm, layout_, obj, scratchReg);
|
||||
masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
|
||||
expectOutOfBounds_ ? &oobWrite : &failure);
|
||||
|
||||
// Load the elements vector.
|
||||
masm.loadPtr(Address(obj, TypedArrayLayout::dataOffset()), scratchReg);
|
||||
LoadTypedThingData(masm, layout_, obj, scratchReg);
|
||||
|
||||
BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
||||
Address value(BaselineStackReg, ICStackValueOffset);
|
||||
@ -5575,64 +5772,15 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
regs.take(scratchReg);
|
||||
Register secondScratch = regs.takeAny();
|
||||
|
||||
if (type_ == Scalar::Float32 || type_ == Scalar::Float64) {
|
||||
masm.ensureDouble(value, FloatReg0, &failure);
|
||||
if (type_ == Scalar::Float32)
|
||||
{
|
||||
masm.convertDoubleToFloat32(FloatReg0, ScratchFloat32Reg);
|
||||
masm.storeToTypedFloatArray(type_, ScratchFloat32Reg, dest);
|
||||
} else {
|
||||
masm.storeToTypedFloatArray(type_, FloatReg0, dest);
|
||||
}
|
||||
EmitReturnFromIC(masm);
|
||||
} else if (type_ == Scalar::Uint8Clamped) {
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, value, ¬Int32);
|
||||
masm.unboxInt32(value, secondScratch);
|
||||
masm.clampIntToUint8(secondScratch);
|
||||
|
||||
Label clamped;
|
||||
masm.bind(&clamped);
|
||||
masm.storeToTypedIntArray(type_, secondScratch, dest);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
// If the value is a double, clamp to uint8 and jump back.
|
||||
// Else, jump to failure.
|
||||
masm.bind(¬Int32);
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
masm.branchTestDouble(Assembler::NotEqual, value, &failure);
|
||||
masm.unboxDouble(value, FloatReg0);
|
||||
masm.clampDoubleToUint8(FloatReg0, secondScratch);
|
||||
masm.jump(&clamped);
|
||||
} else {
|
||||
masm.jump(&failure);
|
||||
}
|
||||
} else {
|
||||
Label notInt32;
|
||||
masm.branchTestInt32(Assembler::NotEqual, value, ¬Int32);
|
||||
masm.unboxInt32(value, secondScratch);
|
||||
|
||||
Label isInt32;
|
||||
masm.bind(&isInt32);
|
||||
masm.storeToTypedIntArray(type_, secondScratch, dest);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
// If the value is a double, truncate and jump back.
|
||||
// Else, jump to failure.
|
||||
Label failureRestoreRegs;
|
||||
masm.bind(¬Int32);
|
||||
if (cx->runtime()->jitSupportsFloatingPoint) {
|
||||
masm.branchTestDouble(Assembler::NotEqual, value, &failure);
|
||||
masm.unboxDouble(value, FloatReg0);
|
||||
masm.branchTruncateDouble(FloatReg0, secondScratch, &failureRestoreRegs);
|
||||
masm.jump(&isInt32);
|
||||
} else {
|
||||
masm.jump(&failure);
|
||||
}
|
||||
Label failureModifiedSecondScratch;
|
||||
StoreToTypedArray(cx, masm, type_, value, dest,
|
||||
secondScratch, &failure, &failureModifiedSecondScratch);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
if (failureModifiedSecondScratch.used()) {
|
||||
// Writing to secondScratch may have clobbered R0 or R1, restore them
|
||||
// first.
|
||||
masm.bind(&failureRestoreRegs);
|
||||
masm.bind(&failureModifiedSecondScratch);
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, obj, R0);
|
||||
masm.tagValue(JSVAL_TYPE_INT32, key, R1);
|
||||
}
|
||||
@ -5642,6 +5790,7 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
EmitStubGuardFailure(masm);
|
||||
|
||||
if (expectOutOfBounds_) {
|
||||
MOZ_ASSERT(layout_ == Layout_TypedArray);
|
||||
masm.bind(&oobWrite);
|
||||
EmitReturnFromIC(masm);
|
||||
}
|
||||
@ -6603,6 +6752,46 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachTypedObjectGetPropStub(JSContext *cx, HandleScript script,
|
||||
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
|
||||
bool *attached)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
|
||||
if (!cx->runtime()->jitSupportsFloatingPoint)
|
||||
return true;
|
||||
|
||||
if (!val.isObject() || !val.toObject().is<TypedObject>())
|
||||
return true;
|
||||
Rooted<TypedObject *> obj(cx, &val.toObject().as<TypedObject>());
|
||||
|
||||
if (!obj->typeDescr().is<StructTypeDescr>())
|
||||
return true;
|
||||
Rooted<StructTypeDescr *> structDescr(cx, &obj->typeDescr().as<StructTypeDescr>());
|
||||
|
||||
size_t fieldIndex;
|
||||
if (!structDescr->fieldIndex(NameToId(name), &fieldIndex))
|
||||
return true;
|
||||
|
||||
Rooted<TypeDescr *> fieldDescr(cx, &structDescr->fieldDescr(fieldIndex));
|
||||
if (!fieldDescr->is<SimpleTypeDescr>())
|
||||
return true;
|
||||
|
||||
uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
|
||||
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
|
||||
ICGetProp_TypedObject::Compiler compiler(cx, monitorStub, obj->lastProperty(),
|
||||
fieldOffset, &fieldDescr->as<SimpleTypeDescr>());
|
||||
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
|
||||
if (!newStub)
|
||||
return false;
|
||||
stub->addNewStub(newStub);
|
||||
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
|
||||
@ -6810,6 +6999,11 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
|
||||
if (attached)
|
||||
return true;
|
||||
|
||||
if (!TryAttachTypedObjectGetPropStub(cx, script, stub, name, val, &attached))
|
||||
return false;
|
||||
if (attached)
|
||||
return true;
|
||||
|
||||
if (val.isString() || val.isNumber() || val.isBoolean()) {
|
||||
if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
|
||||
return false;
|
||||
@ -7705,6 +7899,82 @@ ICGetProp_Generic::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICGetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
Label failure;
|
||||
|
||||
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||
|
||||
GeneralRegisterSet regs(availableGeneralRegs(1));
|
||||
|
||||
Register scratch1 = regs.takeAnyExcluding(BaselineTailCallReg);
|
||||
Register scratch2 = regs.takeAnyExcluding(BaselineTailCallReg);
|
||||
|
||||
// Object and shape guard.
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
Register object = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICGetProp_TypedObject::offsetOfShape()), scratch1);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, scratch1, &failure);
|
||||
|
||||
// Get the object's data pointer.
|
||||
LoadTypedThingData(masm, layout_, object, scratch1);
|
||||
|
||||
// Get the address being written to.
|
||||
masm.load32(Address(BaselineStubReg, ICGetProp_TypedObject::offsetOfFieldOffset()), scratch2);
|
||||
masm.addPtr(scratch2, scratch1);
|
||||
|
||||
// Only monitor the result if the type produced by this stub might vary.
|
||||
bool monitorLoad;
|
||||
|
||||
if (fieldDescr_->is<ScalarTypeDescr>()) {
|
||||
Scalar::Type type = fieldDescr_->as<ScalarTypeDescr>().type();
|
||||
monitorLoad = type == Scalar::Uint32;
|
||||
|
||||
masm.loadFromTypedArray(type, Address(scratch1, 0), R0, /* allowDouble = */ true,
|
||||
scratch2, nullptr);
|
||||
} else {
|
||||
ReferenceTypeDescr::Type type = fieldDescr_->as<ReferenceTypeDescr>().type();
|
||||
monitorLoad = type != ReferenceTypeDescr::TYPE_STRING;
|
||||
|
||||
switch (type) {
|
||||
case ReferenceTypeDescr::TYPE_ANY:
|
||||
masm.loadValue(Address(scratch1, 0), R0);
|
||||
break;
|
||||
|
||||
case ReferenceTypeDescr::TYPE_OBJECT: {
|
||||
Label notNull, done;
|
||||
masm.loadPtr(Address(scratch1, 0), scratch1);
|
||||
masm.branchTestPtr(Assembler::NonZero, scratch1, scratch1, ¬Null);
|
||||
masm.moveValue(NullValue(), R0);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Null);
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, scratch1, R0);
|
||||
masm.bind(&done);
|
||||
break;
|
||||
}
|
||||
|
||||
case ReferenceTypeDescr::TYPE_STRING:
|
||||
masm.loadPtr(Address(scratch1, 0), scratch1);
|
||||
masm.tagValue(JSVAL_TYPE_STRING, scratch1, R0);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
if (monitorLoad)
|
||||
EmitEnterTypeMonitorIC(masm);
|
||||
else
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
||||
{
|
||||
@ -7883,6 +8153,48 @@ TryAttachSetAccessorPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachTypedObjectSetPropStub(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<TypedObject>())
|
||||
return true;
|
||||
|
||||
if (!obj->as<TypedObject>().typeDescr().is<StructTypeDescr>())
|
||||
return true;
|
||||
Rooted<StructTypeDescr *> structDescr(cx);
|
||||
structDescr = &obj->as<TypedObject>().typeDescr().as<StructTypeDescr>();
|
||||
|
||||
size_t fieldIndex;
|
||||
if (!structDescr->fieldIndex(id, &fieldIndex))
|
||||
return true;
|
||||
|
||||
Rooted<TypeDescr *> fieldDescr(cx, &structDescr->fieldDescr(fieldIndex));
|
||||
if (!fieldDescr->is<SimpleTypeDescr>())
|
||||
return true;
|
||||
|
||||
uint32_t fieldOffset = structDescr->fieldOffset(fieldIndex);
|
||||
|
||||
ICSetProp_TypedObject::Compiler compiler(cx, obj->lastProperty(), obj->type(), fieldOffset,
|
||||
&fieldDescr->as<SimpleTypeDescr>());
|
||||
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);
|
||||
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_,
|
||||
HandleValue lhs, HandleValue rhs, MutableHandleValue res)
|
||||
@ -7977,6 +8289,15 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
|
||||
if (attached)
|
||||
return true;
|
||||
|
||||
if (!attached &&
|
||||
lhs.isObject() &&
|
||||
!TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (attached)
|
||||
return true;
|
||||
|
||||
MOZ_ASSERT(!attached);
|
||||
if (!isTemporarilyUnoptimizable)
|
||||
stub->noteUnoptimizableAccess();
|
||||
@ -8256,6 +8577,128 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetProp_TypedObject::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
Label failure;
|
||||
|
||||
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||
|
||||
// Guard input is an object.
|
||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||
|
||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||
Register scratch = regs.takeAny();
|
||||
|
||||
// Unbox and shape guard.
|
||||
Register object = masm.extractObject(R0, ExtractTemp0);
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_TypedObject::offsetOfShape()), scratch);
|
||||
masm.branchTestObjShape(Assembler::NotEqual, object, scratch, &failure);
|
||||
|
||||
// Guard that the type object matches.
|
||||
masm.loadPtr(Address(BaselineStubReg, ICSetProp_TypedObject::offsetOfType()), scratch);
|
||||
masm.branchPtr(Assembler::NotEqual, Address(object, JSObject::offsetOfType()), scratch,
|
||||
&failure);
|
||||
|
||||
if (needsUpdateStubs()) {
|
||||
// Stow both R0 and R1 (object and value).
|
||||
masm.push(object);
|
||||
masm.push(BaselineStubReg);
|
||||
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);
|
||||
masm.pop(BaselineStubReg);
|
||||
masm.pop(object);
|
||||
|
||||
// Trigger post barriers here on the values being written. Descriptors
|
||||
// which can write objects also need update stubs.
|
||||
GeneralRegisterSet saveRegs;
|
||||
saveRegs.add(R0);
|
||||
saveRegs.add(R1);
|
||||
saveRegs.addUnchecked(object);
|
||||
saveRegs.add(BaselineStubReg);
|
||||
emitPostWriteBarrierSlot(masm, object, R1, scratch, saveRegs);
|
||||
}
|
||||
|
||||
// Save the rhs on the stack so we can get a second scratch register.
|
||||
Label failurePopRHS;
|
||||
masm.pushValue(R1);
|
||||
regs = availableGeneralRegs(1);
|
||||
regs.takeUnchecked(object);
|
||||
regs.take(scratch);
|
||||
Register secondScratch = regs.takeAny();
|
||||
|
||||
// Get the object's data pointer.
|
||||
LoadTypedThingData(masm, layout_, object, scratch);
|
||||
|
||||
// Compute the address being written to.
|
||||
masm.load32(Address(BaselineStubReg, ICSetProp_TypedObject::offsetOfFieldOffset()), secondScratch);
|
||||
masm.addPtr(secondScratch, scratch);
|
||||
|
||||
Address dest(scratch, 0);
|
||||
Address value(BaselineStackReg, 0);
|
||||
|
||||
if (fieldDescr_->is<ScalarTypeDescr>()) {
|
||||
Scalar::Type type = fieldDescr_->as<ScalarTypeDescr>().type();
|
||||
StoreToTypedArray(cx, masm, type, value, dest,
|
||||
secondScratch, &failurePopRHS, &failurePopRHS);
|
||||
masm.popValue(R1);
|
||||
EmitReturnFromIC(masm);
|
||||
} else {
|
||||
ReferenceTypeDescr::Type type = fieldDescr_->as<ReferenceTypeDescr>().type();
|
||||
|
||||
masm.popValue(R1);
|
||||
|
||||
switch (type) {
|
||||
case ReferenceTypeDescr::TYPE_ANY:
|
||||
EmitPreBarrier(masm, dest, MIRType_Value);
|
||||
masm.storeValue(R1, dest);
|
||||
break;
|
||||
|
||||
case ReferenceTypeDescr::TYPE_OBJECT: {
|
||||
EmitPreBarrier(masm, dest, MIRType_Object);
|
||||
Label notObject;
|
||||
masm.branchTestObject(Assembler::NotEqual, R1, ¬Object);
|
||||
Register rhsObject = masm.extractObject(R1, ExtractTemp0);
|
||||
masm.storePtr(rhsObject, dest);
|
||||
EmitReturnFromIC(masm);
|
||||
masm.bind(¬Object);
|
||||
masm.branchTestNull(Assembler::NotEqual, R1, &failure);
|
||||
masm.storePtr(ImmWord(0), dest);
|
||||
break;
|
||||
}
|
||||
|
||||
case ReferenceTypeDescr::TYPE_STRING: {
|
||||
EmitPreBarrier(masm, dest, MIRType_String);
|
||||
masm.branchTestString(Assembler::NotEqual, R1, &failure);
|
||||
Register rhsString = masm.extractString(R1, ExtractTemp0);
|
||||
masm.storePtr(rhsString, dest);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
EmitReturnFromIC(masm);
|
||||
}
|
||||
|
||||
masm.bind(&failurePopRHS);
|
||||
masm.popValue(R1);
|
||||
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
||||
{
|
||||
|
@ -14,9 +14,11 @@
|
||||
#include "jsgc.h"
|
||||
#include "jsopcode.h"
|
||||
|
||||
#include "builtin/TypedObject.h"
|
||||
#include "jit/BaselineJIT.h"
|
||||
#include "jit/BaselineRegisters.h"
|
||||
#include "vm/ArrayObject.h"
|
||||
#include "vm/TypedArrayCommon.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
@ -421,6 +423,7 @@ class ICEntry
|
||||
_(GetProp_Native) \
|
||||
_(GetProp_NativeDoesNotExist) \
|
||||
_(GetProp_NativePrototype) \
|
||||
_(GetProp_TypedObject) \
|
||||
_(GetProp_CallScripted) \
|
||||
_(GetProp_CallNative) \
|
||||
_(GetProp_CallNativePrototype)\
|
||||
@ -434,6 +437,7 @@ class ICEntry
|
||||
_(SetProp_Fallback) \
|
||||
_(SetProp_Native) \
|
||||
_(SetProp_NativeAdd) \
|
||||
_(SetProp_TypedObject) \
|
||||
_(SetProp_CallScripted) \
|
||||
_(SetProp_CallNative) \
|
||||
\
|
||||
@ -3406,6 +3410,26 @@ class ICGetElem_Dense : public ICMonitoredStub
|
||||
};
|
||||
};
|
||||
|
||||
// Enum for stubs handling a combination of typed arrays and typed objects.
|
||||
enum TypedThingLayout {
|
||||
Layout_TypedArray,
|
||||
Layout_OutlineTypedObject,
|
||||
Layout_InlineTypedObject
|
||||
};
|
||||
|
||||
static inline TypedThingLayout
|
||||
GetTypedThingLayout(const Class *clasp)
|
||||
{
|
||||
if (IsAnyTypedArrayClass(clasp))
|
||||
return Layout_TypedArray;
|
||||
if (IsOutlineTypedObjectClass(clasp))
|
||||
return Layout_OutlineTypedObject;
|
||||
if (IsInlineTypedObjectClass(clasp))
|
||||
return Layout_InlineTypedObject;
|
||||
MOZ_CRASH("Bad object class");
|
||||
}
|
||||
|
||||
// Accesses scalar elements of a typed array or typed object.
|
||||
class ICGetElem_TypedArray : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
@ -3435,19 +3459,23 @@ class ICGetElem_TypedArray : public ICStub
|
||||
class Compiler : public ICStubCompiler {
|
||||
RootedShape shape_;
|
||||
Scalar::Type type_;
|
||||
TypedThingLayout layout_;
|
||||
|
||||
protected:
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16);
|
||||
return static_cast<int32_t>(kind) |
|
||||
(static_cast<int32_t>(type_) << 16) |
|
||||
(static_cast<int32_t>(layout_) << 24);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext *cx, Shape *shape, Scalar::Type type)
|
||||
: ICStubCompiler(cx, ICStub::GetElem_TypedArray),
|
||||
shape_(cx, shape),
|
||||
type_(type)
|
||||
type_(type),
|
||||
layout_(GetTypedThingLayout(shape->getObjectClass()))
|
||||
{}
|
||||
|
||||
ICStub *getStub(ICStubSpace *space) {
|
||||
@ -3721,6 +3749,7 @@ class ICSetElemDenseAddCompiler : public ICStubCompiler {
|
||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
||||
};
|
||||
|
||||
// Accesses scalar elements of a typed array or typed object.
|
||||
class ICSetElem_TypedArray : public ICStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
@ -3760,14 +3789,17 @@ class ICSetElem_TypedArray : public ICStub
|
||||
class Compiler : public ICStubCompiler {
|
||||
RootedShape shape_;
|
||||
Scalar::Type type_;
|
||||
TypedThingLayout layout_;
|
||||
bool expectOutOfBounds_;
|
||||
|
||||
protected:
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) | (static_cast<int32_t>(type_) << 16) |
|
||||
(static_cast<int32_t>(expectOutOfBounds_) << 24);
|
||||
return static_cast<int32_t>(kind) |
|
||||
(static_cast<int32_t>(type_) << 16) |
|
||||
(static_cast<int32_t>(layout_) << 24) |
|
||||
(static_cast<int32_t>(expectOutOfBounds_) << 28);
|
||||
}
|
||||
|
||||
public:
|
||||
@ -3775,6 +3807,7 @@ class ICSetElem_TypedArray : public ICStub
|
||||
: ICStubCompiler(cx, ICStub::SetElem_TypedArray),
|
||||
shape_(cx, shape),
|
||||
type_(type),
|
||||
layout_(GetTypedThingLayout(shape->getObjectClass())),
|
||||
expectOutOfBounds_(expectOutOfBounds)
|
||||
{}
|
||||
|
||||
@ -4571,6 +4604,84 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
|
||||
ICStub *getStub(ICStubSpace *space);
|
||||
};
|
||||
|
||||
static uint32_t
|
||||
SimpleTypeDescrKey(SimpleTypeDescr *descr)
|
||||
{
|
||||
if (descr->is<ScalarTypeDescr>())
|
||||
return uint32_t(descr->as<ScalarTypeDescr>().type()) << 1;
|
||||
return (uint32_t(descr->as<ReferenceTypeDescr>().type()) << 1) | 1;
|
||||
}
|
||||
|
||||
class ICGetProp_TypedObject : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
HeapPtrShape shape_;
|
||||
uint32_t fieldOffset_;
|
||||
|
||||
ICGetProp_TypedObject(JitCode *stubCode, ICStub *firstMonitorStub, HandleShape shape,
|
||||
uint32_t fieldOffset)
|
||||
: ICMonitoredStub(ICStub::GetProp_TypedObject, stubCode, firstMonitorStub),
|
||||
shape_(shape), fieldOffset_(fieldOffset)
|
||||
{
|
||||
(void) fieldOffset_; // Silence clang warning
|
||||
}
|
||||
|
||||
public:
|
||||
static inline ICGetProp_TypedObject *New(ICStubSpace *space, JitCode *code,
|
||||
ICStub *firstMonitorStub, HandleShape shape,
|
||||
uint32_t fieldOffset)
|
||||
{
|
||||
if (!code)
|
||||
return nullptr;
|
||||
return space->allocate<ICGetProp_TypedObject>(code, firstMonitorStub, shape, fieldOffset);
|
||||
}
|
||||
|
||||
HeapPtrShape &shape() {
|
||||
return shape_;
|
||||
}
|
||||
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(ICGetProp_TypedObject, shape_);
|
||||
}
|
||||
static size_t offsetOfFieldOffset() {
|
||||
return offsetof(ICGetProp_TypedObject, fieldOffset_);
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
ICStub *firstMonitorStub_;
|
||||
RootedShape shape_;
|
||||
uint32_t fieldOffset_;
|
||||
TypedThingLayout layout_;
|
||||
Rooted<SimpleTypeDescr *> fieldDescr_;
|
||||
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) |
|
||||
(static_cast<int32_t>(SimpleTypeDescrKey(fieldDescr_)) << 16) |
|
||||
(static_cast<int32_t>(layout_) << 24);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext *cx, ICStub *firstMonitorStub,
|
||||
Shape *shape, uint32_t fieldOffset, SimpleTypeDescr *fieldDescr)
|
||||
: ICStubCompiler(cx, ICStub::GetProp_TypedObject),
|
||||
firstMonitorStub_(firstMonitorStub),
|
||||
shape_(cx, shape),
|
||||
fieldOffset_(fieldOffset),
|
||||
layout_(GetTypedThingLayout(shape->getObjectClass())),
|
||||
fieldDescr_(cx, fieldDescr)
|
||||
{}
|
||||
|
||||
ICStub *getStub(ICStubSpace *space) {
|
||||
return ICGetProp_TypedObject::New(space, getStubCode(), firstMonitorStub_,
|
||||
shape_, fieldOffset_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class ICGetPropCallGetter : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
@ -5413,6 +5524,102 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
|
||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
||||
};
|
||||
|
||||
class ICSetProp_TypedObject : public ICUpdatedStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
HeapPtrShape shape_;
|
||||
HeapPtrTypeObject type_;
|
||||
uint32_t fieldOffset_;
|
||||
bool isObjectReference_;
|
||||
|
||||
ICSetProp_TypedObject(JitCode *stubCode, HandleShape shape, HandleTypeObject type,
|
||||
uint32_t fieldOffset, bool isObjectReference)
|
||||
: ICUpdatedStub(ICStub::SetProp_TypedObject, stubCode),
|
||||
shape_(shape),
|
||||
type_(type),
|
||||
fieldOffset_(fieldOffset),
|
||||
isObjectReference_(isObjectReference)
|
||||
{
|
||||
(void) fieldOffset_; // Silence clang warning
|
||||
}
|
||||
|
||||
public:
|
||||
static inline ICSetProp_TypedObject *New(ICStubSpace *space, JitCode *code,
|
||||
HandleShape shape, HandleTypeObject type,
|
||||
uint32_t fieldOffset, bool isObjectReference)
|
||||
{
|
||||
if (!code)
|
||||
return nullptr;
|
||||
return space->allocate<ICSetProp_TypedObject>(code, shape, type,
|
||||
fieldOffset, isObjectReference);
|
||||
}
|
||||
|
||||
HeapPtrShape &shape() {
|
||||
return shape_;
|
||||
}
|
||||
HeapPtrTypeObject &type() {
|
||||
return type_;
|
||||
}
|
||||
bool isObjectReference() {
|
||||
return isObjectReference_;
|
||||
}
|
||||
|
||||
static size_t offsetOfShape() {
|
||||
return offsetof(ICSetProp_TypedObject, shape_);
|
||||
}
|
||||
static size_t offsetOfType() {
|
||||
return offsetof(ICSetProp_TypedObject, type_);
|
||||
}
|
||||
static size_t offsetOfFieldOffset() {
|
||||
return offsetof(ICSetProp_TypedObject, fieldOffset_);
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
protected:
|
||||
RootedShape shape_;
|
||||
RootedTypeObject type_;
|
||||
uint32_t fieldOffset_;
|
||||
TypedThingLayout layout_;
|
||||
Rooted<SimpleTypeDescr *> fieldDescr_;
|
||||
|
||||
bool generateStubCode(MacroAssembler &masm);
|
||||
|
||||
virtual int32_t getKey() const {
|
||||
return static_cast<int32_t>(kind) |
|
||||
(static_cast<int32_t>(SimpleTypeDescrKey(fieldDescr_)) << 16) |
|
||||
(static_cast<int32_t>(layout_) << 24);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext *cx, Shape *shape, types::TypeObject *type, uint32_t fieldOffset,
|
||||
SimpleTypeDescr *fieldDescr)
|
||||
: ICStubCompiler(cx, ICStub::SetProp_TypedObject),
|
||||
shape_(cx, shape),
|
||||
type_(cx, type),
|
||||
fieldOffset_(fieldOffset),
|
||||
layout_(GetTypedThingLayout(shape->getObjectClass())),
|
||||
fieldDescr_(cx, fieldDescr)
|
||||
{}
|
||||
|
||||
ICUpdatedStub *getStub(ICStubSpace *space) {
|
||||
bool isObjectReference =
|
||||
fieldDescr_->is<ReferenceTypeDescr>() &&
|
||||
fieldDescr_->as<ReferenceTypeDescr>().type() == ReferenceTypeDescr::TYPE_OBJECT;
|
||||
ICUpdatedStub *stub = ICSetProp_TypedObject::New(space, getStubCode(), shape_, type_,
|
||||
fieldOffset_, isObjectReference);
|
||||
if (!stub || !stub->initUpdatingChain(cx, space))
|
||||
return nullptr;
|
||||
return stub;
|
||||
}
|
||||
|
||||
bool needsUpdateStubs() {
|
||||
return fieldDescr_->is<ReferenceTypeDescr>() &&
|
||||
fieldDescr_->as<ReferenceTypeDescr>().type() != ReferenceTypeDescr::TYPE_STRING;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Base stub for calling a setters on a native object.
|
||||
class ICSetPropCallSetter : public ICStub
|
||||
{
|
||||
|
@ -56,6 +56,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
|
||||
lastAnimationTime(0),
|
||||
regExps(runtime_),
|
||||
globalWriteBarriered(false),
|
||||
neuteredTypedObjects(0),
|
||||
propertyTree(thisForCtor()),
|
||||
selfHostingScriptSource(nullptr),
|
||||
lazyArrayBuffers(nullptr),
|
||||
|
@ -241,6 +241,9 @@ struct JSCompartment
|
||||
*/
|
||||
bool globalWriteBarriered;
|
||||
|
||||
// Non-zero if any typed objects in this compartment might be neutered.
|
||||
int32_t neuteredTypedObjects;
|
||||
|
||||
public:
|
||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||
size_t *tiAllocationSiteTables,
|
||||
|
@ -529,6 +529,7 @@ ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
|
||||
if (!cx->global()->getType(cx))
|
||||
CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
|
||||
types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED);
|
||||
cx->compartment()->neuteredTypedObjects = 1;
|
||||
}
|
||||
|
||||
// Neuter all views on the buffer, clear out the list of views and the
|
||||
|
Loading…
Reference in New Issue
Block a user