Bug 1267163 - Port primitive value getprop stub to CacheIR. r=efaust

--HG--
extra : rebase_source : 1a6d1a66695288fdfd83ea9f10f6d8aa60ad3c06
This commit is contained in:
Jan de Mooij 2016-10-06 14:58:35 +02:00
parent 6b779e5f7a
commit eb36b16c2d
7 changed files with 99 additions and 201 deletions

View File

@ -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()
{

View File

@ -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)));
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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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)

View File

@ -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
{

View File

@ -35,7 +35,6 @@ namespace jit {
_(Compare_Int32WithBoolean) \
\
_(GetProp_Fallback) \
_(GetProp_Primitive) \
_(GetProp_StringLength) \
_(GetProp_CallScripted) \
_(GetProp_CallNative) \