mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 416601: property cache is properly disabled under with statements with generators. r=brendan a1.9=blocking1.9
This commit is contained in:
parent
08cc7ed6d6
commit
f86e5a86d2
@ -898,9 +898,12 @@ js_ReportOutOfMemory(JSContext *cx)
|
||||
}
|
||||
|
||||
/*
|
||||
* If debugErrorHook is present then we give it a chance to veto
|
||||
* sending the error on to the regular ErrorReporter.
|
||||
* If debugErrorHook is present then we give it a chance to veto sending
|
||||
* the error on to the regular ErrorReporter. We also clear a pending
|
||||
* exception if any now so the hooks can replace the out-of-memory error
|
||||
* by a script-catchable exception.
|
||||
*/
|
||||
cx->throwing = JS_FALSE;
|
||||
if (onError) {
|
||||
JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
|
||||
if (hook &&
|
||||
|
@ -1325,57 +1325,12 @@ FlushPops(JSContext *cx, JSCodeGenerator *cg, intN *npops)
|
||||
|
||||
/*
|
||||
* Emit additional bytecode(s) for non-local jumps.
|
||||
*
|
||||
* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=379758
|
||||
*/
|
||||
static JSBool
|
||||
EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
JSOp *returnop)
|
||||
EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt)
|
||||
{
|
||||
intN depth, npops;
|
||||
JSStmtInfo *stmt;
|
||||
ptrdiff_t jmp;
|
||||
|
||||
/*
|
||||
* Return from a try block that has a finally clause or from a for-in loop
|
||||
* must be split into two ops: JSOP_SETRVAL, to pop the r.v. and store it
|
||||
* in fp->rval; and JSOP_RETRVAL, which makes control flow go back to the
|
||||
* caller, who picks up fp->rval as usual. Otherwise, the stack will be
|
||||
* unbalanced when executing the finally clause.
|
||||
*
|
||||
* We mutate *returnop once only if we find an enclosing try-block (viz,
|
||||
* STMT_FINALLY) or a for-in loop to ensure that we emit just one
|
||||
* JSOP_SETRVAL before one or more JSOP_GOSUBs/JSOP_ENDITERs and other
|
||||
* fixup opcodes emitted by this function.
|
||||
*
|
||||
* Our caller (the TOK_RETURN case of js_EmitTree) then emits *returnop.
|
||||
* The fixup opcodes and gosubs/enditers must interleave in the proper
|
||||
* order, from inner statement to outer, so that finally clauses run at
|
||||
* the correct stack depth.
|
||||
*/
|
||||
if (returnop) {
|
||||
JS_ASSERT(*returnop == JSOP_RETURN);
|
||||
for (stmt = cg->treeContext.topStmt; stmt != toStmt;
|
||||
stmt = stmt->down) {
|
||||
if (stmt->type == STMT_FINALLY ||
|
||||
((cg->treeContext.flags & TCF_FUN_HEAVYWEIGHT) &&
|
||||
STMT_MAYBE_SCOPE(stmt)) ||
|
||||
stmt->type == STMT_FOR_IN_LOOP) {
|
||||
if (js_Emit1(cx, cg, JSOP_SETRVAL) < 0)
|
||||
return JS_FALSE;
|
||||
*returnop = JSOP_RETRVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If there are no try-with-finally blocks open around this return
|
||||
* statement, we can generate a return forthwith and skip generating
|
||||
* any fixup code.
|
||||
*/
|
||||
if (*returnop == JSOP_RETURN)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* The non-local jump fixup we emit will unbalance cg->stackDepth, because
|
||||
@ -1394,8 +1349,7 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
FLUSH_POPS();
|
||||
if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0)
|
||||
return JS_FALSE;
|
||||
jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt));
|
||||
if (jmp < 0)
|
||||
if (EmitBackPatchOp(cx, cg, JSOP_BACKPATCH, &GOSUBS(*stmt)) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
@ -1455,7 +1409,7 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
{
|
||||
intN index;
|
||||
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, toStmt, NULL))
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, toStmt))
|
||||
return -1;
|
||||
|
||||
if (label)
|
||||
@ -5112,18 +5066,26 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
}
|
||||
|
||||
/*
|
||||
* EmitNonLocalJumpFixup mutates op to JSOP_RETRVAL after emitting a
|
||||
* JSOP_SETRVAL if there are open try blocks having finally clauses.
|
||||
* EmitNonLocalJumpFixup may add fixup bytecode to close open try
|
||||
* blocks having finally clauses and to exit intermingled let blocks.
|
||||
* We can't simply transfer control flow to our caller in that case,
|
||||
* because we must gosub to those clauses from inner to outer, with
|
||||
* the correct stack pointer (i.e., after popping any with, for/in,
|
||||
* etc., slots nested inside the finally's try).
|
||||
* because we must gosub to those finally clauses from inner to outer,
|
||||
* with the correct stack pointer (i.e., after popping any with,
|
||||
* for/in, etc., slots nested inside the finally's try).
|
||||
*
|
||||
* In this case we mutate JSOP_RETURN into JSOP_SETRVAL and add an
|
||||
* extra JSOP_RETRVAL after the fixups.
|
||||
*/
|
||||
op = JSOP_RETURN;
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, NULL, &op))
|
||||
top = CG_OFFSET(cg);
|
||||
if (js_Emit1(cx, cg, JSOP_RETURN) < 0)
|
||||
return JS_FALSE;
|
||||
if (js_Emit1(cx, cg, op) < 0)
|
||||
if (!EmitNonLocalJumpFixup(cx, cg, NULL))
|
||||
return JS_FALSE;
|
||||
if (top + JSOP_RETURN_LENGTH != CG_OFFSET(cg)) {
|
||||
CG_BASE(cg)[top] = JSOP_SETRVAL;
|
||||
if (js_Emit1(cx, cg, JSOP_RETRVAL) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
@ -678,8 +678,8 @@ AllocateAfterSP(JSContext *cx, jsval *sp, uintN nslots)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(jsval *)
|
||||
js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
|
||||
static jsval *
|
||||
AllocRawStack(JSContext *cx, uintN nslots, void **markp)
|
||||
{
|
||||
jsval *sp;
|
||||
|
||||
@ -702,8 +702,8 @@ js_AllocRawStack(JSContext *cx, uintN nslots, void **markp)
|
||||
return sp;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
js_FreeRawStack(JSContext *cx, void *mark)
|
||||
static void
|
||||
FreeRawStack(JSContext *cx, void *mark)
|
||||
{
|
||||
JS_ARENA_RELEASE(&cx->stackPool, mark);
|
||||
}
|
||||
@ -722,7 +722,7 @@ js_AllocStack(JSContext *cx, uintN nslots, void **markp)
|
||||
}
|
||||
|
||||
/* Allocate 2 extra slots for the stack segment header we'll likely need. */
|
||||
sp = js_AllocRawStack(cx, 2 + nslots, markp);
|
||||
sp = AllocRawStack(cx, 2 + nslots, markp);
|
||||
if (!sp)
|
||||
return NULL;
|
||||
|
||||
@ -864,27 +864,6 @@ js_GetScopeChain(JSContext *cx, JSStackFrame *fp)
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* Walk the scope chain looking for block scopes whose locals need to be
|
||||
* copied from stack slots into object slots before fp goes away.
|
||||
*/
|
||||
static JSBool
|
||||
PutBlockObjects(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
JSBool ok;
|
||||
JSObject *obj;
|
||||
|
||||
ok = JS_TRUE;
|
||||
for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
if (OBJ_GET_CLASS(cx, obj) == &js_BlockClass) {
|
||||
if (OBJ_GET_PRIVATE(cx, obj) != fp)
|
||||
break;
|
||||
ok &= js_PutBlockObject(cx, obj);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
JSBool
|
||||
js_GetPrimitiveThis(JSContext *cx, jsval *vp, JSClass *clasp, jsval *thisvp)
|
||||
{
|
||||
@ -1265,7 +1244,7 @@ have_fun:
|
||||
*/
|
||||
if (!AllocateAfterSP(cx, sp, nslots)) {
|
||||
rootedArgsFlag = 0;
|
||||
newvp = js_AllocRawStack(cx, 2 + argc + nslots, NULL);
|
||||
newvp = AllocRawStack(cx, 2 + argc + nslots, NULL);
|
||||
if (!newvp) {
|
||||
ok = JS_FALSE;
|
||||
goto out2;
|
||||
@ -1315,7 +1294,7 @@ have_fun:
|
||||
if (nvars) {
|
||||
if (!AllocateAfterSP(cx, sp, nvars)) {
|
||||
/* NB: Discontinuity between argv and vars. */
|
||||
sp = js_AllocRawStack(cx, nvars, NULL);
|
||||
sp = AllocRawStack(cx, nvars, NULL);
|
||||
if (!sp) {
|
||||
ok = JS_FALSE;
|
||||
goto out2;
|
||||
@ -1360,9 +1339,6 @@ have_fun:
|
||||
frame.dormantNext = NULL;
|
||||
frame.xmlNamespace = NULL;
|
||||
frame.blockChain = NULL;
|
||||
#ifdef DEBUG
|
||||
frame.pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
|
||||
#endif
|
||||
|
||||
/* From here on, control must flow through label out: to return. */
|
||||
cx->fp = &frame;
|
||||
@ -1584,7 +1560,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
if (script->regexpsOffset != 0)
|
||||
frame.nvars += JS_SCRIPT_REGEXPS(script)->length;
|
||||
if (frame.nvars != 0) {
|
||||
frame.vars = js_AllocRawStack(cx, frame.nvars, &mark);
|
||||
frame.vars = AllocRawStack(cx, frame.nvars, &mark);
|
||||
if (!frame.vars) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
@ -1607,9 +1583,6 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
frame.dormantNext = NULL;
|
||||
frame.xmlNamespace = NULL;
|
||||
frame.blockChain = NULL;
|
||||
#ifdef DEBUG
|
||||
frame.pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Here we wrap the call to js_Interpret with code to (conditionally)
|
||||
@ -1649,7 +1622,7 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script,
|
||||
hook(cx, &frame, JS_FALSE, &ok, hookData);
|
||||
}
|
||||
if (mark)
|
||||
js_FreeRawStack(cx, mark);
|
||||
FreeRawStack(cx, mark);
|
||||
cx->fp = oldfp;
|
||||
|
||||
if (oldfp && oldfp != down) {
|
||||
@ -2078,11 +2051,83 @@ LeaveWith(JSContext *cx)
|
||||
|
||||
withobj = cx->fp->scopeChain;
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, withobj) == &js_WithClass);
|
||||
JS_ASSERT(OBJ_GET_PRIVATE(cx, withobj) == cx->fp);
|
||||
JS_ASSERT(OBJ_BLOCK_DEPTH(cx, withobj) >= 0);
|
||||
cx->fp->scopeChain = OBJ_GET_PARENT(cx, withobj);
|
||||
JS_SetPrivate(cx, withobj, NULL);
|
||||
js_EnablePropertyCache(cx);
|
||||
}
|
||||
|
||||
static JSClass *
|
||||
IsActiveWithOrBlock(JSContext *cx, JSObject *obj, int stackDepth)
|
||||
{
|
||||
JSClass *clasp;
|
||||
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if ((clasp == &js_WithClass || clasp == &js_BlockClass) &&
|
||||
OBJ_GET_PRIVATE(cx, obj) == cx->fp &&
|
||||
OBJ_BLOCK_DEPTH(cx, obj) >= stackDepth) {
|
||||
return clasp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static jsint
|
||||
CountWithBlocks(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
jsint n;
|
||||
JSObject *obj;
|
||||
JSClass *clasp;
|
||||
|
||||
n = 0;
|
||||
for (obj = fp->scopeChain;
|
||||
(clasp = IsActiveWithOrBlock(cx, obj, 0)) != NULL;
|
||||
obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
if (clasp == &js_WithClass)
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unwind block and scope chains to match the given depth. The function sets
|
||||
* fp->sp on return to stackDepth.
|
||||
*/
|
||||
static JSBool
|
||||
UnwindScope(JSContext *cx, JSStackFrame *fp, jsint stackDepth,
|
||||
JSBool normalUnwind)
|
||||
{
|
||||
JSObject *obj;
|
||||
JSClass *clasp;
|
||||
|
||||
JS_ASSERT(stackDepth >= 0);
|
||||
JS_ASSERT(fp->spbase + stackDepth <= fp->sp);
|
||||
|
||||
for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
|
||||
if (OBJ_BLOCK_DEPTH(cx, obj) < stackDepth)
|
||||
break;
|
||||
}
|
||||
fp->blockChain = obj;
|
||||
|
||||
for (;;) {
|
||||
obj = fp->scopeChain;
|
||||
clasp = IsActiveWithOrBlock(cx, obj, stackDepth);
|
||||
if (!clasp)
|
||||
break;
|
||||
if (clasp == &js_BlockClass) {
|
||||
/* Don't fail until after we've updated all stacks. */
|
||||
normalUnwind &= js_PutBlockObject(cx, obj, normalUnwind);
|
||||
fp->scopeChain = OBJ_GET_PARENT(cx, obj);
|
||||
} else {
|
||||
LeaveWith(cx);
|
||||
}
|
||||
}
|
||||
|
||||
fp->sp = fp->spbase + stackDepth;
|
||||
return normalUnwind;
|
||||
}
|
||||
|
||||
/*
|
||||
* Threaded interpretation via computed goto appears to be well-supported by
|
||||
* GCC 3 and higher. IBM's C compiler when run with the right options (e.g.,
|
||||
@ -2306,7 +2351,6 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||
#if JS_HAS_GETTER_SETTER
|
||||
JSPropertyOp getter, setter;
|
||||
#endif
|
||||
int stackDummy;
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define JS_EXTENSION __extension__
|
||||
@ -2352,6 +2396,9 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||
# define EMPTY_CASE(OP) BEGIN_CASE(OP) END_CASE(OP)
|
||||
#endif
|
||||
|
||||
/* Check for too deep a C stack. */
|
||||
JS_CHECK_RECURSION(cx, return JS_FALSE);
|
||||
|
||||
*result = JSVAL_VOID;
|
||||
rt = cx->runtime;
|
||||
|
||||
@ -2391,26 +2438,6 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_FunctionClass); \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
* Optimized Get and SetVersion for proper script language versioning.
|
||||
*
|
||||
* If any native method or JSClass/JSObjectOps hook calls js_SetVersion
|
||||
* and changes cx->version, the effect will "stick" and we will stop
|
||||
* maintaining currentVersion. This is relied upon by testsuites, for
|
||||
* the most part -- web browsers select version before compiling and not
|
||||
* at run-time.
|
||||
*/
|
||||
currentVersion = (JSVersion) script->version;
|
||||
originalVersion = (JSVersion) cx->version;
|
||||
if (currentVersion != originalVersion)
|
||||
js_SetVersion(cx, currentVersion);
|
||||
|
||||
#ifdef __GNUC__
|
||||
flags = 0; /* suppress gcc warnings */
|
||||
id = 0;
|
||||
atom = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Prepare to call a user-supplied branch handler, and abort the script
|
||||
* if it returns false.
|
||||
@ -2446,13 +2473,27 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||
|
||||
LOAD_INTERRUPT_HANDLER(cx);
|
||||
|
||||
/* Check for too much js_Interpret nesting, or too deep a C stack. */
|
||||
/*
|
||||
* Optimized Get and SetVersion for proper script language versioning.
|
||||
*
|
||||
* If any native method or JSClass/JSObjectOps hook calls js_SetVersion
|
||||
* and changes cx->version, the effect will "stick" and we will stop
|
||||
* maintaining currentVersion. This is relied upon by testsuites, for
|
||||
* the most part -- web browsers select version before compiling and not
|
||||
* at run-time.
|
||||
*/
|
||||
currentVersion = (JSVersion) script->version;
|
||||
originalVersion = (JSVersion) cx->version;
|
||||
if (currentVersion != originalVersion)
|
||||
js_SetVersion(cx, currentVersion);
|
||||
|
||||
++cx->interpLevel;
|
||||
if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {
|
||||
js_ReportOverRecursed(cx);
|
||||
ok = JS_FALSE;
|
||||
goto out2;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
fp->pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
|
||||
#endif
|
||||
|
||||
/* From this point the control must flow through the label exit. */
|
||||
ok = JS_TRUE;
|
||||
|
||||
/*
|
||||
* Allocate operand and pc stack slots for the script's worst-case depth,
|
||||
@ -2461,36 +2502,40 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
|
||||
*/
|
||||
depth = (jsint) script->depth;
|
||||
if (JS_LIKELY(!fp->spbase)) {
|
||||
newsp = js_AllocRawStack(cx, (uintN)(2 * depth), &mark);
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
newsp = AllocRawStack(cx, (uintN)(2 * depth), &mark);
|
||||
if (!newsp) {
|
||||
mark = NULL;
|
||||
ok = JS_FALSE;
|
||||
goto out2;
|
||||
goto exit;
|
||||
}
|
||||
JS_ASSERT(mark);
|
||||
sp = newsp + depth;
|
||||
fp->spbase = sp;
|
||||
SAVE_SP(fp);
|
||||
} else {
|
||||
JS_ASSERT(fp->flags & JSFRAME_GENERATOR);
|
||||
sp = fp->sp;
|
||||
JS_ASSERT(JS_UPTRDIFF(sp, fp->spbase) <= depth * sizeof(jsval));
|
||||
newsp = fp->spbase - depth;
|
||||
mark = NULL;
|
||||
}
|
||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
|
||||
JS_PROPERTY_CACHE(cx).disabled += CountWithBlocks(cx, fp);
|
||||
|
||||
/*
|
||||
* To support generator_throw and to catch ignored exceptions, fail right
|
||||
* away if cx->throwing is set. If no exception is pending, null obj in
|
||||
* case a callable object is being sent into a yield expression, and the
|
||||
* yield's result is invoked.
|
||||
*/
|
||||
ok = !cx->throwing;
|
||||
if (!ok) {
|
||||
/*
|
||||
* To support generator_throw and to catch ignored exceptions,
|
||||
* fail if cx->throwing is set.
|
||||
*/
|
||||
if (cx->throwing) {
|
||||
#ifdef DEBUG_NOT_THROWING
|
||||
if (cx->exception != JSVAL_ARETURN) {
|
||||
printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n",
|
||||
(unsigned long) cx->exception);
|
||||
}
|
||||
if (cx->exception != JSVAL_ARETURN) {
|
||||
printf("JS INTERPRETER CALLED WITH PENDING EXCEPTION %lx\n",
|
||||
(unsigned long) cx->exception);
|
||||
}
|
||||
#endif
|
||||
goto out;
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
#if JS_THREADED_INTERP
|
||||
@ -2520,7 +2565,7 @@ interrupt:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->throwing = JS_TRUE;
|
||||
cx->exception = rval;
|
||||
@ -2579,7 +2624,7 @@ interrupt:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->throwing = JS_TRUE;
|
||||
cx->exception = rval;
|
||||
@ -2594,9 +2639,6 @@ interrupt:
|
||||
|
||||
#endif /* !JS_THREADED_INTERP */
|
||||
|
||||
BEGIN_CASE(JSOP_STOP)
|
||||
goto out;
|
||||
|
||||
EMPTY_CASE(JSOP_NOP)
|
||||
|
||||
EMPTY_CASE(JSOP_GROUP)
|
||||
@ -2683,6 +2725,7 @@ interrupt:
|
||||
/* FALL THROUGH */
|
||||
|
||||
BEGIN_CASE(JSOP_RETRVAL) /* fp->rval already set */
|
||||
BEGIN_CASE(JSOP_STOP)
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
if (inlineCallCount)
|
||||
inline_return:
|
||||
@ -2690,17 +2733,9 @@ interrupt:
|
||||
JSInlineFrame *ifp = (JSInlineFrame *) fp;
|
||||
void *hookData = ifp->hookData;
|
||||
|
||||
/*
|
||||
* If fp has blocks on its scope chain, home their locals now,
|
||||
* before calling any debugger hook, and before freeing stack.
|
||||
* This matches the order of block putting and hook calling in
|
||||
* the "out-of-line" return code at the bottom of js_Interpret
|
||||
* and in js_Invoke.
|
||||
*/
|
||||
if (fp->flags & JSFRAME_POP_BLOCKS) {
|
||||
SAVE_SP_AND_PC(fp);
|
||||
ok &= PutBlockObjects(cx, fp);
|
||||
}
|
||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
|
||||
JS_ASSERT(!fp->blockChain);
|
||||
JS_ASSERT(!IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||
|
||||
if (hookData) {
|
||||
JSInterpreterHook hook = cx->debugHooks->callHook;
|
||||
@ -2770,8 +2805,9 @@ interrupt:
|
||||
len = JSOP_CALL_LENGTH;
|
||||
DO_NEXT_OP(len);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
goto exit;
|
||||
|
||||
BEGIN_CASE(JSOP_DEFAULT)
|
||||
(void) POP();
|
||||
@ -4456,7 +4492,8 @@ interrupt:
|
||||
newifp->frame.xmlNamespace = NULL;
|
||||
newifp->frame.blockChain = NULL;
|
||||
#ifdef DEBUG
|
||||
newifp->frame.pcDisabledSave = JS_PROPERTY_CACHE(cx).disabled;
|
||||
newifp->frame.pcDisabledSave =
|
||||
JS_PROPERTY_CACHE(cx).disabled;
|
||||
#endif
|
||||
newifp->rvp = rvp;
|
||||
newifp->mark = newmark;
|
||||
@ -4525,7 +4562,7 @@ interrupt:
|
||||
script = fp->script;
|
||||
depth = (jsint) script->depth;
|
||||
atoms = script->atomMap.vector;
|
||||
js_FreeRawStack(cx, newmark);
|
||||
FreeRawStack(cx, newmark);
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
@ -5153,7 +5190,7 @@ interrupt:
|
||||
DO_OP();
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->throwing = JS_TRUE;
|
||||
cx->exception = rval;
|
||||
@ -5968,7 +6005,7 @@ interrupt:
|
||||
break;
|
||||
case JSTRAP_RETURN:
|
||||
fp->rval = rval;
|
||||
goto out;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->throwing = JS_TRUE;
|
||||
cx->exception = rval;
|
||||
@ -6334,7 +6371,7 @@ interrupt:
|
||||
* its locals to their property slots.
|
||||
*/
|
||||
SAVE_SP_AND_PC(fp);
|
||||
ok = js_PutBlockObject(cx, obj);
|
||||
ok = js_PutBlockObject(cx, obj, JS_TRUE);
|
||||
if (!ok)
|
||||
goto out;
|
||||
}
|
||||
@ -6352,9 +6389,8 @@ interrupt:
|
||||
: fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
|
||||
|
||||
*chainp = OBJ_GET_PARENT(cx, obj);
|
||||
JS_ASSERT(chainp != &fp->blockChain ||
|
||||
!*chainp ||
|
||||
OBJ_GET_CLASS(cx, *chainp) == &js_BlockClass);
|
||||
JS_ASSERT_IF(fp->blockChain,
|
||||
OBJ_GET_CLASS(cx, fp->blockChain) == &js_BlockClass);
|
||||
}
|
||||
END_CASE(JSOP_LEAVEBLOCK)
|
||||
|
||||
@ -6425,11 +6461,13 @@ interrupt:
|
||||
obj = js_NewGenerator(cx, fp);
|
||||
if (!obj) {
|
||||
ok = JS_FALSE;
|
||||
} else {
|
||||
JS_ASSERT(!fp->callobj && !fp->argsobj);
|
||||
fp->rval = OBJECT_TO_JSVAL(obj);
|
||||
goto out;
|
||||
}
|
||||
goto out;
|
||||
JS_ASSERT(!fp->callobj && !fp->argsobj);
|
||||
fp->rval = OBJECT_TO_JSVAL(obj);
|
||||
if (inlineCallCount != 0)
|
||||
goto inline_return;
|
||||
goto exit;
|
||||
|
||||
BEGIN_CASE(JSOP_YIELD)
|
||||
ASSERT_NOT_THROWING(cx);
|
||||
@ -6444,7 +6482,9 @@ interrupt:
|
||||
fp->flags |= JSFRAME_YIELDING;
|
||||
pc += JSOP_YIELD_LENGTH;
|
||||
SAVE_SP_AND_PC(fp);
|
||||
goto out;
|
||||
JS_PROPERTY_CACHE(cx).disabled -= CountWithBlocks(cx, fp);
|
||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled >= 0);
|
||||
goto exit;
|
||||
|
||||
BEGIN_CASE(JSOP_ARRAYPUSH)
|
||||
slot = GET_UINT16(pc);
|
||||
@ -6580,7 +6620,7 @@ interrupt:
|
||||
}
|
||||
#endif /* !JS_THREADED_INTERP */
|
||||
|
||||
out:
|
||||
out:
|
||||
JS_ASSERT((size_t)(pc - script->code) < script->length);
|
||||
if (!ok && cx->throwing) {
|
||||
/* An exception has been raised. */
|
||||
@ -6588,9 +6628,7 @@ out:
|
||||
JSTryNote *tn, *tnlimit;
|
||||
uint32 offset;
|
||||
|
||||
/*
|
||||
* Call debugger throw hook if set (XXX thread safety?).
|
||||
*/
|
||||
/* Call debugger throw hook if set. */
|
||||
handler = cx->debugHooks->throwHook;
|
||||
if (handler) {
|
||||
SAVE_SP_AND_PC(fp);
|
||||
@ -6598,12 +6636,12 @@ out:
|
||||
cx->debugHooks->throwHookData)) {
|
||||
case JSTRAP_ERROR:
|
||||
cx->throwing = JS_FALSE;
|
||||
goto no_catch;
|
||||
goto forced_return;
|
||||
case JSTRAP_RETURN:
|
||||
ok = JS_TRUE;
|
||||
cx->throwing = JS_FALSE;
|
||||
fp->rval = rval;
|
||||
goto no_catch;
|
||||
ok = JS_TRUE;
|
||||
goto forced_return;
|
||||
case JSTRAP_THROW:
|
||||
cx->exception = rval;
|
||||
case JSTRAP_CONTINUE:
|
||||
@ -6647,55 +6685,24 @@ out:
|
||||
if (tn->stackDepth > sp - fp->spbase)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Prepare to execute the try note handler and unwind the block
|
||||
* and scope chains until we match the stack depth of the try
|
||||
* note. Note that we set sp after we call js_PutBlockObject to
|
||||
* avoid potential GC hazards.
|
||||
*/
|
||||
ok = JS_TRUE;
|
||||
i = tn->stackDepth;
|
||||
for (obj = fp->blockChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_BlockClass);
|
||||
if (OBJ_BLOCK_DEPTH(cx, obj) < i)
|
||||
break;
|
||||
}
|
||||
fp->blockChain = obj;
|
||||
|
||||
JS_ASSERT(ok);
|
||||
for (;;) {
|
||||
obj = fp->scopeChain;
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if (clasp != &js_WithClass && clasp != &js_BlockClass)
|
||||
break;
|
||||
if (OBJ_GET_PRIVATE(cx, obj) != fp ||
|
||||
OBJ_BLOCK_DEPTH(cx, obj) < i) {
|
||||
break;
|
||||
}
|
||||
if (clasp == &js_BlockClass) {
|
||||
/* Don't fail until after we've updated all stacks. */
|
||||
ok &= js_PutBlockObject(cx, obj);
|
||||
fp->scopeChain = OBJ_GET_PARENT(cx, obj);
|
||||
} else {
|
||||
LeaveWith(cx);
|
||||
}
|
||||
}
|
||||
|
||||
sp = fp->spbase + i;
|
||||
|
||||
/*
|
||||
* Set pc to the first bytecode after the the try note to point
|
||||
* to the beginning of catch or finally or to [enditer] closing
|
||||
* the for-in loop.
|
||||
*
|
||||
* We do it before checking for ok so, when failing during the
|
||||
* scope recovery, we restart the exception search with the
|
||||
* updated stack and pc avoiding calling the handler again.
|
||||
*/
|
||||
offset = tn->start + tn->length;
|
||||
pc = (script)->main + offset;
|
||||
if (!ok)
|
||||
pc = (script)->main + tn->start + tn->length;
|
||||
|
||||
SAVE_SP_AND_PC(fp);
|
||||
ok = UnwindScope(cx, fp, tn->stackDepth, JS_TRUE);
|
||||
JS_ASSERT(fp->sp == fp->spbase + tn->stackDepth);
|
||||
sp = fp->sp;
|
||||
if (!ok) {
|
||||
/*
|
||||
* Restart the handler search with updated pc and stack depth
|
||||
* to properly notify the debugger.
|
||||
*/
|
||||
goto out;
|
||||
}
|
||||
|
||||
switch (tn->kind) {
|
||||
case JSTN_CATCH:
|
||||
@ -6769,34 +6776,35 @@ out:
|
||||
#endif
|
||||
}
|
||||
|
||||
forced_return:
|
||||
/*
|
||||
* We either have an error or uncaught exception or were forced to return
|
||||
* from a trap handler.
|
||||
*/
|
||||
SAVE_SP_AND_PC(fp);
|
||||
|
||||
/* ok must stay false even when UnwindScope returns true. */
|
||||
ok &= UnwindScope(cx, fp, 0, ok || cx->throwing);
|
||||
JS_ASSERT(fp->sp == fp->spbase);
|
||||
sp = fp->sp;
|
||||
|
||||
if (inlineCallCount)
|
||||
goto inline_return;
|
||||
|
||||
exit:
|
||||
/*
|
||||
* At this point we are inevitably leaving an interpreted function or a
|
||||
* top-level script, and returning to one of:
|
||||
* (a) an inline call in the same js_Interpret;
|
||||
* (b) an "out of line" call made through js_Invoke;
|
||||
* (c) a js_Execute activation;
|
||||
* (d) a generator (SendToGenerator, jsiter.c).
|
||||
* (a) an "out of line" call made through js_Invoke;
|
||||
* (b) a js_Execute activation;
|
||||
* (c) a generator (SendToGenerator, jsiter.c).
|
||||
*
|
||||
* We must not be in an inline frame since the check above ensures that
|
||||
* for the error case and for a normal return the code jumps directly to
|
||||
* parent's frame pc.
|
||||
*/
|
||||
if (!ok) {
|
||||
for (obj = fp->scopeChain; obj; obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
clasp = OBJ_GET_CLASS(cx, obj);
|
||||
if (clasp != &js_WithClass && clasp != &js_BlockClass)
|
||||
break;
|
||||
if (OBJ_GET_PRIVATE(cx, obj) != fp || OBJ_BLOCK_DEPTH(cx, obj) < 0)
|
||||
break;
|
||||
if (clasp == &js_WithClass)
|
||||
js_EnablePropertyCache(cx);
|
||||
}
|
||||
}
|
||||
JS_ASSERT_IF(mark, JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
|
||||
|
||||
/*
|
||||
* Check whether control fell off the end of a lightweight function, or an
|
||||
* exception thrown under such a function was not caught by it. If so, go
|
||||
* to the inline code under JSOP_RETURN.
|
||||
*/
|
||||
if (inlineCallCount)
|
||||
goto inline_return;
|
||||
JS_ASSERT(inlineCallCount == 0);
|
||||
JS_ASSERT(JS_PROPERTY_CACHE(cx).disabled == fp->pcDisabledSave);
|
||||
|
||||
/*
|
||||
* Reset sp before freeing stack slots, because our caller may GC soon.
|
||||
@ -6804,26 +6812,20 @@ out:
|
||||
* Restore the previous frame's execution state.
|
||||
*/
|
||||
if (JS_LIKELY(mark != NULL)) {
|
||||
/* If fp has blocks on its scope chain, home their locals now. */
|
||||
if (fp->flags & JSFRAME_POP_BLOCKS) {
|
||||
SAVE_SP_AND_PC(fp);
|
||||
ok &= PutBlockObjects(cx, fp);
|
||||
}
|
||||
|
||||
JS_ASSERT(!fp->blockChain);
|
||||
JS_ASSERT(!IsActiveWithOrBlock(cx, fp->scopeChain, 0));
|
||||
JS_ASSERT(!(fp->flags & JSFRAME_GENERATOR));
|
||||
fp->sp = fp->spbase;
|
||||
fp->spbase = NULL;
|
||||
js_FreeRawStack(cx, mark);
|
||||
} else {
|
||||
SAVE_SP(fp);
|
||||
FreeRawStack(cx, mark);
|
||||
}
|
||||
|
||||
out2:
|
||||
if (cx->version == currentVersion && currentVersion != originalVersion)
|
||||
js_SetVersion(cx, originalVersion);
|
||||
cx->interpLevel--;
|
||||
return ok;
|
||||
|
||||
atom_not_defined:
|
||||
atom_not_defined:
|
||||
{
|
||||
const char *printable;
|
||||
|
||||
|
@ -360,10 +360,10 @@ js_ComputeThis(JSContext *cx, jsval *argv);
|
||||
* NB: js_Invoke requires that cx is currently running JS (i.e., that cx->fp
|
||||
* is non-null), and that vp points to the callee, |this| parameter, and
|
||||
* actual arguments of the call. [vp .. vp + 2 + argc) must belong to the last
|
||||
* JS stack segment that js_AllocStack or js_AllocRawStack allocated. The
|
||||
* function may use the space available after vp + 2 + argc in the stack
|
||||
* segment for temporaries so the caller should not use that space for values
|
||||
* that must be preserved across the call.
|
||||
* JS stack segment that js_AllocStack allocated. The function may use the
|
||||
* space available after vp + 2 + argc in the stack segment for temporaries,
|
||||
* so the caller should not use that space for values that must be preserved
|
||||
* across the call.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSBool)
|
||||
js_Invoke(JSContext *cx, uintN argc, jsval *vp, uintN flags);
|
||||
|
@ -1922,33 +1922,44 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
|
||||
* the prototype's scope harder!
|
||||
*/
|
||||
JSBool
|
||||
js_PutBlockObject(JSContext *cx, JSObject *obj)
|
||||
js_PutBlockObject(JSContext *cx, JSObject *obj, JSBool normalUnwind)
|
||||
{
|
||||
JSStackFrame *fp;
|
||||
uintN depth, slot;
|
||||
JSScopeProperty *sprop;
|
||||
|
||||
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
||||
JS_ASSERT(fp);
|
||||
depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||
for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) {
|
||||
if (sprop->getter != js_BlockClass.getProperty)
|
||||
continue;
|
||||
if (!(sprop->flags & SPROP_HAS_SHORTID))
|
||||
continue;
|
||||
slot = depth + (uintN)sprop->shortid;
|
||||
JS_ASSERT(slot < fp->script->depth);
|
||||
if (!js_DefineNativeProperty(cx, obj, sprop->id,
|
||||
fp->spbase[slot], NULL, NULL,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
SPROP_HAS_SHORTID, sprop->shortid,
|
||||
NULL)) {
|
||||
JS_SetPrivate(cx, obj, NULL);
|
||||
return JS_FALSE;
|
||||
if (normalUnwind) {
|
||||
fp = (JSStackFrame *) JS_GetPrivate(cx, obj);
|
||||
JS_ASSERT(fp);
|
||||
depth = OBJ_BLOCK_DEPTH(cx, obj);
|
||||
for (sprop = OBJ_SCOPE(obj)->lastProp; sprop; sprop = sprop->parent) {
|
||||
if (sprop->getter != js_BlockClass.getProperty)
|
||||
continue;
|
||||
if (!(sprop->flags & SPROP_HAS_SHORTID))
|
||||
continue;
|
||||
slot = depth + (uintN)sprop->shortid;
|
||||
JS_ASSERT(slot < fp->script->depth);
|
||||
if (!js_DefineNativeProperty(cx, obj, sprop->id,
|
||||
fp->spbase[slot], NULL, NULL,
|
||||
JSPROP_ENUMERATE | JSPROP_PERMANENT,
|
||||
SPROP_HAS_SHORTID, sprop->shortid,
|
||||
NULL)) {
|
||||
/*
|
||||
* Stop adding properties if we failed due to out-of-memory or
|
||||
* other quit-asap errors.
|
||||
*/
|
||||
if (!cx->throwing) {
|
||||
normalUnwind = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return JS_SetPrivate(cx, obj, NULL);
|
||||
out:
|
||||
/* We must clear the private slot even with errors. */
|
||||
JS_SetPrivate(cx, obj, NULL);
|
||||
return normalUnwind;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -350,7 +350,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, JSObject *parent,
|
||||
JSStackFrame *fp);
|
||||
|
||||
extern JSBool
|
||||
js_PutBlockObject(JSContext *cx, JSObject *obj);
|
||||
js_PutBlockObject(JSContext *cx, JSObject *obj, JSBool normalUnwind);
|
||||
|
||||
struct JSSharpObjectMap {
|
||||
jsrefcount depth;
|
||||
|
@ -202,7 +202,7 @@ JS_XDRFindClassById(JSXDRState *xdr, uint32 id);
|
||||
* before deserialization of bytecode. If the saved version does not match
|
||||
* the current version, abort deserialization and invalidate the file.
|
||||
*/
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 19)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 20)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
@ -66,7 +66,6 @@ js_Emit1 ; 63012
|
||||
JS_ContextIterator ; 57847
|
||||
JS_GetInstancePrivate ; 57817
|
||||
JS_HashTableRawRemove ; 57057
|
||||
js_AllocRawStack ; 54181
|
||||
js_Invoke ; 53568
|
||||
js_FindProperty ; 53150
|
||||
JS_GetFrameScript ; 51395
|
||||
@ -123,7 +122,6 @@ js_DestroyScope ; 17198
|
||||
JS_GetStringLength ; 16306
|
||||
js_PopStatementCG ; 15418
|
||||
JS_GetFrameAnnotation ; 14949
|
||||
js_FreeRawStack ; 14032
|
||||
js_Interpret ; 14032
|
||||
js_TransferScopeLock ; 13899
|
||||
JS_ResolveStandardClass ; 13645
|
||||
|
Loading…
Reference in New Issue
Block a user