Bug 558830 - Trace script getters. r=brendan.

--HG--
extra : rebase_source : 240b5a7248165aefdc9527abc94902afe4b510e0
This commit is contained in:
Jason Orendorff 2010-04-22 17:10:38 -05:00
parent a0222dfbf2
commit 6b63be3117
11 changed files with 286 additions and 67 deletions

View File

@ -1,3 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 ts=8 et tw=78 ft=javascript: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
@ -124,11 +125,33 @@ function immediate(op) {
throw new Error(info.jsop + " format not yet implemented");
}
function simulate_cfg(imacro, depth, i) {
function simulate_cfg(igroup, imacro, depth, i) {
let any_group_opcode = undefined;
let expected_depth = undefined;
for (let opcode in igroup.ops) {
let opi = opinfo[opcode];
if (any_group_opcode === undefined) {
any_group_opcode = opcode;
expected_depth = (opi.pops < 0) ? undefined : opi.pushes - opi.pops;
} else if (expected_depth === undefined) {
if (opi.pops >= 0)
throw Error("imacro shared by constant- and variable-stack-defs/uses instructions");
} else {
if (opi.pops < 0)
throw Error("imacro shared by constant- and variable-stack-defs/uses instructions");
if (opi.pushes - opi.pops != expected_depth)
throw Error("imacro shared by instructions with different stack depths");
}
}
while (i < imacro.code.length) {
let op = imacro.code[i];
depth -= (op.info.pops < 0) ? 2 + Number(op.imm1) : op.info.pops;
depth += op.info.pushes;
let opi = op.info;
if (opi.opname == 'imacop')
opi = opinfo[any_group_opcode];
depth -= (opi.pops < 0) ? 2 + Number(op.imm1) : opi.pops;
depth += opi.pushes;
if (imacro.depths.hasOwnProperty(i) && imacro.depths[i] != depth)
throw Error("Mismatched depth at " + imacro.filename + ":" + op.line);
@ -150,13 +173,16 @@ function simulate_cfg(imacro, depth, i) {
if (op.target_index <= i)
throw Error("Backward jump at " + imacro.filename + ":" + op.line);
simulate_cfg(imacro, depth, op.target_index);
simulate_cfg(igroup, imacro, depth, op.target_index);
if (op.info.opname == "goto" || op.info.opname == "gotox")
return;
}
++i;
}
if (expected_depth !== undefined && depth != expected_depth)
throw Error("Expected depth " + expected_depth + ", got " + depth);
}
/*
@ -181,7 +207,7 @@ function simulate_cfg(imacro, depth, i) {
const line_regexp_parts = [
"^(?:(\\w+):)?", // optional label at start of line
"\\s*(\\.?\\w+)", // optional spaces, (pseudo-)opcode
"(?:\\s+(\\w+|\\([^)]*\\)))?", // optional first immediate operand
"(?:\\s+([+-]?\\w+|\\([^)]*\\)))?", // optional first immediate operand
"(?:\\s+([\\w-,]+|\\([^)]*\\)))?", // optional second immediate operand
"(?:\\s*(?:#.*))?$" // optional spaces and comment
];
@ -258,10 +284,26 @@ function assemble(filename) {
labeldef_indexes: {},
labelrefs: {},
filename: filename,
depths: {}
depths: {},
initdepth: 0,
};
break;
case ".fixup":
if (!imacro)
throw new Error(".fixup outside of .imacro");
if (imacro.code.length !== 0)
throw new Error(".fixup must be first item in .imacro");
if (!imm1)
throw new Error("missing .fixup argument");
let fixup = Number(imm1);
if (isNaN(fixup) || fixup !== parseInt(imm1) || fixup == 0)
throw new Error(".fixup argument must be a nonzero integer");
if (imacro.initdepth !== 0)
throw new Error("more than one .fixup in .imacro");
imacro.initdepth = fixup;
break;
case ".end":
if (!imacro) {
if (!igroup)
@ -291,8 +333,8 @@ function assemble(filename) {
}
imacro.maxdepth = 0;
simulate_cfg(imacro, 0, 0);
imacro.maxdepth = imacro.initdepth;
simulate_cfg(igroup, imacro, imacro.initdepth, 0);
if (imacro.maxdepth > maxdepth)
maxdepth = imacro.maxdepth;

View File

@ -675,6 +675,31 @@ static struct {
/*34*/ JSOP_STOP,
},
};
static struct {
jsbytecode scriptgetter[4];
} getprop_imacros = {
{
/* 0*/ JSOP_CALL, 0, 0,
/* 3*/ JSOP_STOP,
},
};
static struct {
jsbytecode scriptgetter[5];
} callprop_imacros = {
{
/* 0*/ JSOP_CALL, 0, 0,
/* 3*/ JSOP_SWAP,
/* 4*/ JSOP_STOP,
},
};
static struct {
jsbytecode scriptgetter[4];
} getthisprop_imacros = {
{
/* 0*/ JSOP_CALL, 0, 0,
/* 3*/ JSOP_STOP,
},
};
uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_NOP */
0, /* JSOP_PUSH */
@ -729,7 +754,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_NAMEDEC */
0, /* JSOP_PROPDEC */
0, /* JSOP_ELEMDEC */
0, /* JSOP_GETPROP */
1, /* JSOP_GETPROP */
0, /* JSOP_SETPROP */
0, /* JSOP_GETELEM */
0, /* JSOP_SETELEM */
@ -860,7 +885,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_XMLCDATA */
0, /* JSOP_XMLCOMMENT */
0, /* JSOP_XMLPI */
0, /* JSOP_CALLPROP */
2, /* JSOP_CALLPROP */
0, /* JSOP_GETUPVAR */
0, /* JSOP_CALLUPVAR */
0, /* JSOP_DELDESC */
@ -885,9 +910,9 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
0, /* JSOP_GETFUNNS */
0, /* JSOP_ENUMCONSTELEM */
0, /* JSOP_LEAVEBLOCKEXPR */
0, /* JSOP_GETTHISPROP */
0, /* JSOP_GETARGPROP */
0, /* JSOP_GETLOCALPROP */
2, /* JSOP_GETTHISPROP */
2, /* JSOP_GETARGPROP */
2, /* JSOP_GETLOCALPROP */
0, /* JSOP_INDEXBASE1 */
0, /* JSOP_INDEXBASE2 */
0, /* JSOP_INDEXBASE3 */
@ -938,11 +963,16 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|| x == JSOP_MOD \
|| x == JSOP_NEG \
|| x == JSOP_POS \
|| x == JSOP_GETPROP \
|| x == JSOP_CALL \
|| x == JSOP_ITER \
|| x == JSOP_NEXTITER \
|| x == JSOP_APPLY \
|| x == JSOP_NEW \
|| x == JSOP_CALLPROP \
|| x == JSOP_GETTHISPROP \
|| x == JSOP_GETARGPROP \
|| x == JSOP_GETLOCALPROP \
|| x == JSOP_OBJTOSTR \
)
jsbytecode*
@ -983,5 +1013,8 @@ js_GetImacroStart(jsbytecode* pc) {
if (size_t(pc - nextiter_imacros.custom_iter_next) < 12) return nextiter_imacros.custom_iter_next;
if (size_t(pc - nextiter_imacros.native_iter_next) < 12) return nextiter_imacros.native_iter_next;
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 - getthisprop_imacros.scriptgetter) < 4) return getthisprop_imacros.scriptgetter;
return NULL;
}

