Bug 851109 - Add NAME IC for invoking getters on the global object. r=djvj

--HG--
extra : rebase_source : 4a4fa5be4a6ee0dc24f309ead094f90a420c6bab
This commit is contained in:
Jan de Mooij 2013-03-18 22:34:34 +01:00
parent 34b1b23ac6
commit d824ce1336
5 changed files with 81 additions and 31 deletions

View File

@ -4690,11 +4690,12 @@ CodeGenerator::visitCallsiteCloneIC(OutOfLineUpdateCache *ool, CallsiteCloneIC *
bool
CodeGenerator::visitGetNameCache(LGetNameCache *ins)
{
RegisterSet liveRegs = ins->safepoint()->liveRegs();
Register scopeChain = ToRegister(ins->scopeObj());
TypedOrValueRegister output(GetValueOutput(ins));
bool isTypeOf = ins->mir()->accessKind() != MGetNameCache::NAME;
NameIC cache(isTypeOf, scopeChain, ins->mir()->name(), output);
NameIC cache(liveRegs, isTypeOf, scopeChain, ins->mir()->name(), output);
return addCache(ins, allocateCache(cache));
}

View File

@ -513,20 +513,12 @@ struct GetNativePropertyStub
masm.popValue(tempVal);
}
// Reserve scratch register for prototype guards.
bool restoreScratch = false;
Register scratchReg = Register::FromCode(0); // Quell compiler warning.
// If we need a scratch register, use either an output register or the object
// register (and restore it afterwards). After this point, we cannot jump
// directly to |stubFailure| since we may still have to pop the object register.
Label prototypeFailures;
JS_ASSERT(output.hasValue());
scratchReg = output.valueReg().scratchReg();
Register scratchReg = output.valueReg().scratchReg();
// Note: this may clobber the object register if it's used as scratch.
if (obj != holder)
GeneratePrototypeGuards(cx, masm, obj, holder, object, scratchReg, &prototypeFailures);
GeneratePrototypeGuards(cx, masm, obj, holder, object, scratchReg, &stubFailure);
// Guard on the holder's shape.
Register holderReg = scratchReg;
@ -534,10 +526,7 @@ struct GetNativePropertyStub
masm.branchPtr(Assembler::NotEqual,
Address(holderReg, JSObject::offsetOfShape()),
ImmGCPtr(holder->lastProperty()),
&prototypeFailures);
if (restoreScratch)
masm.pop(scratchReg);
&stubFailure);
// Now we're good to go to invoke the native call.
@ -696,9 +685,6 @@ struct GetNativePropertyStub
masm.bind(&rejoin_);
// Exit jump.
masm.bind(&prototypeFailures);
if (restoreScratch)
masm.pop(scratchReg);
masm.bind(&stubFailure);
if (nonRepatchFailures)
masm.bind(nonRepatchFailures);
@ -1918,7 +1904,8 @@ BindNameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain)
}
bool
NameIC::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder, HandleShape shape)
NameIC::attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject holder,
HandleShape shape)
{
MacroAssembler masm(cx);
Label failures;
@ -1958,8 +1945,9 @@ NameIC::attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObj
}
static bool
IsCacheableName(JSContext *cx, HandleObject scopeChain, HandleObject obj, HandleObject holder,
HandleShape shape, jsbytecode *pc, const TypedOrValueRegister &output)
IsCacheableNameReadSlot(JSContext *cx, HandleObject scopeChain, HandleObject obj,
HandleObject holder, HandleShape shape, jsbytecode *pc,
const TypedOrValueRegister &output)
{
if (!shape)
return false;
@ -1996,13 +1984,51 @@ IsCacheableName(JSContext *cx, HandleObject scopeChain, HandleObject obj, Handle
return obj == obj2;
}
bool
NameIC::attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
HandleShape shape, const SafepointIndex *safepointIndex, void *returnAddr)
{
MacroAssembler masm(cx);
RepatchLabel failures;
// Need to set correct framePushed on the masm so that exit frame descriptors are
// properly constructed.
masm.setFramePushed(ion->frameSize());
GetNativePropertyStub getprop;
if (!getprop.generateCallGetter(cx, masm, obj, name(), holder, shape, liveRegs_,
scopeChainReg(), outputReg(), returnAddr, pc, &failures))
{
return false;
}
const char *attachKind = "name getter";
return linkAndAttachStub(cx, masm, ion, attachKind, getprop.rejoinOffset, &getprop.exitOffset,
&getprop.stubCodePatchOffset);
}
static bool
IsCacheableNameCallGetter(JSObject *scopeChain, JSObject *obj, JSObject *holder, RawShape shape)
{
if (obj != scopeChain)
return false;
if (!obj->isGlobal())
return false;
return IsCacheableGetPropCallNative(obj, holder, shape) ||
IsCacheableGetPropCallPropertyOp(obj, holder, shape);
}
bool
NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
MutableHandleValue vp)
{
AutoFlushCache afc ("GetNameCache");
IonScript *ion = GetTopIonJSScript(cx)->ionScript();
const SafepointIndex *safepointIndex;
void *returnAddr;
IonScript *ion = GetTopIonJSScript(cx, &safepointIndex, &returnAddr)->ionScript();
NameIC &cache = ion->getCache(cacheIndex).toName();
RootedPropertyName name(cx, cache.name());
@ -2017,11 +2043,14 @@ NameIC::update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain,
if (!LookupName(cx, name, scopeChain, &obj, &holder, &shape))
return false;
if (cache.canAttachStub() &&
IsCacheableName(cx, scopeChain, obj, holder, shape, pc, cache.outputReg()))
{
if (!cache.attach(cx, ion, scopeChain, obj, shape))
return false;
if (cache.canAttachStub()) {
if (IsCacheableNameReadSlot(cx, scopeChain, obj, holder, shape, pc, cache.outputReg())) {
if (!cache.attachReadSlot(cx, ion, scopeChain, obj, shape))
return false;
} else if (IsCacheableNameCallGetter(scopeChain, obj, holder, shape)) {
if (!cache.attachCallGetter(cx, ion, obj, holder, shape, safepointIndex, returnAddr))
return false;
}
}
if (cache.isTypeOf()) {

View File

@ -493,16 +493,21 @@ class BindNameIC : public IonCache
class NameIC : public IonCache
{
protected:
// Registers live after the cache, excluding output registers. The initial
// value of these registers must be preserved by the cache.
RegisterSet liveRegs_;
bool typeOf_;
Register scopeChain_;
PropertyName *name_;
TypedOrValueRegister output_;
public:
NameIC(bool typeOf,
NameIC(RegisterSet liveRegs, bool typeOf,
Register scopeChain, PropertyName *name,
TypedOrValueRegister output)
: typeOf_(typeOf),
: liveRegs_(liveRegs),
typeOf_(typeOf),
scopeChain_(scopeChain),
name_(name),
output_(output)
@ -524,8 +529,11 @@ class NameIC : public IonCache
return typeOf_;
}
bool attach(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject obj,
HandleShape shape);
bool attachReadSlot(JSContext *cx, IonScript *ion, HandleObject scopeChain, HandleObject obj,
HandleShape shape);
bool attachCallGetter(JSContext *cx, IonScript *ion, JSObject *obj, JSObject *holder,
HandleShape shape, const SafepointIndex *safepointIndex,
void *returnAddr);
static bool
update(JSContext *cx, size_t cacheIndex, HandleObject scopeChain, MutableHandleValue vp);

View File

@ -0,0 +1,6 @@
function f() {
for (var i=0; i<50; i++) {
assertEq(customNative, undefined);
}
}
f();

View File

@ -4780,6 +4780,12 @@ NewGlobalObject(JSContext *cx)
its_setter, JSPROP_READONLY))
return NULL;
if (!JS_DefineProperty(cx, glob, "customNative", UndefinedValue(),
(JSPropertyOp)its_get_customNative,
(JSStrictPropertyOp)its_set_customNative,
JSPROP_READONLY | JSPROP_NATIVE_ACCESSORS))
return NULL;
/* Initialize FakeDOMObject. */
static js::DOMCallbacks DOMcallbacks = {
InstanceClassHasProtoAtDepth