Bug 559813 - Trace script setters. r=brendan.

This commit is contained in:
Jason Orendorff 2010-06-02 12:05:53 -07:00
parent 882ce0d27b
commit 6869b77cae
6 changed files with 101 additions and 19 deletions

View File

@ -730,6 +730,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

View File

@ -4515,7 +4515,7 @@ class DefaultSlotMap : public SlotMap
DefaultSlotMap(TraceRecorder& tr) : SlotMap(tr)
{
}
virtual ~DefaultSlotMap()
{
}
@ -11322,6 +11322,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->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, uint32 slot, jsval v)
{
@ -11386,7 +11403,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);
}
@ -12047,6 +12064,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->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->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->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)
{
@ -12061,28 +12105,22 @@ TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScope
switch (*cx->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:
@ -12411,9 +12449,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_ltui,
@ -12481,7 +12519,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) {
@ -12510,7 +12548,7 @@ TraceRecorder::setElem(int lval_spindex, int idx_spindex, int v_spindex)
lir->insStore(LIR_std, 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,

View File

@ -1303,6 +1303,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);
@ -1320,6 +1323,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);

View File

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

View File

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

View File

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