Bug 609296 - Make accessing properties like toString on numbers/booleans fast. r=bhackett

This commit is contained in:
Jan de Mooij 2013-11-27 20:48:42 +01:00
parent f322dc55d3
commit d4bfe37616
3 changed files with 83 additions and 55 deletions

View File

@ -316,9 +316,9 @@ ICStub::trace(JSTracer *trc)
gc::MarkValue(trc, &constantStub->value(), "baseline-getintrinsic-constant-value");
break;
}
case ICStub::GetProp_String: {
ICGetProp_String *propStub = toGetProp_String();
MarkShape(trc, &propStub->stringProtoShape(), "baseline-getpropstring-stub-shape");
case ICStub::GetProp_Primitive: {
ICGetProp_Primitive *propStub = toGetProp_Primitive();
MarkShape(trc, &propStub->protoShape(), "baseline-getprop-primitive-stub-shape");
break;
}
case ICStub::GetProp_Native: {
@ -6156,35 +6156,47 @@ TryAttachNativeGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
}
static bool
TryAttachStringGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
HandleValue res, bool *attached)
TryAttachPrimitiveGetPropStub(JSContext *cx, HandleScript script, jsbytecode *pc,
ICGetProp_Fallback *stub, HandlePropertyName name, HandleValue val,
HandleValue res, bool *attached)
{
JS_ASSERT(!*attached);
JS_ASSERT(val.isString());
RootedObject stringProto(cx, script->global().getOrCreateStringPrototype(cx));
if (!stringProto)
JSValueType primitiveType;
RootedObject proto(cx);
if (val.isString()) {
primitiveType = JSVAL_TYPE_STRING;
proto = script->global().getOrCreateStringPrototype(cx);
} else if (val.isNumber()) {
primitiveType = JSVAL_TYPE_DOUBLE;
proto = script->global().getOrCreateNumberPrototype(cx);
} else {
JS_ASSERT(val.isBoolean());
primitiveType = JSVAL_TYPE_BOOLEAN;
proto = script->global().getOrCreateBooleanPrototype(cx);
}
if (!proto)
return false;
// Instantiate this property, for use during Ion compilation.
RootedId id(cx, NameToId(name));
if (IsIonEnabled(cx))
types::EnsureTrackPropertyTypes(cx, stringProto, NameToId(name));
types::EnsureTrackPropertyTypes(cx, proto, id);
// For now, only look for properties directly set on String.prototype
RootedId propId(cx, NameToId(name));
RootedShape shape(cx, stringProto->nativeLookup(cx, propId));
// For now, only look for properties directly set on the prototype.
RootedShape shape(cx, proto->nativeLookup(cx, id));
if (!shape || !shape->hasSlot() || !shape->hasDefaultGetter())
return true;
bool isFixedSlot;
uint32_t offset;
GetFixedOrDynamicSlotOffset(stringProto, shape->slot(), &isFixedSlot, &offset);
GetFixedOrDynamicSlotOffset(proto, shape->slot(), &isFixedSlot, &offset);
ICStub *monitorStub = stub->fallbackMonitorStub()->firstMonitorStub();
IonSpew(IonSpew_BaselineIC, " Generating GetProp(String.ID from prototype) stub");
ICGetProp_String::Compiler compiler(cx, monitorStub, stringProto, isFixedSlot, offset);
IonSpew(IonSpew_BaselineIC, " Generating GetProp_Primitive stub");
ICGetProp_Primitive::Compiler compiler(cx, monitorStub, primitiveType, proto,
isFixedSlot, offset);
ICStub *newStub = compiler.getStub(compiler.getStubSpace(script));
if (!newStub)
return false;
@ -6267,8 +6279,8 @@ DoGetPropFallback(JSContext *cx, BaselineFrame *frame, ICGetProp_Fallback *stub,
if (attached)
return true;
if (val.isString()) {
if (!TryAttachStringGetPropStub(cx, script, pc, stub, name, val, res, &attached))
if (val.isString() || val.isNumber() || val.isBoolean()) {
if (!TryAttachPrimitiveGetPropStub(cx, script, pc, stub, name, val, res, &attached))
return false;
if (attached)
return true;
@ -6409,19 +6421,31 @@ ICGetProp_StringLength::Compiler::generateStubCode(MacroAssembler &masm)
}
bool
ICGetProp_String::Compiler::generateStubCode(MacroAssembler &masm)
ICGetProp_Primitive::Compiler::generateStubCode(MacroAssembler &masm)
{
Label failure;
masm.branchTestString(Assembler::NotEqual, R0, &failure);
switch (primitiveType_) {
case JSVAL_TYPE_STRING:
masm.branchTestString(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_ASSUME_UNREACHABLE("unexpected type");
}
GeneralRegisterSet regs(availableGeneralRegs(1));
Register holderReg = regs.takeAny();
Register scratchReg = regs.takeAny();
// Verify the shape of |String.prototype|
masm.movePtr(ImmGCPtr(stringPrototype_.get()), holderReg);
// Verify the shape of the prototype.
masm.movePtr(ImmGCPtr(prototype_.get()), holderReg);
Address shapeAddr(BaselineStubReg, ICGetProp_String::offsetOfStringProtoShape());
Address shapeAddr(BaselineStubReg, ICGetProp_Primitive::offsetOfProtoShape());
masm.loadPtr(Address(holderReg, JSObject::offsetOfShape()), scratchReg);
masm.branchPtr(Assembler::NotEqual, shapeAddr, scratchReg, &failure);
@ -9593,10 +9617,10 @@ ICGetIntrinsic_Constant::ICGetIntrinsic_Constant(IonCode *stubCode, HandleValue
ICGetIntrinsic_Constant::~ICGetIntrinsic_Constant()
{ }
ICGetProp_String::ICGetProp_String(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape stringProtoShape, uint32_t offset)
: ICMonitoredStub(GetProp_String, stubCode, firstMonitorStub),
stringProtoShape_(stringProtoShape),
ICGetProp_Primitive::ICGetProp_Primitive(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape protoShape, uint32_t offset)
: ICMonitoredStub(GetProp_Primitive, stubCode, firstMonitorStub),
protoShape_(protoShape),
offset_(offset)
{ }

View File

@ -362,7 +362,7 @@ class ICEntry
_(GetProp_Fallback) \
_(GetProp_ArrayLength) \
_(GetProp_TypedArrayLength) \
_(GetProp_String) \
_(GetProp_Primitive) \
_(GetProp_StringLength) \
_(GetProp_Native) \
_(GetProp_NativePrototype) \
@ -4105,44 +4105,45 @@ class ICGetProp_TypedArrayLength : public ICStub
};
};
// Stub for accessing a string's length.
class ICGetProp_String : 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 to check for.
HeapPtrShape stringProtoShape_;
// Shape of String.prototype/Number.prototype to check for.
HeapPtrShape protoShape_;
// Fixed or dynamic slot offset.
uint32_t offset_;
ICGetProp_String(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape stringProtoShape, uint32_t offset);
ICGetProp_Primitive(IonCode *stubCode, ICStub *firstMonitorStub,
HandleShape protoShape, uint32_t offset);
public:
static inline ICGetProp_String *New(ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape stringProtoShape, uint32_t offset)
static inline ICGetProp_Primitive *New(ICStubSpace *space, IonCode *code, ICStub *firstMonitorStub,
HandleShape protoShape, uint32_t offset)
{
if (!code)
return nullptr;
return space->allocate<ICGetProp_String>(code, firstMonitorStub, stringProtoShape, offset);
return space->allocate<ICGetProp_Primitive>(code, firstMonitorStub, protoShape, offset);
}
HeapPtrShape &stringProtoShape() {
return stringProtoShape_;
HeapPtrShape &protoShape() {
return protoShape_;
}
static size_t offsetOfStringProtoShape() {
return offsetof(ICGetProp_String, stringProtoShape_);
static size_t offsetOfProtoShape() {
return offsetof(ICGetProp_Primitive, protoShape_);
}
static size_t offsetOfOffset() {
return offsetof(ICGetProp_String, offset_);
return offsetof(ICGetProp_Primitive, offset_);
}
class Compiler : public ICStubCompiler {
ICStub *firstMonitorStub_;
RootedObject stringPrototype_;
JSValueType primitiveType_;
RootedObject prototype_;
bool isFixedSlot_;
uint32_t offset_;
@ -4150,23 +4151,27 @@ class ICGetProp_String : public ICMonitoredStub
protected:
virtual int32_t getKey() const {
return static_cast<int32_t>(kind) | (static_cast<int32_t>(isFixedSlot_) << 16);
static_assert(sizeof(JSValueType) == 1, "JSValueType should fit in one byte");
return static_cast<int32_t>(kind)
| (static_cast<int32_t>(isFixedSlot_) << 16)
| (static_cast<int32_t>(primitiveType_) << 24);
}
public:
Compiler(JSContext *cx, ICStub *firstMonitorStub, HandleObject stringPrototype,
bool isFixedSlot, uint32_t offset)
: ICStubCompiler(cx, ICStub::GetProp_String),
Compiler(JSContext *cx, ICStub *firstMonitorStub, JSValueType primitiveType,
HandleObject prototype, bool isFixedSlot, uint32_t offset)
: ICStubCompiler(cx, ICStub::GetProp_Primitive),
firstMonitorStub_(firstMonitorStub),
stringPrototype_(cx, stringPrototype),
primitiveType_(primitiveType),
prototype_(cx, prototype),
isFixedSlot_(isFixedSlot),
offset_(offset)
{}
ICStub *getStub(ICStubSpace *space) {
RootedShape stringProtoShape(cx, stringPrototype_->lastProperty());
return ICGetProp_String::New(space, getStubCode(), firstMonitorStub_,
stringProtoShape, offset_);
RootedShape protoShape(cx, prototype_->lastProperty());
return ICGetProp_Primitive::New(space, getStubCode(), firstMonitorStub_,
protoShape, offset_);
}
};
};

View File

@ -6051,10 +6051,6 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
*testString = false;
types::TemporaryTypeSet *types = obj->resultTypeSet();
if (!types && obj->type() != MIRType_String)
return false;
if (types && types->unknownObject())
return false;
@ -6079,6 +6075,9 @@ IonBuilder::testSingletonPropertyTypes(MDefinition *obj, JSObject *singleton, Pr
case MIRType_Object:
case MIRType_Value: {
if (!types)
return false;
if (types->hasType(types::Type::StringType())) {
key = JSProto_String;
*testString = true;