зеркало из https://github.com/mozilla/gecko-dev.git
Bug 559813 - Trace script setters. r=brendan.
This commit is contained in:
Родитель
840d7479f0
Коммит
e652102394
|
@ -692,6 +692,15 @@ static struct {
|
|||
/* 4*/ JSOP_STOP,
|
||||
},
|
||||
};
|
||||
static struct {
|
||||
jsbytecode scriptsetter[5];
|
||||
} setprop_imacros = {
|
||||
{
|
||||
/* 0*/ JSOP_CALL, 0, 1,
|
||||
/* 3*/ JSOP_POP,
|
||||
/* 4*/ JSOP_STOP,
|
||||
},
|
||||
};
|
||||
static struct {
|
||||
jsbytecode scriptgetter[4];
|
||||
} getthisprop_imacros = {
|
||||
|
@ -755,7 +764,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||
0, /* JSOP_PROPDEC */
|
||||
0, /* JSOP_ELEMDEC */
|
||||
1, /* JSOP_GETPROP */
|
||||
0, /* JSOP_SETPROP */
|
||||
2, /* JSOP_SETPROP */
|
||||
0, /* JSOP_GETELEM */
|
||||
0, /* JSOP_SETELEM */
|
||||
0, /* JSOP_CALLNAME */
|
||||
|
@ -810,7 +819,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||
0, /* JSOP_FORELEM */
|
||||
0, /* JSOP_POPN */
|
||||
0, /* JSOP_BINDNAME */
|
||||
0, /* JSOP_SETNAME */
|
||||
2, /* JSOP_SETNAME */
|
||||
0, /* JSOP_THROW */
|
||||
0, /* JSOP_IN */
|
||||
0, /* JSOP_INSTANCEOF */
|
||||
|
@ -936,7 +945,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||
0, /* JSOP_DEFLOCALFUN_DBGFC */
|
||||
0, /* JSOP_LAMBDA_DBGFC */
|
||||
0, /* JSOP_CONCATN */
|
||||
0, /* JSOP_SETMETHOD */
|
||||
2, /* JSOP_SETMETHOD */
|
||||
0, /* JSOP_INITMETHOD */
|
||||
0, /* JSOP_UNBRAND */
|
||||
0, /* JSOP_UNBRANDTHIS */
|
||||
|
@ -964,15 +973,18 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
|||
|| x == JSOP_NEG \
|
||||
|| x == JSOP_POS \
|
||||
|| x == JSOP_GETPROP \
|
||||
|| x == JSOP_SETPROP \
|
||||
|| x == JSOP_CALL \
|
||||
|| x == JSOP_ITER \
|
||||
|| x == JSOP_NEXTITER \
|
||||
|| x == JSOP_APPLY \
|
||||
|| x == JSOP_NEW \
|
||||
|| x == JSOP_SETNAME \
|
||||
|| x == JSOP_CALLPROP \
|
||||
|| x == JSOP_GETTHISPROP \
|
||||
|| x == JSOP_GETARGPROP \
|
||||
|| x == JSOP_GETLOCALPROP \
|
||||
|| x == JSOP_SETMETHOD \
|
||||
|| x == JSOP_OBJTOSTR \
|
||||
)
|
||||
jsbytecode*
|
||||
|
@ -1015,6 +1027,7 @@ js_GetImacroStart(jsbytecode* pc) {
|
|||
if (size_t(pc - objtostr_imacros.toString) < 35) return objtostr_imacros.toString;
|
||||
if (size_t(pc - getprop_imacros.scriptgetter) < 4) return getprop_imacros.scriptgetter;
|
||||
if (size_t(pc - callprop_imacros.scriptgetter) < 5) return callprop_imacros.scriptgetter;
|
||||
if (size_t(pc - setprop_imacros.scriptsetter) < 5) return setprop_imacros.scriptsetter;
|
||||
if (size_t(pc - getthisprop_imacros.scriptgetter) < 4) return getthisprop_imacros.scriptgetter;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -740,6 +740,15 @@
|
|||
.end
|
||||
.end callprop
|
||||
|
||||
.igroup setprop JSOP_SETPROP,JSOP_SETNAME,JSOP_SETMETHOD
|
||||
.imacro scriptsetter # obj val
|
||||
.fixup +2 # val setter obj val
|
||||
call 1 # val ret
|
||||
pop # val
|
||||
stop
|
||||
.end
|
||||
.end setprop
|
||||
|
||||
.igroup getthisprop JSOP_GETTHISPROP,JSOP_GETARGPROP,JSOP_GETLOCALPROP
|
||||
.imacro scriptgetter #
|
||||
.fixup +2 # getter obj
|
||||
|
|
|
@ -4510,7 +4510,7 @@ class DefaultSlotMap : public SlotMap
|
|||
DefaultSlotMap(TraceRecorder& tr) : SlotMap(tr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual ~DefaultSlotMap()
|
||||
{
|
||||
}
|
||||
|
@ -11323,6 +11323,23 @@ TraceRecorder::lookupForSetPropertyOp(JSObject* obj, LIns* obj_ins, jsid id,
|
|||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::setPropertyWithScriptSetter(JSScopeProperty* sprop)
|
||||
{
|
||||
if (!canCallImacro())
|
||||
RETURN_STOP("cannot trace script setter, already in imacro");
|
||||
|
||||
// Rearrange the stack in preparation for the imacro. See the comment in
|
||||
// getPropertyWithScriptGetter.
|
||||
JSObject *setterObj = JSVAL_TO_OBJECT(sprop->setterValue());
|
||||
cx->fp->regs->sp += 2; // obj val --- ---
|
||||
stackCopy(-2, -4); // obj val obj ---
|
||||
stackCopy(-4, -3); // val val obj ---
|
||||
stackCopy(-1, -3); // val val obj val
|
||||
stackStoreConstObject(-3, setterObj); // val setter obj val
|
||||
return callImacroInfallibly(setprop_imacros.scriptsetter);
|
||||
}
|
||||
|
||||
static JSBool FASTCALL
|
||||
MethodWriteBarrier(JSContext* cx, JSObject* obj, JSScopeProperty* sprop, JSObject* funobj)
|
||||
{
|
||||
|
@ -11388,7 +11405,7 @@ TraceRecorder::nativeSet(JSObject* obj, LIns* obj_ins, JSScopeProperty* sprop,
|
|||
// Call the setter, if any.
|
||||
if (!sprop->hasDefaultSetter()) {
|
||||
if (sprop->hasSetterValue())
|
||||
RETURN_STOP("can't trace JavaScript function setter yet");
|
||||
return setPropertyWithScriptSetter(sprop);
|
||||
emitNativePropertyOp(scope, sprop, obj_ins, true, boxed_ins);
|
||||
}
|
||||
|
||||
|
@ -12039,6 +12056,33 @@ TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop
|
|||
return RECORD_CONTINUE;
|
||||
}
|
||||
|
||||
/* Set sp[dest] = sp[src], both on the real interpreter stack and in the tracker. */
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::stackCopy(int dest, int src)
|
||||
{
|
||||
jsval* sp = cx->fp->regs->sp;
|
||||
sp[dest] = sp[src];
|
||||
set(&sp[dest], get(&sp[src]));
|
||||
}
|
||||
|
||||
/* Set sp[dest] = obj, both on the real interpreter stack and in the tracker. */
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::stackStoreConstObject(int dest, JSObject *obj)
|
||||
{
|
||||
jsval* sp = cx->fp->regs->sp;
|
||||
sp[dest] = OBJECT_TO_JSVAL(obj);
|
||||
set(&sp[dest], INS_CONSTOBJ(obj));
|
||||
}
|
||||
|
||||
/* Set sp[dest] = obj/obj_ins, both on the real interpreter stack and in the tracker. */
|
||||
JS_REQUIRES_STACK void
|
||||
TraceRecorder::stackStore(int dest, JSObject* obj, LIns* obj_ins)
|
||||
{
|
||||
jsval* sp = cx->fp->regs->sp;
|
||||
sp[dest] = OBJECT_TO_JSVAL(obj);
|
||||
set(&sp[dest], obj_ins);
|
||||
}
|
||||
|
||||
JS_REQUIRES_STACK RecordingStatus
|
||||
TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScopeProperty* sprop)
|
||||
{
|
||||
|
@ -12053,28 +12097,22 @@ TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScope
|
|||
switch (*cx->fp->regs->pc) {
|
||||
case JSOP_GETPROP:
|
||||
sp++;
|
||||
sp[-1] = sp[-2];
|
||||
set(&sp[-1], get(&sp[-2]));
|
||||
sp[-2] = getter;
|
||||
set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter)));
|
||||
stackCopy(-1, -2);
|
||||
stackStoreConstObject(-2, JSVAL_TO_OBJECT(getter));
|
||||
return callImacroInfallibly(getprop_imacros.scriptgetter);
|
||||
|
||||
case JSOP_CALLPROP:
|
||||
sp += 2;
|
||||
sp[-2] = getter;
|
||||
set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter)));
|
||||
sp[-1] = sp[-3];
|
||||
set(&sp[-1], get(&sp[-3]));
|
||||
stackStoreConstObject(-2, JSVAL_TO_OBJECT(getter));
|
||||
stackCopy(-1, -3);
|
||||
return callImacroInfallibly(callprop_imacros.scriptgetter);
|
||||
|
||||
case JSOP_GETTHISPROP:
|
||||
case JSOP_GETARGPROP:
|
||||
case JSOP_GETLOCALPROP:
|
||||
sp += 2;
|
||||
sp[-2] = getter;
|
||||
set(&sp[-2], INS_CONSTOBJ(JSVAL_TO_OBJECT(getter)));
|
||||
sp[-1] = OBJECT_TO_JSVAL(obj);
|
||||
set(&sp[-1], obj_ins);
|
||||
stackStoreConstObject(-2, JSVAL_TO_OBJECT(getter));
|
||||
stackStore(-1, obj, obj_ins);
|
||||
return callImacroInfallibly(getthisprop_imacros.scriptgetter);
|
||||
|
||||
default:
|
||||
|
@ -12403,9 +12441,9 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
LIns* priv_ins = stobj_get_const_fslot(obj_ins, JSSLOT_PRIVATE);
|
||||
|
||||
// The index was on the stack and is therefore a LIR float; force it to
|
||||
// be an integer.
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
// be an integer.
|
||||
idx_ins = makeNumberInt32(idx_ins);
|
||||
|
||||
// Ensure idx >= 0 && idx < length (by using uint32)
|
||||
lir->insGuard(LIR_xf,
|
||||
lir->ins2(LIR_ult,
|
||||
|
@ -12473,7 +12511,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
// Do nothing, this is already a float
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("Unknown typed array type in tracer");
|
||||
JS_NOT_REACHED("Unknown typed array type in tracer");
|
||||
}
|
||||
|
||||
switch (tarray->type) {
|
||||
|
@ -12502,7 +12540,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
|
|||
lir->insStore(LIR_stfi, typed_v_ins, addr_ins, 0, ACC_OTHER);
|
||||
break;
|
||||
default:
|
||||
JS_NOT_REACHED("Unknown typed array type in tracer");
|
||||
JS_NOT_REACHED("Unknown typed array type in tracer");
|
||||
}
|
||||
} else if (JSVAL_TO_INT(idx) < 0 || !obj->isDenseArray()) {
|
||||
CHECK_STATUS_A(initOrSetPropertyByIndex(obj_ins, idx_ins, &v,
|
||||
|
|
|
@ -1300,6 +1300,9 @@ class TraceRecorder
|
|||
JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins,
|
||||
JSScopeProperty* sprop,
|
||||
jsval* outp);
|
||||
JS_REQUIRES_STACK void stackCopy(int dest, int src);
|
||||
JS_REQUIRES_STACK void stackStoreConstObject(int dest, JSObject *obj);
|
||||
JS_REQUIRES_STACK void stackStore(int dest, JSObject* obj, nanojit::LIns* obj_ins);
|
||||
JS_REQUIRES_STACK RecordingStatus getPropertyWithScriptGetter(JSObject *obj,
|
||||
nanojit::LIns* obj_ins,
|
||||
JSScopeProperty* sprop);
|
||||
|
@ -1317,6 +1320,7 @@ class TraceRecorder
|
|||
jsid id, bool* safep,
|
||||
JSObject** pobjp,
|
||||
JSScopeProperty** spropp);
|
||||
JS_REQUIRES_STACK RecordingStatus setPropertyWithScriptSetter(JSScopeProperty* sprop);
|
||||
JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
|
||||
JSScopeProperty* sprop,
|
||||
jsval v, nanojit::LIns* v_ins);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
function s(f) { this._m = f; }
|
||||
|
||||
function C(i) {
|
||||
Object.defineProperty(this, "m", {set: s});
|
||||
this.m = function () { return 17; };
|
||||
}
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < 9; i++)
|
||||
arr[i] = new C(i);
|
||||
|
||||
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});
|
||||
|
||||
//BUG - uncomment this when bug 559912 is fixed
|
||||
//for (var i = 1; i < 9; i++)
|
||||
// assertEq(arr[0]._m === arr[i]._m, false);
|
|
@ -0,0 +1,8 @@
|
|||
var n = 0;
|
||||
Object.defineProperty(this, "p", {get: function () { return n; },
|
||||
set: function (x) { n += x; }});
|
||||
for (var i = 0; i < 9; i++)
|
||||
p = i;
|
||||
assertEq(n, 36);
|
||||
|
||||
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});
|
|
@ -0,0 +1,7 @@
|
|||
var n = 0;
|
||||
var a = {set p(x) { n += x; }};
|
||||
for (var i = 0; i < 9; i++)
|
||||
a.p = i;
|
||||
assertEq(n, 36);
|
||||
|
||||
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});
|
Загрузка…
Ссылка в новой задаче