Bug 507683 part 1 - Trace native getters. r=gal.

--HG--
extra : rebase_source : f73754b7946e3d525b11f5973c61e22bd2f56dba
This commit is contained in:
Jason Orendorff 2009-08-25 15:01:29 -07:00
parent 8c36a6157c
commit c45d09492c
4 changed files with 77 additions and 59 deletions

View File

@ -334,17 +334,6 @@ js_HasNamedPropertyInt32(JSContext* cx, JSObject* obj, int32 index)
}
JS_DEFINE_CALLINFO_3(extern, BOOL, js_HasNamedPropertyInt32, CONTEXT, OBJECT, INT32, 0, 0)
jsval FASTCALL
js_CallGetter(JSContext* cx, JSObject* obj, JSScopeProperty* sprop)
{
JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
jsval v;
if (!js_GetSprop(cx, sprop, obj, &v))
return JSVAL_ERROR_COOKIE;
return v;
}
JS_DEFINE_CALLINFO_3(extern, JSVAL, js_CallGetter, CONTEXT, OBJECT, SCOPEPROP, 0, 0)
JSString* FASTCALL
js_TypeOfObject(JSContext* cx, JSObject* obj)
{

View File

@ -497,7 +497,6 @@ JS_DECLARE_CALLINFO(js_CallTree)
JS_DECLARE_CALLINFO(js_AddProperty)
JS_DECLARE_CALLINFO(js_HasNamedProperty)
JS_DECLARE_CALLINFO(js_HasNamedPropertyInt32)
JS_DECLARE_CALLINFO(js_CallGetter)
JS_DECLARE_CALLINFO(js_TypeOfObject)
JS_DECLARE_CALLINFO(js_TypeOfBoolean)
JS_DECLARE_CALLINFO(js_BooleanOrUndefinedToNumber)

View File

@ -5707,6 +5707,8 @@ LeaveTree(InterpState& state, VMSideExit* lr)
JSFrameRegs* regs = cx->fp->regs;
JSOp op = (JSOp) *regs->pc;
JS_ASSERT(op == JSOP_CALL || op == JSOP_APPLY || op == JSOP_NEW ||
op == JSOP_GETPROP || op == JSOP_GETTHISPROP || op == JSOP_GETARGPROP ||
op == JSOP_GETLOCALPROP || op == JSOP_LENGTH ||
op == JSOP_GETELEM || op == JSOP_CALLELEM ||
op == JSOP_SETPROP || op == JSOP_SETNAME ||
op == JSOP_SETELEM || op == JSOP_INITELEM ||
@ -7427,7 +7429,7 @@ TraceRecorder::incProp(jsint incr, bool pre)
uint32 slot;
LIns* v_ins;
CHECK_STATUS(prop(obj, obj_ins, slot, v_ins));
CHECK_STATUS(prop(obj, obj_ins, &slot, &v_ins, NULL));
if (slot == SPROP_INVALID_SLOT)
ABORT_TRACE("incProp on invalid slot");
@ -10110,6 +10112,45 @@ TraceRecorder::getPropertyByIndex(LIns* obj_ins, LIns* index_ins, jsval* outp)
return JSRS_CONTINUE;
}
static JSBool FASTCALL
GetPropertyById(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
{
js_LeaveTraceIfGlobalObject(cx, obj);
if (!obj->getProperty(cx, id, vp)) {
js_SetBuiltinError(cx);
return JS_FALSE;
}
return cx->interpState->builtinStatus == 0;
}
JS_DEFINE_CALLINFO_4(static, BOOL_FAIL, GetPropertyById, CONTEXT, OBJECT, JSVAL, JSVALPTR, 0, 0)
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::getPropertyById(LIns* obj_ins, jsval* outp)
{
// Find the atom.
JSAtom* atom;
jsbytecode* pc = cx->fp->regs->pc;
const JSCodeSpec& cs = js_CodeSpec[*pc];
if (*pc == JSOP_LENGTH) {
atom = cx->runtime->atomState.lengthAtom;
} else if (JOF_TYPE(cs.format) == JOF_ATOM) {
atom = atoms[GET_INDEX(pc)];
} else {
JS_ASSERT(JOF_TYPE(cs.format) == JOF_SLOTATOM);
atom = atoms[GET_INDEX(pc + SLOTNO_LEN)];
}
// Call GetPropertyById. See note in getPropertyByName about vp.
enterDeepBailCall();
jsid id = ATOM_TO_JSID(atom);
LIns* vp_ins = addName(lir->insAlloc(sizeof(jsval)), "vp");
LIns* args[] = {vp_ins, INS_CONSTWORD(id), obj_ins, cx_ins};
LIns* ok_ins = lir->insCall(&GetPropertyById_ci, args);
finishGetProp(obj_ins, vp_ins, ok_ins, outp);
leaveDeepBailCall();
return JSRS_CONTINUE;
}
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::record_JSOP_GETELEM()
{
@ -10962,9 +11003,19 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
return JSRS_CONTINUE;
}
/*
* Get a property. The current opcode has JOF_ATOM.
*
* There are two modes. The caller must pass nonnull pointers for either outp
* or both slotp and v_insp. In the latter case, we require a plain old
* property with a slot; if the property turns out to be anything else, abort
* tracing (rather than emit a call to a native getter or GetAnyProperty).
*/
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp, jsval *outp)
{
JS_ASSERT((slotp && v_insp && !outp) || (!slotp && !v_insp && outp));
/*
* Can't specialize to assert obj != global, must guard to avoid aliasing
* stale homes of stacked global variables.
@ -10982,6 +11033,9 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
/* Check for non-existent property reference, which results in undefined. */
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
if (PCVAL_IS_NULL(pcval)) {
if (slotp)
ABORT_TRACE("property not found");
/*
* We could specialize to guard on just JSClass.getProperty, but a mere
* class guard is simpler and slightly faster.
@ -11013,15 +11067,14 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
ABORT_TRACE("non-native object involved in undefined property access");
} while (guardHasPrototype(obj, obj_ins, &obj, &obj_ins, exit));
v_ins = INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID));
slot = SPROP_INVALID_SLOT;
set(outp, INS_CONST(JSVAL_TO_SPECIAL(JSVAL_VOID)), true);
return JSRS_CONTINUE;
}
uint32 setflags = (cs.format & (JOF_INCDEC | JOF_FOR));
JS_ASSERT(!(cs.format & JOF_SET));
/* Don't trace getter or setter calls, our caller wants a direct slot. */
uint32 slot;
if (PCVAL_IS_SPROP(pcval)) {
JSScopeProperty* sprop = PCVAL_TO_SPROP(pcval);
@ -11029,37 +11082,12 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
ABORT_TRACE("non-stub setter");
if (setflags && (sprop->attrs & JSPROP_READONLY))
ABORT_TRACE("writing to a readonly property");
if (setflags != JOF_SET && !SPROP_HAS_STUB_GETTER(sprop)) {
// FIXME 450335: generalize this away from regexp built-in getters.
if (setflags == 0 &&
sprop->getter == js_RegExpClass.getProperty &&
sprop->shortid < 0) {
if (sprop->shortid == REGEXP_LAST_INDEX)
ABORT_TRACE("can't trace RegExp.lastIndex yet");
LIns* args[] = { INS_CONSTSPROP(sprop), obj_ins, cx_ins };
v_ins = lir->insCall(&js_CallGetter_ci, args);
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
/*
* BIG FAT WARNING: This snapshot cannot be a BRANCH_EXIT, since
* the value to the top of the stack is not the value we unbox.
*/
v_ins =
unbox_jsval((sprop->shortid == REGEXP_SOURCE) ? JSVAL_STRING : JSVAL_SPECIAL,
v_ins,
snapshot(MISMATCH_EXIT));
return JSRS_CONTINUE;
}
if (setflags == 0 &&
sprop->getter == js_StringClass.getProperty &&
sprop->id == ATOM_KEY(cx->runtime->atomState.lengthAtom)) {
if (!guardClass(obj, obj_ins, &js_StringClass, snapshot(MISMATCH_EXIT)))
ABORT_TRACE("can't trace String.length on non-String objects");
LIns* str_ins = stobj_get_private(obj_ins, JSVAL_TAGMASK);
v_ins = lir->ins1(LIR_i2f, getStringLength(str_ins));
return JSRS_CONTINUE;
}
ABORT_TRACE("non-stub getter");
if (!SPROP_HAS_STUB_GETTER(sprop)) {
if (slotp)
ABORT_TRACE("can't trace non-stub getter for this opcode");
if (sprop->attrs & JSPROP_GETTER)
ABORT_TRACE("script getter");
return getPropertyById(obj_ins, outp);
}
if (!SPROP_HAS_VALID_SLOT(sprop, OBJ_SCOPE(obj2)))
ABORT_TRACE("no valid slot");
@ -11086,10 +11114,16 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32& slot, LIns*& v_ins)
}
LIns* dslots_ins = NULL;
v_ins = unbox_jsval(STOBJ_GET_SLOT(obj, slot),
stobj_get_slot(obj_ins, slot, dslots_ins),
snapshot(BRANCH_EXIT));
LIns* v_ins = unbox_jsval(STOBJ_GET_SLOT(obj, slot),
stobj_get_slot(obj_ins, slot, dslots_ins),
snapshot(BRANCH_EXIT));
if (slotp) {
*slotp = slot;
*v_insp = v_ins;
}
if (outp)
set(outp, v_ins, true);
return JSRS_CONTINUE;
}
@ -11205,14 +11239,9 @@ TraceRecorder::denseArrayElement(jsval& oval, jsval& ival, jsval*& vp, LIns*& v_
JS_REQUIRES_STACK JSRecordingStatus
TraceRecorder::getProp(JSObject* obj, LIns* obj_ins)
{
uint32 slot;
LIns* v_ins;
CHECK_STATUS(prop(obj, obj_ins, slot, v_ins));
const JSCodeSpec& cs = js_CodeSpec[*cx->fp->regs->pc];
JS_ASSERT(cs.ndefs == 1);
stack(-cs.nuses, v_ins);
return JSRS_CONTINUE;
return prop(obj, obj_ins, NULL, NULL, &stackval(-cs.nuses));
}
JS_REQUIRES_STACK JSRecordingStatus

View File

@ -857,8 +857,8 @@ class TraceRecorder : public avmplus::GCObject {
nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
JS_REQUIRES_STACK JSRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32& slot,
nanojit::LIns*& v_ins);
JS_REQUIRES_STACK JSRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins, uint32 *slotp,
nanojit::LIns** v_insp, jsval* outp);
JS_REQUIRES_STACK JSRecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
nanojit::LIns*& v_ins,
nanojit::LIns*& addr_ins);
@ -876,6 +876,7 @@ class TraceRecorder : public avmplus::GCObject {
jsval* outp);
JS_REQUIRES_STACK JSRecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins,
nanojit::LIns* index_ins, jsval* outp);
JS_REQUIRES_STACK JSRecordingStatus getPropertyById(nanojit::LIns* obj_ins, jsval* outp);
JS_REQUIRES_STACK JSRecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
JSScopeProperty* sprop,