зеркало из https://github.com/mozilla/gecko-dev.git
Backout bug 468782. Confirmed to leak.
This commit is contained in:
Родитель
b014d7265b
Коммит
f3bca92387
|
@ -81,6 +81,8 @@ BUILTIN3(extern, JSVAL, js_Any_getprop, CONTEXT, OBJECT, STRING,
|
||||||
BUILTIN4(extern, BOOL, js_Any_setprop, CONTEXT, OBJECT, STRING, JSVAL, 0, 0)
|
BUILTIN4(extern, BOOL, js_Any_setprop, CONTEXT, OBJECT, STRING, JSVAL, 0, 0)
|
||||||
BUILTIN3(extern, JSVAL, js_Any_getelem, CONTEXT, OBJECT, INT32, 0, 0)
|
BUILTIN3(extern, JSVAL, js_Any_getelem, CONTEXT, OBJECT, INT32, 0, 0)
|
||||||
BUILTIN4(extern, BOOL, js_Any_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, 0)
|
BUILTIN4(extern, BOOL, js_Any_setelem, CONTEXT, OBJECT, INT32, JSVAL, 0, 0)
|
||||||
|
BUILTIN3(extern, OBJECT, js_FastValueToIterator, CONTEXT, UINT32, JSVAL, 0, 0)
|
||||||
|
BUILTIN2(extern, JSVAL, js_FastCallIteratorNext, CONTEXT, OBJECT, 0, 0)
|
||||||
BUILTIN2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0)
|
BUILTIN2(FRIEND, BOOL, js_CloseIterator, CONTEXT, JSVAL, 0, 0)
|
||||||
BUILTIN2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0)
|
BUILTIN2(extern, SIDEEXIT, js_CallTree, INTERPSTATE, FRAGMENT, 0, 0)
|
||||||
BUILTIN2(extern, OBJECT, js_FastNewObject, CONTEXT, OBJECT, 0, 0)
|
BUILTIN2(extern, OBJECT, js_FastNewObject, CONTEXT, OBJECT, 0, 0)
|
||||||
|
|
|
@ -109,24 +109,11 @@ function immediate(op) {
|
||||||
info.flags.indexOf("JOF_INT8") >= 0) {
|
info.flags.indexOf("JOF_INT8") >= 0) {
|
||||||
return (op.imm1 & 0xff);
|
return (op.imm1 & 0xff);
|
||||||
}
|
}
|
||||||
if (info.flags.indexOf("JOF_UINT16") >= 0) {
|
if (info.flags.indexOf("JOF_UINT16") >= 0)
|
||||||
if (/^\(/.test(op.imm1))
|
|
||||||
return '(_ & 0xff00) >> 8, (_ & 0xff)'.replace(/_/g, op.imm1);
|
|
||||||
return ((op.imm1 & 0xff00) >> 8) + ", " + (op.imm1 & 0xff);
|
return ((op.imm1 & 0xff00) >> 8) + ", " + (op.imm1 & 0xff);
|
||||||
}
|
|
||||||
throw new Error(info.jsop + " format not yet implemented");
|
throw new Error(info.jsop + " format not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
const line_regexp_parts = [
|
|
||||||
"^(?:(\\w+):)?",
|
|
||||||
"\\s*(\\.?\\w+)",
|
|
||||||
"(?:\\s+(\\w+|\\([^)]*\\)))?",
|
|
||||||
"(?:\\s+([\\w-]+|\\([^)]*\\)))?",
|
|
||||||
"(?:\\s*(?:#.*))?$"
|
|
||||||
];
|
|
||||||
|
|
||||||
const line_regexp = new RegExp(line_regexp_parts.join(""));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Syntax (spaces are significant only to delimit tokens):
|
* Syntax (spaces are significant only to delimit tokens):
|
||||||
*
|
*
|
||||||
|
@ -134,13 +121,10 @@ const line_regexp = new RegExp(line_regexp_parts.join(""));
|
||||||
* Directive ::= (name ':')? Operation
|
* Directive ::= (name ':')? Operation
|
||||||
* Operation ::= opname Operands?
|
* Operation ::= opname Operands?
|
||||||
* Operands ::= Operand (',' Operand)*
|
* Operands ::= Operand (',' Operand)*
|
||||||
* Operand ::= name | number | '(' Expr ')'
|
* Operand ::= name | number
|
||||||
* Expr ::= a constant-expression in the C++ language
|
|
||||||
* containing no parentheses
|
|
||||||
*
|
*
|
||||||
* We simplify given line structure and the maximum of one immediate operand,
|
* We simplify given line structure and the maximum of one immediate operand,
|
||||||
* by parsing using split and regexps. For ease of parsing, parentheses are
|
* by parsing using split and regexps.
|
||||||
* banned in an Expr for now, even in quotes or a C++ comment.
|
|
||||||
*
|
*
|
||||||
* Pseudo-ops start with . and include .igroup and .imacro, terminated by .end.
|
* Pseudo-ops start with . and include .igroup and .imacro, terminated by .end.
|
||||||
* .imacro must nest in .igroup, neither nests in itself. See imacros.jsasm for
|
* .imacro must nest in .igroup, neither nests in itself. See imacros.jsasm for
|
||||||
|
@ -157,7 +141,7 @@ function assemble(filename) {
|
||||||
for (let i = 0; i < a.length; i++) {
|
for (let i = 0; i < a.length; i++) {
|
||||||
if (/^\s*(?:#.*)?$/.test(a[i]))
|
if (/^\s*(?:#.*)?$/.test(a[i]))
|
||||||
continue;
|
continue;
|
||||||
let m = line_regexp.exec(a[i]);
|
let m = /(?:(\w+):)?\s*(\.?\w+)(?:\s+(\w+))?(?:\s+([\w-]+))?(?:\s*(?:#.*))?$/.exec(a[i]);
|
||||||
if (!m)
|
if (!m)
|
||||||
throw new Error(a[i]);
|
throw new Error(a[i]);
|
||||||
|
|
||||||
|
@ -224,6 +208,7 @@ function assemble(filename) {
|
||||||
print(" {");
|
print(" {");
|
||||||
for (let k = 0; k < imacro.code.length; k++) {
|
for (let k = 0; k < imacro.code.length; k++) {
|
||||||
let op = imacro.code[k];
|
let op = imacro.code[k];
|
||||||
|
|
||||||
print("/*" + formatoffset(op.offset,2) + "*/ " + op.info.jsop +
|
print("/*" + formatoffset(op.offset,2) + "*/ " + op.info.jsop +
|
||||||
(op.imm1 ? ", " + immediate(op) : "") + ",");
|
(op.imm1 ? ", " + immediate(op) : "") + ",");
|
||||||
|
|
||||||
|
|
|
@ -536,64 +536,6 @@ static struct {
|
||||||
/* 6*/ JSOP_STOP,
|
/* 6*/ JSOP_STOP,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
static struct {
|
|
||||||
jsbytecode for_in[10];
|
|
||||||
jsbytecode for_each[10];
|
|
||||||
jsbytecode for_in_native[10];
|
|
||||||
jsbytecode for_each_native[10];
|
|
||||||
} iter_imacros = {
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator),
|
|
||||||
/* 3*/ JSOP_INT8, 0,
|
|
||||||
/* 5*/ JSOP_CALL, 0, 1,
|
|
||||||
/* 8*/ JSOP_PUSH,
|
|
||||||
/* 9*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator),
|
|
||||||
/* 3*/ JSOP_INT8, 0,
|
|
||||||
/* 5*/ JSOP_CALL, 0, 1,
|
|
||||||
/* 8*/ JSOP_PUSH,
|
|
||||||
/* 9*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_CALLBUILTIN, ((JSBUILTIN_ObjectToIterator) & 0xff00) >> 8, ((JSBUILTIN_ObjectToIterator) & 0xff),
|
|
||||||
/* 3*/ JSOP_INT8, 0,
|
|
||||||
/* 5*/ JSOP_CALL, 0, 1,
|
|
||||||
/* 8*/ JSOP_PUSH,
|
|
||||||
/* 9*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_CALLBUILTIN, ((JSBUILTIN_ObjectToIterator) & 0xff00) >> 8, ((JSBUILTIN_ObjectToIterator) & 0xff),
|
|
||||||
/* 3*/ JSOP_INT8, 0,
|
|
||||||
/* 5*/ JSOP_CALL, 0, 1,
|
|
||||||
/* 8*/ JSOP_PUSH,
|
|
||||||
/* 9*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
static struct {
|
|
||||||
jsbytecode custom_iter_next[10];
|
|
||||||
jsbytecode native_iter_next[12];
|
|
||||||
} nextiter_imacros = {
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_POP,
|
|
||||||
/* 1*/ JSOP_DUP,
|
|
||||||
/* 2*/ JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(next),
|
|
||||||
/* 5*/ JSOP_CALL, 0, 0,
|
|
||||||
/* 8*/ JSOP_TRUE,
|
|
||||||
/* 9*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
/* 0*/ JSOP_POP,
|
|
||||||
/* 1*/ JSOP_DUP,
|
|
||||||
/* 2*/ JSOP_CALLBUILTIN, ((JSBUILTIN_CallIteratorNext) & 0xff00) >> 8, ((JSBUILTIN_CallIteratorNext) & 0xff),
|
|
||||||
/* 5*/ JSOP_CALL, 0, 0,
|
|
||||||
/* 8*/ JSOP_DUP,
|
|
||||||
/* 9*/ JSOP_HOLE,
|
|
||||||
/*10*/ JSOP_STRICTNE,
|
|
||||||
/*11*/ JSOP_STOP,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
uint8 js_opcode2extra[JSOP_LIMIT] = {
|
uint8 js_opcode2extra[JSOP_LIMIT] = {
|
||||||
0, /* JSOP_NOP */
|
0, /* JSOP_NOP */
|
||||||
0, /* JSOP_PUSH */
|
0, /* JSOP_PUSH */
|
||||||
|
@ -670,8 +612,8 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
||||||
0, /* JSOP_STRICTEQ */
|
0, /* JSOP_STRICTEQ */
|
||||||
0, /* JSOP_STRICTNE */
|
0, /* JSOP_STRICTNE */
|
||||||
0, /* JSOP_NULLTHIS */
|
0, /* JSOP_NULLTHIS */
|
||||||
3, /* JSOP_ITER */
|
0, /* JSOP_ITER */
|
||||||
2, /* JSOP_NEXTITER */
|
0, /* JSOP_NEXTITER */
|
||||||
0, /* JSOP_ENDITER */
|
0, /* JSOP_ENDITER */
|
||||||
7, /* JSOP_APPLY */
|
7, /* JSOP_APPLY */
|
||||||
0, /* JSOP_SWAP */
|
0, /* JSOP_SWAP */
|
||||||
|
@ -821,7 +763,7 @@ uint8 js_opcode2extra[JSOP_LIMIT] = {
|
||||||
0, /* JSOP_CALLGVAR */
|
0, /* JSOP_CALLGVAR */
|
||||||
0, /* JSOP_CALLLOCAL */
|
0, /* JSOP_CALLLOCAL */
|
||||||
0, /* JSOP_CALLARG */
|
0, /* JSOP_CALLARG */
|
||||||
0, /* JSOP_CALLBUILTIN */
|
0, /* JSOP_UNUSED226 */
|
||||||
0, /* JSOP_INT8 */
|
0, /* JSOP_INT8 */
|
||||||
0, /* JSOP_INT32 */
|
0, /* JSOP_INT32 */
|
||||||
0, /* JSOP_LENGTH */
|
0, /* JSOP_LENGTH */
|
||||||
|
|
|
@ -575,63 +575,3 @@
|
||||||
.end #
|
.end #
|
||||||
|
|
||||||
.end
|
.end
|
||||||
|
|
||||||
.igroup iter JSOP_ITER
|
|
||||||
|
|
||||||
.imacro for_in # obj
|
|
||||||
callprop iterator # fun obj
|
|
||||||
int8 (JSITER_ENUMERATE) # fun obj flags
|
|
||||||
call 1 # iterobj
|
|
||||||
push # iterobj undef
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.imacro for_each # obj
|
|
||||||
callprop iterator # fun obj
|
|
||||||
int8 (JSITER_ENUMERATE|JSITER_FOREACH) # fun obj flags
|
|
||||||
call 1 # iterobj
|
|
||||||
push # iterobj undef
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.imacro for_in_native # obj
|
|
||||||
callbuiltin (JSBUILTIN_ObjectToIterator) # fun obj
|
|
||||||
int8 JSITER_ENUMERATE # fun obj flags
|
|
||||||
call 1 # iterobj
|
|
||||||
push # iterobj undef
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.imacro for_each_native # obj
|
|
||||||
callbuiltin (JSBUILTIN_ObjectToIterator) # fun obj
|
|
||||||
int8 (JSITER_ENUMERATE|JSITER_FOREACH) # fun obj flags
|
|
||||||
call 1 # iterobj
|
|
||||||
push # iterobj undef
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.end
|
|
||||||
|
|
||||||
.igroup nextiter JSOP_NEXTITER
|
|
||||||
|
|
||||||
.imacro custom_iter_next # iterobj prevval
|
|
||||||
pop # iterobj
|
|
||||||
dup # iterobj iterobj
|
|
||||||
callprop next # iterobj fun iterobj
|
|
||||||
call 0 # iterobj nextval
|
|
||||||
true # iterobj nextval true
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.imacro native_iter_next # iterobj prevval
|
|
||||||
pop # iterobj
|
|
||||||
dup # iterobj iterobj
|
|
||||||
callbuiltin (JSBUILTIN_CallIteratorNext) # iterobj fun iterobj
|
|
||||||
call 0 # iterobj nextval?
|
|
||||||
dup # iterobj nextval? nextval?
|
|
||||||
hole # iterobj nextval? nextval? hole
|
|
||||||
strictne # iterobj nextval? boolean
|
|
||||||
stop
|
|
||||||
.end
|
|
||||||
|
|
||||||
.end
|
|
||||||
|
|
|
@ -243,6 +243,23 @@ js_Any_setelem(JSContext* cx, JSObject* obj, int32 index, jsval v)
|
||||||
return OBJ_SET_PROPERTY(cx, obj, id, &v);
|
return OBJ_SET_PROPERTY(cx, obj, id, &v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JSObject* FASTCALL
|
||||||
|
js_FastValueToIterator(JSContext* cx, jsuint flags, jsval v)
|
||||||
|
{
|
||||||
|
if (!js_ValueToIterator(cx, flags, &v))
|
||||||
|
return NULL;
|
||||||
|
return JSVAL_TO_OBJECT(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
jsval FASTCALL
|
||||||
|
js_FastCallIteratorNext(JSContext* cx, JSObject* iterobj)
|
||||||
|
{
|
||||||
|
jsval v;
|
||||||
|
if (!js_CallIteratorNext(cx, iterobj, &v))
|
||||||
|
return JSVAL_ERROR_COOKIE;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
SideExit* FASTCALL
|
SideExit* FASTCALL
|
||||||
js_CallTree(InterpState* state, Fragment* f)
|
js_CallTree(InterpState* state, Fragment* f)
|
||||||
{
|
{
|
||||||
|
|
|
@ -227,12 +227,6 @@ typedef enum JSRuntimeState {
|
||||||
JSRTS_LANDING
|
JSRTS_LANDING
|
||||||
} JSRuntimeState;
|
} JSRuntimeState;
|
||||||
|
|
||||||
typedef enum JSBuiltinFunctionId {
|
|
||||||
JSBUILTIN_ObjectToIterator,
|
|
||||||
JSBUILTIN_CallIteratorNext,
|
|
||||||
JSBUILTIN_LIMIT
|
|
||||||
} JSBuiltinFunctionId;
|
|
||||||
|
|
||||||
typedef struct JSPropertyTreeEntry {
|
typedef struct JSPropertyTreeEntry {
|
||||||
JSDHashEntryHdr hdr;
|
JSDHashEntryHdr hdr;
|
||||||
JSScopeProperty *child;
|
JSScopeProperty *child;
|
||||||
|
@ -341,14 +335,6 @@ struct JSRuntime {
|
||||||
JSString *emptyString;
|
JSString *emptyString;
|
||||||
JSString **unitStrings;
|
JSString **unitStrings;
|
||||||
|
|
||||||
/*
|
|
||||||
* Builtin functions, lazily created and held for use by the trace recorder.
|
|
||||||
*
|
|
||||||
* This field would be #ifdef JS_TRACER, but XPConnect is compiled without
|
|
||||||
* -DJS_TRACER and includes this header.
|
|
||||||
*/
|
|
||||||
JSObject *builtinFunctions[JSBUILTIN_LIMIT];
|
|
||||||
|
|
||||||
/* List of active contexts sharing this runtime; protected by gcLock. */
|
/* List of active contexts sharing this runtime; protected by gcLock. */
|
||||||
JSCList contextList;
|
JSCList contextList;
|
||||||
|
|
||||||
|
|
|
@ -3105,11 +3105,6 @@ js_TraceRuntime(JSTracer *trc, JSBool allAtoms)
|
||||||
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
|
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
|
||||||
|
|
||||||
#ifdef JS_TRACER
|
#ifdef JS_TRACER
|
||||||
for (int i = 0; i < JSBUILTIN_LIMIT; i++) {
|
|
||||||
if (rt->builtinFunctions[i])
|
|
||||||
JS_CALL_OBJECT_TRACER(trc, rt->builtinFunctions[i], "builtin function");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef JS_THREADSAFE
|
#ifdef JS_THREADSAFE
|
||||||
/* Trace the loop table(s) which can contain pointers to code objects. */
|
/* Trace the loop table(s) which can contain pointers to code objects. */
|
||||||
while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
|
while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
|
||||||
|
|
|
@ -3227,6 +3227,7 @@ js_Interpret(JSContext *cx)
|
||||||
CHECK_INTERRUPT_HANDLER();
|
CHECK_INTERRUPT_HANDLER();
|
||||||
rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE);
|
rval = BOOLEAN_TO_JSVAL(regs.sp[-1] != JSVAL_HOLE);
|
||||||
PUSH(rval);
|
PUSH(rval);
|
||||||
|
TRACE_0(IteratorNextComplete);
|
||||||
END_CASE(JSOP_NEXTITER)
|
END_CASE(JSOP_NEXTITER)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_ENDITER)
|
BEGIN_CASE(JSOP_ENDITER)
|
||||||
|
@ -6731,19 +6732,6 @@ js_Interpret(JSContext *cx)
|
||||||
}
|
}
|
||||||
END_CASE(JSOP_LEAVEBLOCK)
|
END_CASE(JSOP_LEAVEBLOCK)
|
||||||
|
|
||||||
BEGIN_CASE(JSOP_CALLBUILTIN)
|
|
||||||
#ifdef JS_TRACER
|
|
||||||
obj = js_GetBuiltinFunction(cx, GET_INDEX(regs.pc));
|
|
||||||
if (!obj)
|
|
||||||
goto error;
|
|
||||||
rval = FETCH_OPND(-1);
|
|
||||||
PUSH_OPND(rval);
|
|
||||||
STORE_OPND(-2, OBJECT_TO_JSVAL(obj));
|
|
||||||
#else
|
|
||||||
goto bad_opcode; /* This is an imacro-only opcode. */
|
|
||||||
#endif
|
|
||||||
END_CASE(JSOP_CALLBUILTIN)
|
|
||||||
|
|
||||||
#if JS_HAS_GENERATORS
|
#if JS_HAS_GENERATORS
|
||||||
BEGIN_CASE(JSOP_GENERATOR)
|
BEGIN_CASE(JSOP_GENERATOR)
|
||||||
ASSERT_NOT_THROWING(cx);
|
ASSERT_NOT_THROWING(cx);
|
||||||
|
@ -6853,12 +6841,10 @@ js_Interpret(JSContext *cx)
|
||||||
L_JSOP_UNUSED208:
|
L_JSOP_UNUSED208:
|
||||||
L_JSOP_UNUSED209:
|
L_JSOP_UNUSED209:
|
||||||
L_JSOP_UNUSED219:
|
L_JSOP_UNUSED219:
|
||||||
|
L_JSOP_UNUSED226:
|
||||||
|
|
||||||
#else /* !JS_THREADED_INTERP */
|
#else /* !JS_THREADED_INTERP */
|
||||||
default:
|
default:
|
||||||
#endif
|
|
||||||
#ifndef JS_TRACER
|
|
||||||
bad_opcode:
|
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
char numBuf[12];
|
char numBuf[12];
|
||||||
|
@ -6877,8 +6863,7 @@ js_Interpret(JSContext *cx)
|
||||||
if (fp->imacpc && cx->throwing) {
|
if (fp->imacpc && cx->throwing) {
|
||||||
// To keep things simple, we hard-code imacro exception handlers here.
|
// To keep things simple, we hard-code imacro exception handlers here.
|
||||||
if (*fp->imacpc == JSOP_NEXTITER) {
|
if (*fp->imacpc == JSOP_NEXTITER) {
|
||||||
// pc may point to JSOP_DUP here due to bug 474854.
|
JS_ASSERT(*regs.pc == JSOP_CALL);
|
||||||
JS_ASSERT(*regs.pc == JSOP_CALL || *regs.pc == JSOP_DUP);
|
|
||||||
if (js_ValueIsStopIteration(cx->exception)) {
|
if (js_ValueIsStopIteration(cx->exception)) {
|
||||||
cx->throwing = JS_FALSE;
|
cx->throwing = JS_FALSE;
|
||||||
cx->exception = JSVAL_VOID;
|
cx->exception = JSVAL_VOID;
|
||||||
|
|
|
@ -545,7 +545,7 @@ OPDEF(JSOP_INDEXBASE3, 222,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |
|
||||||
OPDEF(JSOP_CALLGVAR, 223, "callgvar", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLGVAR, 223, "callgvar", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLLOCAL, 224, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLLOCAL, 224, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLARG, 225, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP)
|
OPDEF(JSOP_CALLARG, 225, "callarg", NULL, 3, 0, 2, 19, JOF_QARG |JOF_NAME|JOF_CALLOP)
|
||||||
OPDEF(JSOP_CALLBUILTIN, 226, "callbuiltin", NULL, 3, 0, 2, 0, JOF_UINT16)
|
OPDEF(JSOP_UNUSED226, 226, "unused226", NULL, 1, 0, 1, 1, JOF_BYTE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opcodes to hold 8-bit and 32-bit immediate integer operands.
|
* Opcodes to hold 8-bit and 32-bit immediate integer operands.
|
||||||
|
|
|
@ -1995,7 +1995,7 @@ TraceRecorder::snapshot(ExitType exitType)
|
||||||
bool resumeAfter = (pendingTraceableNative &&
|
bool resumeAfter = (pendingTraceableNative &&
|
||||||
JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL);
|
JSTN_ERRTYPE(pendingTraceableNative) == FAIL_JSVAL);
|
||||||
if (resumeAfter) {
|
if (resumeAfter) {
|
||||||
JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY);
|
JS_ASSERT(*pc == JSOP_CALL || *pc == JSOP_APPLY || *pc == JSOP_NEXTITER);
|
||||||
pc += cs.length;
|
pc += cs.length;
|
||||||
regs->pc = pc;
|
regs->pc = pc;
|
||||||
MUST_FLOW_THROUGH("restore_pc");
|
MUST_FLOW_THROUGH("restore_pc");
|
||||||
|
@ -2022,10 +2022,11 @@ TraceRecorder::snapshot(ExitType exitType)
|
||||||
);
|
);
|
||||||
JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots);
|
JS_ASSERT(unsigned(m - typemap) == ngslots + stackSlots);
|
||||||
|
|
||||||
/* If we are capturing the stack state on a specific instruction, the value on
|
/* If we are capturing the stack state on a specific instruction, the value on or near
|
||||||
the top of the stack is a boxed value. */
|
the top of the stack is a boxed value. Either pc[-cs.length] is JSOP_NEXTITER and we
|
||||||
|
want one below top of stack, or else it's JSOP_CALL and we want top of stack. */
|
||||||
if (resumeAfter) {
|
if (resumeAfter) {
|
||||||
typemap[stackSlots - 1] = JSVAL_BOXED;
|
typemap[stackSlots + ((pc[-cs.length] == JSOP_NEXTITER) ? -2 : -1)] = JSVAL_BOXED;
|
||||||
|
|
||||||
/* Now restore the the original pc (after which early returns are ok). */
|
/* Now restore the the original pc (after which early returns are ok). */
|
||||||
MUST_FLOW_LABEL(restore_pc);
|
MUST_FLOW_LABEL(restore_pc);
|
||||||
|
@ -7532,40 +7533,114 @@ TraceRecorder::record_JSOP_IMACOP()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
jsbytecode for_in[10];
|
||||||
|
jsbytecode for_each[10];
|
||||||
|
} iter_imacros = {
|
||||||
|
{
|
||||||
|
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator),
|
||||||
|
JSOP_INT8, JSITER_ENUMERATE,
|
||||||
|
JSOP_CALL, 0, 1,
|
||||||
|
JSOP_PUSH,
|
||||||
|
JSOP_STOP
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(iterator),
|
||||||
|
JSOP_INT8, JSITER_ENUMERATE | JSITER_FOREACH,
|
||||||
|
JSOP_CALL, 0, 1,
|
||||||
|
JSOP_PUSH,
|
||||||
|
JSOP_STOP
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
JS_STATIC_ASSERT(sizeof(iter_imacros) < IMACRO_PC_ADJ_LIMIT);
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_ITER()
|
TraceRecorder::record_JSOP_ITER()
|
||||||
{
|
{
|
||||||
jsval& v = stackval(-1);
|
jsval& v = stackval(-1);
|
||||||
if (JSVAL_IS_PRIMITIVE(v))
|
if (!JSVAL_IS_PRIMITIVE(v)) {
|
||||||
ABORT_TRACE("for-in on a primitive value");
|
jsuint flags = cx->fp->regs->pc[1];
|
||||||
|
|
||||||
jsuint flags = cx->fp->regs->pc[1];
|
if (!hasIteratorMethod(JSVAL_TO_OBJECT(v))) {
|
||||||
|
LIns* args[] = { get(&v), INS_CONST(flags), cx_ins };
|
||||||
|
LIns* v_ins = lir->insCall(&js_FastValueToIterator_ci, args);
|
||||||
|
guard(false, lir->ins_eq0(v_ins), MISMATCH_EXIT);
|
||||||
|
set(&v, v_ins);
|
||||||
|
|
||||||
|
LIns* void_ins = INS_CONST(JSVAL_TO_BOOLEAN(JSVAL_VOID));
|
||||||
|
stack(0, void_ins);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (hasIteratorMethod(JSVAL_TO_OBJECT(v))) {
|
|
||||||
if (flags == JSITER_ENUMERATE)
|
if (flags == JSITER_ENUMERATE)
|
||||||
return call_imacro(iter_imacros.for_in);
|
return call_imacro(iter_imacros.for_in);
|
||||||
if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
|
if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
|
||||||
return call_imacro(iter_imacros.for_each);
|
return call_imacro(iter_imacros.for_each);
|
||||||
} else {
|
ABORT_TRACE("unimplemented JSITER_* flags");
|
||||||
if (flags == JSITER_ENUMERATE)
|
|
||||||
return call_imacro(iter_imacros.for_in_native);
|
|
||||||
if (flags == (JSITER_ENUMERATE | JSITER_FOREACH))
|
|
||||||
return call_imacro(iter_imacros.for_each_native);
|
|
||||||
}
|
}
|
||||||
ABORT_TRACE("unimplemented JSITER_* flags");
|
|
||||||
|
ABORT_TRACE("for-in on a primitive value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSTraceableNative js_FastCallIteratorNext_tn = {
|
||||||
|
NULL, // JSFastNative native;
|
||||||
|
&js_FastCallIteratorNext_ci, // const nanojit::CallInfo *builtin;
|
||||||
|
"C", // const char *prefix;
|
||||||
|
"o", // const char *argtypes;
|
||||||
|
FAIL_JSVAL // uintN flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
static jsbytecode nextiter_imacro[] = {
|
||||||
|
JSOP_POP,
|
||||||
|
JSOP_DUP,
|
||||||
|
JSOP_CALLPROP, 0, COMMON_ATOM_INDEX(next),
|
||||||
|
JSOP_CALL, 0, 0,
|
||||||
|
JSOP_TRUE,
|
||||||
|
JSOP_STOP
|
||||||
|
};
|
||||||
|
|
||||||
|
JS_STATIC_ASSERT(sizeof(nextiter_imacro) < IMACRO_PC_ADJ_LIMIT);
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_NEXTITER()
|
TraceRecorder::record_JSOP_NEXTITER()
|
||||||
{
|
{
|
||||||
jsval& iterobj_val = stackval(-2);
|
jsval& iterobj_val = stackval(-2);
|
||||||
if (JSVAL_IS_PRIMITIVE(iterobj_val))
|
if (!JSVAL_IS_PRIMITIVE(iterobj_val)) {
|
||||||
ABORT_TRACE("for-in on a primitive value");
|
LIns* iterobj_ins = get(&iterobj_val);
|
||||||
|
|
||||||
LIns* iterobj_ins = get(&iterobj_val);
|
if (guardClass(JSVAL_TO_OBJECT(iterobj_val), iterobj_ins, &js_IteratorClass, BRANCH_EXIT)) {
|
||||||
if (guardClass(JSVAL_TO_OBJECT(iterobj_val), iterobj_ins, &js_IteratorClass, BRANCH_EXIT))
|
LIns* args[] = { iterobj_ins, cx_ins };
|
||||||
return call_imacro(nextiter_imacros.native_iter_next);
|
LIns* v_ins = lir->insCall(&js_FastCallIteratorNext_ci, args);
|
||||||
return call_imacro(nextiter_imacros.custom_iter_next);
|
guard(false, lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_ERROR_COOKIE)), OOM_EXIT);
|
||||||
|
|
||||||
|
LIns* flag_ins = lir->ins_eq0(lir->ins2(LIR_eq, v_ins, INS_CONST(JSVAL_HOLE)));
|
||||||
|
stack(-1, v_ins);
|
||||||
|
stack(0, flag_ins);
|
||||||
|
|
||||||
|
pendingTraceableNative = &js_FastCallIteratorNext_tn;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom iterator, possibly a generator.
|
||||||
|
return call_imacro(nextiter_imacro);
|
||||||
|
}
|
||||||
|
|
||||||
|
ABORT_TRACE("for-in on a primitive value");
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_REQUIRES_STACK bool
|
||||||
|
TraceRecorder::record_IteratorNextComplete()
|
||||||
|
{
|
||||||
|
JS_ASSERT(*cx->fp->regs->pc == JSOP_NEXTITER);
|
||||||
|
JS_ASSERT(pendingTraceableNative == &js_FastCallIteratorNext_tn);
|
||||||
|
|
||||||
|
jsval& v = stackval(-2);
|
||||||
|
LIns* v_ins = get(&v);
|
||||||
|
unbox_jsval(v, v_ins);
|
||||||
|
set(&v, v_ins);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
|
@ -8594,86 +8669,6 @@ TraceRecorder::record_JSOP_CALLARG()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Functions for use with JSOP_CALLBUILTIN. */
|
|
||||||
|
|
||||||
static JSBool
|
|
||||||
ObjectToIterator(JSContext *cx, uintN argc, jsval *vp)
|
|
||||||
{
|
|
||||||
jsval *argv = JS_ARGV(cx, vp);
|
|
||||||
JS_ASSERT(JSVAL_IS_INT(argv[0]));
|
|
||||||
JS_SET_RVAL(cx, vp, JS_THIS(cx, vp));
|
|
||||||
return js_ValueToIterator(cx, JSVAL_TO_INT(argv[0]), &JS_RVAL(cx, vp));
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSObject* FASTCALL
|
|
||||||
ObjectToIterator_tn(JSContext* cx, JSObject *obj, int32 flags)
|
|
||||||
{
|
|
||||||
jsval v = OBJECT_TO_JSVAL(obj);
|
|
||||||
if (!js_ValueToIterator(cx, flags, &v))
|
|
||||||
return NULL;
|
|
||||||
return JSVAL_TO_OBJECT(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
static JSBool
|
|
||||||
CallIteratorNext(JSContext *cx, uintN argc, jsval *vp)
|
|
||||||
{
|
|
||||||
return js_CallIteratorNext(cx, JS_THIS_OBJECT(cx, vp), &JS_RVAL(cx, vp));
|
|
||||||
}
|
|
||||||
|
|
||||||
static jsval FASTCALL
|
|
||||||
CallIteratorNext_tn(JSContext* cx, JSObject* iterobj)
|
|
||||||
{
|
|
||||||
jsval v;
|
|
||||||
if (!js_CallIteratorNext(cx, iterobj, &v))
|
|
||||||
return JSVAL_ERROR_COOKIE;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_DEFINE_TRCINFO_1(ObjectToIterator,
|
|
||||||
(3, (static, OBJECT_FAIL_NULL, ObjectToIterator_tn, CONTEXT, THIS, INT32, 0, 0)))
|
|
||||||
JS_DEFINE_TRCINFO_1(CallIteratorNext,
|
|
||||||
(2, (static, JSVAL_FAIL, CallIteratorNext_tn, CONTEXT, THIS, 0, 0)))
|
|
||||||
|
|
||||||
static const struct BuiltinFunctionInfo {
|
|
||||||
JSTraceableNative *tn;
|
|
||||||
int nargs;
|
|
||||||
} builtinFunctionInfo[JSBUILTIN_LIMIT] = {
|
|
||||||
{ObjectToIterator_trcinfo, 1},
|
|
||||||
{CallIteratorNext_trcinfo, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
JSObject *
|
|
||||||
js_GetBuiltinFunction(JSContext *cx, uintN index)
|
|
||||||
{
|
|
||||||
JSRuntime *rt = cx->runtime;
|
|
||||||
JSObject *funobj = rt->builtinFunctions[index];
|
|
||||||
if (!funobj) {
|
|
||||||
/* Use NULL parent and atom. Builtin functions never escape to scripts. */
|
|
||||||
JSFunction *fun = js_NewFunction(cx,
|
|
||||||
NULL,
|
|
||||||
(JSNative) builtinFunctionInfo[index].tn,
|
|
||||||
builtinFunctionInfo[index].nargs,
|
|
||||||
JSFUN_FAST_NATIVE | JSFUN_TRACEABLE,
|
|
||||||
NULL,
|
|
||||||
NULL);
|
|
||||||
if (fun)
|
|
||||||
rt->builtinFunctions[index] = funobj = FUN_OBJECT(fun);
|
|
||||||
}
|
|
||||||
return funobj;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
|
||||||
TraceRecorder::record_JSOP_CALLBUILTIN()
|
|
||||||
{
|
|
||||||
JSObject *obj = js_GetBuiltinFunction(cx, GET_INDEX(cx->fp->regs->pc));
|
|
||||||
if (!obj)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
stack(0, get(&stackval(-1)));
|
|
||||||
stack(-1, INS_CONSTPTR(obj));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_REQUIRES_STACK bool
|
JS_REQUIRES_STACK bool
|
||||||
TraceRecorder::record_JSOP_NULLTHIS()
|
TraceRecorder::record_JSOP_NULLTHIS()
|
||||||
{
|
{
|
||||||
|
@ -8832,7 +8827,7 @@ static void
|
||||||
InitIMacroCode()
|
InitIMacroCode()
|
||||||
{
|
{
|
||||||
if (imacro_code[JSOP_NEXTITER]) {
|
if (imacro_code[JSOP_NEXTITER]) {
|
||||||
JS_ASSERT(imacro_code[JSOP_NEXTITER] == (jsbytecode*)&nextiter_imacros - 1);
|
JS_ASSERT(imacro_code[JSOP_NEXTITER] == nextiter_imacro - 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8843,7 +8838,7 @@ InitIMacroCode()
|
||||||
imacro_code[JSOP_ADD] = (jsbytecode*)&add_imacros - 1;
|
imacro_code[JSOP_ADD] = (jsbytecode*)&add_imacros - 1;
|
||||||
|
|
||||||
imacro_code[JSOP_ITER] = (jsbytecode*)&iter_imacros - 1;
|
imacro_code[JSOP_ITER] = (jsbytecode*)&iter_imacros - 1;
|
||||||
imacro_code[JSOP_NEXTITER] = (jsbytecode*)&nextiter_imacros - 1;
|
imacro_code[JSOP_NEXTITER] = nextiter_imacro - 1;
|
||||||
imacro_code[JSOP_APPLY] = (jsbytecode*)&apply_imacros - 1;
|
imacro_code[JSOP_APPLY] = (jsbytecode*)&apply_imacros - 1;
|
||||||
|
|
||||||
imacro_code[JSOP_NEG] = (jsbytecode*)&unary_imacros - 1;
|
imacro_code[JSOP_NEG] = (jsbytecode*)&unary_imacros - 1;
|
||||||
|
@ -8869,3 +8864,4 @@ UNUSED(207)
|
||||||
UNUSED(208)
|
UNUSED(208)
|
||||||
UNUSED(209)
|
UNUSED(209)
|
||||||
UNUSED(219)
|
UNUSED(219)
|
||||||
|
UNUSED(226)
|
||||||
|
|
|
@ -518,6 +518,7 @@ public:
|
||||||
JS_REQUIRES_STACK bool record_SetPropMiss(JSPropCacheEntry* entry);
|
JS_REQUIRES_STACK bool record_SetPropMiss(JSPropCacheEntry* entry);
|
||||||
JS_REQUIRES_STACK bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
JS_REQUIRES_STACK bool record_DefLocalFunSetSlot(uint32 slot, JSObject* obj);
|
||||||
JS_REQUIRES_STACK bool record_FastNativeCallComplete();
|
JS_REQUIRES_STACK bool record_FastNativeCallComplete();
|
||||||
|
JS_REQUIRES_STACK bool record_IteratorNextComplete();
|
||||||
|
|
||||||
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
|
nanojit::Fragment* getOuterToBlacklist() { return outerToBlacklist; }
|
||||||
void deepAbort() { deepAborted = true; }
|
void deepAbort() { deepAborted = true; }
|
||||||
|
@ -574,9 +575,6 @@ js_FlushJITCache(JSContext* cx);
|
||||||
extern void
|
extern void
|
||||||
js_FlushJITOracle(JSContext* cx);
|
js_FlushJITOracle(JSContext* cx);
|
||||||
|
|
||||||
extern JSObject *
|
|
||||||
js_GetBuiltinFunction(JSContext *cx, uintN index);
|
|
||||||
|
|
||||||
#else /* !JS_TRACER */
|
#else /* !JS_TRACER */
|
||||||
|
|
||||||
#define TRACE_0(x) ((void)0)
|
#define TRACE_0(x) ((void)0)
|
||||||
|
|
|
@ -2545,17 +2545,6 @@ function testApply() {
|
||||||
testApply.expected = "5,5,5,5,5,5,5,5,5,5";
|
testApply.expected = "5,5,5,5,5,5,5,5,5,5";
|
||||||
test(testApply);
|
test(testApply);
|
||||||
|
|
||||||
function testNestedForIn() {
|
|
||||||
var a = {x: 1, y: 2, z: 3};
|
|
||||||
var s = '';
|
|
||||||
for (var p1 in a)
|
|
||||||
for (var p2 in a)
|
|
||||||
s += p1 + p2 + ' ';
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
testNestedForIn.expected = 'xx xy xz yx yy yz zx zy zz ';
|
|
||||||
test(testNestedForIn);
|
|
||||||
|
|
||||||
function testComparisons()
|
function testComparisons()
|
||||||
{
|
{
|
||||||
// All the special values from each of the types in
|
// All the special values from each of the types in
|
||||||
|
|
Загрузка…
Ссылка в новой задаче