View File

@ -723,3 +723,27 @@
.end objtostr
.igroup getprop JSOP_GETPROP
.imacro scriptgetter # obj
.fixup +1 # getter obj
call 0 # val
stop
.end
.end getprop
.igroup callprop JSOP_CALLPROP
.imacro scriptgetter # obj
.fixup +2 # obj getter obj
call 0 # obj method
swap # method obj
stop
.end
.end callprop
.igroup getthisprop JSOP_GETTHISPROP,JSOP_GETARGPROP,JSOP_GETLOCALPROP
.imacro scriptgetter #
.fixup +2 # getter obj
call 0 # val
stop
.end
.end getthisprop

View File

@ -8335,16 +8335,25 @@ TraceRecorder::stringify(jsval& v)
return v_ins;
}
JS_REQUIRES_STACK bool
TraceRecorder::canCallImacro() const
{
/* We cannot nest imacros. */
return !cx->fp->imacpc;
}
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::call_imacro(jsbytecode* imacro)
TraceRecorder::callImacro(jsbytecode* imacro)
{
return canCallImacro() ? callImacroInfallibly(imacro) : RECORD_STOP;
}
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::callImacroInfallibly(jsbytecode* imacro)
{
JSStackFrame* fp = cx->fp;
JS_ASSERT(!fp->imacpc);
JSFrameRegs* regs = fp->regs;
/* We cannot nest imacros. */
if (fp->imacpc)
return RECORD_STOP;
fp->imacpc = regs->pc;
regs->pc = imacro;
atoms = COMMON_ATOMS_START(&cx->runtime->atomState);
@ -8747,11 +8756,11 @@ TraceRecorder::equalityHelper(jsval& l, jsval& r, LIns* l_ins, LIns* r_ins,
}
if ((JSVAL_IS_STRING(l) || isNumber(l)) && !JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS_A(guardNativeConversion(r));
return InjectStatus(call_imacro(equality_imacros.any_obj));
return InjectStatus(callImacro(equality_imacros.any_obj));
}
if (!JSVAL_IS_PRIMITIVE(l) && (JSVAL_IS_STRING(r) || isNumber(r))) {
CHECK_STATUS_A(guardNativeConversion(l));
return InjectStatus(call_imacro(equality_imacros.obj_any));
return InjectStatus(callImacro(equality_imacros.obj_any));
}
l_ins = lir->insImmI(0);
@ -8815,13 +8824,13 @@ TraceRecorder::relational(LOpcode op, bool tryBranchAfterCond)
CHECK_STATUS_A(guardNativeConversion(l));
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS_A(guardNativeConversion(r));
return InjectStatus(call_imacro(binary_imacros.obj_obj));
return InjectStatus(callImacro(binary_imacros.obj_obj));
}
return InjectStatus(call_imacro(binary_imacros.obj_any));
return InjectStatus(callImacro(binary_imacros.obj_any));
}
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS_A(guardNativeConversion(r));
return InjectStatus(call_imacro(binary_imacros.any_obj));
return InjectStatus(callImacro(binary_imacros.any_obj));
}
/* 11.8.5 steps 3, 16-21. */
@ -8964,13 +8973,13 @@ TraceRecorder::binary(LOpcode op)
CHECK_STATUS(guardNativeConversion(l));
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS(guardNativeConversion(r));
return call_imacro(binary_imacros.obj_obj);
return callImacro(binary_imacros.obj_obj);
}
return call_imacro(binary_imacros.obj_any);
return callImacro(binary_imacros.obj_any);
}
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS(guardNativeConversion(r));
return call_imacro(binary_imacros.any_obj);
return callImacro(binary_imacros.any_obj);
}
bool intop = retTypes[op] == LTy_I;
@ -10196,13 +10205,13 @@ TraceRecorder::record_JSOP_ADD()
CHECK_STATUS_A(guardNativeConversion(l));
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS_A(guardNativeConversion(r));
return InjectStatus(call_imacro(add_imacros.obj_obj));
return InjectStatus(callImacro(add_imacros.obj_obj));
}
return InjectStatus(call_imacro(add_imacros.obj_any));
return InjectStatus(callImacro(add_imacros.obj_any));
}
if (!JSVAL_IS_PRIMITIVE(r)) {
CHECK_STATUS_A(guardNativeConversion(r));
return InjectStatus(call_imacro(add_imacros.any_obj));
return InjectStatus(callImacro(add_imacros.any_obj));
}
if (JSVAL_IS_STRING(l) || JSVAL_IS_STRING(r)) {
@ -10277,7 +10286,7 @@ TraceRecorder::record_JSOP_NEG()
if (!JSVAL_IS_PRIMITIVE(v)) {
CHECK_STATUS_A(guardNativeConversion(v));
return InjectStatus(call_imacro(unary_imacros.sign));
return InjectStatus(callImacro(unary_imacros.sign));
}
if (isNumber(v)) {
@ -10337,7 +10346,7 @@ TraceRecorder::record_JSOP_POS()
if (!JSVAL_IS_PRIMITIVE(v)) {
CHECK_STATUS_A(guardNativeConversion(v));
return InjectStatus(call_imacro(unary_imacros.sign));
return InjectStatus(callImacro(unary_imacros.sign));
}
if (isNumber(v))
@ -10454,7 +10463,7 @@ TraceRecorder::newString(JSObject* ctor, uint32 argc, jsval* argv, jsval* rval)
if (!JSVAL_IS_PRIMITIVE(argv[0])) {
CHECK_STATUS(guardNativeConversion(argv[0]));
return call_imacro(new_imacros.String);
return callImacro(new_imacros.String);
}
LIns* proto_ins;
@ -11023,7 +11032,7 @@ TraceRecorder::functionCall(uintN argc, JSOp mode)
return newString(JSVAL_TO_OBJECT(fval), 1, argv, &fval);
if (!JSVAL_IS_PRIMITIVE(argv[0])) {
CHECK_STATUS(guardNativeConversion(argv[0]));
return call_imacro(call_imacros.String);
return callImacro(call_imacros.String);
}
set(&fval, stringify(argv[0]));
pendingSpecializedNative = IGNORE_NATIVE_CALL_COMPLETE_CALLBACK;
@ -11766,6 +11775,49 @@ TraceRecorder::getPropertyWithNativeGetter(LIns* obj_ins, JSScopeProperty* sprop
return RECORD_CONTINUE;
}
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::getPropertyWithScriptGetter(JSObject *obj, LIns* obj_ins, JSScopeProperty* sprop)
{
if (!canCallImacro())
RETURN_STOP("cannot trace script getter, already in imacro");
// Rearrange the stack in preparation for the imacro, taking care to adjust
// the interpreter state and the tracker in the same way. This adjustment
// is noted in imacros.jsasm with .fixup tags.
jsval getter = sprop->getterValue();
jsval*& sp = cx->fp->regs->sp;
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)));
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]));
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);
return callImacroInfallibly(getthisprop_imacros.scriptgetter);
default:
RETURN_STOP("cannot trace script getter for this opcode");
}
}
// Typed array tracing depends on EXPANDED_LOADSTORE and F2I
#if NJ_EXPANDED_LOADSTORE_SUPPORTED && NJ_F2I_SUPPORTED
static bool OkToTraceTypedArrays = true;
@ -12675,13 +12727,13 @@ TraceRecorder::record_JSOP_APPLY()
if (length >= JS_ARRAY_LENGTH(apply_imacro_table))
RETURN_STOP_A("too many arguments to apply");
return InjectStatus(call_imacro(apply_imacro_table[length]));
return InjectStatus(callImacro(apply_imacro_table[length]));
}
if (argc >= JS_ARRAY_LENGTH(call_imacro_table))
RETURN_STOP_A("too many arguments to call");
return InjectStatus(call_imacro(call_imacro_table[argc]));
return InjectStatus(callImacro(call_imacro_table[argc]));
}
static JSBool FASTCALL
@ -12917,10 +12969,10 @@ TraceRecorder::prop(JSObject* obj, LIns* obj_ins, uint32 *slotp, LIns** v_insp,
return ARECORD_CONTINUE;
}
return propTail(obj, obj_ins, obj2, pcval, slotp, v_insp, outp);
return InjectStatus(propTail(obj, obj_ins, obj2, pcval, slotp, v_insp, outp));
}
JS_REQUIRES_STACK AbortableRecordingStatus
JS_REQUIRES_STACK RecordingStatus
TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcval,
uint32 *slotp, LIns** v_insp, jsval *outp)
{
@ -12937,26 +12989,26 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva
JS_ASSERT(obj2->scope()->hasProperty(sprop));
if (setflags && !sprop->hasDefaultSetter())
RETURN_STOP_A("non-stub setter");
RETURN_STOP("non-stub setter");
if (setflags && !sprop->writable())
RETURN_STOP_A("writing to a readonly property");
RETURN_STOP("writing to a readonly property");
if (!sprop->hasDefaultGetterOrIsMethod()) {
if (slotp)
RETURN_STOP_A("can't trace non-stub getter for this opcode");
RETURN_STOP("can't trace non-stub getter for this opcode");
if (sprop->hasGetterValue())
RETURN_STOP_A("script getter");
return getPropertyWithScriptGetter(obj, obj_ins, sprop);
if (sprop->slot == SPROP_INVALID_SLOT)
return InjectStatus(getPropertyWithNativeGetter(obj_ins, sprop, outp));
return InjectStatus(getPropertyById(obj_ins, outp));
return getPropertyWithNativeGetter(obj_ins, sprop, outp);
return getPropertyById(obj_ins, outp);
}
if (!SPROP_HAS_VALID_SLOT(sprop, obj2->scope()))
RETURN_STOP_A("no valid slot");
RETURN_STOP("no valid slot");
slot = sprop->slot;
isMethod = sprop->isMethod();
JS_ASSERT_IF(isMethod, obj2->scope()->hasMethodBarrier());
} else {
if (!pcval.isSlot())
RETURN_STOP_A("PCE is not a slot");
RETURN_STOP("PCE is not a slot");
slot = pcval.toSlot();
sprop = NULL;
isMethod = false;
@ -12965,7 +13017,7 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva
/* We have a slot. Check whether it is direct or in a prototype. */
if (obj2 != obj) {
if (setflags)
RETURN_STOP_A("JOF_INCDEC|JOF_FOR opcode hit prototype chain");
RETURN_STOP("JOF_INCDEC|JOF_FOR opcode hit prototype chain");
/*
* We're getting a prototype property. Two cases:
@ -13013,7 +13065,7 @@ TraceRecorder::propTail(JSObject* obj, LIns* obj_ins, JSObject* obj2, PCVal pcva
}
if (outp)
set(outp, v_ins);
return ARECORD_CONTINUE;
return RECORD_CONTINUE;
}
JS_REQUIRES_STACK RecordingStatus
@ -13533,14 +13585,14 @@ TraceRecorder::record_JSOP_ITER()
return InjectStatus(status);
if (found) {
if (flags == JSITER_ENUMERATE)
return InjectStatus(call_imacro(iter_imacros.for_in));
return InjectStatus(callImacro(iter_imacros.for_in));
if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
return InjectStatus(call_imacro(iter_imacros.for_each));
return InjectStatus(callImacro(iter_imacros.for_each));
} else {
if (flags == JSITER_ENUMERATE)
return InjectStatus(call_imacro(iter_imacros.for_in_native));
return InjectStatus(callImacro(iter_imacros.for_in_native));
if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
return InjectStatus(call_imacro(iter_imacros.for_each_native));
return InjectStatus(callImacro(iter_imacros.for_each_native));
}
RETURN_STOP_A("unimplemented JSITER_* flags");
}
@ -13557,8 +13609,8 @@ TraceRecorder::record_JSOP_NEXTITER()
LIns* iterobj_ins = get(&iterobj_val);
guardClass(iterobj, iterobj_ins, clasp, snapshot(BRANCH_EXIT), ACC_OTHER);
if (clasp == &js_IteratorClass || clasp == &js_GeneratorClass)
return InjectStatus(call_imacro(nextiter_imacros.native_iter_next));
return InjectStatus(call_imacro(nextiter_imacros.custom_iter_next));
return InjectStatus(callImacro(nextiter_imacros.native_iter_next));
return InjectStatus(callImacro(nextiter_imacros.custom_iter_next));
}
JS_REQUIRES_STACK AbortableRecordingStatus
@ -14659,9 +14711,7 @@ TraceRecorder::record_JSOP_CALLPROP()
JS_ASSERT_IF(pcval.isSprop(), !pcval.toSprop()->isMethod());
AbortableRecordingStatus status = propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l);
if (status != ARECORD_CONTINUE)
return status;
CHECK_STATUS_A(propTail(obj, obj_ins, obj2, pcval, NULL, NULL, &l));
}
stack(0, this_ins);
return ARECORD_CONTINUE;
@ -15157,7 +15207,7 @@ TraceRecorder::record_JSOP_OBJTOSTR()
if (JSVAL_IS_PRIMITIVE(v))
return ARECORD_CONTINUE;
CHECK_STATUS_A(guardNativeConversion(v));
return InjectStatus(call_imacro(objtostr_imacros.toString));
return InjectStatus(callImacro(objtostr_imacros.toString));
}
JS_REQUIRES_STACK AbortableRecordingStatus

View File

@ -1167,7 +1167,9 @@ class TraceRecorder
JS_REQUIRES_STACK nanojit::LIns* newArguments(nanojit::LIns* callee_ins);
JS_REQUIRES_STACK RecordingStatus call_imacro(jsbytecode* imacro);
JS_REQUIRES_STACK bool canCallImacro() const;
JS_REQUIRES_STACK RecordingStatus callImacro(jsbytecode* imacro);
JS_REQUIRES_STACK RecordingStatus callImacroInfallibly(jsbytecode* imacro);
JS_REQUIRES_STACK AbortableRecordingStatus ifop();
JS_REQUIRES_STACK RecordingStatus switchop();
@ -1244,10 +1246,10 @@ class TraceRecorder
JS_REQUIRES_STACK AbortableRecordingStatus prop(JSObject* obj, nanojit::LIns* obj_ins,
uint32 *slotp, nanojit::LIns** v_insp,
jsval* outp);
JS_REQUIRES_STACK AbortableRecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins,
JSObject* obj2, PCVal pcval,
uint32 *slotp, nanojit::LIns** v_insp,
jsval* outp);
JS_REQUIRES_STACK RecordingStatus propTail(JSObject* obj, nanojit::LIns* obj_ins,
JSObject* obj2, PCVal pcval,
uint32 *slotp, nanojit::LIns** v_insp,
jsval* outp);
JS_REQUIRES_STACK RecordingStatus denseArrayElement(jsval& oval, jsval& idx, jsval*& vp,
nanojit::LIns*& v_ins,
nanojit::LIns*& addr_ins);
@ -1265,13 +1267,16 @@ class TraceRecorder
JS_REQUIRES_STACK void finishGetProp(nanojit::LIns* obj_ins, nanojit::LIns* vp_ins,
nanojit::LIns* ok_ins, jsval* outp);
JS_REQUIRES_STACK RecordingStatus getPropertyByName(nanojit::LIns* obj_ins, jsval* idvalp,
jsval* outp);
jsval* outp);
JS_REQUIRES_STACK RecordingStatus getPropertyByIndex(nanojit::LIns* obj_ins,
nanojit::LIns* index_ins, jsval* outp);
nanojit::LIns* index_ins, jsval* outp);
JS_REQUIRES_STACK RecordingStatus getPropertyById(nanojit::LIns* obj_ins, jsval* outp);
JS_REQUIRES_STACK RecordingStatus getPropertyWithNativeGetter(nanojit::LIns* obj_ins,
JSScopeProperty* sprop,
jsval* outp);
JSScopeProperty* sprop,
jsval* outp);
JS_REQUIRES_STACK RecordingStatus getPropertyWithScriptGetter(JSObject *obj,
nanojit::LIns* obj_ins,
JSScopeProperty* sprop);
JS_REQUIRES_STACK RecordingStatus nativeSet(JSObject* obj, nanojit::LIns* obj_ins,
JSScopeProperty* sprop,

View File

@ -0,0 +1,13 @@
// Test that the tracer is not confused by a.m() when a is the same shape each
// time through the loop but a.m is a scripted getter that returns different
// functions.
function f() { return 'f'; }
function g() { return 'g'; }
var arr = [f, f, f, f, f, f, f, f, g];
var a = {get m() { return arr[i]; }};
var s = '';
for (var i = 0; i < 9; i++)
s += a.m();
assertEq(s, 'ffffffffg');

View File

@ -0,0 +1,12 @@
var a = {_val: 'q',
get p() { return f; }};
function f() { return this._val; }
var g = '';
for (var i = 0; i < 9; i++)
g += a.p();
assertEq(g, 'qqqqqqqqq');
print(uneval(jitstats));
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});

View File

@ -0,0 +1,9 @@
function test(a) {
var s = '';
for (var i = 0; i < 9; i++)
s += a.p;
assertEq(s, 'qqqqqqqqq');
}
test({get p() { return 'q'; }});
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});

View File

@ -0,0 +1,10 @@
function test() {
var a = {get p() { return 'q'; }};
var s = '';
for (var i = 0; i < 9; i++)
s += a.p;
assertEq(s, 'qqqqqqqqq');
}
test();
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});

View File

@ -0,0 +1,10 @@
var a = {get p() { return 11; }};
function f() { return a; }
var g = 0;
for (var i = 0; i < 9; i++)
g += f().p;
assertEq(g, 99);
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});

View File

@ -0,0 +1,11 @@
var a = {
get p() { return 11; },
test: function () {
var s = 0;
for (var i = 0; i < 9; i++)
s += this.p;
assertEq(s, 99);
}};
a.test();
checkStats({recorderStarted: 1, recorderAborted: 0, traceCompleted: 1, traceTriggered: 1});