Bug 559813 - Trace script setters. r=brendan.

This commit is contained in:
Jason Orendorff 2010-04-28 11:43:27 -05:00
Родитель 840d7479f0
Коммит e652102394
7 изменённых файлов: 117 добавлений и 22 удалений

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

@ -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});