mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 22:25:30 +00:00
Bug 379758: SETSP is removed
This commit is contained in:
parent
815166396c
commit
1972c7985b
26
js/src/js.c
26
js/src/js.c
@ -1068,19 +1068,29 @@ Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_STATIC_ASSERT(JSTN_CATCH == 0);
|
||||
JS_STATIC_ASSERT(JSTN_FINALLY == 1);
|
||||
|
||||
static const char* const TryNoteNames[] = { "catch", "finally" };
|
||||
|
||||
static JSBool
|
||||
TryNotes(JSContext *cx, JSScript *script)
|
||||
{
|
||||
JSTryNote *tn = script->trynotes;
|
||||
JSTryNote *tn, *tnlimit;
|
||||
|
||||
if (!tn)
|
||||
if (!script->trynotes)
|
||||
return JS_TRUE;
|
||||
fprintf(gOutFile, "\nException table:\nstart\tend\tcatch\n");
|
||||
while (tn->start && tn->catchStart) {
|
||||
fprintf(gOutFile, " %d\t%d\t%d\n",
|
||||
tn->start, tn->start + tn->length, tn->catchStart);
|
||||
tn++;
|
||||
}
|
||||
|
||||
tn = script->trynotes->notes;
|
||||
tnlimit = tn + script->trynotes->length;
|
||||
fprintf(gOutFile, "\nException table:\n"
|
||||
"kind stack start end\n");
|
||||
do {
|
||||
JS_ASSERT(tn->kind == JSTN_CATCH || tn->kind == JSTN_FINALLY);
|
||||
fprintf(gOutFile, " %-7s %6u %8u %8u\n",
|
||||
TryNoteNames[tn->kind], tn->stackDepth,
|
||||
tn->start, tn->start + tn->length);
|
||||
} while (++tn != tnlimit);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
|
@ -1492,7 +1492,6 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||
JSObject *obj;
|
||||
jsatomid i;
|
||||
jssrcnote *sn, *notes;
|
||||
JSTryNote *tn, *tnotes;
|
||||
JSPrincipals *principals;
|
||||
|
||||
nbytes = sizeof *script;
|
||||
@ -1513,11 +1512,9 @@ JS_GetScriptTotalSize(JSContext *cx, JSScript *script)
|
||||
continue;
|
||||
nbytes += (sn - notes + 1) * sizeof *sn;
|
||||
|
||||
tnotes = script->trynotes;
|
||||
if (tnotes) {
|
||||
for (tn = tnotes; tn->catchStart; tn++)
|
||||
continue;
|
||||
nbytes += (tn - tnotes + 1) * sizeof *tn;
|
||||
if (script->trynotes) {
|
||||
nbytes += offsetof(JSTryNoteArray, notes) +
|
||||
script->trynotes->length * sizeof script->trynotes->notes[0];
|
||||
}
|
||||
|
||||
principals = script->principals;
|
||||
|
122
js/src/jsemit.c
122
js/src/jsemit.c
@ -1079,16 +1079,6 @@ OptimizeSpanDeps(JSContext *cx, JSCodeGenerator *cg)
|
||||
sd2 = FindNearestSpanDep(cg, offset + length, sd - sdbase, &guard);
|
||||
if (sd2 != sd)
|
||||
tn->length = length + sd2->offset - sd2->before - delta;
|
||||
|
||||
/*
|
||||
* Finally, adjust tn->catchStart upward only if it is non-zero,
|
||||
* and provided there are spandeps below it that grew.
|
||||
*/
|
||||
offset = tn->catchStart;
|
||||
if (offset != 0) {
|
||||
sd = FindNearestSpanDep(cg, offset, sd2 - sdbase, &guard);
|
||||
tn->catchStart = offset + sd->offset - sd->before;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4812,11 +4802,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
|
||||
case TOK_TRY:
|
||||
{
|
||||
ptrdiff_t start, end, catchJump, catchStart, finallyCatch;
|
||||
ptrdiff_t tryStart, tryEnd, catchJump, finallyStart;
|
||||
intN depth;
|
||||
JSParseNode *lastCatch;
|
||||
|
||||
catchJump = catchStart = finallyCatch = -1;
|
||||
catchJump = -1;
|
||||
|
||||
/*
|
||||
* Push stmtInfo to track jumps-over-catches and gosubs-to-finally
|
||||
@ -4832,22 +4822,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
CG_OFFSET(cg));
|
||||
|
||||
/*
|
||||
* About JSOP_SETSP: an exception can be thrown while the stack is in
|
||||
* an unbalanced state, and this imbalance causes problems with things
|
||||
* like function invocation later on.
|
||||
* Since an exception can be thrown at any place inside the try block,
|
||||
* we need to restore the stack and the scope chain before we transfer
|
||||
* the control to the exception handler.
|
||||
*
|
||||
* To fix this, we compute the 'balanced' stack depth upon try entry,
|
||||
* and then restore the stack to this depth when we hit the first catch
|
||||
* or finally block. We can't just zero the stack, because things like
|
||||
* for/in and with that are active upon entry to the block keep state
|
||||
* variables on the stack.
|
||||
* For that we store in a try note associated with the catch or
|
||||
* finally block the stack depth upon the try entry. The interpreter
|
||||
* uses this depth to properly unwind the stack and the scope chain.
|
||||
*/
|
||||
depth = cg->stackDepth;
|
||||
|
||||
/* Mark try location for decompilation, then emit try block. */
|
||||
if (js_Emit1(cx, cg, JSOP_TRY) < 0)
|
||||
return JS_FALSE;
|
||||
start = CG_OFFSET(cg);
|
||||
tryStart = CG_OFFSET(cg);
|
||||
if (!js_EmitTree(cx, cg, pn->pn_kid1))
|
||||
return JS_FALSE;
|
||||
|
||||
@ -4870,7 +4858,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
end = CG_OFFSET(cg);
|
||||
tryEnd = CG_OFFSET(cg);
|
||||
|
||||
/* If this try has a catch block, emit it. */
|
||||
pn2 = pn->pn_kid2;
|
||||
@ -4878,8 +4866,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (pn2) {
|
||||
jsint count = 0; /* previous catch block's population */
|
||||
|
||||
catchStart = end;
|
||||
|
||||
/*
|
||||
* The emitted code for a catch block looks like:
|
||||
*
|
||||
@ -4905,12 +4891,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) {
|
||||
ptrdiff_t guardJump, catchNote;
|
||||
|
||||
JS_ASSERT(cg->stackDepth == depth);
|
||||
guardJump = GUARDJUMP(stmtInfo);
|
||||
if (guardJump == -1) {
|
||||
/* Set stack to original depth (see SETSP comment above). */
|
||||
EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);
|
||||
cg->stackDepth = depth;
|
||||
} else {
|
||||
if (guardJump != -1) {
|
||||
/* Fix up and clean up previous catch block. */
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, guardJump);
|
||||
|
||||
@ -4918,7 +4901,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* Account for the pushed exception object that we still
|
||||
* have after the jumping from the previous guard.
|
||||
*/
|
||||
JS_ASSERT(cg->stackDepth == depth);
|
||||
cg->stackDepth = depth + 1;
|
||||
|
||||
/*
|
||||
@ -5017,24 +4999,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
JS_ASSERT(cg->stackDepth == depth);
|
||||
|
||||
/* Emit finally handler if any. */
|
||||
finallyStart = 0; /* to quell GCC uninitialized warnings */
|
||||
if (pn->pn_kid3) {
|
||||
/*
|
||||
* We emit [setsp][gosub] to call try-finally when an exception is
|
||||
* thrown from try or try-catch blocks. The [gosub] and [retsub]
|
||||
* opcodes will take care of stacking and rethrowing any exception
|
||||
* pending across the finally.
|
||||
*/
|
||||
finallyCatch = CG_OFFSET(cg);
|
||||
EMIT_UINT16_IMM_OP(JSOP_SETSP, (jsatomid)depth);
|
||||
|
||||
jmp = EmitBackPatchOp(cx, cg, JSOP_BACKPATCH,
|
||||
&GOSUBS(stmtInfo));
|
||||
if (jmp < 0)
|
||||
return JS_FALSE;
|
||||
|
||||
JS_ASSERT(cg->stackDepth == depth);
|
||||
JS_ASSERT((uintN)depth <= cg->maxStackDepth);
|
||||
|
||||
/*
|
||||
* Fix up the gosubs that might have been emitted before non-local
|
||||
* jumps to the finally code.
|
||||
@ -5042,13 +5008,20 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
if (!BackPatch(cx, cg, GOSUBS(stmtInfo), CG_NEXT(cg), JSOP_GOSUB))
|
||||
return JS_FALSE;
|
||||
|
||||
finallyStart = CG_OFFSET(cg);
|
||||
|
||||
/*
|
||||
* The stack budget must be balanced at this point. All [gosub]
|
||||
* calls emitted before this point will push two stack slots, one
|
||||
* for the pending exception (or JSVAL_HOLE if there is no pending
|
||||
* exception) and one for the [retsub] pc-index.
|
||||
* The stack depth at the begining of finally must match the try
|
||||
* depth plus 2 slots. The interpreter uses these two slots to
|
||||
* either push (true, exception) pair when it transfers control
|
||||
* flow to the finally after capturing an exception, or to push
|
||||
* (false, pc-index) when it calls finally from [gosub]. The first
|
||||
* element of the pair indicates for [retsub] that it should
|
||||
* either rethrow the pending exception or transfer the control
|
||||
* back to the caller of finally.
|
||||
*/
|
||||
JS_ASSERT(cg->stackDepth == depth);
|
||||
JS_ASSERT((uintN)depth <= cg->maxStackDepth);
|
||||
cg->stackDepth += 2;
|
||||
if ((uintN)cg->stackDepth > cg->maxStackDepth)
|
||||
cg->maxStackDepth = cg->stackDepth;
|
||||
@ -5083,10 +5056,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* Add the try note last, to let post-order give us the right ordering
|
||||
* (first to last for a given nesting level, inner to outer by level).
|
||||
*/
|
||||
if (pn->pn_kid2) {
|
||||
JS_ASSERT(end != -1 && catchStart != -1);
|
||||
if (!js_NewTryNote(cx, cg, start, end, catchStart))
|
||||
return JS_FALSE;
|
||||
if (pn->pn_kid2 &&
|
||||
!js_NewTryNote(cx, cg, JSTN_CATCH, depth, tryStart, tryEnd)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5094,10 +5066,10 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
||||
* trynote to catch exceptions (re)thrown from a catch block or
|
||||
* for the try{}finally{} case.
|
||||
*/
|
||||
if (pn->pn_kid3) {
|
||||
JS_ASSERT(finallyCatch != -1);
|
||||
if (!js_NewTryNote(cx, cg, start, finallyCatch, finallyCatch))
|
||||
return JS_FALSE;
|
||||
if (pn->pn_kid3 &&
|
||||
!js_NewTryNote(cx, cg, JSTN_FINALLY, depth, tryStart,
|
||||
finallyStart)) {
|
||||
return JS_FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -6910,31 +6882,29 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg)
|
||||
}
|
||||
|
||||
JSTryNote *
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
||||
ptrdiff_t end, ptrdiff_t catchStart)
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
|
||||
uintN stackDepth, size_t start, size_t end)
|
||||
{
|
||||
JSTryNote *tn;
|
||||
|
||||
JS_ASSERT(cg->tryBase <= cg->tryNext);
|
||||
JS_ASSERT(catchStart >= 0);
|
||||
JS_ASSERT(kind == JSTN_FINALLY || kind == JSTN_CATCH);
|
||||
JS_ASSERT((uintN)(uint16)stackDepth == stackDepth);
|
||||
JS_ASSERT(start <= end);
|
||||
JS_ASSERT((size_t)(uint32)start == start);
|
||||
JS_ASSERT((size_t)(uint32)end == end);
|
||||
tn = cg->tryNext++;
|
||||
tn->start = start;
|
||||
tn->length = end - start;
|
||||
tn->catchStart = catchStart;
|
||||
tn->kind = kind;
|
||||
tn->stackDepth = (uint16)stackDepth;
|
||||
tn->start = (uint32)start;
|
||||
tn->length = (uint32)(end - start);
|
||||
return tn;
|
||||
}
|
||||
|
||||
void
|
||||
js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote *notes)
|
||||
js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg,
|
||||
JSTryNoteArray *array)
|
||||
{
|
||||
uintN count;
|
||||
|
||||
count = PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote);
|
||||
if (!count)
|
||||
return;
|
||||
|
||||
memcpy(notes, cg->tryBase, TRYNOTE_SIZE(count));
|
||||
notes[count].start = 0;
|
||||
notes[count].length = CG_OFFSET(cg);
|
||||
notes[count].catchStart = 0;
|
||||
JS_ASSERT(cg->tryNext - cg->tryBase == array->length);
|
||||
memcpy(array->notes, cg->tryBase, TRYNOTE_SIZE(array->length));
|
||||
}
|
||||
|
@ -48,6 +48,7 @@
|
||||
#include "jstypes.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsopcode.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
@ -718,24 +719,12 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg);
|
||||
* Grab the next trynote slot in cg, filling it in appropriately.
|
||||
*/
|
||||
extern JSTryNote *
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start,
|
||||
ptrdiff_t end, ptrdiff_t catchStart);
|
||||
|
||||
/*
|
||||
* Finish generating exception information into the space at notes. As with
|
||||
* js_FinishTakingSrcNotes, the caller must use CG_COUNT_FINAL_TRYNOTES(cg) to
|
||||
* preallocate enough space in a JSTryNote[] to pass as the notes parameter of
|
||||
* js_FinishTakingTryNotes.
|
||||
*/
|
||||
#define CG_COUNT_FINAL_TRYNOTES(cg, cnt) \
|
||||
JS_BEGIN_MACRO \
|
||||
cnt = ((cg)->tryNext > (cg)->tryBase) \
|
||||
? PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote) + 1 \
|
||||
: 0; \
|
||||
JS_END_MACRO
|
||||
js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind,
|
||||
uintN stackDepth, size_t start, size_t end);
|
||||
|
||||
extern void
|
||||
js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote *notes);
|
||||
js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg,
|
||||
JSTryNoteArray *array);
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
|
@ -1144,7 +1144,7 @@ FindAndMarkObjectsToClose(JSTracer *trc, JSGCInvocationKind gckind)
|
||||
|
||||
*genp = gen->next;
|
||||
if (gen->state == JSGEN_OPEN &&
|
||||
js_FindFinallyHandler(gen->frame.script, gen->frame.pc) &&
|
||||
js_IsInsideTryWithFinally(gen->frame.script, gen->frame.pc) &&
|
||||
CanScheduleCloseHook(gen)) {
|
||||
/*
|
||||
* Generator yielded inside a try with a finally block.
|
||||
|
@ -5291,65 +5291,15 @@ interrupt:
|
||||
EMPTY_CASE(JSOP_TRY)
|
||||
EMPTY_CASE(JSOP_FINALLY)
|
||||
|
||||
/* Reset the stack to the given depth. */
|
||||
BEGIN_CASE(JSOP_SETSP)
|
||||
i = (jsint) GET_UINT16(pc);
|
||||
|
||||
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)) == &js_WithClass ||
|
||||
clasp == &js_BlockClass;
|
||||
obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
if (JS_GetPrivate(cx, obj) != fp ||
|
||||
OBJ_BLOCK_DEPTH(cx, obj) < i) {
|
||||
break;
|
||||
}
|
||||
if (clasp == &js_BlockClass)
|
||||
ok &= js_PutBlockObject(cx, obj);
|
||||
else
|
||||
JS_SetPrivate(cx, obj, NULL);
|
||||
}
|
||||
|
||||
fp->scopeChain = obj;
|
||||
|
||||
/* Set sp after js_PutBlockObject to avoid potential GC hazards. */
|
||||
sp = fp->spbase + i;
|
||||
|
||||
/* Don't fail until after we've updated all stacks. */
|
||||
if (!ok)
|
||||
goto out;
|
||||
END_CASE(JSOP_SETSP)
|
||||
|
||||
BEGIN_CASE(JSOP_GOSUB)
|
||||
JS_ASSERT(cx->exception != JSVAL_HOLE);
|
||||
if (!cx->throwing) {
|
||||
lval = JSVAL_HOLE;
|
||||
} else {
|
||||
lval = cx->exception;
|
||||
cx->throwing = JS_FALSE;
|
||||
}
|
||||
PUSH(lval);
|
||||
PUSH(JSVAL_FALSE);
|
||||
i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUB_LENGTH;
|
||||
len = GET_JUMP_OFFSET(pc);
|
||||
PUSH(INT_TO_JSVAL(i));
|
||||
END_VARLEN_CASE
|
||||
|
||||
BEGIN_CASE(JSOP_GOSUBX)
|
||||
JS_ASSERT(cx->exception != JSVAL_HOLE);
|
||||
if (!cx->throwing) {
|
||||
lval = JSVAL_HOLE;
|
||||
} else {
|
||||
lval = cx->exception;
|
||||
cx->throwing = JS_FALSE;
|
||||
}
|
||||
PUSH(lval);
|
||||
PUSH(JSVAL_FALSE);
|
||||
i = PTRDIFF(pc, script->main, jsbytecode) + JSOP_GOSUBX_LENGTH;
|
||||
len = GET_JUMPX_OFFSET(pc);
|
||||
PUSH(INT_TO_JSVAL(i));
|
||||
@ -5357,9 +5307,9 @@ interrupt:
|
||||
|
||||
BEGIN_CASE(JSOP_RETSUB)
|
||||
rval = POP();
|
||||
JS_ASSERT(JSVAL_IS_INT(rval));
|
||||
lval = POP();
|
||||
if (lval != JSVAL_HOLE) {
|
||||
JS_ASSERT(JSVAL_IS_BOOLEAN(lval));
|
||||
if (JSVAL_TO_BOOLEAN(lval)) {
|
||||
/*
|
||||
* Exception was pending during finally, throw it *before* we
|
||||
* adjust pc, because pc indexes into script->trynotes. This
|
||||
@ -5367,10 +5317,11 @@ interrupt:
|
||||
* it points out a FIXME: 350509, due to Igor Bukanov.
|
||||
*/
|
||||
cx->throwing = JS_TRUE;
|
||||
cx->exception = lval;
|
||||
cx->exception = rval;
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
JS_ASSERT(JSVAL_IS_INT(rval));
|
||||
len = JSVAL_TO_INT(rval);
|
||||
pc = script->main;
|
||||
END_VARLEN_CASE
|
||||
@ -5993,6 +5944,7 @@ interrupt:
|
||||
#if JS_THREADED_INTERP
|
||||
L_JSOP_BACKPATCH:
|
||||
L_JSOP_BACKPATCH_POP:
|
||||
L_JSOP_UNUSED117:
|
||||
#else
|
||||
default:
|
||||
#endif
|
||||
@ -6050,6 +6002,7 @@ interrupt:
|
||||
#endif /* !JS_THREADED_INTERP */
|
||||
|
||||
out:
|
||||
JS_ASSERT((size_t)(pc - script->code) < script->length);
|
||||
if (!ok) {
|
||||
/*
|
||||
* Has an exception been raised? Also insist that we are not in an
|
||||
@ -6076,10 +6029,14 @@ out:
|
||||
* FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=309894
|
||||
*/
|
||||
if (cx->throwing && !(fp->flags & JSFRAME_FILTERING)) {
|
||||
JSTrapHandler handler;
|
||||
JSTryNote *tn, *tnlimit;
|
||||
uint32 offset;
|
||||
|
||||
/*
|
||||
* Call debugger throw hook if set (XXX thread safety?).
|
||||
*/
|
||||
JSTrapHandler handler = rt->throwHook;
|
||||
handler = rt->throwHook;
|
||||
if (handler) {
|
||||
SAVE_SP_AND_PC(fp);
|
||||
switch (handler(cx, script, pc, &rval, rt->throwHookData)) {
|
||||
@ -6102,27 +6059,100 @@ out:
|
||||
/*
|
||||
* Look for a try block in script that can catch this exception.
|
||||
*/
|
||||
if (!script->trynotes)
|
||||
goto no_catch;
|
||||
|
||||
offset = (uint32)(pc - script->main);
|
||||
tn = script->trynotes->notes;
|
||||
tnlimit = tn + script->trynotes->length;
|
||||
for (;;) {
|
||||
if (offset - tn->start < tn->length) {
|
||||
if (tn->kind == JSTN_FINALLY)
|
||||
break;
|
||||
JS_ASSERT(tn->kind == JSTN_CATCH);
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_LIKELY(cx->exception != JSVAL_ARETURN)) {
|
||||
SCRIPT_FIND_CATCH_START(script, pc, pc);
|
||||
if (!pc)
|
||||
goto no_catch;
|
||||
} else {
|
||||
pc = js_FindFinallyHandler(script, pc);
|
||||
if (!pc) {
|
||||
cx->throwing = JS_FALSE;
|
||||
ok = JS_TRUE;
|
||||
fp->rval = JSVAL_VOID;
|
||||
/* Catch can not intercept closing of a generator. */
|
||||
if (JS_LIKELY(cx->exception != JSVAL_ARETURN))
|
||||
break;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (++tn == tnlimit) {
|
||||
#if JS_HAS_GENERATORS
|
||||
if (JS_UNLIKELY(cx->exception == JSVAL_ARETURN)) {
|
||||
cx->throwing = JS_FALSE;
|
||||
ok = JS_TRUE;
|
||||
fp->rval = JSVAL_VOID;
|
||||
}
|
||||
#endif
|
||||
goto no_catch;
|
||||
}
|
||||
}
|
||||
#else
|
||||
SCRIPT_FIND_CATCH_START(script, pc, pc);
|
||||
if (!pc)
|
||||
goto no_catch;
|
||||
#endif
|
||||
|
||||
/* Don't clear cx->throwing to save cx->exception from GC. */
|
||||
ok = JS_TRUE;
|
||||
|
||||
/*
|
||||
* Unwind the block and scope chains until we match the stack
|
||||
* depth of the try note.
|
||||
*/
|
||||
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)) == &js_WithClass ||
|
||||
clasp == &js_BlockClass;
|
||||
obj = OBJ_GET_PARENT(cx, obj)) {
|
||||
if (JS_GetPrivate(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);
|
||||
} else {
|
||||
JS_SetPrivate(cx, obj, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
fp->scopeChain = obj;
|
||||
|
||||
/* Set sp after js_PutBlockObject to avoid potential GC hazards. */
|
||||
sp = fp->spbase + i;
|
||||
|
||||
/* The catch or finally begins right after the code they protect. */
|
||||
pc = (script)->main + tn->start + tn->length;
|
||||
|
||||
/*
|
||||
* When failing during the scope recovery, restart the exception
|
||||
* search with the updated stack and pc.
|
||||
*/
|
||||
if (!ok)
|
||||
goto out;
|
||||
|
||||
JS_ASSERT(cx->exception != JSVAL_HOLE);
|
||||
if (tn->kind == JSTN_FINALLY) {
|
||||
/*
|
||||
* Push (false, exception) pair for finally to indicate that
|
||||
* [retsub] should rethrow the exception.
|
||||
*/
|
||||
PUSH(JSVAL_TRUE);
|
||||
PUSH(cx->exception);
|
||||
cx->throwing = JS_FALSE;
|
||||
} else {
|
||||
/*
|
||||
* Don't clear cx->throwing to save cx->exception from GC
|
||||
* until it is pushed to the stack via [exception] in the
|
||||
* catch block.
|
||||
*/
|
||||
}
|
||||
|
||||
len = 0;
|
||||
ok = JS_TRUE;
|
||||
DO_NEXT_OP(len);
|
||||
|
@ -2103,9 +2103,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
jp->indent += 4;
|
||||
|
||||
/*
|
||||
* We must push an empty string placeholder for gosub's return
|
||||
* address, popped by JSOP_RETSUB and counted by script->depth
|
||||
* but not by ss->top (see JSOP_SETSP, below).
|
||||
* We push push the pair of exception/restsub cookies to
|
||||
* simulate the effects [gosub] or control transfer during
|
||||
* exception capturing on the stack.
|
||||
*/
|
||||
todo = Sprint(&ss->sprinter, exception_cookie);
|
||||
if (todo < 0 || !PushOff(ss, todo, op))
|
||||
@ -2139,7 +2139,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
todo = -2;
|
||||
break;
|
||||
|
||||
case JSOP_SETSP:
|
||||
case JSOP_POPN:
|
||||
{
|
||||
uintN newtop, oldtop, i;
|
||||
@ -2150,10 +2149,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
* The decompiler must match the code generator's model, which
|
||||
* is why JSOP_FINALLY pushes a cookie that JSOP_RETSUB pops.
|
||||
*/
|
||||
newtop = GET_UINT16(pc);
|
||||
oldtop = ss->top;
|
||||
if (op == JSOP_POPN)
|
||||
newtop = oldtop - newtop;
|
||||
newtop = oldtop - GET_UINT16(pc);
|
||||
LOCAL_ASSERT(newtop <= oldtop);
|
||||
todo = -2;
|
||||
|
||||
@ -2182,7 +2179,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
* Kill newtop before the end_groupassignment: label by
|
||||
* retracting/popping early. Control will either jump to
|
||||
* do_forloop: or do_letheadbody: or else break from our
|
||||
* case JSOP_SETSP: after the switch (*pc2) below.
|
||||
* case JSOP_POPN: after the switch (*pc2) below.
|
||||
*/
|
||||
if (newtop < oldtop) {
|
||||
ss->sprinter.offset = GetOff(ss, newtop);
|
||||
@ -2225,7 +2222,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
LOCAL_ASSERT(pc[len] == JSOP_LEAVEBLOCK);
|
||||
js_printf(jp, "\tlet (%s) {\n", rval);
|
||||
js_printf(jp, "\t}\n");
|
||||
goto end_setsp;
|
||||
goto end_popn;
|
||||
}
|
||||
todo = SprintCString(&ss->sprinter, rval);
|
||||
if (todo < 0 || !PushOff(ss, todo, JSOP_NOP))
|
||||
@ -2255,7 +2252,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
||||
*/
|
||||
if (todo == -2)
|
||||
js_printf(jp, "\t%s;\n", rval);
|
||||
end_setsp:
|
||||
end_popn:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -4954,10 +4951,6 @@ js_DecompileValueGenerator(JSContext *cx, intN spindex, jsval v,
|
||||
cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
|
||||
if (op == JSOP_SETSP) {
|
||||
pcdepth = GET_UINT16(pc);
|
||||
continue;
|
||||
}
|
||||
if (op == JSOP_POPN) {
|
||||
pcdepth -= GET_UINT16(pc);
|
||||
continue;
|
||||
|
@ -262,7 +262,7 @@ OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
/* More exception handling ops. */
|
||||
OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_SETSP, 117,"setsp", NULL, 3, 0, 0, 0, JOF_UINT16)
|
||||
OPDEF(JSOP_UNUSED117, 117,"", NULL, 0, 0, 0, 0, 0)
|
||||
|
||||
/*
|
||||
* ECMA-compliant switch statement ops.
|
||||
|
@ -390,6 +390,54 @@ out:
|
||||
|
||||
#endif /* JS_HAS_SCRIPT_OBJECT */
|
||||
|
||||
|
||||
/*
|
||||
* JSTryNoteArray is allocated after script notes and an extra gap to ensure
|
||||
* that JSTryNoteArray is alligned on sizeof(uint32) boundary, the maximum
|
||||
* size of JSTryNoteArray.length and JSTryNote fields.
|
||||
*/
|
||||
JS_STATIC_ASSERT(sizeof(JSTryNote) == 3 * sizeof(uint32));
|
||||
JS_STATIC_ASSERT(sizeof(JSTryNoteArray) == 4 * sizeof(uint32));
|
||||
|
||||
#define JSTRYNOTE_ALIGNMASK (sizeof(uint32) - 1)
|
||||
|
||||
/*
|
||||
* Calculate the amount of memory required for a script.
|
||||
*/
|
||||
static size_t
|
||||
GetScriptSize(uint32 bytecodeLength, uint32 nsrcnotes, uint32 ntrynotes)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = sizeof(JSScript) +
|
||||
bytecodeLength * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote);
|
||||
if (ntrynotes != 0) {
|
||||
size += JSTRYNOTE_ALIGNMASK +
|
||||
offsetof(JSTryNoteArray, notes) +
|
||||
ntrynotes * sizeof(JSTryNote);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static void
|
||||
InitScriptTryNotes(JSScript *script, uint32 bytecodeLength, uint32 nsrcnotes,
|
||||
uint32 ntrynotes)
|
||||
{
|
||||
size_t offset;
|
||||
|
||||
JS_ASSERT(ntrynotes != 0);
|
||||
offset = sizeof(JSScript) +
|
||||
bytecodeLength * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote) +
|
||||
JSTRYNOTE_ALIGNMASK;
|
||||
script->trynotes = (JSTryNoteArray *)(((jsword)script + offset) &
|
||||
~(jsword)JSTRYNOTE_ALIGNMASK);
|
||||
script->trynotes->length = ntrynotes;
|
||||
memset(script->trynotes->notes, 0,
|
||||
ntrynotes * sizeof script->trynotes->notes[0]);
|
||||
}
|
||||
|
||||
#if JS_HAS_XDR
|
||||
|
||||
static JSBool
|
||||
@ -517,12 +565,7 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
||||
nsrcnotes = PTRDIFF(sn, notes, jssrcnote);
|
||||
nsrcnotes++; /* room for the terminator */
|
||||
|
||||
/* Count the trynotes. */
|
||||
if (script->trynotes) {
|
||||
while (script->trynotes[ntrynotes].catchStart)
|
||||
ntrynotes++;
|
||||
ntrynotes++; /* room for the end marker */
|
||||
}
|
||||
ntrynotes = script->trynotes ? script->trynotes->length : 0;
|
||||
}
|
||||
|
||||
if (!JS_XDRUint32(xdr, &length))
|
||||
@ -649,53 +692,47 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic)
|
||||
script->depth = (uintN)depth;
|
||||
|
||||
if (magic < JSXDR_MAGIC_SCRIPT_4) {
|
||||
size_t scriptSize;
|
||||
|
||||
/*
|
||||
* Argh, we have to reallocate script, copy notes into the extra
|
||||
* space after the bytecodes, and free the temporary notes vector.
|
||||
* First, add enough slop to nsrcnotes so we can align the address
|
||||
* after the srcnotes of the first trynote.
|
||||
*/
|
||||
uint32 osrcnotes = nsrcnotes;
|
||||
|
||||
if (ntrynotes)
|
||||
nsrcnotes += JSTRYNOTE_ALIGNMASK;
|
||||
newscript = (JSScript *) JS_realloc(cx, script,
|
||||
sizeof(JSScript) +
|
||||
length * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote) +
|
||||
ntrynotes * sizeof(JSTryNote));
|
||||
scriptSize = GetScriptSize(length, nsrcnotes, ntrynotes);
|
||||
newscript = (JSScript *) JS_realloc(cx, script, scriptSize);
|
||||
if (!newscript)
|
||||
goto error;
|
||||
|
||||
*scriptp = script = newscript;
|
||||
script->code = (jsbytecode *)(script + 1);
|
||||
script->main = script->code + prologLength;
|
||||
memcpy(script->code + length, notes, osrcnotes * sizeof(jssrcnote));
|
||||
memcpy(script->code + length, notes, nsrcnotes * sizeof(jssrcnote));
|
||||
JS_free(cx, (void *) notes);
|
||||
notes = NULL;
|
||||
if (ntrynotes) {
|
||||
script->trynotes = (JSTryNote *)
|
||||
((jsword)(SCRIPT_NOTES(script) + nsrcnotes) &
|
||||
~(jsword)JSTRYNOTE_ALIGNMASK);
|
||||
memset(script->trynotes, 0, ntrynotes * sizeof(JSTryNote));
|
||||
}
|
||||
if (ntrynotes)
|
||||
InitScriptTryNotes(script, length, nsrcnotes, ntrynotes);
|
||||
}
|
||||
}
|
||||
|
||||
while (ntrynotes) {
|
||||
JSTryNote *tn = &script->trynotes[--ntrynotes];
|
||||
uint32 start = (uint32) tn->start,
|
||||
catchLength = (uint32) tn->length,
|
||||
catchStart = (uint32) tn->catchStart;
|
||||
/*
|
||||
* We combine kind and stackDepth when serializing as XDR is not
|
||||
* efficient when serializing small integer types.
|
||||
*/
|
||||
JSTryNote *tn = &script->trynotes->notes[--ntrynotes];
|
||||
uint32 kindAndDepth = ((uint32)tn->kind << 16) | (uint32)tn->stackDepth;
|
||||
JS_STATIC_ASSERT(sizeof(tn->kind) == sizeof(uint8));
|
||||
JS_STATIC_ASSERT(sizeof(tn->stackDepth) == sizeof(uint16));
|
||||
|
||||
if (!JS_XDRUint32(xdr, &start) ||
|
||||
!JS_XDRUint32(xdr, &catchLength) ||
|
||||
!JS_XDRUint32(xdr, &catchStart)) {
|
||||
if (!JS_XDRUint32(xdr, &kindAndDepth) ||
|
||||
!JS_XDRUint32(xdr, &tn->start) ||
|
||||
!JS_XDRUint32(xdr, &tn->length)) {
|
||||
goto error;
|
||||
}
|
||||
tn->start = (ptrdiff_t) start;
|
||||
tn->length = (ptrdiff_t) catchLength;
|
||||
tn->catchStart = (ptrdiff_t) catchStart;
|
||||
tn->kind = (uint8)(kindAndDepth >> 16);
|
||||
tn->stackDepth = (uint16)kindAndDepth;
|
||||
}
|
||||
|
||||
xdr->script = oldscript;
|
||||
@ -1345,26 +1382,16 @@ js_NewScript(JSContext *cx, uint32 length, uint32 nsrcnotes, uint32 ntrynotes)
|
||||
{
|
||||
JSScript *script;
|
||||
|
||||
/* Round up source note count to align script->trynotes for its type. */
|
||||
if (ntrynotes)
|
||||
nsrcnotes += JSTRYNOTE_ALIGNMASK;
|
||||
script = (JSScript *) JS_malloc(cx,
|
||||
sizeof(JSScript) +
|
||||
length * sizeof(jsbytecode) +
|
||||
nsrcnotes * sizeof(jssrcnote) +
|
||||
ntrynotes * sizeof(JSTryNote));
|
||||
script = (JSScript *) JS_malloc(cx, GetScriptSize(length, nsrcnotes,
|
||||
ntrynotes));
|
||||
if (!script)
|
||||
return NULL;
|
||||
memset(script, 0, sizeof(JSScript));
|
||||
script->code = script->main = (jsbytecode *)(script + 1);
|
||||
script->length = length;
|
||||
script->version = cx->version;
|
||||
if (ntrynotes) {
|
||||
script->trynotes = (JSTryNote *)
|
||||
((jsword)(SCRIPT_NOTES(script) + nsrcnotes) &
|
||||
~(jsword)JSTRYNOTE_ALIGNMASK);
|
||||
memset(script->trynotes, 0, ntrynotes * sizeof(JSTryNote));
|
||||
}
|
||||
if (ntrynotes != 0)
|
||||
InitScriptTryNotes(script, length, nsrcnotes, ntrynotes);
|
||||
return script;
|
||||
}
|
||||
|
||||
@ -1378,7 +1405,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun)
|
||||
mainLength = CG_OFFSET(cg);
|
||||
prologLength = CG_PROLOG_OFFSET(cg);
|
||||
CG_COUNT_FINAL_SRCNOTES(cg, nsrcnotes);
|
||||
CG_COUNT_FINAL_TRYNOTES(cg, ntrynotes);
|
||||
ntrynotes = (uint32)(cg->tryNext - cg->tryBase);
|
||||
script = js_NewScript(cx, prologLength + mainLength, nsrcnotes, ntrynotes);
|
||||
if (!script)
|
||||
return NULL;
|
||||
@ -1680,40 +1707,30 @@ js_GetScriptLineExtent(JSScript *script)
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
|
||||
jsbytecode *
|
||||
js_FindFinallyHandler(JSScript *script, jsbytecode *pc)
|
||||
JSBool
|
||||
js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc)
|
||||
{
|
||||
JSTryNote *tn;
|
||||
ptrdiff_t off;
|
||||
JSOp op2;
|
||||
JSTryNote *tn, *tnlimit;
|
||||
uint32 off;
|
||||
|
||||
tn = script->trynotes;
|
||||
if (!tn)
|
||||
return NULL;
|
||||
JS_ASSERT(script->code <= pc);
|
||||
JS_ASSERT(pc < script->code + script->length);
|
||||
|
||||
off = pc - script->main;
|
||||
if (off < 0)
|
||||
return NULL;
|
||||
if (!script->trynotes)
|
||||
return JS_FALSE;
|
||||
JS_ASSERT(script->trynotes->length != 0);
|
||||
|
||||
JS_ASSERT(tn->catchStart != 0);
|
||||
tn = script->trynotes->notes;
|
||||
tnlimit = tn + script->trynotes->length;
|
||||
off = (uint32)(pc - script->main);
|
||||
do {
|
||||
if ((jsuword)(off - tn->start) < (jsuword)tn->length) {
|
||||
/*
|
||||
* We have a handler: is it the finally one, or a catch handler?
|
||||
*
|
||||
* Catch bytecode begins with: JSOP_SETSP JSOP_ENTERBLOCK
|
||||
* Finally bytecode begins with: JSOP_SETSP JSOP_(GOSUB|EXCEPTION)
|
||||
*/
|
||||
pc = script->main + tn->catchStart;
|
||||
JS_ASSERT(*pc == JSOP_SETSP);
|
||||
op2 = pc[JSOP_SETSP_LENGTH];
|
||||
if (op2 != JSOP_ENTERBLOCK) {
|
||||
JS_ASSERT(op2 == JSOP_GOSUB || op2 == JSOP_EXCEPTION);
|
||||
return pc;
|
||||
}
|
||||
if (off - tn->start < tn->length) {
|
||||
if (tn->kind == JSTN_FINALLY)
|
||||
return JS_TRUE;
|
||||
JS_ASSERT(tn->kind == JSTN_CATCH);
|
||||
}
|
||||
} while ((++tn)->catchStart != 0);
|
||||
return NULL;
|
||||
} while (++tn != tnlimit);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
@ -49,20 +50,29 @@
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Exception handling runtime information.
|
||||
*
|
||||
* All fields except length are code offsets relative to the main entry point
|
||||
* of the script. If script->trynotes is not null, it points to a vector of
|
||||
* these structs terminated by one with catchStart == 0.
|
||||
* Type of try note associated with each catch block or finally block.
|
||||
*/
|
||||
typedef enum JSTryNoteKind {
|
||||
JSTN_CATCH,
|
||||
JSTN_FINALLY
|
||||
} JSTryNoteKind;
|
||||
|
||||
/*
|
||||
* Exception handling record.
|
||||
*/
|
||||
struct JSTryNote {
|
||||
ptrdiff_t start; /* start of try statement */
|
||||
ptrdiff_t length; /* count of try statement bytecodes */
|
||||
ptrdiff_t catchStart; /* start of catch block (0 if end) */
|
||||
uint8 kind; /* one of JSTryNoteKind */
|
||||
uint8 padding; /* explicit padding on uint16 boundary */
|
||||
uint16 stackDepth; /* stack depth upon exception handler entry */
|
||||
uint32 start; /* start of the try statement relative to
|
||||
script->main */
|
||||
uint32 length; /* length of the try statement */
|
||||
};
|
||||
|
||||
#define JSTRYNOTE_GRAIN sizeof(ptrdiff_t)
|
||||
#define JSTRYNOTE_ALIGNMASK (JSTRYNOTE_GRAIN - 1)
|
||||
typedef struct JSTryNoteArray {
|
||||
uint32 length; /* number of notes in the array */
|
||||
JSTryNote notes[1]; /* the first eleemnt of notes array */
|
||||
} JSTryNoteArray;
|
||||
|
||||
struct JSScript {
|
||||
jsbytecode *code; /* bytecodes and their immediate operands */
|
||||
@ -74,7 +84,7 @@ struct JSScript {
|
||||
const char *filename; /* source filename or null */
|
||||
uintN lineno; /* base line number of script */
|
||||
uintN depth; /* maximum stack depth in slots */
|
||||
JSTryNote *trynotes; /* exception table for this script */
|
||||
JSTryNoteArray *trynotes; /* exception table for this script */
|
||||
JSPrincipals *principals; /* principals for this script */
|
||||
JSObject *object; /* optional Script-class object wrapper */
|
||||
};
|
||||
@ -82,29 +92,13 @@ struct JSScript {
|
||||
/* No need to store script->notes now that it is allocated right after code. */
|
||||
#define SCRIPT_NOTES(script) ((jssrcnote*)((script)->code+(script)->length))
|
||||
|
||||
#define SCRIPT_FIND_CATCH_START(script, pc, catchpc) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSTryNote *tn_ = (script)->trynotes; \
|
||||
jsbytecode *catchpc_ = NULL; \
|
||||
if (tn_) { \
|
||||
ptrdiff_t off_ = PTRDIFF(pc, (script)->main, jsbytecode); \
|
||||
if (off_ >= 0) { \
|
||||
while ((jsuword)(off_ - tn_->start) >= (jsuword)tn_->length) \
|
||||
++tn_; \
|
||||
if (tn_->catchStart) \
|
||||
catchpc_ = (script)->main + tn_->catchStart; \
|
||||
} \
|
||||
} \
|
||||
catchpc = catchpc_; \
|
||||
JS_END_MACRO
|
||||
|
||||
/*
|
||||
* Find the innermost finally block that handles the given pc. This is a
|
||||
* version of SCRIPT_FIND_CATCH_START that ignore catch blocks and is used
|
||||
* to implement generator.close().
|
||||
* Check if pc is inside a try block that has finally code. GC calls this to
|
||||
* check if it is necessary to schedule generator.close() invocation for an
|
||||
* unreachable generator.
|
||||
*/
|
||||
jsbytecode *
|
||||
js_FindFinallyHandler(JSScript *script, jsbytecode *pc);
|
||||
JSBool
|
||||
js_IsInsideTryWithFinally(JSScript *script, jsbytecode *pc);
|
||||
|
||||
extern JS_FRIEND_DATA(JSClass) js_ScriptClass;
|
||||
|
||||
|
@ -200,7 +200,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 - 11)
|
||||
#define JSXDR_BYTECODE_VERSION (0xb973c0de - 12)
|
||||
|
||||
/*
|
||||
* Library-private functions.
|
||||
|
Loading…
Reference in New Issue
Block a user