Conservatively track modifications along the prototype chain of arrays (469625, r=jorendorff).

This commit is contained in:
brendan@mozilla.org 2009-01-28 16:16:20 -08:00
Родитель 1a7c5ba3c1
Коммит d4a74db4aa
4 изменённых файлов: 35 добавлений и 8 удалений

Просмотреть файл

@ -833,8 +833,6 @@ array_defineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
if (!isIndex || attrs != JSPROP_ENUMERATE) {
if (!ENSURE_SLOW_ARRAY(cx, obj))
return JS_FALSE;
if (isIndex && STOBJ_IS_DELEGATE(obj))
cx->runtime->anyArrayProtoHasElement = JS_TRUE;
return js_DefineProperty(cx, obj, id, value, getter, setter, attrs, propp);
}

Просмотреть файл

@ -1705,7 +1705,6 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, JSCodeGenerator *cg)
return JS_FALSE; \
JS_END_MACRO
static JSBool
EmitAtomOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
{
@ -2339,6 +2338,9 @@ EmitXMLName(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
}
#endif
static JSBool
EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg);
static JSBool
EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
JSBool callContext)
@ -2346,6 +2348,14 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
JSParseNode *pn2, *pndot, *pnup, *pndown;
ptrdiff_t top;
/*
* 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.
*/
if (pn->pn_atom == cx->runtime->atomState.protoAtom)
return EmitElemOp(cx, pn, callContext ? JSOP_CALLELEM : JSOP_GETELEM, cg);
pn2 = pn->pn_expr;
if (callContext) {
JS_ASSERT(pn->pn_type == TOK_DOT);
@ -5338,6 +5348,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
if (pn2->pn_atom == cx->runtime->atomState.lengthAtom) {
if (js_Emit1(cx, cg, JSOP_LENGTH) < 0)
return JS_FALSE;
} else if (pn2->pn_atom == cx->runtime->atomState.protoAtom) {
if (!EmitIndexOp(cx, JSOP_QNAMEPART, atomIndex, cg))
return JS_FALSE;
if (js_Emit1(cx, cg, JSOP_GETELEM) < 0)
return JS_FALSE;
} else {
EMIT_INDEX_OP(JSOP_GETPROP, atomIndex);
}

Просмотреть файл

@ -326,10 +326,20 @@ js_SetProtoOrParent(JSContext *cx, JSObject *obj, uint32 slot, JSObject *pobj)
return JS_FALSE;
}
// Maintain the "any Array prototype has indexed properties hazard" flag.
/*
* Maintain the "any Array prototype has indexed properties hazard" flag by
* conservatively setting it. We simply don't know what pobj has in the way
* of indexed properties, either directly or along its prototype chain, and
* we won't expend effort here to find out. We do know that if obj is not
* an array or a prototype (delegate), then we're ok. And, of course, pobj
* must be non-null.
*
* This pessimistic approach could be improved, but setting __proto__ is
* quite rare and arguably deserving of deoptimization.
*/
if (slot == JSSLOT_PROTO &&
OBJ_IS_ARRAY(cx, pobj) &&
pobj->fslots[JSSLOT_ARRAY_LENGTH] != 0) {
pobj &&
(OBJ_IS_ARRAY(cx, obj) || OBJ_IS_DELEGATE(cx, obj))) {
rt->anyArrayProtoHasElement = JS_TRUE;
}
return JS_TRUE;
@ -3388,6 +3398,9 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
* nominal initial value of a slot-full property, while GC safety wants that
* value to be stored before the call-out through the hook. Optimize to do
* both while saving cycles for classes that stub their addProperty hook.
*
* As in js_SetProtoOrParent (see above), we maintain the "any Array prototype
* has indexed properties hazard" flag by conservatively setting it.
*/
#define ADD_PROPERTY_HELPER(cx,clasp,obj,scope,sprop,vp,cleanup) \
JS_BEGIN_MACRO \
@ -3401,6 +3414,8 @@ js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *(vp)); \
} \
} \
if (STOBJ_IS_DELEGATE(obj) && JSID_IS_INT(sprop->id)) \
cx->runtime->anyArrayProtoHasElement = JS_TRUE; \
JS_END_MACRO
JSBool

Просмотреть файл

@ -8101,7 +8101,6 @@ TraceRecorder::record_JSOP_GOTOX()
JS_REQUIRES_STACK bool
TraceRecorder::record_JSOP_IFEQX()
{
trackCfgMerges(cx->fp->regs->pc);
return record_JSOP_IFEQ();
}
@ -8888,7 +8887,7 @@ TraceRecorder::record_JSOP_LENGTH()
jsval& l = stackval(-1);
if (JSVAL_IS_PRIMITIVE(l)) {
if (!JSVAL_IS_STRING(l))
ABORT_TRACE("non-string primitives unsupported");
ABORT_TRACE("non-string primitive JSOP_LENGTH unsupported");
LIns* str_ins = get(&l);
LIns* len_ins = lir->insLoad(LIR_ldp, str_ins, (int)offsetof(JSString, length));