Remove emitter special casing for __proto__, bug 717249. r=waldo

This commit is contained in:
Brian Hackett 2012-01-20 07:14:55 -08:00
parent 1727869633
commit a9a3610803
6 changed files with 25 additions and 85 deletions

View File

@ -1946,32 +1946,6 @@ EmitElemOpBase(JSContext *cx, BytecodeEmitter *bce, JSOp op)
return true;
}
static bool
EmitSpecialPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce)
{
/*
* Special case for obj.__proto__ to deoptimize away from fast paths in the
* interpreter and trace recorder, which skip dense array instances by
* going up to Array.prototype before looking up the property name.
*/
jsatomid index;
if (!bce->makeAtomIndex(pn->pn_atom, &index))
return false;
if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, bce))
return false;
if (op == JSOP_CALLELEM && Emit1(cx, bce, JSOP_DUP) < 0)
return false;
if (!EmitElemOpBase(cx, bce, op))
return false;
if (op == JSOP_CALLELEM && Emit1(cx, bce, JSOP_SWAP) < 0)
return false;
return true;
}
static bool
EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce,
JSBool callContext, JSOp *psuffix = NULL)
@ -1982,14 +1956,6 @@ EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce,
JS_ASSERT(pn->isArity(PN_NAME));
pn2 = pn->maybeExpr();
/* Special case deoptimization for __proto__. */
if ((op == JSOP_GETPROP || op == JSOP_CALLPROP) &&
pn->pn_atom == cx->runtime->atomState.protoAtom) {
if (pn2 && !EmitTree(cx, bce, pn2))
return false;
return EmitSpecialPropOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, bce);
}
if (callContext) {
JS_ASSERT(pn->isKind(PNK_DOT));
JS_ASSERT(op == JSOP_GETPROP);
@ -2031,13 +1997,8 @@ EmitPropOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce,
if (NewSrcNote2(cx, bce, SRC_PCBASE, bce->offset() - pndown->pn_offset) < 0)
return false;
/* Special case deoptimization on __proto__, as above. */
if (pndot->isArity(PN_NAME) && pndot->pn_atom == cx->runtime->atomState.protoAtom) {
if (!EmitSpecialPropOp(cx, pndot, JSOP_GETELEM, bce))
if (!EmitAtomOp(cx, pndot, pndot->getOp(), bce))
return false;
} else if (!EmitAtomOp(cx, pndot, pndot->getOp(), bce)) {
return false;
}
/* Reverse the pn_expr link again. */
pnup = pndot->pn_expr;
@ -3778,19 +3739,13 @@ EmitAssignment(JSContext *cx, BytecodeEmitter *bce, ParseNode *lhs, JSOp op, Par
EMIT_UINT16_IMM_OP(lhs->isOp(JSOP_SETARG) ? JSOP_GETARG : JSOP_GETLOCAL, atomIndex);
}
break;
case PNK_DOT:
case PNK_DOT: {
if (Emit1(cx, bce, JSOP_DUP) < 0)
return false;
if (lhs->pn_atom == cx->runtime->atomState.protoAtom) {
if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, bce))
return false;
if (!EmitElemOpBase(cx, bce, JSOP_GETELEM))
return false;
} else {
bool isLength = (lhs->pn_atom == cx->runtime->atomState.lengthAtom);
EMIT_INDEX_OP(isLength ? JSOP_LENGTH : JSOP_GETPROP, atomIndex);
}
break;
}
case PNK_LB:
case PNK_LP:
#if JS_HAS_XML_SUPPORT

View File

@ -0,0 +1,2 @@
// |jit-test| error: TypeError
[].__proto__();

View File

