зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d5035d862f
Коммит
77f18d8038
|
@ -154,6 +154,10 @@ class TypedProto : public NativeObject
|
||||||
}
|
}
|
||||||
|
|
||||||
inline type::Kind kind() const;
|
inline type::Kind kind() const;
|
||||||
|
|
||||||
|
static int32_t offsetOfTypeDescr() {
|
||||||
|
return getFixedSlotOffset(JS_TYPROTO_SLOT_DESCR);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TypeDescr : public NativeObject
|
class TypeDescr : public NativeObject
|
||||||
|
@ -432,6 +436,10 @@ class ArrayTypeDescr : public ComplexTypeDescr
|
||||||
int32_t length() const {
|
int32_t length() const {
|
||||||
return getReservedSlot(JS_DESCR_SLOT_ARRAY_LENGTH).toInt32();
|
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;
|
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_CallDOMProxyNative:
|
||||||
case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
|
case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
|
||||||
ICGetPropCallDOMProxyNativeStub *propStub;
|
ICGetPropCallDOMProxyNativeStub *propStub;
|
||||||
|
@ -435,6 +440,12 @@ ICStub::trace(JSTracer *trc)
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case ICStub::SetProp_CallScripted: {
|
||||||
ICSetProp_CallScripted *callStub = toSetProp_CallScripted();
|
ICSetProp_CallScripted *callStub = toSetProp_CallScripted();
|
||||||
MarkShape(trc, &callStub->shape(), "baseline-setpropcallscripted-stub-shape");
|
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);
|
types::AddTypePropertyId(cx, obj, id, value);
|
||||||
break;
|
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:
|
default:
|
||||||
MOZ_CRASH("Invalid stub");
|
MOZ_CRASH("Invalid stub");
|
||||||
}
|
}
|
||||||
|
@ -3893,9 +3923,35 @@ static bool TryAttachNativeGetElemStub(JSContext *cx, HandleScript script, jsbyt
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
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 ||
|
return type == Scalar::Uint32 ||
|
||||||
type == Scalar::Float32 ||
|
type == Scalar::Float32 ||
|
||||||
type == Scalar::Float64;
|
type == Scalar::Float64;
|
||||||
|
@ -3987,8 +4043,10 @@ TryAttachGetElemStub(JSContext *cx, JSScript *script, jsbytecode *pc, ICGetElem_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for TypedArray[int] => Number accesses.
|
// Check for TypedArray[int] => Number and TypedObject[int] => Number accesses.
|
||||||
if (IsAnyTypedArray(obj.get()) && rhs.isNumber() && res.isNumber() &&
|
if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
|
||||||
|
rhs.isNumber() &&
|
||||||
|
res.isNumber() &&
|
||||||
!TypedArrayGetElemStubExists(stub, obj))
|
!TypedArrayGetElemStubExists(stub, obj))
|
||||||
{
|
{
|
||||||
// Don't attach CALLELEM stubs for accesses on typed array expected to yield numbers.
|
// 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
|
#endif
|
||||||
|
|
||||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||||
(TypedArrayRequiresFloatingPoint(obj) || rhs.isDouble()))
|
(TypedThingRequiresFloatingPoint(obj) || rhs.isDouble()))
|
||||||
{
|
{
|
||||||
return true;
|
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");
|
JitSpew(JitSpew_BaselineIC, " Generating GetElem(TypedArray[Int32]) stub");
|
||||||
ICGetElem_TypedArray::Compiler compiler(cx,
|
ICGetElem_TypedArray::Compiler compiler(cx, obj->lastProperty(),
|
||||||
AnyTypedArrayShape(obj.get()),
|
TypedThingElementType(obj));
|
||||||
AnyTypedArrayType(obj.get()));
|
|
||||||
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
||||||
if (!typedArrayStub)
|
if (!typedArrayStub)
|
||||||
return false;
|
return false;
|
||||||
|
@ -4614,10 +4676,60 @@ ICGetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
// GetElem_TypedArray
|
// 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
|
bool
|
||||||
ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
{
|
{
|
||||||
Label failure;
|
Label failure;
|
||||||
|
|
||||||
|
if (layout_ != Layout_TypedArray)
|
||||||
|
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||||
|
|
||||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||||
|
|
||||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||||
|
@ -4650,11 +4762,11 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
Register key = masm.extractInt32(R1, ExtractTemp1);
|
Register key = masm.extractInt32(R1, ExtractTemp1);
|
||||||
|
|
||||||
// Bounds check.
|
// Bounds check.
|
||||||
masm.unboxInt32(Address(obj, TypedArrayLayout::lengthOffset()), scratchReg);
|
LoadTypedThingLength(masm, layout_, obj, scratchReg);
|
||||||
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
|
masm.branch32(Assembler::BelowOrEqual, scratchReg, key, &failure);
|
||||||
|
|
||||||
// Load the elements vector.
|
// Load the elements vector.
|
||||||
masm.loadPtr(Address(obj, TypedArrayLayout::dataOffset()), scratchReg);
|
LoadTypedThingData(masm, layout_, obj, scratchReg);
|
||||||
|
|
||||||
// Load the value.
|
// Load the value.
|
||||||
BaseIndex source(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
BaseIndex source(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
||||||
|
@ -5113,31 +5225,45 @@ DoSetElemFallback(JSContext *cx, BaselineFrame *frame, ICSetElem_Fallback *stub_
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsAnyTypedArray(obj.get()) && index.isNumber() && rhs.isNumber()) {
|
if ((IsAnyTypedArray(obj.get()) || IsPrimitiveArrayTypedObject(obj)) &&
|
||||||
|
index.isNumber() &&
|
||||||
|
rhs.isNumber())
|
||||||
|
{
|
||||||
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
if (!cx->runtime()->jitSupportsFloatingPoint &&
|
||||||
(TypedArrayRequiresFloatingPoint(obj) || index.isDouble()))
|
(TypedThingRequiresFloatingPoint(obj) || index.isDouble()))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t len = AnyTypedArrayLength(obj.get());
|
bool expectOutOfBounds;
|
||||||
double idx = index.toNumber();
|
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)) {
|
if (!TypedArraySetElemStubExists(stub, obj, expectOutOfBounds)) {
|
||||||
// Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
|
// Remove any existing TypedArraySetElemStub that doesn't handle out-of-bounds
|
||||||
if (expectOutOfBounds)
|
if (expectOutOfBounds)
|
||||||
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
|
RemoveExistingTypedArraySetElemStub(cx, stub, obj);
|
||||||
|
|
||||||
|
Shape *shape = obj->lastProperty();
|
||||||
|
Scalar::Type type = TypedThingElementType(obj);
|
||||||
|
|
||||||
JitSpew(JitSpew_BaselineIC,
|
JitSpew(JitSpew_BaselineIC,
|
||||||
" Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
|
" Generating SetElem_TypedArray stub (shape=%p, type=%u, oob=%s)",
|
||||||
AnyTypedArrayShape(obj.get()),
|
shape, type, expectOutOfBounds ? "yes" : "no");
|
||||||
AnyTypedArrayType(obj.get()),
|
ICSetElem_TypedArray::Compiler compiler(cx, shape, type, expectOutOfBounds);
|
||||||
expectOutOfBounds ? "yes" : "no");
|
|
||||||
ICSetElem_TypedArray::Compiler compiler(cx,
|
|
||||||
AnyTypedArrayShape(obj.get()),
|
|
||||||
AnyTypedArrayType(obj.get()),
|
|
||||||
expectOutOfBounds);
|
|
||||||
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
ICStub *typedArrayStub = compiler.getStub(compiler.getStubSpace(script));
|
||||||
if (!typedArrayStub)
|
if (!typedArrayStub)
|
||||||
return false;
|
return false;
|
||||||
|
@ -5521,10 +5647,80 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
// SetElem_TypedArray
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
masm.bind(&done);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
{
|
{
|
||||||
Label failure;
|
Label failure;
|
||||||
|
|
||||||
|
if (layout_ != Layout_TypedArray)
|
||||||
|
CheckForNeuteredTypedObject(cx, masm, &failure);
|
||||||
|
|
||||||
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
masm.branchTestObject(Assembler::NotEqual, R0, &failure);
|
||||||
|
|
||||||
GeneralRegisterSet regs(availableGeneralRegs(2));
|
GeneralRegisterSet regs(availableGeneralRegs(2));
|
||||||
|
@ -5558,12 +5754,12 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
|
|
||||||
// Bounds check.
|
// Bounds check.
|
||||||
Label oobWrite;
|
Label oobWrite;
|
||||||
masm.unboxInt32(Address(obj, TypedArrayLayout::lengthOffset()), scratchReg);
|
LoadTypedThingLength(masm, layout_, obj, scratchReg);
|
||||||
masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
|
masm.branch32(Assembler::BelowOrEqual, scratchReg, key,
|
||||||
expectOutOfBounds_ ? &oobWrite : &failure);
|
expectOutOfBounds_ ? &oobWrite : &failure);
|
||||||
|
|
||||||
// Load the elements vector.
|
// Load the elements vector.
|
||||||
masm.loadPtr(Address(obj, TypedArrayLayout::dataOffset()), scratchReg);
|
LoadTypedThingData(masm, layout_, obj, scratchReg);
|
||||||
|
|
||||||
BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
BaseIndex dest(scratchReg, key, ScaleFromElemWidth(Scalar::byteSize(type_)));
|
||||||
Address value(BaselineStackReg, ICStackValueOffset);
|
Address value(BaselineStackReg, ICStackValueOffset);
|
||||||
|
@ -5576,64 +5772,15 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
regs.take(scratchReg);
|
regs.take(scratchReg);
|
||||||
Register secondScratch = regs.takeAny();
|
Register secondScratch = regs.takeAny();
|
||||||
|
|
||||||
if (type_ == Scalar::Float32 || type_ == Scalar::Float64) {
|
Label failureModifiedSecondScratch;
|
||||||
masm.ensureDouble(value, FloatReg0, &failure);
|
StoreToTypedArray(cx, masm, type_, value, dest,
|
||||||
if (type_ == Scalar::Float32)
|
secondScratch, &failure, &failureModifiedSecondScratch);
|
||||||
{
|
EmitReturnFromIC(masm);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (failureModifiedSecondScratch.used()) {
|
||||||
// Writing to secondScratch may have clobbered R0 or R1, restore them
|
// Writing to secondScratch may have clobbered R0 or R1, restore them
|
||||||
// first.
|
// first.
|
||||||
masm.bind(&failureRestoreRegs);
|
masm.bind(&failureModifiedSecondScratch);
|
||||||
masm.tagValue(JSVAL_TYPE_OBJECT, obj, R0);
|
masm.tagValue(JSVAL_TYPE_OBJECT, obj, R0);
|
||||||
masm.tagValue(JSVAL_TYPE_INT32, key, R1);
|
masm.tagValue(JSVAL_TYPE_INT32, key, R1);
|
||||||
}
|
}
|
||||||
|
@ -5643,6 +5790,7 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
EmitStubGuardFailure(masm);
|
EmitStubGuardFailure(masm);
|
||||||
|
|
||||||
if (expectOutOfBounds_) {
|
if (expectOutOfBounds_) {
|
||||||
|
MOZ_ASSERT(layout_ == Layout_TypedArray);
|
||||||
masm.bind(&oobWrite);
|
masm.bind(&oobWrite);
|
||||||
EmitReturnFromIC(masm);
|
EmitReturnFromIC(masm);
|
||||||
}
|
}
|
||||||
|
@ -6604,6 +6752,46 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||||
return true;
|
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
|
static bool
|
||||||
TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||||
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
|
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
|
||||||
|
@ -6811,6 +6999,11 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub_
|
||||||
if (attached)
|
if (attached)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (!TryAttachTypedObjectGetPropStub(cx, script, stub, name, val, &attached))
|
||||||
|
return false;
|
||||||
|
if (attached)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (val.isString() || val.isNumber() || val.isBoolean()) {
|
if (val.isString() || val.isNumber() || val.isBoolean()) {
|
||||||
if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
|
if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
|
||||||
return false;
|
return false;
|
||||||
|
@ -7706,6 +7899,82 @@ ICGetProp_Generic::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
return true;
|
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
|
void
|
||||||
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
||||||
{
|
{
|
||||||
|
@ -7884,6 +8153,48 @@ TryAttachSetAccessorPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
|
||||||
return true;
|
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
|
static bool
|
||||||
DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_,
|
DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_,
|
||||||
HandleValue lhs, HandleValue rhs, MutableHandleValue res)
|
HandleValue lhs, HandleValue rhs, MutableHandleValue res)
|
||||||
|
@ -7985,6 +8296,15 @@ DoSetPropFallback(JSContext *cx, BaselineFrame *frame, ICSetProp_Fallback *stub_
|
||||||
if (attached)
|
if (attached)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (!attached &&
|
||||||
|
lhs.isObject() &&
|
||||||
|
!TryAttachTypedObjectSetPropStub(cx, script, stub, id, obj, rhs, &attached))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (attached)
|
||||||
|
return true;
|
||||||
|
|
||||||
MOZ_ASSERT(!attached);
|
MOZ_ASSERT(!attached);
|
||||||
if (!isTemporarilyUnoptimizable)
|
if (!isTemporarilyUnoptimizable)
|
||||||
stub->noteUnoptimizableAccess();
|
stub->noteUnoptimizableAccess();
|
||||||
|
@ -8264,6 +8584,128 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
|
||||||
return true;
|
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
|
bool
|
||||||
ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
ICSetProp_CallScripted::Compiler::generateStubCode(MacroAssembler &masm)
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,9 +14,11 @@
|
||||||
#include "jsgc.h"
|
#include "jsgc.h"
|
||||||
#include "jsopcode.h"
|
#include "jsopcode.h"
|
||||||
|
|
||||||
|
#include "builtin/TypedObject.h"
|
||||||
#include "jit/BaselineJIT.h"
|
#include "jit/BaselineJIT.h"
|
||||||
#include "jit/BaselineRegisters.h"
|
#include "jit/BaselineRegisters.h"
|
||||||
#include "vm/ArrayObject.h"
|
#include "vm/ArrayObject.h"
|
||||||
|
#include "vm/TypedArrayCommon.h"
|
||||||
|
|
||||||
namespace js {
|
namespace js {
|
||||||
|
|
||||||
|
@ -424,6 +426,7 @@ class ICEntry
|
||||||
_(GetProp_Native) \
|
_(GetProp_Native) \
|
||||||
_(GetProp_NativeDoesNotExist) \
|
_(GetProp_NativeDoesNotExist) \
|
||||||
_(GetProp_NativePrototype) \
|
_(GetProp_NativePrototype) \
|
||||||
|
_(GetProp_TypedObject) \
|
||||||
_(GetProp_CallScripted) \
|
_(GetProp_CallScripted) \
|
||||||
_(GetProp_CallNative) \
|
_(GetProp_CallNative) \
|
||||||
_(GetProp_CallNativePrototype)\
|
_(GetProp_CallNativePrototype)\
|
||||||
|
@ -437,6 +440,7 @@ class ICEntry
|
||||||
_(SetProp_Fallback) \
|
_(SetProp_Fallback) \
|
||||||
_(SetProp_Native) \
|
_(SetProp_Native) \
|
||||||
_(SetProp_NativeAdd) \
|
_(SetProp_NativeAdd) \
|
||||||
|
_(SetProp_TypedObject) \
|
||||||
_(SetProp_CallScripted) \
|
_(SetProp_CallScripted) \
|
||||||
_(SetProp_CallNative) \
|
_(SetProp_CallNative) \
|
||||||
\
|
\
|
||||||
|
@ -3409,6 +3413,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
|
class ICGetElem_TypedArray : public ICStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
@ -3438,19 +3462,23 @@ class ICGetElem_TypedArray : public ICStub
|
||||||
class Compiler : public ICStubCompiler {
|
class Compiler : public ICStubCompiler {
|
||||||
RootedShape shape_;
|
RootedShape shape_;
|
||||||
Scalar::Type type_;
|
Scalar::Type type_;
|
||||||
|
TypedThingLayout layout_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool generateStubCode(MacroAssembler &masm);
|
bool generateStubCode(MacroAssembler &masm);
|
||||||
|
|
||||||
virtual int32_t getKey() const {
|
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:
|
public:
|
||||||
Compiler(JSContext *cx, Shape *shape, Scalar::Type type)
|
Compiler(JSContext *cx, Shape *shape, Scalar::Type type)
|
||||||
: ICStubCompiler(cx, ICStub::GetElem_TypedArray),
|
: ICStubCompiler(cx, ICStub::GetElem_TypedArray),
|
||||||
shape_(cx, shape),
|
shape_(cx, shape),
|
||||||
type_(type)
|
type_(type),
|
||||||
|
layout_(GetTypedThingLayout(shape->getObjectClass()))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
ICStub *getStub(ICStubSpace *space) {
|
ICStub *getStub(ICStubSpace *space) {
|
||||||
|
@ -3724,6 +3752,7 @@ class ICSetElemDenseAddCompiler : public ICStubCompiler {
|
||||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
ICUpdatedStub *getStub(ICStubSpace *space);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Accesses scalar elements of a typed array or typed object.
|
||||||
class ICSetElem_TypedArray : public ICStub
|
class ICSetElem_TypedArray : public ICStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
@ -3763,14 +3792,17 @@ class ICSetElem_TypedArray : public ICStub
|
||||||
class Compiler : public ICStubCompiler {
|
class Compiler : public ICStubCompiler {
|
||||||
RootedShape shape_;
|
RootedShape shape_;
|
||||||
Scalar::Type type_;
|
Scalar::Type type_;
|
||||||
|
TypedThingLayout layout_;
|
||||||
bool expectOutOfBounds_;
|
bool expectOutOfBounds_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool generateStubCode(MacroAssembler &masm);
|
bool generateStubCode(MacroAssembler &masm);
|
||||||
|
|
||||||
virtual int32_t getKey() const {
|
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>(expectOutOfBounds_) << 24);
|
(static_cast<int32_t>(type_) << 16) |
|
||||||
|
(static_cast<int32_t>(layout_) << 24) |
|
||||||
|
(static_cast<int32_t>(expectOutOfBounds_) << 28);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -3778,6 +3810,7 @@ class ICSetElem_TypedArray : public ICStub
|
||||||
: ICStubCompiler(cx, ICStub::SetElem_TypedArray),
|
: ICStubCompiler(cx, ICStub::SetElem_TypedArray),
|
||||||
shape_(cx, shape),
|
shape_(cx, shape),
|
||||||
type_(type),
|
type_(type),
|
||||||
|
layout_(GetTypedThingLayout(shape->getObjectClass())),
|
||||||
expectOutOfBounds_(expectOutOfBounds)
|
expectOutOfBounds_(expectOutOfBounds)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -4574,6 +4607,84 @@ class ICGetPropNativeDoesNotExistCompiler : public ICStubCompiler
|
||||||
ICStub *getStub(ICStubSpace *space);
|
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
|
class ICGetPropCallGetter : public ICMonitoredStub
|
||||||
{
|
{
|
||||||
friend class ICStubSpace;
|
friend class ICStubSpace;
|
||||||
|
@ -5416,6 +5527,102 @@ class ICSetPropNativeAddCompiler : public ICStubCompiler
|
||||||
ICUpdatedStub *getStub(ICStubSpace *space);
|
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.
|
// Base stub for calling a setters on a native object.
|
||||||
class ICSetPropCallSetter : public ICStub
|
class ICSetPropCallSetter : public ICStub
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,6 +56,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
|
||||||
lastAnimationTime(0),
|
lastAnimationTime(0),
|
||||||
regExps(runtime_),
|
regExps(runtime_),
|
||||||
globalWriteBarriered(false),
|
globalWriteBarriered(false),
|
||||||
|
neuteredTypedObjects(0),
|
||||||
propertyTree(thisForCtor()),
|
propertyTree(thisForCtor()),
|
||||||
selfHostingScriptSource(nullptr),
|
selfHostingScriptSource(nullptr),
|
||||||
lazyArrayBuffers(nullptr),
|
lazyArrayBuffers(nullptr),
|
||||||
|
|
|
@ -241,6 +241,9 @@ struct JSCompartment
|
||||||
*/
|
*/
|
||||||
bool globalWriteBarriered;
|
bool globalWriteBarriered;
|
||||||
|
|
||||||
|
// Non-zero if any typed objects in this compartment might be neutered.
|
||||||
|
int32_t neuteredTypedObjects;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
void addSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf,
|
||||||
size_t *tiAllocationSiteTables,
|
size_t *tiAllocationSiteTables,
|
||||||
|
|
|
@ -529,6 +529,7 @@ ArrayBufferObject::neuter(JSContext *cx, Handle<ArrayBufferObject*> buffer,
|
||||||
if (!cx->global()->getType(cx))
|
if (!cx->global()->getType(cx))
|
||||||
CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
|
CrashAtUnhandlableOOM("ArrayBufferObject::neuter");
|
||||||
types::MarkTypeObjectFlags(cx, cx->global(), types::OBJECT_FLAG_TYPED_OBJECT_NEUTERED);
|
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
|
// Neuter all views on the buffer, clear out the list of views and the
|
||||||
|
|
Загрузка…
Ссылка в новой задаче