mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 558830 - Trace script getters. r=brendan.
--HG-- extra : rebase_source : 240b5a7248165aefdc9527abc94902afe4b510e0
This commit is contained in:
parent
a0222dfbf2
commit
6b63be3117
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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');
|
@ -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});
|
@ -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});
|
@ -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});
|
@ -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});
|
@ -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});
|
Loading…
Reference in New Issue
Block a user