зеркало из https://github.com/mozilla/pjs.git
Bug 495330: trace JSOP_INCNAME and related ops for closures, r=gal
This commit is contained in:
Родитель
6df3475470
Коммит
cd07287c5b
|
@ -6755,15 +6755,12 @@ JS_DEFINE_CALLINFO_6(extern, UINT32, GetClosureArg, CONTEXT, OBJECT, UINT32,
|
|||
* generate LIR to access the given property. Return JSRS_CONTINUE on success,
|
||||
* otherwise abort and return JSRS_STOP. There are 3 outparams:
|
||||
*
|
||||
* vp the address of the current property value
|
||||
* ins LIR instruction representing the property value on trace
|
||||
* tracked true iff the property value is tracked on this trace. If true,
|
||||
* then the tracked value can be modified using the tracker set
|
||||
* functions. If false, then the value comes from a call to a
|
||||
* builtin to access an upvar, and can't be modified directly.
|
||||
* vp the address of the current property value
|
||||
* ins LIR instruction representing the property value on trace
|
||||
* NameResult describes how to look up name; see comment for NameResult in jstracer.h
|
||||
*/
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& tracked)
|
||||
TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, NameResult& nr)
|
||||
{
|
||||
JS_ASSERT(obj != globalObj);
|
||||
|
||||
|
@ -6793,7 +6790,7 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
vp = &STOBJ_GET_SLOT(obj, sprop->slot);
|
||||
ins = get(vp);
|
||||
OBJ_DROP_PROPERTY(cx, obj2, prop);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -6830,7 +6827,7 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
// At this point we are guaranteed to be looking at an active call object
|
||||
// whose properties are stored in the corresponding JSStackFrame.
|
||||
ins = get(vp);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
} else {
|
||||
// Compute number of scope chain links to result.
|
||||
|
@ -6865,7 +6862,10 @@ TraceRecorder::scopeChainProp(JSObject* obj, jsval*& vp, LIns*& ins, bool& track
|
|||
"guard(type-stable name access)"),
|
||||
BRANCH_EXIT);
|
||||
ins = stackLoad(outp, type);
|
||||
tracked = false;
|
||||
nr.tracked = false;
|
||||
nr.obj = obj;
|
||||
nr.scopeIndex = scopeIndex;
|
||||
nr.sprop = sprop;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
@ -9539,13 +9539,20 @@ TraceRecorder::incName(jsint incr, bool pre)
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
if (!tracked)
|
||||
ABORT_TRACE("incName on non-tracked value not supported");
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
CHECK_STATUS(inc(*vp, v_ins, incr, pre));
|
||||
set(vp, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
if (nr.tracked) {
|
||||
set(vp, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
if (OBJ_GET_CLASS(cx, nr.obj) != &js_CallClass)
|
||||
ABORT_TRACE("incName on unsupported object class");
|
||||
LIns* callobj_ins = get(&cx->fp->argv[-2]);
|
||||
for (jsint i = 0; i < nr.scopeIndex; ++i)
|
||||
callobj_ins = stobj_get_parent(callobj_ins);
|
||||
return setCallProp(callobj_ins, nr.sprop, v_ins, *vp);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
|
@ -9693,26 +9700,8 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop
|
|||
|
||||
// Fast path for CallClass. This is about 20% faster than the general case.
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_CallClass) {
|
||||
const CallInfo* ci = NULL;
|
||||
if (sprop->setter == SetCallArg)
|
||||
ci = &js_SetCallArg_ci;
|
||||
else if (sprop->setter == SetCallVar)
|
||||
ci = &js_SetCallVar_ci;
|
||||
else
|
||||
ABORT_TRACE("can't trace special CallClass setter");
|
||||
|
||||
v_ins = get(&v);
|
||||
LIns* v_boxed_ins = v_ins;
|
||||
box_jsval(v, v_boxed_ins);
|
||||
LIns* args[] = {
|
||||
v_boxed_ins,
|
||||
INS_CONST(SPROP_USERID(sprop)),
|
||||
obj_ins,
|
||||
cx_ins
|
||||
};
|
||||
LIns* call_ins = lir->insCall(ci, args);
|
||||
guard(false, addName(lir->ins_eq0(call_ins), "guard(set upvar)"), STATUS_EXIT);
|
||||
return JSRS_CONTINUE;
|
||||
return setCallProp(obj_ins, sprop, v_ins, v);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -9757,6 +9746,29 @@ TraceRecorder::setProp(jsval &l, JSPropCacheEntry* entry, JSScopeProperty* sprop
|
|||
return nativeSet(obj, obj_ins, sprop, v, v_ins);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::setCallProp(LIns *callobj_ins, JSScopeProperty *sprop, LIns *v_ins, jsval v)
|
||||
{
|
||||
const CallInfo* ci = NULL;
|
||||
if (sprop->setter == SetCallArg)
|
||||
ci = &js_SetCallArg_ci;
|
||||
else if (sprop->setter == SetCallVar)
|
||||
ci = &js_SetCallVar_ci;
|
||||
else
|
||||
ABORT_TRACE("can't trace special CallClass setter");
|
||||
|
||||
box_jsval(v, v_ins);
|
||||
LIns* args[] = {
|
||||
v_ins,
|
||||
INS_CONST(SPROP_USERID(sprop)),
|
||||
callobj_ins,
|
||||
cx_ins
|
||||
};
|
||||
LIns* call_ins = lir->insCall(ci, args);
|
||||
guard(false, addName(lir->ins_eq0(call_ins), "guard(set upvar)"), STATUS_EXIT);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::record_SetPropHit(JSPropCacheEntry* entry, JSScopeProperty* sprop)
|
||||
{
|
||||
|
@ -10138,8 +10150,8 @@ TraceRecorder::record_JSOP_CALLNAME()
|
|||
if (obj != globalObj) {
|
||||
jsval* vp;
|
||||
LIns* ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(scopeChainProp(obj, vp, ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(scopeChainProp(obj, vp, ins, nr));
|
||||
stack(0, ins);
|
||||
stack(1, INS_CONSTPTR(globalObj));
|
||||
return JSRS_CONTINUE;
|
||||
|
@ -10606,11 +10618,11 @@ TraceRecorder::record_NativeCallComplete()
|
|||
}
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus
|
||||
TraceRecorder::name(jsval*& vp, LIns*& ins, bool& tracked)
|
||||
TraceRecorder::name(jsval*& vp, LIns*& ins, NameResult& nr)
|
||||
{
|
||||
JSObject* obj = cx->fp->scopeChain;
|
||||
if (obj != globalObj)
|
||||
return scopeChainProp(obj, vp, ins, tracked);
|
||||
return scopeChainProp(obj, vp, ins, nr);
|
||||
|
||||
/* Can't use prop here, because we don't want unboxing from global slots. */
|
||||
LIns* obj_ins = scopeChain();
|
||||
|
@ -10650,7 +10662,7 @@ TraceRecorder::name(jsval*& vp, LIns*& ins, bool& tracked)
|
|||
|
||||
vp = &STOBJ_GET_SLOT(obj, slot);
|
||||
ins = get(vp);
|
||||
tracked = true;
|
||||
nr.tracked = true;
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -10920,8 +10932,8 @@ TraceRecorder::record_JSOP_NAME()
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
stack(0, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
@ -11250,9 +11262,9 @@ TraceRecorder::record_JSOP_FORNAME()
|
|||
{
|
||||
jsval* vp;
|
||||
LIns* x_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, x_ins, tracked));
|
||||
if (!tracked)
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, x_ins, nr));
|
||||
if (!nr.tracked)
|
||||
ABORT_TRACE("forname on non-tracked value not supported");
|
||||
set(vp, stack(-1));
|
||||
return JSRS_CONTINUE;
|
||||
|
@ -12223,8 +12235,8 @@ TraceRecorder::record_JSOP_GETXPROP()
|
|||
|
||||
jsval* vp;
|
||||
LIns* v_ins;
|
||||
bool tracked;
|
||||
CHECK_STATUS(name(vp, v_ins, tracked));
|
||||
NameResult nr;
|
||||
CHECK_STATUS(name(vp, v_ins, nr));
|
||||
stack(-1, v_ins);
|
||||
return JSRS_CONTINUE;
|
||||
}
|
||||
|
|
|
@ -627,9 +627,19 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK jsval& varval(unsigned n) const;
|
||||
JS_REQUIRES_STACK jsval& stackval(int n) const;
|
||||
|
||||
struct NameResult {
|
||||
// |tracked| is true iff the result of the name lookup is a variable that
|
||||
// is already in the tracker. The rest of the fields are set only if
|
||||
// |tracked| is false.
|
||||
bool tracked;
|
||||
JSObject *obj; // Call object where name was found
|
||||
jsint scopeIndex; // scope chain links from callee to obj
|
||||
JSScopeProperty *sprop; // sprop name was resolved to
|
||||
};
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* scopeChain() const;
|
||||
JS_REQUIRES_STACK JSStackFrame* frameIfInRange(JSObject* obj, unsigned* depthp = NULL) const;
|
||||
JS_REQUIRES_STACK JSRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, bool& tracked);
|
||||
JS_REQUIRES_STACK JSRecordingStatus scopeChainProp(JSObject* obj, jsval*& vp, nanojit::LIns*& ins, NameResult& nr);
|
||||
|
||||
JS_REQUIRES_STACK nanojit::LIns* arg(unsigned n);
|
||||
JS_REQUIRES_STACK void arg(unsigned n, nanojit::LIns* i);
|
||||
|
@ -719,7 +729,7 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
|
||||
nanojit::LIns* getStringLength(nanojit::LIns* str_ins);
|
||||
|
||||
JS_REQUIRES_STACK JSRecordingStatus name(jsval*& vp, nanojit::LIns*& ins, bool& tracked);
|
||||
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 denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
|
||||
|
@ -735,6 +745,9 @@ class TraceRecorder : public avmplus::GCObject {
|
|||
JS_REQUIRES_STACK JSRecordingStatus setProp(jsval &l, JSPropCacheEntry* entry,
|
||||
JSScopeProperty* sprop,
|
||||
jsval &v, nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK JSRecordingStatus setCallProp(nanojit::LIns *callobj_ins,
|
||||
JSScopeProperty *sprop, nanojit::LIns *v_ins,
|
||||
jsval v);
|
||||
|
||||
JS_REQUIRES_STACK void box_jsval(jsval v, nanojit::LIns*& v_ins);
|
||||
JS_REQUIRES_STACK void unbox_jsval(jsval v, nanojit::LIns*& v_ins, VMSideExit* exit);
|
||||
|
|
Загрузка…
Ссылка в новой задаче