@ -74,28 +74,6 @@ js_IdIsIndex(jsid id, jsuint *indexp)
return js::StringIsArrayIndex(JSID_TO_ATOM(id), indexp);
}
/*
* Dense arrays are not native -- aobj->isNative() for a dense array aobj
* results in false, meaning aobj->map does not point to a js::Shape.
*
* But Array methods are called via aobj.sort(), e.g., and the interpreter and
* the trace recorder must consult the property cache in order to perform well.
* The cache works only for native objects.
*
* Therefore the interpreter (js_Interpret in JSOP_GETPROP and JSOP_CALLPROP)
* and js_GetPropertyHelper use this inline function to skip up one link in the
* prototype chain when obj is a dense array, in order to find a native object
* (to wit, Array.prototype) in which to probe for cached methods.
*
* Note that setting aobj.__proto__ for a dense array aobj turns aobj into a
* slow array, avoiding the neede to skip.
*
* Callers of js_GetProtoIfDenseArray must take care to use the original object
* (obj) for the |this| value of a getter, setter, or method call (bug 476447).
*/
inline JSObject *
js_GetProtoIfDenseArray(JSObject *obj);
extern JSObject *
js_InitArrayClass(JSContext *cx, JSObject *obj);

View File

@ -5359,16 +5359,15 @@ static JS_ALWAYS_INLINE JSBool
js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id,
uint32_t getHow, Value *vp)
{
JSObject *aobj, *obj2;
JSObject *obj2;
JSProperty *prop;
const Shape *shape;
/* Convert string indices to integers if appropriate. */
id = js_CheckForStringIndex(id);
aobj = js_GetProtoIfDenseArray(obj);
/* This call site is hot -- use the always-inlined variant of LookupPropertyWithFlags(). */
if (!LookupPropertyWithFlagsInline(cx, aobj, id, cx->resolveFlags, &obj2, &prop))
if (!LookupPropertyWithFlagsInline(cx, obj, id, cx->resolveFlags, &obj2, &prop))
return false;
if (!prop) {
@ -5442,7 +5441,7 @@ js_GetPropertyHelperInline(JSContext *cx, JSObject *obj, JSObject *receiver, jsi
shape = (Shape *) prop;
if (getHow & JSGET_CACHE_RESULT)
JS_PROPERTY_CACHE(cx).fill(cx, aobj, 0, obj2, shape);
JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, obj2, shape);
/* This call site is hot -- use the always-inlined variant of js_NativeGet(). */
if (!js_NativeGetInline(cx, receiver, obj, obj2, shape, getHow, vp))

View File

@ -1995,12 +1995,6 @@ js_InitClass(JSContext *cx, js::HandleObject obj, JSObject *parent_proto,
JSObject **ctorp = NULL,
js::gc::AllocKind ctorKind = JSFunction::FinalizeKind);
inline JSObject *
js_GetProtoIfDenseArray(JSObject *obj)
{
return obj->isDenseArray() ? obj->getProto() : obj;
}
/*
* js_PurgeScopeChain does nothing if obj is not itself a prototype or parent
* scope, else it reshapes the scope and prototype chains it links. It calls

View File

@ -761,7 +761,19 @@ struct GetPropHelper {
}
LookupStatus lookup() {
JSObject *aobj = js_GetProtoIfDenseArray(obj);
/*
* Skip to the prototype of dense arrays, which are non-native objects
* and otherwise uncacheable. This is not valid to do for indexed
* properties (which will not be a PropertyName), nor for __proto__,
* which needs to be filtered here.
*/
JSObject *aobj = obj;
if (obj->isDenseArray()) {
if (name == cx->runtime->atomState.protoAtom)
return ic.disable(cx, "__proto__");
aobj = obj->getProto();
}
if (!aobj->isNative())
return ic.disable(f, "non-native");
@ -2604,8 +2616,8 @@ GetElementIC::update(VMFrame &f, JSObject *obj, const Value &v, jsid id, Value *
/*
* Only treat this as a GETPROP for non-numeric string identifiers. The
* GETPROP IC assumes the id has already gone through filtering for string
* indexes in the emitter, i.e. js_GetProtoIfDenseArray is only valid to
* use when looking up non-integer identifiers.
* indexes in the emitter, i.e. skipping to the prototype of dense arrays
* is only valid to do when looking up non-integer identifiers.
*/
if (v.isString() && js_CheckForStringIndex(id) == id)
return attachGetProp(f, obj, v, JSID_TO_ATOM(id)->asPropertyName(), vp);