mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-17 07:15:46 +00:00
Bug 1267163 - Port primitive value getprop stub to CacheIR. r=efaust
--HG-- extra : rebase_source : 1a6d1a66695288fdfd83ea9f10f6d8aa60ad3c06
This commit is contained in:
parent
6b779e5f7a
commit
eb36b16c2d
@ -694,6 +694,36 @@ BaselineCacheIRCompiler::emitGuardIsObject()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardType()
|
||||
{
|
||||
ValueOperand input = allocator.useRegister(masm, reader.valOperandId());
|
||||
JSValueType type = reader.valueType();
|
||||
|
||||
FailurePath* failure;
|
||||
if (!addFailurePath(&failure))
|
||||
return false;
|
||||
|
||||
switch (type) {
|
||||
case JSVAL_TYPE_STRING:
|
||||
masm.branchTestString(Assembler::NotEqual, input, failure->label());
|
||||
break;
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
masm.branchTestSymbol(Assembler::NotEqual, input, failure->label());
|
||||
break;
|
||||
case JSVAL_TYPE_DOUBLE:
|
||||
masm.branchTestNumber(Assembler::NotEqual, input, failure->label());
|
||||
break;
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
masm.branchTestBoolean(Assembler::NotEqual, input, failure->label());
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
BaselineCacheIRCompiler::emitGuardShape()
|
||||
{
|
||||
|
@ -814,9 +814,13 @@ GetCacheIRExpectedInputType(ICCacheIR_Monitored* stub)
|
||||
{
|
||||
CacheIRReader reader(stub->stubInfo());
|
||||
|
||||
// For now, all CacheIR stubs expect an object.
|
||||
MOZ_ALWAYS_TRUE(reader.matchOp(CacheOp::GuardIsObject, ObjOperandId(0)));
|
||||
return MIRType::Object;
|
||||
if (reader.matchOp(CacheOp::GuardIsObject, ValOperandId(0)))
|
||||
return MIRType::Object;
|
||||
if (reader.matchOp(CacheOp::GuardType, ValOperandId(0))) {
|
||||
JSValueType type = reader.valueType();
|
||||
return MIRTypeFromValueType(type);
|
||||
}
|
||||
MOZ_CRASH("Unexpected instruction");
|
||||
}
|
||||
|
||||
MIRType
|
||||
@ -870,10 +874,6 @@ BaselineInspector::expectedPropertyAccessInputType(jsbytecode* pc)
|
||||
stubType = MIRType::Object;
|
||||
break;
|
||||
|
||||
case ICStub::GetProp_Primitive:
|
||||
stubType = MIRTypeFromValueType(stub->toGetProp_Primitive()->primitiveType());
|
||||
break;
|
||||
|
||||
case ICStub::GetProp_StringLength:
|
||||
stubType = MIRType::String;
|
||||
break;
|
||||
|
@ -68,8 +68,12 @@ GetPropIRGenerator::tryAttachStub(Maybe<CacheIRWriter>& writer)
|
||||
return false;
|
||||
if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!emitted_ && !tryAttachPrimitive(*writer, valId))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -415,3 +419,53 @@ GetPropIRGenerator::tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject
|
||||
EmitLoadSlotResult(writer, envId, env, shape);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId)
|
||||
{
|
||||
MOZ_ASSERT(!emitted_);
|
||||
|
||||
JSValueType primitiveType;
|
||||
RootedNativeObject proto(cx_);
|
||||
if (val_.isString()) {
|
||||
if (name_ == cx_->names().length) {
|
||||
// String length is special-cased, see js::GetProperty.
|
||||
return true;
|
||||
}
|
||||
primitiveType = JSVAL_TYPE_STRING;
|
||||
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_String));
|
||||
} else if (val_.isNumber()) {
|
||||
primitiveType = JSVAL_TYPE_DOUBLE;
|
||||
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Number));
|
||||
} else if (val_.isBoolean()) {
|
||||
primitiveType = JSVAL_TYPE_BOOLEAN;
|
||||
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Boolean));
|
||||
} else if (val_.isSymbol()) {
|
||||
primitiveType = JSVAL_TYPE_SYMBOL;
|
||||
proto = MaybeNativeObject(GetBuiltinPrototypePure(cx_->global(), JSProto_Symbol));
|
||||
} else {
|
||||
MOZ_ASSERT(val_.isNullOrUndefined() || val_.isMagic());
|
||||
return true;
|
||||
}
|
||||
if (!proto)
|
||||
return true;
|
||||
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
RootedId id(cx_, NameToId(name_));
|
||||
if (IsIonEnabled(cx_))
|
||||
EnsureTrackPropertyTypes(cx_, proto, id);
|
||||
|
||||
// For now, only look for properties directly set on the prototype.
|
||||
Shape* shape = proto->lookup(cx_, id);
|
||||
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
writer.guardType(valId, primitiveType);
|
||||
|
||||
ObjOperandId protoId = writer.loadObject(proto);
|
||||
writer.guardShape(protoId, proto->lastProperty());
|
||||
EmitLoadSlotResult(writer, protoId, proto, shape);
|
||||
|
||||
emitted_ = true;
|
||||
return true;
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ class ObjOperandId : public OperandId
|
||||
|
||||
#define CACHE_IR_OPS(_) \
|
||||
_(GuardIsObject) \
|
||||
_(GuardType) \
|
||||
_(GuardShape) \
|
||||
_(GuardGroup) \
|
||||
_(GuardProto) \
|
||||
@ -247,6 +248,11 @@ class MOZ_RAII CacheIRWriter
|
||||
writeOpWithOperandId(CacheOp::GuardIsObject, val);
|
||||
return ObjOperandId(val.id());
|
||||
}
|
||||
void guardType(ValOperandId val, JSValueType type) {
|
||||
writeOpWithOperandId(CacheOp::GuardType, val);
|
||||
MOZ_ASSERT(uint32_t(type) <= UINT8_MAX);
|
||||
buffer_.writeByte(uint32_t(type));
|
||||
}
|
||||
void guardShape(ObjOperandId obj, Shape* shape) {
|
||||
writeOpWithOperandId(CacheOp::GuardShape, obj);
|
||||
addStubWord(uintptr_t(shape), StubField::GCType::Shape);
|
||||
@ -422,6 +428,8 @@ class MOZ_RAII GetPropIRGenerator
|
||||
MOZ_MUST_USE bool tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj,
|
||||
ObjOperandId objId);
|
||||
|
||||
MOZ_MUST_USE bool tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId);
|
||||
|
||||
GetPropIRGenerator(const GetPropIRGenerator&) = delete;
|
||||
GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
|
||||
|
||||
|
@ -400,11 +400,6 @@ ICStub::trace(JSTracer* trc)
|
||||
TraceEdge(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
|
||||
break;
|
||||
}
|
||||
case ICStub::GetProp_Primitive: {
|
||||
ICGetProp_Primitive* propStub = toGetProp_Primitive();
|
||||
TraceEdge(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape");
|
||||
break;
|
||||
}
|
||||
case ICStub::GetProp_CallDOMProxyNative:
|
||||
case ICStub::GetProp_CallDOMProxyWithGenerationNative: {
|
||||
ICGetPropCallDOMProxyNativeStub* propStub;
|
||||
@ -2544,61 +2539,6 @@ TryAttachNativeGetAccessorPropStub(JSContext* cx, SharedStubInfo* info,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
TryAttachPrimitiveGetPropStub(JSContext* cx, SharedStubInfo* info,
|
||||
ICGetProp_Fallback* stub, HandlePropertyName name,
|
||||
HandleValue val, HandleValue res, bool* attached)
|
||||
{
|
||||
MOZ_ASSERT(!*attached);
|
||||
|
||||
JSValueType primitiveType;
|
||||
RootedNativeObject proto(cx);
|
||||
Rooted<GlobalObject*> global(cx, &info->script()->global());
|
||||
if (val.isString()) {
|
||||
primitiveType = JSVAL_TYPE_STRING;
|
||||
proto = GlobalObject::getOrCreateStringPrototype(cx, global);
|
||||
} else if (val.isSymbol()) {
|
||||
primitiveType = JSVAL_TYPE_SYMBOL;
|
||||
proto = GlobalObject::getOrCreateSymbolPrototype(cx, global);
|
||||
} else if (val.isNumber()) {
|
||||
primitiveType = JSVAL_TYPE_DOUBLE;
|
||||
proto = GlobalObject::getOrCreateNumberPrototype(cx, global);
|
||||
} else {
|
||||
MOZ_ASSERT(val.isBoolean());
|
||||
primitiveType = JSVAL_TYPE_BOOLEAN;
|
||||
proto = GlobalObject::getOrCreateBooleanPrototype(cx, global);
|
||||
}
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
RootedId id(cx, NameToId(name));
|
||||
if (IsIonEnabled(cx))
|
||||
EnsureTrackPropertyTypes(cx, proto, id);
|
||||
|
||||
// For now, only look for properties directly set on the prototype.
|
||||
RootedShape shape(cx, proto->lookup(cx, id));
|
||||
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
|
||||
return true;
|
||||
|
||||
bool isFixedSlot;
|
||||
uint32_t offset;
|
||||
GetFixedOrDynamicSlotOffset(shape, &isFixedSlot, &offset);
|
||||
|
||||
ICStub* monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
|
||||
|
||||
JitSpew(JitSpew_BaselineIC, " Generating GetProp_Primitive stub");
|
||||
ICGetProp_Primitive::Compiler compiler(cx, info->engine(), monitorStub, primitiveType, proto,
|
||||
isFixedSlot, offset);
|
||||
ICStub* newStub = compiler.getStub(compiler.getStubSpace(info->outerScript(cx)));
|
||||
if (!newStub)
|
||||
return false;
|
||||
|
||||
stub->addNewStub(newStub);
|
||||
*attached = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name,
|
||||
JSObject** lastProto, size_t* protoChainDepthOut)
|
||||
@ -2777,13 +2717,6 @@ DoGetPropFallback(JSContext* cx, void* payload, ICGetProp_Fallback* stub_,
|
||||
return true;
|
||||
|
||||
|
||||
if (val.isString() || val.isNumber() || val.isBoolean()) {
|
||||
if (!TryAttachPrimitiveGetPropStub(cx, &info, stub, name, val, res, &attached))
|
||||
return false;
|
||||
if (attached)
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!attached);
|
||||
if (!isTemporarilyUnoptimizable)
|
||||
stub->noteUnoptimizableAccess();
|
||||
@ -2868,53 +2801,6 @@ ICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
{
|
||||
Label failure;
|
||||
switch (primitiveType_) {
|
||||
case JSVAL_TYPE_STRING:
|
||||
masm.branchTestString(Assembler::NotEqual, R0, &failure);
|
||||
break;
|
||||
case JSVAL_TYPE_SYMBOL:
|
||||
masm.branchTestSymbol(Assembler::NotEqual, R0, &failure);
|
||||
break;
|
||||
case JSVAL_TYPE_DOUBLE: // Also used for int32.
|
||||
masm.branchTestNumber(Assembler::NotEqual, R0, &failure);
|
||||
break;
|
||||
case JSVAL_TYPE_BOOLEAN:
|
||||
masm.branchTestBoolean(Assembler::NotEqual, R0, &failure);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("unexpected type");
|
||||
}
|
||||
|
||||
AllocatableGeneralRegisterSet regs(availableGeneralRegs(1));
|
||||
Register holderReg = regs.takeAny();
|
||||
Register scratchReg = regs.takeAny();
|
||||
|
||||
// Verify the shape of the prototype.
|
||||
masm.movePtr(ImmGCPtr(prototype_.get()), holderReg);
|
||||
|
||||
Address shapeAddr(ICStubReg, ICGetProp_Primitive::offsetOfProtoShape());
|
||||
masm.loadPtr(Address(holderReg, ShapedObject::offsetOfShape()), scratchReg);
|
||||
masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
|
||||
|
||||
if (!isFixedSlot_)
|
||||
masm.loadPtr(Address(holderReg, NativeObject::offsetOfSlots()), holderReg);
|
||||
|
||||
masm.load32(Address(ICStubReg, ICGetProp_Primitive::offsetOfOffset()), scratchReg);
|
||||
masm.loadValue(BaseIndex(holderReg, scratchReg, TimesOne), R0);
|
||||
|
||||
// Enter type monitor IC to type-check result.
|
||||
EmitEnterTypeMonitorIC(masm);
|
||||
|
||||
// Failure case - jump to next stub
|
||||
masm.bind(&failure);
|
||||
EmitStubGuardFailure(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
ICGetPropNativeStub*
|
||||
ICGetPropNativeCompiler::getStub(ICStubSpace* space)
|
||||
{
|
||||
@ -3704,17 +3590,6 @@ BaselineScript::noteAccessedGetter(uint32_t pcOffset)
|
||||
stub->toGetProp_Fallback()->noteAccessedGetter();
|
||||
}
|
||||
|
||||
ICGetProp_Primitive::ICGetProp_Primitive(JitCode* stubCode, ICStub* firstMonitorStub,
|
||||
JSValueType primitiveType, Shape* protoShape,
|
||||
uint32_t offset)
|
||||
: ICMonitoredStub(GetProp_Primitive, stubCode, firstMonitorStub),
|
||||
protoShape_(protoShape),
|
||||
offset_(offset)
|
||||
{
|
||||
extra_ = uint16_t(primitiveType);
|
||||
MOZ_ASSERT(JSValueType(extra_) == primitiveType);
|
||||
}
|
||||
|
||||
ICGetPropNativeStub::ICGetPropNativeStub(ICStub::Kind kind, JitCode* stubCode,
|
||||
ICStub* firstMonitorStub,
|
||||
ReceiverGuard guard, uint32_t offset)
|
||||
|
@ -2374,74 +2374,6 @@ class ICGetProp_Generic : public ICMonitoredStub
|
||||
};
|
||||
};
|
||||
|
||||
// Stub for accessing a property on a primitive's prototype.
|
||||
class ICGetProp_Primitive : public ICMonitoredStub
|
||||
{
|
||||
friend class ICStubSpace;
|
||||
|
||||
protected: // Protected to silence Clang warning.
|
||||
// Shape of String.prototype/Number.prototype to check for.
|
||||
GCPtrShape protoShape_;
|
||||
|
||||
// Fixed or dynamic slot offset.
|
||||
uint32_t offset_;
|
||||
|
||||
ICGetProp_Primitive(JitCode* stubCode, ICStub* firstMonitorStub, JSValueType primitiveType,
|
||||
Shape* protoShape, uint32_t offset);
|
||||
|
||||
public:
|
||||
GCPtrShape& protoShape() {
|
||||
return protoShape_;
|
||||
}
|
||||
JSValueType primitiveType() const {
|
||||
return JSValueType(extra_);
|
||||
}
|
||||
|
||||
static size_t offsetOfProtoShape() {
|
||||
return offsetof(ICGetProp_Primitive, protoShape_);
|
||||
}
|
||||
|
||||
static size_t offsetOfOffset() {
|
||||
return offsetof(ICGetProp_Primitive, offset_);
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
ICStub* firstMonitorStub_;
|
||||
JSValueType primitiveType_;
|
||||
RootedObject prototype_;
|
||||
bool isFixedSlot_;
|
||||
uint32_t offset_;
|
||||
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
|
||||
protected:
|
||||
virtual int32_t getKey() const {
|
||||
static_assert(sizeof(JSValueType) == 1, "JSValueType should fit in one byte");
|
||||
return static_cast<int32_t>(engine_) |
|
||||
(static_cast<int32_t>(kind) << 1) |
|
||||
(static_cast<int32_t>(isFixedSlot_) << 17) |
|
||||
(static_cast<int32_t>(primitiveType_) << 25);
|
||||
}
|
||||
|
||||
public:
|
||||
Compiler(JSContext* cx, Engine engine, ICStub* firstMonitorStub, JSValueType primitiveType,
|
||||
HandleObject prototype, bool isFixedSlot, uint32_t offset)
|
||||
: ICStubCompiler(cx, ICStub::GetProp_Primitive, engine),
|
||||
firstMonitorStub_(firstMonitorStub),
|
||||
primitiveType_(primitiveType),
|
||||
prototype_(cx, prototype),
|
||||
isFixedSlot_(isFixedSlot),
|
||||
offset_(offset)
|
||||
{}
|
||||
|
||||
ICStub* getStub(ICStubSpace* space) {
|
||||
RootedShape protoShape(cx, prototype_->as<NativeObject>().lastProperty());
|
||||
return newStub<ICGetProp_Primitive>(space, getStubCode(), firstMonitorStub_,
|
||||
primitiveType_, protoShape, offset_);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// Stub for accessing a string's length.
|
||||
class ICGetProp_StringLength : public ICStub
|
||||
{
|
||||
|
@ -35,7 +35,6 @@ namespace jit {
|
||||
_(Compare_Int32WithBoolean) \
|
||||
\
|
||||
_(GetProp_Fallback) \
|
||||
_(GetProp_Primitive) \
|
||||
_(GetProp_StringLength) \
|
||||
_(GetProp_CallScripted) \
|
||||
_(GetProp_CallNative) \
|
||||
|
Loading…
Reference in New Issue
Block a user