Bug 777630 - add missing prop ic (r=bhackett)

This commit is contained in:
Luke Wagner 2012-07-30 11:36:23 -07:00
parent a563f124d1
commit f8cc7bf5e0
3 changed files with 113 additions and 18 deletions

View File

@ -0,0 +1,49 @@
function isnan(n) { return n !== n }
function f(x) {
var sum = 0;
for (var i = 0; i < 100; ++i)
sum += x.x;
return sum;
}
var o = {};
assertEq(isnan(f(o)), true);
o.x = 1;
assertEq(f(o), 100);
var o = {a:1, b:2};
assertEq(isnan(f(o)), true);
o.x = 2;
assertEq(f(o), 200);
function g(x) {
var sum = 0;
for (var i = 0; i < 100; ++i)
sum += x.x;
return sum;
}
var o = {c:1, x:1};
assertEq(g(o), 100);
var o = {};
assertEq(isnan(g(o)), true);
function h(x) {
var sum = 0;
for (var i = 0; i < 100; ++i)
sum += x.x;
return sum;
}
var proto1 = {};
var proto2 = Object.create(proto1);
var o = Object.create(proto2);
assertEq(isnan(f(o)), true);
assertEq(isnan(g(o)), true);
assertEq(isnan(h(o)), true);
proto2.x = 2;
assertEq(f(o), 200);
assertEq(g(o), 200);
assertEq(h(o), 200);
var o = {}
assertEq(isnan(f(o)), true);
assertEq(isnan(g(o)), true);
assertEq(isnan(h(o)), true);

View File

@ -650,8 +650,26 @@ struct GetPropHelper {
if (monitor.recompiled())
return Lookup_Uncacheable;
if (!prop)
return ic.disable(f, "lookup failed");
if (!prop) {
/*
* Just because we didn't find the property on the object doesn't
* mean it won't magically appear through various engine hacks:
*/
if (obj->getClass()->getProperty && obj->getClass()->getProperty != JS_PropertyStub)
return Lookup_Uncacheable;
#if JS_HAS_NO_SUCH_METHOD
/*
* The __noSuchMethod__ hook may substitute in a valid method.
* Since, if o.m is missing, o.m() will probably be an error,
* just mark all missing callprops as uncacheable.
*/
if (*f.pc() == JSOP_CALLPROP)
return Lookup_Uncacheable;
#endif
return Lookup_NoProperty;
}
if (!IsCacheableProtoChain(obj, holder))
return ic.disable(f, "non-native holder");
shape = prop;
@ -1215,22 +1233,39 @@ class GetPropCompiler : public PICStubCompiler
return error();
}
// Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
holderReg = pic.shapeReg;
masm.move(ImmPtr(holder), holderReg);
pic.shapeRegHasBaseShape = false;
if (holder) {
// Bake in the holder identity. Careful not to clobber |objReg|, since we can't remat it.
holderReg = pic.shapeReg;
masm.move(ImmPtr(holder), holderReg);
pic.shapeRegHasBaseShape = false;
// Guard on the holder's shape.
Jump j = masm.guardShape(holderReg, holder);
if (!shapeMismatches.append(j))
return error();
// Guard on the holder's shape.
Jump j = masm.guardShape(holderReg, holder);
if (!shapeMismatches.append(j))
return error();
} else {
// Like when we add a property, we need to guard on the shape of
// everything on the prototype chain.
JSObject *proto = obj->getProto();
RegisterID lastReg = pic.objReg;
while (proto) {
masm.loadPtr(Address(lastReg, JSObject::offsetOfType()), pic.shapeReg);
masm.loadPtr(Address(pic.shapeReg, offsetof(types::TypeObject, proto)), pic.shapeReg);
Jump protoGuard = masm.guardShape(pic.shapeReg, proto);
if (!shapeMismatches.append(protoGuard))
return error();
proto = proto->getProto();
lastReg = pic.shapeReg;
}
}
pic.secondShapeGuard = masm.distanceOf(masm.label()) - masm.distanceOf(start);
} else {
pic.secondShapeGuard = 0;
}
if (!shape->hasDefaultGetter()) {
if (shape && !shape->hasDefaultGetter()) {
if (shape->hasGetterValue()) {
generateNativeGetterStub(masm, shape, start, shapeMismatches);
} else {
@ -1244,10 +1279,19 @@ class GetPropCompiler : public PICStubCompiler
return Lookup_Cacheable;
}
/* Load the value out of the object. */
masm.loadObjProp(holder, holderReg, shape, pic.shapeReg, pic.objReg);
Jump done = masm.jump();
/*
* A non-null 'shape' tells us where to find the property value in the
* holder object. A null shape means that the above checks guard the
* absence of the property, so the get-prop returns 'undefined'. A
* missing property guarantees a type barrier below so we don't have to
* check type information.
*/
if (shape)
masm.loadObjProp(holder, holderReg, shape, pic.shapeReg, pic.objReg);
else
masm.loadValueAsComponents(UndefinedValue(), pic.shapeReg, pic.objReg);
Jump done = masm.jump();
pic.updatePCCounters(f, masm);
PICLinker buffer(masm, pic);
@ -1319,12 +1363,13 @@ class GetPropCompiler : public PICStubCompiler
GetPropHelper<GetPropCompiler> getprop(cx, obj, name, *this, f);
LookupStatus status = getprop.lookupAndTest();
if (status != Lookup_Cacheable)
if (status != Lookup_Cacheable && status != Lookup_NoProperty)
return status;
if (hadGC())
return Lookup_Uncacheable;
if (obj == getprop.holder &&
if (status == Lookup_Cacheable &&
obj == getprop.holder &&
getprop.shape->hasDefaultGetter() &&
!pic.inlinePathPatched) {
return patchInline(getprop.holder, getprop.shape);
@ -2457,7 +2502,7 @@ ic::GetElement(VMFrame &f, ic::GetElementIC *ic)
f.regs.sp[-2] = MagicValue(JS_GENERIC_MAGIC);
#endif
LookupStatus status = ic->update(f, obj, idval_, id, res);
if (status != Lookup_Uncacheable) {
if (status != Lookup_Uncacheable && status != Lookup_NoProperty) {
if (status == Lookup_Error)
THROW();

View File

@ -31,7 +31,8 @@ static const uint32_t MAX_GETELEM_IC_STUBS = 17;
enum LookupStatus {
Lookup_Error = 0,
Lookup_Uncacheable,
Lookup_Cacheable
Lookup_Cacheable,
Lookup_NoProperty
};
struct BaseIC : public MacroAssemblerTypedefs {