diff --git a/mozilla/js/ref/js.c b/mozilla/js/ref/js.c index dfe6e7de1bd..5ccb78d6e5f 100644 --- a/mozilla/js/ref/js.c +++ b/mozilla/js/ref/js.c @@ -42,6 +42,10 @@ #include "jsscope.h" #include "jsscript.h" +#ifdef PERLCONNECT +#include "jsperl.h" +#endif + #ifdef LIVECONNECT #include "jsjava.h" #endif @@ -51,6 +55,9 @@ #ifdef JSDEBUGGER_JAVA_UI #include "jsdjava.h" #endif /* JSDEBUGGER_JAVA_UI */ +#ifdef JSDEBUGGER_C_UI +#include "jsdb.h" +#endif /* JSDEBUGGER_C_UI */ #endif /* JSDEBUGGER */ #ifdef XP_UNIX @@ -64,7 +71,7 @@ #define isatty(f) 1 #include -#include +#include static char* mac_argv[] = { "js", NULL }; @@ -72,12 +79,12 @@ static void initConsole(StringPtr consoleName, const char* startupMessage, int * { SIOUXSettings.autocloseonquit = true; SIOUXSettings.asktosaveonclose = false; - // SIOUXSettings.initializeTB = false; - // SIOUXSettings.showstatusline = true; + /* SIOUXSettings.initializeTB = false; + SIOUXSettings.showstatusline = true;*/ puts(startupMessage); SIOUXSetTitle(consoleName); - // set up a buffer for stderr (otherwise it's a pig). + /* set up a buffer for stderr (otherwise it's a pig). */ setvbuf(stderr, malloc(BUFSIZ), _IOLBF, BUFSIZ); *argc = 1; @@ -261,8 +268,6 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); static JSBool Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { - JSContext *cx2; - JSVersion version; uintN i; JSString *str; const char *filename; @@ -270,39 +275,22 @@ Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSBool ok; jsval result; - /* - * Create new context to execute in so that gc will still find - * roots for the script that called load(). - */ - cx2 = JS_NewContext(cx->runtime, 8192); - if (!cx2) - return JS_FALSE; - JS_SetErrorReporter(cx2, my_ErrorReporter); - JS_SetGlobalObject(cx2, JS_GetGlobalObject(cx)); - version = JS_GetVersion(cx); - if (version != JSVERSION_DEFAULT) - JS_SetVersion(cx2, version); - - ok = JS_TRUE; for (i = 0; i < argc; i++) { str = JS_ValueToString(cx, argv[i]); - if (!str) { - ok = JS_FALSE; - break; - } + if (!str) + return JS_FALSE; argv[i] = STRING_TO_JSVAL(str); filename = JS_GetStringBytes(str); errno = 0; script = JS_CompileFile(cx, obj, filename); if (!script) continue; - ok = JS_ExecuteScript(cx2, obj, script, &result); + ok = JS_ExecuteScript(cx, obj, script, &result); JS_DestroyScript(cx, script); if (!ok) - break; + return JS_FALSE; } - JS_DestroyContext(cx2); - return ok; + return JS_TRUE; } static JSBool @@ -543,6 +531,11 @@ SrcNotes(JSContext *cx, JSFunction *fun ) atom = js_GetAtom(cx, &fun->script->atomMap, atomIndex); printf(" atom %u (%s)", (uintN)atomIndex, ATOM_BYTES(atom)); break; + case SRC_CATCH: + delta = (uintN) js_GetSrcNoteOffset(sn, 0); + if (delta) + printf(" guard size %u", delta); + break; default:; } putchar('\n'); @@ -573,10 +566,10 @@ TryNotes(JSContext *cx, JSFunction *fun) if (!tn) return JS_TRUE; - printf("\nException table:\nstart\tend\tcatch\tfinally\n"); - while (tn->catchStart || tn->finallyStart) { - printf(" %d\t%d\t%d\t%d\n", - tn->start, tn->length, tn->catchStart, tn->finallyStart); + printf("\nException table:\nstart\tend\tcatch\n"); + while (tn->start && tn->catchStart) { + printf(" %d\t%d\t%d\n", + tn->start, tn->length, tn->catchStart); tn++; } return JS_TRUE; @@ -1285,9 +1278,10 @@ main(int argc, char **argv) #endif version = JSVERSION_DEFAULT; +#ifndef LIVECONNECT argc--; argv++; - +#endif rt = JS_NewRuntime(8L * 1024L * 1024L); if (!rt) return 1; @@ -1314,6 +1308,11 @@ main(int argc, char **argv) if (!JS_DefineProperties(cx, it, its_props)) return 1; +#ifdef PERLCONNECT + if (!js_InitPerlClass(cx, glob)) + return 1; +#endif + #ifdef LIVECONNECT if (!JSJ_SimpleInit(cx, glob, NULL, getenv("CLASSPATH"))) return 1; @@ -1340,6 +1339,9 @@ main(int argc, char **argv) * is passed on the cmd line. */ #endif /* JSDEBUGGER_JAVA_UI */ +#ifdef JSDEBUGGER_C_UI + JSDB_InitDebugger(rt, _jsdc, 0); +#endif /* JSDEBUGGER_C_UI */ #endif /* JSDEBUGGER */ result = ProcessArgs(cx, glob, argv, argc); diff --git a/mozilla/js/ref/jsapi.c b/mozilla/js/ref/jsapi.c index 24724a4796e..7529ea0bd86 100644 --- a/mozilla/js/ref/jsapi.c +++ b/mozilla/js/ref/jsapi.c @@ -2541,7 +2541,7 @@ JS_GetPendingException(JSContext *cx, jsval *vp) #if JS_HAS_EXCEPTIONS if (!cx->fp->throwing) return JS_FALSE; - *vp = cx->fp->rval; + *vp = cx->fp->exception; return JS_TRUE; #else return JS_FALSE; @@ -2554,7 +2554,7 @@ JS_SetPendingException(JSContext *cx, jsval v) CHECK_REQUEST(cx); #if JS_HAS_EXCEPTIONS cx->fp->throwing = JS_TRUE; - cx->fp->rval = v; + cx->fp->exception = v; #endif } diff --git a/mozilla/js/ref/jscntxt.h b/mozilla/js/ref/jscntxt.h index b4c91a4a2bb..ddf03f40266 100644 --- a/mozilla/js/ref/jscntxt.h +++ b/mozilla/js/ref/jscntxt.h @@ -80,6 +80,8 @@ struct JSRuntime { void *newScriptHookData; JSDestroyScriptHook destroyScriptHook; void *destroyScriptHookData; + JSTrapHandler debuggerHandler; + void *debuggerHandlerData; /* More debugging state, see jsdbgapi.c. */ PRCList trapList; @@ -147,7 +149,7 @@ struct JSContext { /* Client opaque pointer */ void *data; - + /* Java environment and JS errors to throw as exceptions. */ void *javaEnv; void *savedErrors; @@ -157,6 +159,7 @@ struct JSContext { JSPackedBool gcActive; jsrefcount requestDepth; #endif + JSStackFrame *dormantFrameChain; /* dormant frame chains */ }; typedef struct JSInterpreterHooks { diff --git a/mozilla/js/ref/jsconfig.h b/mozilla/js/ref/jsconfig.h index 31b72304d1b..fb20b6ad429 100644 --- a/mozilla/js/ref/jsconfig.h +++ b/mozilla/js/ref/jsconfig.h @@ -20,7 +20,7 @@ * JS configuration macros. */ #ifndef JS_VERSION -#define JS_VERSION 130 +#define JS_VERSION 140 #endif #if JS_VERSION == 100 diff --git a/mozilla/js/ref/jsdbgapi.c b/mozilla/js/ref/jsdbgapi.c index 42e9e307e7a..7c464712cf4 100644 --- a/mozilla/js/ref/jsdbgapi.c +++ b/mozilla/js/ref/jsdbgapi.c @@ -757,3 +757,13 @@ JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda) } JS_free(cx, pd); } + +/************************************************************************/ + +JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure) +{ + rt->debuggerHandler = handler; + rt->debuggerHandlerData = closure; + return JS_TRUE; +} diff --git a/mozilla/js/ref/jsdbgapi.h b/mozilla/js/ref/jsdbgapi.h index 66b2f09d6b0..000b734879c 100644 --- a/mozilla/js/ref/jsdbgapi.h +++ b/mozilla/js/ref/jsdbgapi.h @@ -211,6 +211,11 @@ JS_GetPropertyDescArray(JSContext *cx, JSObject *obj, JSPropertyDescArray *pda); extern JS_PUBLIC_API(void) JS_PutPropertyDescArray(JSContext *cx, JSPropertyDescArray *pda); +/************************************************************************/ + +extern JS_PUBLIC_API(JSBool) +JS_SetDebuggerHandler(JSRuntime *rt, JSTrapHandler handler, void *closure); + PR_END_EXTERN_C #endif /* jsdbgapi_h___ */ diff --git a/mozilla/js/ref/jsemit.c b/mozilla/js/ref/jsemit.c index caed6742282..c09104ed607 100644 --- a/mozilla/js/ref/jsemit.c +++ b/mozilla/js/ref/jsemit.c @@ -231,10 +231,18 @@ EmitGoto(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt, { JSStmtInfo *stmt; intN index; + uint16 finallyIndex = 0; ptrdiff_t offset, delta; for (stmt = cg->treeContext.topStmt; stmt != toStmt; stmt = stmt->down) { switch (stmt->type) { + case STMT_FINALLY: + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit3(cx, cg, JSOP_JSR, JUMP_OFFSET_HI(finallyIndex), + JUMP_OFFSET_LO(finallyIndex)) < 0) + return -1; + finallyIndex--; + break; case STMT_WITH: if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return -1; @@ -434,6 +442,57 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body, return JS_TRUE; } +#if JS_HAS_EXCEPTIONS +#define BYTECODE_ITER(pc, max, body) \ + while (pc < max) { \ + JSCodeSpec *cs = &js_CodeSpec[(JSOp)*pc]; \ + body; \ + if ((cs->format & JOF_TYPEMASK) == JOF_TABLESWITCH || \ + (cs->format & JOF_TYPEMASK) == JOF_LOOKUPSWITCH) { \ + pc += GET_JUMP_OFFSET(pc); \ + } else { \ + pc += cs->length; \ + } \ + } + +static JSBool +FixupFinallyJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart, + ptrdiff_t finallyIndex) +{ + jsbytecode *pc; + pc = cg->base + tryStart; + BYTECODE_ITER(pc, cg->next, \ + if (*pc == JSOP_JSR) { \ + ptrdiff_t index = GET_JUMP_OFFSET(pc); \ + if (index <= 0) { \ + if (index == 0) { \ + index = finallyIndex - (pc - cg->base); \ + } else { \ + index++; \ + } \ + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, index); \ + } \ + } \ + ); + return JS_TRUE; +} + +static JSBool +FixupCatchJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart, + ptrdiff_t postCatch) +{ + jsbytecode *pc; + pc = cg->base + tryStart; + BYTECODE_ITER(pc, cg->next, \ + if (*pc == JSOP_GOTO && !GET_JUMP_OFFSET(pc)) { \ + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, postCatch - (pc - cg->base)); \ + } \ + ); + return JS_TRUE; +} + +#endif + JSBool js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) { @@ -1069,24 +1128,46 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) #if JS_HAS_EXCEPTIONS case TOK_TRY: { - ptrdiff_t start, end, catchStart; + ptrdiff_t start, end, catchStart, finallyCatch, catchjmp = -1; + JSParseNode *iter = pn; -#if shaver_finally - /* if this try has a finally, push marker onto treeContext */ + /* XXX use -(CG_OFFSET + 1) */ +#define EMIT_FINALLY_JSR(cx, cg) \ + PR_BEGIN_MACRO \ + if (!js_Emit3(cx, cg, JSOP_JSR, 0, 0)) \ + return JS_FALSE; \ + PR_END_MACRO +; + /* + * When a finally block is `active' (STMT_FINALLY on the treeContext), + * non-local jumps result in a JSR being written into the bytecode + * stream for later fixup. The jsr is written with offset 0 for the + * innermost finally, -1 for the next, etc. As the finally fixup code + * runs for each finished try/finally, it will fix the JSRs with + * offset 0 to match the appropriate finally code for its block + * and decrement all others by one. + * + * NOTE: This will cause problems if we use JSRs for something other + * than finally handling in the future. Caveat hacker! + */ + if (pn->pn_kid3) - js_PushStatement(&cg->treeContext, &stmtInto, STMT_FINALLY, + js_PushStatement(&cg->treeContext, &stmtInfo, STMT_FINALLY, CG_OFFSET(cg)); -#endif /* mark try location for decompilation, then emit try block */ - if (js_NewSrcNote(cx, cg, SRC_TRY) < 0 || + if (js_NewSrcNote2(cx, cg, SRC_TRYFIN, 0) < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) return JS_FALSE; start = CG_OFFSET(cg); if(!js_EmitTree(cx, cg, pn->pn_kid1)) return JS_FALSE; - /* emit (hidden) jump over try and/or finally */ + /* emit (hidden) jump over catch and/or finally */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) + return JS_FALSE; + if (pn->pn_kid3) + EMIT_FINALLY_JSR(cx, cg); if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; jmp = js_Emit3(cx, cg, JSOP_GOTO, 0, 0); @@ -1094,68 +1175,198 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) return JS_FALSE; end = CG_OFFSET(cg); - /* if this try has a catch block, emit it */ if (pn->pn_kid2) { catchStart = end; - if (!js_EmitTree(cx, cg, pn->pn_kid2)) - return JS_FALSE; - } else { - catchStart = 0; + /* + * The emitted code for a catch block looks like: + * + * [ popscope ] only if 2nd+ catch block + * name Object + * pushobj + * newinit + * exception + * initprop maybe marked SRC_CATCHGUARD + * enterwith + * [< catchguard code >] if there's a catchguard + * ifeq + * < catch block contents > + * leavewith + * goto non-local; finally applies + * + * If there's no catch block without a catchguard, the last + * points to rethrow code. This + * code will jsr to the finally code if appropriate, and is + * also used for the catch-all trynote for capturing exceptions + * thrown from catch{} blocks. + */ + do { + JSStmtInfo stmtInfo2; + JSParseNode *disc; + ptrdiff_t guardnote; + + iter = iter->pn_kid2; + disc = iter->pn_kid1; + + if (catchjmp != -1) { + /* fix up and clean up previous catch block */ + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchjmp); + if ((uintN)++cg->stackDepth > cg->maxStackDepth) + cg->maxStackDepth = cg->stackDepth; + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + } + + /* non-zero guardnote is length of catchguard */ + guardnote = js_NewSrcNote2(cx, cg, SRC_CATCH, 0); + if (guardnote < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0) + return JS_FALSE; + + /* construct the scope holder and push it on */ + ale = js_IndexAtom(cx, cx->runtime->atomState.ObjectAtom, + &cg->atomList); + if (!ale) + return JS_FALSE; + EMIT_ATOM_INDEX_OP(JSOP_NAME, ale->index); + + if (js_Emit1(cx, cg, JSOP_PUSHOBJ) < 0 || + js_Emit1(cx, cg, JSOP_NEWINIT) < 0 || + js_Emit1(cx, cg, JSOP_EXCEPTION) < 0) + return JS_FALSE; + + /* setprop */ + ale = js_IndexAtom(cx, disc->pn_atom, &cg->atomList); + if (!ale) + return JS_FALSE; + + EMIT_ATOM_INDEX_OP(JSOP_INITPROP, ale->index); + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_ENTERWITH) < 0) + return JS_FALSE; + + /* boolean_expr */ + if (disc->pn_expr) { + ptrdiff_t guardstart = CG_OFFSET(cg); + if (!js_EmitTree(cx, cg, disc->pn_expr)) + return JS_FALSE; + /* ifeq */ + catchjmp = js_Emit3(cx, cg, JSOP_IFEQ, 0, 0); + if (catchjmp < 0) + return JS_FALSE; + if (!js_SetSrcNoteOffset(cx, cg, guardnote, 0, + (ptrdiff_t)CG_OFFSET(cg) - + guardstart)) + return JS_FALSE; + } + /* emit catch block */ + js_PushStatement(&cg->treeContext, &stmtInfo2, STMT_WITH, + CG_OFFSET(cg)); + if (!js_EmitTree(cx, cg, iter->pn_kid3)) + return JS_FALSE; + js_PopStatementCG(cx, cg); + + /* + * jump over the remaining catch blocks + * this counts as a non-local jump, so do the finally thing + */ + + /* popscope */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0) + return JS_FALSE; + + /* jsr , if required */ + if (pn->pn_kid3) + EMIT_FINALLY_JSR(cx, cg); + + /* this will get fixed up to jump to after catch/finally */ + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit3(cx, cg, JSOP_GOTO, 0, 0) < 0) + return JS_FALSE; + if (!iter->pn_kid2) + break; + } while (iter); + } -#if shaver_finally - /* if we've got a finally, it goes here, and we have to fix up - the jsrs that might have been emitted before non-local jumps */ - if (pn->pn_kid3) { - ptrdiff_t finallyIndex = CG_OFFSET(CG); - js_PopStatement(tc); - if (!FixupFinallyJumps(cx, cg, tryStart, finallyIndex)) + /* + * we use a [leavewith],[jsr],rethrow block for rethrowing + * when there's no unguarded catch, and also for + * running finally code while letting an uncaught exception + * pass through + */ + if (pn->pn_kid3 || + (catchjmp != -1 && iter->pn_kid1->pn_expr)) { + if (catchjmp != -1) { + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, catchjmp); + } + /* last discriminant jumps to rethrow if none match */ + if ((uintN)++cg->stackDepth > cg->maxStackDepth) + cg->maxStackDepth = cg->stackDepth; + if (pn->pn_kid2 && + (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_LEAVEWITH) < 0)) return JS_FALSE; - if (!js_EmitTree(cx, cg, pn->pn_kid3)) + + if (pn->pn_kid3) { + finallyCatch = CG_OFFSET(cg); + EMIT_FINALLY_JSR(cx, cg); + } + if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_EXCEPTION) < 0 || + js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0 || + js_Emit1(cx, cg, JSOP_THROW) < 0) return JS_FALSE; } -#endif - /* come from post-try */ - CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + + /* if we've got a finally, it goes here, and we have to fix up + the jsrs that might have been emitted before non-local jumps */ + + if (pn->pn_kid3) { + ptrdiff_t finallyIndex; + finallyIndex = CG_OFFSET(cg); + if (!FixupFinallyJumps(cx, cg, start, finallyIndex)) + return JS_FALSE; + js_PopStatementCG(cx, cg); + if (js_NewSrcNote2(cx, cg, SRC_TRYFIN, 1) < 0 || + js_Emit1(cx, cg, JSOP_NOP) < 0 || + !js_EmitTree(cx, cg, pn->pn_kid3) || + js_Emit1(cx, cg, JSOP_RETSUB) < 0) + return JS_FALSE; + + } if (js_NewSrcNote(cx, cg, SRC_ENDBRACE) < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) return JS_FALSE; + /* fix up the end-of-try/catch jumps to come here */ + if (!FixupCatchJumps(cx, cg, start, CG_OFFSET(cg))) + return JS_FALSE; + + CHECK_AND_SET_JUMP_OFFSET_AT(cx, cg, jmp); + /* * Add the try note last, to let post-order give us the right ordering * (first to last, inner to outer). */ - if (!js_NewTryNote(cx, cg, start, end, catchStart, 0)) + if (pn->pn_kid2 && + !js_NewTryNote(cx, cg, start, end, catchStart)) + return JS_FALSE; + + /* + * If we've got a finally, mark try+catch region with additional + * trynote to catch exceptions (re)thrown from a catch block or + * for the try{}finally{} case. + */ + if (pn->pn_kid3 && + !js_NewTryNote(cx, cg, start, finallyCatch-1, finallyCatch)) return JS_FALSE; break; } - case TOK_CATCH: - /* - * Catch blocks are very magical. Mainly, the magic involves - * special generation for the declaration/conditional, and - * mucking with the stack depth counter so that the implicit - * push of the exception that happens at runtime doesn't make - * the code generator very confused. - * - * If a catch block has a finally associated with it, the try - * block will already have pushed the appropriate statement info - * onto the tree context, so we don't need to worry about it. - */ - noteIndex = js_NewSrcNote(cx, cg, SRC_CATCH); - if (noteIndex < 0 || - !js_Emit1(cx, cg, JSOP_NOP)) - return JS_FALSE; - - /* need to adjust stack depth */ - if ((uintN)++cg->stackDepth > cg->maxStackDepth) - cg->maxStackDepth = cg->stackDepth; - if (!js_EmitTree(cx, cg, pn->pn_left) || - !js_EmitTree(cx, cg, pn->pn_right)) - return JS_FALSE; - break; #endif /* JS_HAS_EXCEPTIONS */ case TOK_VAR: @@ -1790,6 +2001,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_PRIMARY: return js_Emit1(cx, cg, pn->pn_op) >= 0; +#if JS_HAS_DEBUGGER_KEYWORD + case TOK_DEBUGGER: + return js_Emit1(cx, cg, JSOP_DEBUGGER) >= 0; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + default: PR_ASSERT(0); } @@ -1818,7 +2034,7 @@ JS_FRIEND_DATA(const char *) js_SrcNoteName[] = { "cont2label", "switch", "funcdef", - "try", + "tryfin", "catch", "newline", "setline", @@ -1846,8 +2062,8 @@ uint8 js_SrcNoteArity[] = { 1, /* SRC_CONT2LABEL */ 1, /* SRC_SWITCH */ 1, /* SRC_FUNCDEF */ - 0, /* SRC_TRY */ - 0, /* SRC_CATCH */ + 1, /* SRC_TRYFIN */ + 1, /* SRC_CATCHGUARD */ 0, /* SRC_NEWLINE */ 1, /* SRC_SETLINE */ 0 /* SRC_XDELTA */ @@ -2001,7 +2217,7 @@ js_GetSrcNoteOffset(jssrcnote *sn, uintN which) sn += 2; } if (*sn & SN_3BYTE_OFFSET_FLAG) - return (ptrdiff_t)((((uint32)(*sn & SN_3BYTE_OFFSET_MASK)) << 16) | (sn[1] << 8) | sn[0]); + return (ptrdiff_t)((((uint32)(*sn & SN_3BYTE_OFFSET_MASK)) << 16) | (sn[1] << 8) | sn[2]); return (ptrdiff_t)*sn; } @@ -2089,7 +2305,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg) JS_FRIEND_API(JSTryNote *) js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start, - ptrdiff_t end, ptrdiff_t catchStart, ptrdiff_t finallyStart) + ptrdiff_t end, ptrdiff_t catchStart) { JSTryNote *tn; @@ -2098,7 +2314,6 @@ js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start, tn->start = start; tn->length = end - start; tn->catchStart = catchStart; - tn->finallyStart = finallyStart; return tn; } @@ -2124,7 +2339,6 @@ js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote **tryp) final[count].start = 0; final[count].length = CG_OFFSET(cg); final[count].catchStart = 0; - final[count].finallyStart = 0; *tryp = final; return JS_TRUE; } diff --git a/mozilla/js/ref/jsemit.h b/mozilla/js/ref/jsemit.h index 12274bd71c2..f66af45596e 100644 --- a/mozilla/js/ref/jsemit.h +++ b/mozilla/js/ref/jsemit.h @@ -248,7 +248,7 @@ typedef enum JSSrcNoteType { SRC_ASSIGNOP = 8, /* += or another assign-op follows */ SRC_COND = 9, /* JSOP_IFEQ is from conditional ?: operator */ SRC_PAREN = 10, /* JSOP_NOP generated to mark user parens */ - SRC_HIDDEN = 11, /* JSOP_LEAVEWITH for break/continue in with */ + SRC_HIDDEN = 11, /* opcode shouldn't be decompiled */ SRC_PCBASE = 12, /* offset of first obj.prop.subprop bytecode */ SRC_LABEL = 13, /* JSOP_NOP for label: with atomid immediate */ SRC_LABELBRACE = 14, /* JSOP_NOP for label: {...} begin brace */ @@ -257,8 +257,8 @@ typedef enum JSSrcNoteType { SRC_CONT2LABEL = 17, /* JSOP_GOTO for 'continue label' with atomid */ SRC_SWITCH = 18, /* JSOP_*SWITCH with offset to end of switch */ SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ - SRC_TRY = 20, /* JSOP_NOP for beginning of try{} section */ - SRC_CATCH = 21, /* beginning of catch block (at conditional) */ + SRC_TRYFIN = 20, /* JSOP_NOP for try{} or finally{} section */ + SRC_CATCH = 21, /* catch block has guard */ SRC_NEWLINE = 22, /* bytecode follows a source newline */ SRC_SETLINE = 23, /* a file-absolute source line number note */ SRC_XDELTA = 24 /* 24-31 are for extended delta notes */ @@ -362,7 +362,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg); */ extern JS_FRIEND_API(JSTryNote *) js_NewTryNote(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t start, - ptrdiff_t end, ptrdiff_t catchStart, ptrdiff_t finallyStart); + ptrdiff_t end, ptrdiff_t catchStart); /* * Finish generating exception information, and copy it to JS_malloc diff --git a/mozilla/js/ref/jsgc.c b/mozilla/js/ref/jsgc.c index c437212230c..ba8c9ed3c52 100644 --- a/mozilla/js/ref/jsgc.c +++ b/mozilla/js/ref/jsgc.c @@ -607,7 +607,7 @@ js_GC(JSContext *cx) PRArena *a, *ma, *fa, **ap, **fap; jsval v, *vp, *sp; pruword begin, end; - JSStackFrame *fp; + JSStackFrame *fp, *chain; void *mark; uint8 flags, *flagp; JSGCThing *thing, *final, **flp, **oflp; @@ -695,8 +695,19 @@ restart: js_MarkAtomState(&rt->atomState, gc_mark); iter = NULL; while ((acx = js_ContextIterator(rt, &iter)) != NULL) { - fp = acx->fp; - if (fp) { + /* Iterate frame chain and dormant chains. Temporarily tack current + * frame onto the head of the dormant list to ease iteration. + * + * (NOTE: see comment on this whole 'dormant' thing in js_Execute) + */ + chain = acx->fp; + if (chain) { + PR_ASSERT(!chain->dormantNext); + chain->dormantNext = acx->dormantFrameChain; + } else { + chain = acx->dormantFrameChain; + } + for (fp=chain; fp; fp = chain = chain->dormantNext) { sp = fp->sp; if (sp) { for (a = acx->stackPool.first.next; a; a = a->next) { @@ -728,6 +739,9 @@ restart: GC_MARK(rt, fp->sharpArray, "sharp array", NULL); } while ((fp = fp->down) != NULL); } + /* cleanup temporary link */ + if (acx->fp) + acx->fp->dormantNext = NULL; GC_MARK(rt, acx->globalObject, "global object", NULL); GC_MARK(rt, acx->newborn[GCX_OBJECT], "newborn object", NULL); GC_MARK(rt, acx->newborn[GCX_STRING], "newborn string", NULL); diff --git a/mozilla/js/ref/jsinterp.c b/mozilla/js/ref/jsinterp.c index 54c6ca5d805..da2734d2add 100644 --- a/mozilla/js/ref/jsinterp.c +++ b/mozilla/js/ref/jsinterp.c @@ -390,6 +390,7 @@ js_SetLocalVariable(JSContext *cx, JSObject *obj, jsval id, jsval *vp) } + /* * Find a function reference and its 'this' object implicit first parameter * under argc arguments on cx's stack, and call the function. Push missing @@ -506,6 +507,7 @@ have_fun: frame.overrides = 0; frame.debugging = JS_FALSE; frame.throwing = JS_FALSE; + frame.dormantNext = NULL; /* Compute the 'this' parameter and store it in frame. */ if (thisp && OBJ_GET_CLASS(cx, thisp) != &js_CallClass) { @@ -652,7 +654,7 @@ have_fun: /* Native or script returns JS_FALSE on error or uncaught exception */ if (!ok && frame.throwing) { fp->throwing = JS_TRUE; - fp->rval = frame.rval; + fp->exception = frame.exception; } #endif @@ -774,9 +776,37 @@ js_Execute(JSContext *cx, JSObject *chain, JSScript *script, JSFunction *fun, frame.overrides = 0; frame.debugging = debugging; frame.throwing = JS_FALSE; + frame.dormantNext = NULL; + + + /* Here we wrap the call to js_Interpret with code to (conditionally) + * save and restore the old stack frame chain into a chain of 'dormant' + * frame chains. Since we are replacing cx->fp we were running into the + * problem that if gc was called, then some of the objects associated + * with the old frame chain (stored here in the C stack as 'oldfp') were + * not rooted and were being collected. This was bad. So, now we + * preserve the links to these 'dormant' frame chains in cx before + * calling js_Interpret and cleanup afterwards. gc walks these dormant + * chains and marks objects in the same way that it marks object in the + * primary cx->fp chain. + */ + + if (oldfp && oldfp != down) { + PR_ASSERT(!oldfp->dormantNext); + oldfp->dormantNext = cx->dormantFrameChain; + cx->dormantFrameChain = oldfp; + } + cx->fp = &frame; ok = js_Interpret(cx, result); cx->fp = oldfp; + + if (oldfp && oldfp != down) { + PR_ASSERT(cx->dormantFrameChain == oldfp); + cx->dormantFrameChain = oldfp->dormantNext; + oldfp->dormantNext = NULL; + } + return ok; } @@ -1034,19 +1064,21 @@ js_Interpret(JSContext *cx, jsval *result) if (rt->interruptHandler) { JSTrapHandler handler = (JSTrapHandler) rt->interruptHandler; - - switch (handler(cx, script, pc, &rval, - rt->interruptHandlerData)) { - case JSTRAP_ERROR: - ok = JS_FALSE; - goto out; - case JSTRAP_CONTINUE: - break; - case JSTRAP_RETURN: - fp->rval = rval; - goto out; - default:; - } + /* check copy of pointer for safety in multithreaded situation */ + if (handler) { + switch (handler(cx, script, pc, &rval, + rt->interruptHandlerData)) { + case JSTRAP_ERROR: + ok = JS_FALSE; + goto out; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + goto out; + default:; + } + } } switch (op) { @@ -1869,8 +1901,7 @@ js_Interpret(JSContext *cx, jsval *result) cx->newborn[GCX_OBJECT] = NULL; #if JS_HAS_EXCEPTIONS if (fp->throwing) { - /* do_throw expects to have the exception on the stack */ - PR_ASSERT(vp == sp - 1 && *vp == fp->rval); + sp[-1] = fp->exception; goto do_throw; } #endif @@ -2091,7 +2122,7 @@ js_Interpret(JSContext *cx, jsval *result) #if JS_HAS_EXCEPTIONS if (fp->throwing) { /* do_throw expects to have the exception on the stack */ - PR_ASSERT(sp[-1] == fp->rval); + sp[-1] = fp->exception; goto do_throw; } #endif @@ -2549,18 +2580,31 @@ js_Interpret(JSContext *cx, jsval *result) #endif /* JS_HAS_INITIALIZERS */ #if JS_HAS_EXCEPTIONS + case JSOP_JSR: + len = GET_JUMP_OFFSET(pc); + PUSH(INT_TO_JSVAL(pc - script->code)); + CHECK_BRANCH(len); + break; + + case JSOP_RETSUB: + rval = POP(); + PR_ASSERT(JSVAL_IS_INT(rval)); + pc = script->code + JSVAL_TO_INT(rval) + 3 /* JSR */; + len = 0; + CHECK_BRANCH(-1); + break; + + case JSOP_EXCEPTION: + PUSH(fp->exception); + break; + case JSOP_THROW: - /* - * We enter here with an exception on the stack already, so we - * need to pop it off if we're leaving this frame, but we leave - * it on if we're jumping to a catch block. - */ - PR_ASSERT(!fp->throwing); do_throw: + fp->exception = POP(); tn = script->trynotes; offset = PTRDIFF(pc, script->code, jsbytecode); if (tn) { - while (PR_UPTRDIFF(offset, tn->start) >= tn->length) + while (PR_UPTRDIFF(offset, tn->start) >= (pruword)tn->length) tn++; if (tn->catchStart) { pc = script->code + tn->catchStart; @@ -2571,7 +2615,6 @@ js_Interpret(JSContext *cx, jsval *result) /* Not in a catch block, so propagate the exception. */ fp->throwing = JS_TRUE; - fp->rval = POP(); ok = JS_FALSE; goto out; #endif /* JS_HAS_EXCEPTIONS */ @@ -2601,6 +2644,29 @@ js_Interpret(JSContext *cx, jsval *result) break; #endif /* JS_HAS_INSTANCEOF */ +#if JS_HAS_DEBUGGER_KEYWORD + case JSOP_DEBUGGER: + if (rt->debuggerHandler) { + JSTrapHandler handler = (JSTrapHandler) rt->debuggerHandler; + /* check copy of pointer for safety in multithread situation */ + if (handler) { + switch (handler(cx, script, pc, &rval, + rt->debuggerHandlerData)) { + case JSTRAP_ERROR: + ok = JS_FALSE; + goto out; + case JSTRAP_CONTINUE: + break; + case JSTRAP_RETURN: + fp->rval = rval; + goto out; + default:; + } + } + } + break; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + default: JS_ReportError(cx, "unimplemented JavaScript bytecode %d", op); ok = JS_FALSE; @@ -2631,7 +2697,6 @@ js_Interpret(JSContext *cx, jsval *result) } #endif } - out: /* * Restore the previous frame's execution state. @@ -2640,4 +2705,3 @@ out: cx->interpLevel--; return ok; } - diff --git a/mozilla/js/ref/jsinterp.h b/mozilla/js/ref/jsinterp.h index b6537ee6b81..47da4dcee65 100644 --- a/mozilla/js/ref/jsinterp.h +++ b/mozilla/js/ref/jsinterp.h @@ -49,6 +49,8 @@ struct JSStackFrame { uint8 overrides; /* bit-set of overridden Call properties */ JSPackedBool debugging; /* true if for JS_EvaluateInStackFrame */ JSPackedBool throwing; /* is there a pending exception? */ + jsval exception; /* most-recently-thrown exceptin */ + JSStackFrame *dormantNext; /* next dormant frame chain */ }; /* diff --git a/mozilla/js/ref/jsopcode.c b/mozilla/js/ref/jsopcode.c index 10e8ceb2901..078cb2654e3 100644 --- a/mozilla/js/ref/jsopcode.c +++ b/mozilla/js/ref/jsopcode.c @@ -815,37 +815,35 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) js_printf(jp, "\t}\n"); break; - case SRC_TRY: - js_printf(jp, "\ttry {\n"); + case SRC_TRYFIN: + if (js_GetSrcNoteOffset(sn, 0) == 0) { + js_printf(jp, "\ttry {\n"); + } else { + jp->indent -= 4; + js_printf(jp, "\t} finally {\n"); + } jp->indent += 4; break; case SRC_CATCH: jp->indent -= 4; + sn = js_GetSrcNote(jp->script, pc); pc += oplen; js_printf(jp, "\t} catch ("); /* balance) */ - sn = js_GetSrcNote(jp->script, pc); - len = js_CodeSpec[*pc].length; - switch (*pc) { - case JSOP_SETVAR: - lval = ATOM_BYTES(GetSlotAtom(jp->scope, js_GetLocalVariable, - GET_VARNO(pc))); - goto do_catchvar; - case JSOP_SETARG: - lval = ATOM_BYTES(GetSlotAtom(jp->scope, js_GetArgument, - GET_ARGNO(pc))); - goto do_catchvar; - case JSOP_SETNAME: - lval = ATOM_BYTES(GET_ATOM(cx, jp->script, pc)); - do_catchvar: - js_printf(jp, "%s%s", - (sn && SN_TYPE(sn) == SRC_VAR ? "var " : ""), lval); - break; - default: - PR_ASSERT(0); + pc += 6; /* name Object, pushobj, exception */ + js_printf(jp, "%s", ATOM_BYTES(GET_ATOM(cx, + jp->script, pc))); + len = js_GetSrcNoteOffset(sn, 0); + pc += 4; /* initprop, enterwith */ + if (len) { + js_printf(jp, " if "); + DECOMPILE_CODE(pc, len - 3); /* don't decompile ifeq */ + js_printf(jp, "%s", POP_STR()); + pc += len; } js_printf(jp, ") {\n"); /* balance} */ jp->indent += 4; + len = 0; break; case SRC_FUNCDEF: { @@ -881,6 +879,17 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) todo = Sprint(&ss->sprinter, ""); break; + case JSOP_JSR: + case JSOP_RETSUB: + todo = -2; + break; + + case JSOP_EXCEPTION: + sn = js_GetSrcNote(jp->script, pc); + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + todo = -2; + break; + case JSOP_POP: case JSOP_POPV: sn = js_GetSrcNote(jp->script, pc); @@ -934,10 +943,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case JSOP_ENTERWITH: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; rval = POP_STR(); js_printf(jp, "\twith (%s) {\n", rval); jp->indent += 4; - todo = -2; break; case JSOP_LEAVEWITH: @@ -959,9 +971,12 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) break; case JSOP_THROW: + sn = js_GetSrcNote(jp->script, pc); + todo = -2; + if (sn && SN_TYPE(sn) == SRC_HIDDEN) + break; rval = POP_STR(); js_printf(jp, "\t%s %s;\n", cs->name, rval); - todo = -2; break; case JSOP_GOTO: @@ -1763,6 +1778,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) #endif /* JS_HAS_SHARP_VARS */ #endif /* JS_HAS_INITIALIZERS */ +#if JS_HAS_DEBUGGER_KEYWORD + case JSOP_DEBUGGER: + js_printf(jp, "\tdebugger;\n"); + todo = -2; + break; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + default: todo = -2; break; @@ -1889,7 +1911,7 @@ js_DecompileFunction(JSPrinter *jp, JSFunction *fun, JSBool newlines) } if (atom == NULL) break; - js_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom)); + js_printf(jp, (i > 0 ? ", %s" : "%s"), ATOM_BYTES(atom)); } } js_puts(jp, ") {\n"); diff --git a/mozilla/js/ref/jsopcode.def b/mozilla/js/ref/jsopcode.def index 3733aa6268e..3e561425978 100644 --- a/mozilla/js/ref/jsopcode.def +++ b/mozilla/js/ref/jsopcode.def @@ -190,3 +190,13 @@ OPDEF(JSOP_THROW, 110,"throw", NULL, 1, 1, 0, 0, JOF_BYTE) /* 'in' and 'instanceof' ops. */ OPDEF(JSOP_IN, 111,js_in_str, js_in_str, 1, 2, 1, 6, JOF_BYTE) OPDEF(JSOP_INSTANCEOF,112,js_instanceof_str,js_instanceof_str,1,2,1,6,JOF_BYTE) + +/* debugger op */ +OPDEF(JSOP_DEBUGGER, 113,"debugger", NULL, 1, 0, 0, 0, JOF_BYTE) + +/* jsr/return for finally handling */ +OPDEF(JSOP_JSR, 114,"jsr", NULL, 3, 0, 1, 0, JOF_JUMP) +OPDEF(JSOP_RETSUB, 115,"retsub", NULL, 1, 1, 0, 0, JOF_BYTE) + +/* more exception handling ops */ +OPDEF(JSOP_EXCEPTION, 116,"exception", NULL, 1, 0, 1, 0, JOF_BYTE) diff --git a/mozilla/js/ref/jsparse.c b/mozilla/js/ref/jsparse.c index 286e34ef8ac..8850bd12f88 100644 --- a/mozilla/js/ref/jsparse.c +++ b/mozilla/js/ref/jsparse.c @@ -1081,114 +1081,108 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) return pn; #if JS_HAS_EXCEPTIONS - case TOK_TRY: + case TOK_TRY: { + JSParseNode *catchtail = NULL; /* * try nodes are ternary. * kid1 is the try Statement * kid2 is the catch node * kid3 is the finally Statement + * + * catch nodes are ternary. + * kid1 is the discriminant + * kid2 is the next catch node, or NULL + * kid3 is the catch block (on kid3 so that we can always append a + * new catch pn on catchtail->kid2) + * + * catch discriminant nodes are binary + * atom is the receptacle + * expr is the discriminant code + * + * finally nodes are unary (just the finally expression) */ pn = NewParseNode(cx, &ts->token, PN_TERNARY); - pn1 = Statement(cx, ts, tc); - if (!pn1) + pn->pn_op = JSOP_NOP; + + MUST_MATCH_TOKEN(TOK_LC, "missing { after before try block"); + /* } balance */ + pn->pn_kid1 = Statements(cx, ts, tc); + if (!pn->pn_kid1) return NULL; - if (js_PeekToken(cx, ts) == TOK_CATCH) { - pn2 = NewParseNode(cx, &ts->token, PN_BINARY); - if (!pn2) + /* { balance */ + MUST_MATCH_TOKEN(TOK_RC, "missing } after try block"); + + pn->pn_kid2 = NULL; + catchtail = pn; + while(js_PeekToken(cx, ts) == TOK_CATCH) { + /* + * legal catch forms are: + * catch (v) + * catch (v if ) + */ + + if (!catchtail->pn_kid1->pn_expr) { + js_ReportCompileError(cx, ts, + "catch clause after general catch"); return NULL; - (void)js_GetToken(cx, ts); + } + + /* catch node */ + pn2 = NewParseNode(cx, &ts->token, PN_TERNARY); + pn2->pn_op = JSOP_NOP; + /* + * We use a PN_NAME for the discriminant (catchguard) node + * with the actual discriminant code in the initializer spot + */ + pn3 = NewParseNode(cx, &ts->token, PN_NAME); + if (!pn2 || !pn3) + return NULL; + + (void)js_GetToken(cx, ts); /* eat `catch' */ + MUST_MATCH_TOKEN(TOK_LP, "missing ( after catch"); /* balance) */ - tt = js_PeekToken(cx, ts); - if (tt == TOK_VAR) { - (void)js_GetToken(cx, ts); - pn4 = Variables(cx, ts, tc); - if (!pn4) + MUST_MATCH_TOKEN(TOK_NAME, "missing identifier in catch"); + pn3->pn_atom = ts->token.t_atom; + if (js_PeekToken(cx, ts) == TOK_COLON) { + (void)js_GetToken(cx, ts); /* eat `:' */ + pn3->pn_expr = Expr(cx, ts, tc); + if (!pn3->pn_expr) return NULL; - if (pn4->pn_count != 1) { - js_ReportCompileError(cx, ts, - "only one variable declaration permitted in catch declaration"); - return NULL; - } } else { - pn4 = Expr(cx, ts, tc); - if (!pn4) - return NULL; - /* restrict the expression to instanceof */ - if (pn4->pn_op != JSOP_INSTANCEOF && - pn4->pn_op != JSOP_NAME && - pn4->pn_op != JSOP_GETARG && - pn4->pn_op != JSOP_GETVAR) { - js_ReportCompileError(cx, ts, - "catch conditional must be instanceof or variable declaration"); - PR_ASSERT(0); - return NULL; - } + pn3->pn_expr = NULL; } + pn2->pn_kid1 = pn3; - /* rewrite the declaration/conditional expr as appropriate */ - switch(pn4->pn_type) { - case TOK_NAME: - switch(pn4->pn_op) { - case JSOP_NAME: - pn4->pn_op = JSOP_SETNAME; - break; - case JSOP_GETARG: - pn4->pn_op = JSOP_SETARG; - break; - default: - PR_ASSERT(0); - } - break; - case TOK_VAR: - PR_ASSERT(pn4->pn_head->pn_type == TOK_NAME); - switch(pn4->pn_head->pn_op) { - case JSOP_GETVAR: - pn4->pn_head->pn_op = JSOP_SETVAR; - break; - case JSOP_GETARG: - pn4->pn_head->pn_op = JSOP_SETARG; - break; - case JSOP_NAME: - pn4->pn_head->pn_op = JSOP_SETNAME; - case JSOP_NOP: - break; - default: - PR_ASSERT(0); - } - break; - case TOK_INSTANCEOF: - PR_ASSERT(0); - default: - PR_ASSERT(0); - } - pn2->pn_left = pn4; + /* ( balance: */ + MUST_MATCH_TOKEN(TOK_RP, "missing ) after catch"); - /* (balance: */ - MUST_MATCH_TOKEN(TOK_RP, "missing ) after catch declaration"); - pn2->pn_right = Statement(cx, ts, tc); - if (!pn2->pn_right) + MUST_MATCH_TOKEN(TOK_LC, "missing { before catch block"); + pn2->pn_kid3 = Statements(cx, ts, tc); + if (!pn2->pn_kid3) return NULL; - } else { - pn2 = NULL; + MUST_MATCH_TOKEN(TOK_RC, "missing } after catch block"); + + catchtail = catchtail->pn_kid2 = pn2; } + catchtail->pn_kid2 = NULL; + if (js_MatchToken(cx, ts, TOK_FINALLY)) { - pn3 = Statement(cx, ts, tc); - if (!pn3) + MUST_MATCH_TOKEN(TOK_LC, "missing { before finally block"); + pn->pn_kid3 = Statements(cx, ts, tc); + if (!pn->pn_kid3) return NULL; + MUST_MATCH_TOKEN(TOK_RC, "missing } after finally block"); } else { - pn3 = NULL; + pn->pn_kid3 = NULL; } - if (!pn2 && !pn3) { + if (!pn->pn_kid2 && !pn->pn_kid3) { js_ReportCompileError(cx, ts, "missing catch or finally after try"); return NULL; } tc->tryCount++; - pn->pn_kid1 = pn1; - pn->pn_kid2 = pn2; - pn->pn_kid3 = pn3; return pn; - + } case TOK_THROW: pn = NewParseNode(cx, &ts->token, PN_UNARY); if (!pn) @@ -1204,6 +1198,16 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_op = JSOP_THROW; pn->pn_kid = pn2; break; + + /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */ + case TOK_CATCH: + js_ReportCompileError(cx, ts, "catch without try"); + return NULL; + + case TOK_FINALLY: + js_ReportCompileError(cx, ts, "finally without try"); + return NULL; + #endif /* JS_HAS_EXCEPTIONS */ case TOK_BREAK: @@ -1373,6 +1377,17 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_kid = NULL; return pn; +#if JS_HAS_DEBUGGER_KEYWORD + case TOK_DEBUGGER: + if(!WellTerminated(cx, ts, TOK_ERROR)) + return NULL; + pn = NewParseNode(cx, &ts->token, PN_NULLARY); + if (!pn) + return NULL; + pn->pn_type = TOK_DEBUGGER; + return pn; +#endif /* JS_HAS_DEBUGGER_KEYWORD */ + case TOK_ERROR: return NULL; diff --git a/mozilla/js/ref/jsscan.c b/mozilla/js/ref/jsscan.c index ba6fff8fc47..d91678f3c50 100644 --- a/mozilla/js/ref/jsscan.c +++ b/mozilla/js/ref/jsscan.c @@ -127,10 +127,14 @@ static struct keyword { #endif #ifdef RESERVE_ECMA_KEYWORDS - {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, {"enum", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, #endif +#if JS_HAS_DEBUGGER_KEYWORD + {"debugger", TOK_DEBUGGER, JSOP_NOP}, /* XXX version? */ +#elif defined(RESERVE_ECMA_KEYWORDS) + {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, +#endif {0} }; @@ -249,8 +253,17 @@ static void SendSourceToJSDebugger(JSTokenStream *ts, jschar *str, size_t length) { if (!ts->jsdsrc) { - ts->jsdsrc = JSD_NewSourceText(ts->jsdc, - ts->filename ? ts->filename : "typein"); + const char* filename = ts->filename ? ts->filename : "typein"; + + if (1 == ts->lineno) { + ts->jsdsrc = JSD_NewSourceText(ts->jsdc, filename); + } else { + ts->jsdsrc = JSD_FindSourceForURL(ts->jsdc, filename); + if (ts->jsdsrc && JSD_SOURCE_PARTIAL != + JSD_GetSourceStatus(ts->jsdc, ts->jsdsrc)) { + ts->jsdsrc = NULL; + } + } } if (ts->jsdsrc) { /* here we convert our Unicode into a C string to pass to JSD */ @@ -283,11 +296,11 @@ GetChar(JSTokenStream *ts) int32 c; ptrdiff_t len, olen; jschar *nl; - + if (ts->ungetpos != 0) { c = ts->ungetbuf[--ts->ungetpos]; } else { - if (ts->linebuf.ptr == ts->linebuf.limit) { + if (ts->linebuf.ptr == ts->linebuf.limit) { len = PTRDIFF(ts->userbuf.limit, ts->userbuf.ptr, jschar); if (len <= 0) { #ifdef JSFILE @@ -518,6 +531,7 @@ js_ReportCompileError(JSContext *cx, JSTokenStream *ts, const char *format, fprintf(stderr, "%s:\n%s\n",message, js_DeflateString(cx, ts->linebuf.base, ts->linebuf.limit - ts->linebuf.base)); + #endif } if (lastc == '\n') diff --git a/mozilla/js/ref/jsscan.h b/mozilla/js/ref/jsscan.h index 2695b687f7b..870c383b599 100644 --- a/mozilla/js/ref/jsscan.h +++ b/mozilla/js/ref/jsscan.h @@ -91,6 +91,7 @@ typedef enum JSTokenType { TOK_FINALLY = 57, /* finally keyword */ TOK_THROW = 58, /* throw keyword */ TOK_INSTANCEOF = 59, /* instanceof keyword */ + TOK_DEBUGGER = 60, /* debugger keyword */ TOK_RESERVED, /* reserved keywords */ TOK_LIMIT /* domain size */ } JSTokenType; diff --git a/mozilla/js/ref/jsscript.c b/mozilla/js/ref/jsscript.c index dfa02d98d5a..acaf3fc7ca4 100644 --- a/mozilla/js/ref/jsscript.c +++ b/mozilla/js/ref/jsscript.c @@ -304,60 +304,6 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map) return JS_TRUE; } -#ifdef JS_XDR_SCRIPT_VERIFIER -/* - * Make sure that the script is "safe". - * We currently only check for a balanced stack budget. - */ -static JSBool -VerifyScript(JSContext *cx, JSScript *scr) { - int depth = 0; - jsbytecode *pc, *endpc; - - pc = script->code; - endpc = pc + script->length; /* XXX attack based on falsified length? */ - - while (pc < endpc) { - JSCodeSpec *cs = &js_CodeSpec[(JSOp)*pc]; - intN nuses = cs->nuses; - if (nuses < 0) - nuses = 2 + GET_ARGC(pc); - depth -= nuses; - if (depth < 0) { /* underflow */ - JS_ReportError(cx, - "script verification failed: stack underflow\n"); - return JS_FALSE; - } - depth += cs->ndefs; - if (depth > maxdepth) { - maxdepth = depth; - if (depth > script->depth) { /* overflow */ - JS_ReportError(cx, - "script verification failed: stack overflow\n"); - return JS_FALSE; - } - } - if (cs->format & JOF_TYPEMASK == JOF_TABLESWITCH || - cs->format & JOF_TYPEMASK == JOF_LOOKUPSWITCH) { - /* - * the immediate operand is the length of the switch/lookup table - * (also the default offset) - */ - pc += GET_JUMP_OFFSET(pc); - } else { - pc += cs->length; - } - } - if (maxdepth != script->depth) { /* perhaps not attack, but malformed */ - JS_ReportError(cx, - "script stack budget mismatch (max %d, declared %d)\n", - maxdepth, script->depth); - return JS_FALSE; - } - return JS_TRUE; -} -#endif - JSBool js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic) { @@ -402,13 +348,6 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic) if (xdr->mode == JSXDR_DECODE) { script->lineno = (uintN)lineno; script->depth = (uintN)depth; -#ifdef JS_XDR_SCRIPT_VERIFIER - if (!VerifyScript(xdr->cx, script)) { - js_DestroyScript(xdr->cx, script); - *scriptp = NULL; - return JS_FALSE; - } -#endif } return JS_TRUE; } diff --git a/mozilla/js/ref/jsscript.h b/mozilla/js/ref/jsscript.h index 4872d252115..2ce818db29a 100644 --- a/mozilla/js/ref/jsscript.h +++ b/mozilla/js/ref/jsscript.h @@ -38,8 +38,6 @@ 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 none) */ - ptrdiff_t finallyStart; /* XXX unneeded except for end-of-vector mark: - if (!catchStart && !finallyStart) break */ }; struct JSScript { diff --git a/mozilla/js/ref/jsstddef.h b/mozilla/js/ref/jsstddef.h index 2fbed06db00..3aa02a7e4a5 100644 --- a/mozilla/js/ref/jsstddef.h +++ b/mozilla/js/ref/jsstddef.h @@ -1,20 +1,19 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public License - * Version 1.0 (the "License"); you may not use this file except in - * compliance with the License. You may obtain a copy of the License at + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. * - * The Original Code is Mozilla Communicator client code. - * - * The Initial Developer of the Original Code is Netscape Communications - * Corporation. Portions created by Netscape are Copyright (C) 1998 - * Netscape Communications Corporation. All Rights Reserved. + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. */ /* diff --git a/mozilla/js/ref/jsxdrapi.c b/mozilla/js/ref/jsxdrapi.c index 89abd6b1af2..f5e7e657079 100644 --- a/mozilla/js/ref/jsxdrapi.c +++ b/mozilla/js/ref/jsxdrapi.c @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*- +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in @@ -455,30 +455,30 @@ JS_XDRValue(JSXDRState *xdr, jsval *vp) break; } case JSVAL_BOOLEAN: { - uint32 bool; + uint32 b; if (xdr->mode == JSXDR_ENCODE) - bool = (uint32)JSVAL_TO_BOOLEAN(*vp); - if (!JS_XDRUint32(xdr, &bool)) + b = (uint32)JSVAL_TO_BOOLEAN(*vp); + if (!JS_XDRUint32(xdr, &b)) return JS_FALSE; if (xdr->mode == JSXDR_DECODE) - *vp = BOOLEAN_TO_JSVAL((JSBool)bool); + *vp = BOOLEAN_TO_JSVAL((JSBool)b); break; } case JSVAL_VOID: if (!JS_XDRUint32(xdr, (uint32 *)vp)) return JS_FALSE; break; - case JSVAL_INT: { - uint32 i; - if (xdr->mode == JSXDR_ENCODE) - i = JSVAL_TO_INT(*vp); - if (!JS_XDRUint32(xdr, &i)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) - *vp = INT_TO_JSVAL(i); - break; - } default: + if (type & JSVAL_INT) { + uint32 i; + if (xdr->mode == JSXDR_ENCODE) + i = JSVAL_TO_INT(*vp); + if (!JS_XDRUint32(xdr, &i)) + return JS_FALSE; + if (xdr->mode == JSXDR_DECODE) + *vp = INT_TO_JSVAL(i); + break; + } JS_ReportError(xdr->cx, "unknown jsval type %#lx for XDR", type); return JS_FALSE; } diff --git a/mozilla/js/ref/jsxdrapi.h b/mozilla/js/ref/jsxdrapi.h index d77778fe514..e507f09e4bb 100644 --- a/mozilla/js/ref/jsxdrapi.h +++ b/mozilla/js/ref/jsxdrapi.h @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 8; c-basic-offset: 4 -*- +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in diff --git a/mozilla/js/ref/prarena.c b/mozilla/js/ref/prarena.c index 1b2fe0fa251..6b8d77b1bbc 100644 --- a/mozilla/js/ref/prarena.c +++ b/mozilla/js/ref/prarena.c @@ -44,7 +44,7 @@ static PRArenaStats *arena_stats_list; #define PR_ARENA_DEFAULT_ALIGN sizeof(double) PR_PUBLIC_API(void) -PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, size_t align) +PR_InitArenaPool(PRArenaPool *pool, const char *name, PRUint32 size, PRUint32 align) { if (align == 0) align = PR_ARENA_DEFAULT_ALIGN; @@ -63,13 +63,13 @@ PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, size_t align) } PR_PUBLIC_API(void *) -PR_ArenaAllocate(PRArenaPool *pool, size_t nb) +PR_ArenaAllocate(PRArenaPool *pool, PRUint32 nb) { PRArena **ap, *a, *b; #ifdef JS_THREADSAFE PRArena *c; #endif - size_t sz; + PRUint32 sz; void *p; PR_ASSERT((nb & pool->mask) == 0); @@ -118,7 +118,7 @@ PR_ArenaAllocate(PRArenaPool *pool, size_t nb) } PR_PUBLIC_API(void *) -PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr) +PR_ArenaGrow(PRArenaPool *pool, void *p, PRUint32 size, PRUint32 incr) { void *newp; @@ -258,7 +258,7 @@ PR_ArenaFinish() #ifdef PR_ARENAMETER PR_PUBLIC_API(void) -PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb) +PR_ArenaCountAllocation(PRArenaPool *pool, PRUint32 nb) { pool->stats.nallocs++; pool->stats.nbytes += nb; @@ -268,13 +268,13 @@ PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb) } PR_PUBLIC_API(void) -PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr) +PR_ArenaCountInplaceGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr) { pool->stats.ninplace++; } PR_PUBLIC_API(void) -PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr) +PR_ArenaCountGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr) { pool->stats.ngrows++; pool->stats.nbytes += incr; diff --git a/mozilla/js/ref/prarena.h b/mozilla/js/ref/prarena.h index e0ee941e34d..821e2d98000 100644 --- a/mozilla/js/ref/prarena.h +++ b/mozilla/js/ref/prarena.h @@ -164,8 +164,8 @@ struct PRArenaPool { * with a minimum size per arena of size bytes. */ extern PR_PUBLIC_API(void) -PR_InitArenaPool(PRArenaPool *pool, const char *name, size_t size, - size_t align); +PR_InitArenaPool(PRArenaPool *pool, const char *name, PRUint32 size, + PRUint32 align); /* * Free the arenas in pool. The user may continue to allocate from pool @@ -197,10 +197,10 @@ PR_ArenaFinish(void); * Friend functions used by the PR_ARENA_*() macros. */ extern PR_PUBLIC_API(void *) -PR_ArenaAllocate(PRArenaPool *pool, size_t nb); +PR_ArenaAllocate(PRArenaPool *pool, PRUint32 nb); extern PR_PUBLIC_API(void *) -PR_ArenaGrow(PRArenaPool *pool, void *p, size_t size, size_t incr); +PR_ArenaGrow(PRArenaPool *pool, void *p, PRUint32 size, PRUint32 incr); extern PR_PUBLIC_API(void) PR_ArenaRelease(PRArenaPool *pool, char *mark); @@ -210,13 +210,13 @@ PR_ArenaRelease(PRArenaPool *pool, char *mark); #include extern PR_PUBLIC_API(void) -PR_ArenaCountAllocation(PRArenaPool *pool, size_t nb); +PR_ArenaCountAllocation(PRArenaPool *pool, PRUint32 nb); extern PR_PUBLIC_API(void) -PR_ArenaCountInplaceGrowth(PRArenaPool *pool, size_t size, size_t incr); +PR_ArenaCountInplaceGrowth(PRArenaPool *pool, PRUint32 size, PRUint32 incr); extern PR_PUBLIC_API(void) -PR_ArenaCountGrowth(PRArenaPool *pool, size_t size, size_t incr); +PR_ArenaCountGrowth(PRArenaPool *pool, PRUint32 size, PRUint32incr); extern PR_PUBLIC_API(void) PR_ArenaCountRelease(PRArenaPool *pool, char *mark); diff --git a/mozilla/js/ref/prtypes.h b/mozilla/js/ref/prtypes.h index 0f2a4222dbf..7c098acf24c 100644 --- a/mozilla/js/ref/prtypes.h +++ b/mozilla/js/ref/prtypes.h @@ -126,7 +126,7 @@ typedef struct PRTime PRTime; #endif /* _WIN16 */ #else /* Mac or Unix */ - +#define PR_IMPLEMENT(__type) __type #define PR_PUBLIC_API(__x) __x #define PR_IMPORT_API(__x) __x #define PR_PUBLIC_DATA(__x) __x @@ -134,8 +134,6 @@ typedef struct PRTime PRTime; #define PR_CALLBACK #define PR_STATIC_CALLBACK(__x) static __x #define PR_EXTERN(__type) extern __type -#define PR_IMPLEMENT(__type) __type - #endif /* Mac or Unix */ /************************************************************************/