diff --git a/mozilla/js/src/js.c b/mozilla/js/src/js.c index 9ee1fa4ba11..70b0c80ca8c 100644 --- a/mozilla/js/src/js.c +++ b/mozilla/js/src/js.c @@ -262,7 +262,7 @@ Process(JSContext *cx, JSObject *obj, char *filename) JSScript *script; jsval result; JSString *str; - char buffer[4098]; + char buffer[4096]; char *bufp; int lineno; int startline; @@ -324,8 +324,8 @@ Process(JSContext *cx, JSObject *obj, char *filename) } bufp += strlen(bufp); lineno++; - } while (!JS_BufferIsCompilableUnit(cx, obj, - buffer, strlen(buffer))); + } while (!JS_BufferIsCompilableUnit(cx, obj, buffer, strlen(buffer))); + /* Clear any pending exception from previous failed compiles. */ JS_ClearPendingException(cx); script = JS_CompileScript(cx, obj, buffer, strlen(buffer), @@ -376,7 +376,7 @@ static int usage(void) { fprintf(gErrFile, "%s\n", JS_GetImplementationVersion()); - fprintf(gErrFile, "usage: js [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n"); + fprintf(gErrFile, "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n"); return 2; } @@ -401,10 +401,15 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc) JS_SetVersion(cx, atoi(argv[i+1])); i++; break; + case 'w': reportWarnings++; break; + case 's': + JS_ToggleOptions(cx, JSOPTION_STRICT); + break; + case 'f': if (i+1 == argc) { return usage(); @@ -422,6 +427,7 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc) isInteractive = JS_FALSE; i++; break; + default: return usage(); } @@ -471,6 +477,69 @@ Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } +static struct { + const char *name; + uint32 flag; +} js_options[] = { + {"strict", JSOPTION_STRICT}, + {0} +}; + +static JSBool +Options(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) +{ + uint32 optset, flag; + uintN i, j, found; + JSString *str; + const char *opt; + char *names; + + optset = 0; + for (i = 0; i < argc; i++) { + str = JS_ValueToString(cx, argv[i]); + if (!str) + return JS_FALSE; + opt = JS_GetStringBytes(str); + for (j = 0; js_options[j].name; j++) { + if (strcmp(js_options[j].name, opt) == 0) { + optset |= js_options[j].flag; + break; + } + } + } + optset = JS_ToggleOptions(cx, optset); + + names = NULL; + found = 0; + while (optset != 0) { + flag = optset; + optset &= optset - 1; + flag &= ~optset; + for (j = 0; js_options[j].name; j++) { + if (js_options[j].flag == flag) { + names = JS_sprintf_append(names, "%s%s", + names ? "," : "", js_options[j].name); + found++; + break; + } + } + } + if (!found) + names = strdup(""); + if (!names) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + str = JS_NewString(cx, names, strlen(names)); + if (!str) { + free(names); + return JS_FALSE; + } + *rval = STRING_TO_JSVAL(str); + return JS_TRUE; +} + static void my_LoadErrorReporter(JSContext *cx, const char *message, JSErrorReport *report); @@ -587,22 +656,40 @@ GC(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return JS_TRUE; } +static JSScript * +ValueToScript(JSContext *cx, jsval v) +{ + JSScript *script; + JSFunction *fun; + + if (JSVAL_IS_OBJECT(v) && + JS_GET_CLASS(cx, JSVAL_TO_OBJECT(v)) == &js_ScriptClass) { + script = JS_GetPrivate(cx, JSVAL_TO_OBJECT(v)); + } else { + fun = JS_ValueToFunction(cx, v); + if (!fun) + return JS_FALSE; + script = fun->script; + } + return script; +} + static JSBool GetTrapArgs(JSContext *cx, uintN argc, jsval *argv, JSScript **scriptp, int32 *ip) { uintN intarg; - JSFunction *fun; + JSScript *script; *scriptp = cx->fp->down->script; *ip = 0; if (argc != 0) { intarg = 0; if (JS_TypeOfValue(cx, argv[0]) == JSTYPE_FUNCTION) { - fun = JS_ValueToFunction(cx, argv[0]); - if (!fun) + script = ValueToScript(cx, argv[0]); + if (!script) return JS_FALSE; - *scriptp = fun->script; + *scriptp = script; intarg++; } if (argc > intarg) { @@ -708,7 +795,7 @@ PCToLine(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) #ifdef DEBUG static void -SrcNotes(JSContext *cx, JSFunction *fun ) +SrcNotes(JSContext *cx, JSScript *script) { uintN offset, delta, caseOff; jssrcnote *notes, *sn; @@ -716,7 +803,7 @@ SrcNotes(JSContext *cx, JSFunction *fun ) jsatomid atomIndex; JSAtom *atom; - notes = fun->script->notes; + notes = script->notes; if (notes) { fprintf(gOutFile, "\nSource notes:\n"); offset = 0; @@ -744,11 +831,23 @@ SrcNotes(JSContext *cx, JSFunction *fun ) case SRC_LABELBRACE: case SRC_BREAK2LABEL: case SRC_CONT2LABEL: - case SRC_FUNCDEF: + case SRC_FUNCDEF: { + const char *bytes; + JSFunction *fun; + JSString *str; + atomIndex = (jsatomid) js_GetSrcNoteOffset(sn, 0); - atom = js_GetAtom(cx, &fun->script->atomMap, atomIndex); - fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, ATOM_BYTES(atom)); + atom = js_GetAtom(cx, &script->atomMap, atomIndex); + if (type != SRC_FUNCDEF) { + bytes = ATOM_BYTES(atom); + } else { + fun = JS_GetPrivate(cx, ATOM_TO_OBJECT(atom)); + str = JS_DecompileFunction(cx, fun, JS_DONT_PRETTY_PRINT); + bytes = str ? JS_GetStringBytes(str) : "N/A"; + } + fprintf(gOutFile, " atom %u (%s)", (uintN)atomIndex, bytes); break; + } case SRC_SWITCH: fprintf(gOutFile, " length %u", (uintN) js_GetSrcNoteOffset(sn, 0)); caseOff = (uintN) js_GetSrcNoteOffset(sn, 1); @@ -771,22 +870,22 @@ static JSBool Notes(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { uintN i; - JSFunction *fun; + JSScript *script; for (i = 0; i < argc; i++) { - fun = JS_ValueToFunction(cx, argv[i]); - if (!fun) - return JS_FALSE; + script = ValueToScript(cx, argv[i]); + if (!script) + continue; - SrcNotes(cx, fun); + SrcNotes(cx, script); } return JS_TRUE; } static JSBool -TryNotes(JSContext *cx, JSFunction *fun) +TryNotes(JSContext *cx, JSScript *script) { - JSTryNote *tn = fun->script->trynotes; + JSTryNote *tn = script->trynotes; if (!tn) return JS_TRUE; @@ -804,7 +903,7 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) { JSBool lines; uintN i; - JSFunction *fun; + JSScript *script; if (argc > 0 && JSVAL_IS_STRING(argv[0]) && @@ -815,13 +914,13 @@ Disassemble(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) lines = JS_FALSE; } for (i = 0; i < argc; i++) { - fun = JS_ValueToFunction(cx, argv[i]); - if (!fun) - return JS_FALSE; + script = ValueToScript(cx, argv[i]); + if (!script) + continue; - js_Disassemble(cx, fun->script, lines, stdout); - SrcNotes(cx, fun); - TryNotes(cx, fun); + js_Disassemble(cx, script, lines, stdout); + SrcNotes(cx, script); + TryNotes(cx, script); } return JS_TRUE; } @@ -831,42 +930,42 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval { #define LINE_BUF_LEN 512 uintN i, len, line1, line2, bupline; - JSFunction *fun; + JSScript *script; FILE *file; char linebuf[LINE_BUF_LEN]; jsbytecode *pc, *end; static char sep[] = ";-------------------------"; for (i = 0; i < argc; i++) { - fun = JS_ValueToFunction(cx, argv[i]); - if (!fun) - return JS_FALSE; + script = ValueToScript(cx, argv[i]); + if (!script) + continue; - if (!fun->script || !fun->script->filename) { + if (!script || !script->filename) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_FILE_SCRIPTS_ONLY); return JS_FALSE; } - file = fopen(fun->script->filename, "r"); + file = fopen(script->filename, "r"); if (!file) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_CANT_OPEN, - fun->script->filename, strerror(errno)); + script->filename, strerror(errno)); return JS_FALSE; } - pc = fun->script->code; - end = pc + fun->script->length; + pc = script->code; + end = pc + script->length; /* burn the leading lines */ - line2 = JS_PCToLineNumber(cx, fun->script, pc); + line2 = JS_PCToLineNumber(cx, script, pc); for (line1 = 0; line1 < line2 - 1; line1++) fgets(linebuf, LINE_BUF_LEN, file); bupline = 0; while (pc < end) { - line2 = JS_PCToLineNumber(cx, fun->script, pc); + line2 = JS_PCToLineNumber(cx, script, pc); if (line2 < line1) { if (bupline != line2) { @@ -881,7 +980,7 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval if (!fgets(linebuf, LINE_BUF_LEN, file)) { JS_ReportErrorNumber(cx, my_GetErrorMessage, NULL, JSSMSG_UNEXPECTED_EOF, - fun->script->filename); + script->filename); goto bail; } line1++; @@ -889,7 +988,7 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval } } - len = js_Disassemble1(cx, fun->script, pc, pc - fun->script->code, + len = js_Disassemble1(cx, script, pc, pc - script->code, JS_TRUE, stdout); if (!len) return JS_FALSE; @@ -1206,6 +1305,7 @@ BuildDate(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) static JSFunctionSpec shell_functions[] = { {"version", Version, 0}, + {"options", Options, 0}, {"load", Load, 1}, {"print", Print, 0}, {"help", Help, 0}, @@ -1236,6 +1336,7 @@ static JSFunctionSpec shell_functions[] = { static char *shell_help_messages[] = { "version [number] Get or set JavaScript version number", + "options [option ...] Get or toggle JavaScript options", "load ['foo.js' ...] Load files named by string arguments", "print [expr ...] Evaluate and print expressions", "help [name ...] Display usage and help messages", @@ -1517,7 +1618,7 @@ static void my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) { int i, j, k, n; - char *prefix = NULL, *tmp; + char *prefix, *tmp; const char *ctmp; if (!report) { @@ -1526,9 +1627,10 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) } /* Conditionally ignore reported warnings. */ - if ((JSREPORT_IS_WARNING(report->flags) && !reportWarnings)) + if (JSREPORT_IS_WARNING(report->flags) && !reportWarnings) return; + prefix = NULL; if (report->filename) prefix = JS_smprintf("%s:", report->filename); if (report->lineno) { @@ -1545,10 +1647,12 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) /* embedded newlines -- argh! */ while ((ctmp = strchr(message, '\n')) != 0) { ctmp++; - if (prefix) fputs(prefix, gErrFile); + if (prefix) + fputs(prefix, gErrFile); fwrite(message, 1, ctmp - message, gErrFile); message = ctmp; } + /* If there were no filename or lineno, the prefix might be empty */ if (prefix) fputs(prefix, gErrFile); @@ -1559,7 +1663,13 @@ my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report) goto out; } - fprintf(gErrFile, ":\n%s%s\n%s", prefix, report->linebuf, prefix); + /* report->linebuf usually ends with a newline. */ + n = strlen(report->linebuf); + fprintf(gErrFile, ":\n%s%s%s%s", + prefix, + report->linebuf, + (n > 0 && report->linebuf[n-1] == '\n') ? "" : "\n", + prefix); n = report->tokenptr - report->linebuf; for (i = j = 0; i < n; i++) { if (report->linebuf[i] == '\t') { diff --git a/mozilla/js/src/js.msg b/mozilla/js/src/js.msg index 5f9ef5a6d8c..8d18e070c42 100644 --- a/mozilla/js/src/js.msg +++ b/mozilla/js/src/js.msg @@ -182,8 +182,8 @@ MSG_DEF(JSMSG_COLON_AFTER_ID, 106, 0, JSEXN_SYNTAXERR, "missing : after MSG_DEF(JSMSG_CURLY_AFTER_LIST, 107, 0, JSEXN_SYNTAXERR, "missing } after property list") MSG_DEF(JSMSG_PAREN_IN_PAREN, 108, 0, JSEXN_SYNTAXERR, "missing ) in parenthetical") MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 109, 0, JSEXN_SYNTAXERR, "missing ; before statement") -MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 0, JSEXN_NONE, "function does not always return a value") -MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_NONE, "duplicate formal argument {0}") +MSG_DEF(JSMSG_NO_RETURN_VALUE, 110, 0, JSEXN_TYPEERR, "function does not always return a value") +MSG_DEF(JSMSG_DUPLICATE_FORMAL, 111, 1, JSEXN_TYPEERR, "duplicate formal argument {0}") MSG_DEF(JSMSG_EQUAL_AS_ASSIGN, 112, 1, JSEXN_NONE, "test for equality (==) mistyped as assignment (=)?{0}") MSG_DEF(JSMSG_BAD_IMPORT, 113, 0, JSEXN_SYNTAXERR, "invalid import expression") MSG_DEF(JSMSG_TOO_MANY_DEFAULTS, 114, 0, JSEXN_SYNTAXERR, "more than one switch default") @@ -199,7 +199,7 @@ MSG_DEF(JSMSG_BAD_CONTINUE, 123, 0, JSEXN_SYNTAXERR, "invalid continue MSG_DEF(JSMSG_BAD_RETURN, 124, 0, JSEXN_SYNTAXERR, "invalid return") MSG_DEF(JSMSG_BAD_LABEL, 125, 0, JSEXN_SYNTAXERR, "invalid label") MSG_DEF(JSMSG_DUPLICATE_LABEL, 126, 0, JSEXN_SYNTAXERR, "duplicate label") -MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_NONE, "variable {0} hides argument") +MSG_DEF(JSMSG_VAR_HIDES_ARG, 127, 1, JSEXN_TYPEERR, "variable {0} hides argument") MSG_DEF(JSMSG_BAD_VAR_INIT, 128, 0, JSEXN_SYNTAXERR, "invalid variable initialization") MSG_DEF(JSMSG_BAD_LEFTSIDE_OF_ASS, 129, 0, JSEXN_SYNTAXERR, "invalid assignment left-hand side") MSG_DEF(JSMSG_BAD_OPERAND, 130, 1, JSEXN_SYNTAXERR, "invalid {0} operand") @@ -226,4 +226,6 @@ MSG_DEF(JSMSG_PRECISION_RANGE, 150, 1, JSEXN_RANGEERR, "precision {0} out MSG_DEF(JSMSG_BAD_GETTER_OR_SETTER, 151, 1, JSEXN_SYNTAXERR, "invalid {0} usage") MSG_DEF(JSMSG_BAD_ARRAY_LENGTH, 152, 0, JSEXN_RANGEERR, "invalid array length") MSG_DEF(JSMSG_CANT_DESCRIBE_PROPS, 153, 1, JSEXN_NONE, "can't describe non-native properties of class {0}") -MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 0, JSEXN_TYPEERR, "Second arg to Function.prototype.apply must be array type") +MSG_DEF(JSMSG_BAD_APPLY_ARGS, 154, 0, JSEXN_TYPEERR, "second argument to Function.prototype.apply must be an array") +MSG_DEF(JSMSG_REDECLARED_VAR, 155, 2, JSEXN_TYPEERR, "redeclaration of {0} {1}") +MSG_DEF(JSMSG_UNDECLARED_VAR, 156, 1, JSEXN_TYPEERR, "assignment to undeclared variable {0}") diff --git a/mozilla/js/src/jsapi.c b/mozilla/js/src/jsapi.c index 121c4ab6e76..592a3be7074 100644 --- a/mozilla/js/src/jsapi.c +++ b/mozilla/js/src/jsapi.c @@ -626,7 +626,8 @@ JS_NewRuntime(uint32 maxbytes) if (!rt->requestDone) goto bad; js_SetupLocks(20,20); /* this is asymmetric with JS_ShutDown. */ - js_NewLock(&rt->rtLock); + rt->rtLock = JS_NEW_LOCK(); + rt->stateChange = JS_NEW_CONDVAR(rt->rtLock); #endif rt->propertyCache.empty = JS_TRUE; JS_INIT_CLIST(&rt->contextList); @@ -650,7 +651,7 @@ JS_DestroyRuntime(JSRuntime *rt) JS_DESTROY_CONDVAR(rt->gcDone); if (rt->requestDone) JS_DESTROY_CONDVAR(rt->requestDone); - js_DestroyLock(&rt->rtLock); + JS_DESTROY_LOCK(rt->rtLock); #endif free(rt); } @@ -894,6 +895,28 @@ JS_StringToVersion(const char *string) return JSVERSION_UNKNOWN; } +JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx) +{ + return cx->options; +} + +JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options = options; + return oldopts; +} + +JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options) +{ + uint32 oldopts = cx->options; + cx->options ^= options; + return oldopts; +} + JS_PUBLIC_API(const char *) JS_GetImplementationVersion(void) { @@ -2157,8 +2180,9 @@ JS_NewFunction(JSContext *cx, JSNative call, uintN nargs, uintN flags, CHECK_REQUEST(cx); - atom = NULL; - if (name) { + if (!name) { + atom = NULL; + } else { atom = js_Atomize(cx, name, strlen(name), 0); if (!atom) return NULL; @@ -2237,10 +2261,12 @@ static JSScript * CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts, void *tempMark, JSBool *eofp) { + JSBool eof; JSCodeGenerator cg; JSScript *script; CHECK_REQUEST(cx); + eof = JS_FALSE; if (!js_InitCodeGenerator(cx, &cg, ts->filename, ts->lineno, ts->principals)) { script = NULL; @@ -2248,12 +2274,13 @@ CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts, } if (!js_CompileTokenStream(cx, obj, ts, &cg)) { script = NULL; - if (eofp) - *eofp = (ts->flags & TSF_EOF) != 0; + eof = (ts->flags & TSF_EOF) != 0; goto out; } script = js_NewScriptFromCG(cx, &cg, NULL); out: + if (eofp) + *eofp = eof; if (!js_CloseTokenStream(cx, ts)) { if (script) js_DestroyScript(cx, script); @@ -2336,8 +2363,7 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, void *mark; JSTokenStream *ts; JSErrorReporter older; - JSBool hitEOF; - JSBool result; + JSBool hitEOF, result; JSExceptionState *exnState; CHECK_REQUEST(cx); @@ -2352,7 +2378,6 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, goto out; } - hitEOF = JS_FALSE; older = JS_SetErrorReporter(cx, NULL); script = CompileTokenStream(cx, obj, ts, mark, &hitEOF); JS_SetErrorReporter(cx, older); diff --git a/mozilla/js/src/jsapi.h b/mozilla/js/src/jsapi.h index 8a57e73b9f4..f7c9f61cf3b 100644 --- a/mozilla/js/src/jsapi.h +++ b/mozilla/js/src/jsapi.h @@ -396,6 +396,21 @@ JS_VersionToString(JSVersion version); extern JS_PUBLIC_API(JSVersion) JS_StringToVersion(const char *string); +/* + * JS options are orthogonal to version, and may be freely composed with one + * another as well as with version. + */ +#define JSOPTION_STRICT JS_BIT(0) + +extern JS_PUBLIC_API(uint32) +JS_GetOptions(JSContext *cx); + +extern JS_PUBLIC_API(uint32) +JS_SetOptions(JSContext *cx, uint32 options); + +extern JS_PUBLIC_API(uint32) +JS_ToggleOptions(JSContext *cx, uint32 options); + extern JS_PUBLIC_API(const char *) JS_GetImplementationVersion(void); @@ -615,9 +630,13 @@ JS_InitClass(JSContext *cx, JSObject *obj, JSObject *parent_proto, #ifdef JS_THREADSAFE extern JS_PUBLIC_API(JSClass *) JS_GetClass(JSContext *cx, JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(cx, obj) #else extern JS_PUBLIC_API(JSClass *) JS_GetClass(JSObject *obj); + +#define JS_GET_CLASS(cx,obj) JS_GetClass(obj) #endif extern JS_PUBLIC_API(JSBool) diff --git a/mozilla/js/src/jscntxt.c b/mozilla/js/src/jscntxt.c index be3b398a351..0ff37b34593 100644 --- a/mozilla/js/src/jscntxt.c +++ b/mozilla/js/src/jscntxt.c @@ -60,6 +60,7 @@ JSContext * js_NewContext(JSRuntime *rt, size_t stacksize) { JSContext *cx; + JSBool ok, first; cx = malloc(sizeof *cx); if (!cx) @@ -70,22 +71,47 @@ js_NewContext(JSRuntime *rt, size_t stacksize) #ifdef JS_THREADSAFE js_InitContextForLocking(cx); #endif - if (rt->contextList.next == (JSCList *)&rt->contextList) { + + JS_LOCK_RUNTIME(rt); + for (;;) { + first = (rt->contextList.next == (JSCList *)&rt->contextList); + if (rt->state == JSRTS_UP) { + JS_ASSERT(!first); + break; + } + if (rt->state == JSRTS_DOWN) { + JS_ASSERT(first); + rt->state = JSRTS_LAUNCHING; + break; + } + JS_WAIT_CONDVAR(rt->stateChange, JS_NO_TIMEOUT); + } + JS_APPEND_LINK(&cx->links, &rt->contextList); + JS_UNLOCK_RUNTIME(rt); + + if (first) { /* First context on this runtime: initialize atoms and keywords. */ - if (!js_InitAtomState(cx, &rt->atomState) || - !js_InitScanner(cx)) { + ok = js_InitAtomState(cx, &rt->atomState); + if (ok) + ok = js_InitScanner(cx); + + JS_LOCK_RUNTIME(rt); + rt->state = JSRTS_UP; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + JS_UNLOCK_RUNTIME(rt); + + if (!ok) { free(cx); return NULL; } } - /* Atomicly append cx to rt's context list. */ - JS_LOCK_RUNTIME_VOID(rt, JS_APPEND_LINK(&cx->links, &rt->contextList)); cx->version = JSVERSION_DEFAULT; cx->jsop_eq = JSOP_EQ; cx->jsop_ne = JSOP_NE; JS_InitArenaPool(&cx->stackPool, "stack", stacksize, sizeof(jsval)); JS_InitArenaPool(&cx->codePool, "code", 1024, sizeof(jsbytecode)); + JS_InitArenaPool(&cx->notePool, "note", 256, sizeof(jssrcnote)); JS_InitArenaPool(&cx->tempPool, "temp", 1024, sizeof(jsdouble)); #if JS_HAS_REGEXPS @@ -105,17 +131,20 @@ void js_DestroyContext(JSContext *cx, JSGCMode gcmode) { JSRuntime *rt; - JSBool rtempty; + JSBool last; rt = cx->runtime; /* Remove cx from context list first. */ JS_LOCK_RUNTIME(rt); + JS_ASSERT(rt->state == JSRTS_UP); JS_REMOVE_LINK(&cx->links); - rtempty = (rt->contextList.next == (JSCList *)&rt->contextList); + last = (rt->contextList.next == (JSCList *)&rt->contextList); + if (last) + rt->state = JSRTS_LANDING; JS_UNLOCK_RUNTIME(rt); - if (rtempty) { + if (last) { /* Unpin all pinned atoms before final GC. */ js_UnpinPinnedAtoms(&rt->atomState); @@ -150,7 +179,7 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode) else if (gcmode == JS_MAYBE_GC) JS_MaybeGC(cx); - if (rtempty) { + if (last) { if (gcmode == JS_NO_GC) js_ForceGC(cx); @@ -161,6 +190,7 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode) /* Free the stuff hanging off of cx. */ JS_FinishArenaPool(&cx->stackPool); JS_FinishArenaPool(&cx->codePool); + JS_FinishArenaPool(&cx->notePool); JS_FinishArenaPool(&cx->tempPool); if (cx->lastMessage) free(cx->lastMessage); @@ -171,6 +201,13 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode) JS_EndRequest(cx); #endif free(cx); + + if (last) { + JS_LOCK_RUNTIME(rt); + rt->state = JSRTS_DOWN; + JS_NOTIFY_ALL_CONDVAR(rt->stateChange); + JS_UNLOCK_RUNTIME(rt); + } } JSContext * @@ -361,8 +398,8 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback, void js_ReportErrorNumberVA(JSContext *cx, uintN flags, JSErrorCallback callback, - void *userRef, const uintN errorNumber, - JSBool charArgs, va_list ap) + void *userRef, const uintN errorNumber, + JSBool charArgs, va_list ap) { JSStackFrame *fp; JSErrorReport report; diff --git a/mozilla/js/src/jscntxt.h b/mozilla/js/src/jscntxt.h index 6dfe5cf41d0..1d469210836 100644 --- a/mozilla/js/src/jscntxt.h +++ b/mozilla/js/src/jscntxt.h @@ -53,7 +53,16 @@ JS_BEGIN_EXTERN_C typedef enum JSGCMode { JS_NO_GC, JS_MAYBE_GC, JS_FORCE_GC } JSGCMode; +typedef enum JSRuntimeState { + JSRTS_DOWN, + JSRTS_LAUNCHING, + JSRTS_UP, + JSRTS_LANDING +} JSRuntimeState; + struct JSRuntime { + JSRuntimeState state; + /* Garbage collector state, used by jsgc.c. */ JSArenaPool gcArenaPool; JSArenaPool gcFlagsPool; @@ -132,7 +141,13 @@ struct JSRuntime { uint32 requestCount; /* Lock and owning thread pointer for JS_LOCK_RUNTIME. */ - JSThinLock rtLock; + PRLock *rtLock; +#ifdef DEBUG + jsword rtLockOwner; +#endif + + /* Used to synchronize down/up state change; uses rtLock. */ + PRCondVar *stateChange; #endif }; @@ -173,6 +188,7 @@ struct JSContext { /* Temporary arena pools used while compiling and decompiling. */ JSArenaPool codePool; + JSArenaPool notePool; JSArenaPool tempPool; /* Top-level object and pointer to top stack frame's scope chain. */ @@ -214,8 +230,13 @@ struct JSContext { /* Exception state (NB: throwing is packed with gcActive above). */ JSPackedBool throwing; /* is there a pending exception? */ jsval exception; /* most-recently-thrown exceptin */ + + uint32 options; /* see jsapi.h for JSOPTION_* */ }; +/* Slightly more readable macros, also to hide bitset implementation detail. */ +#define JS_HAS_STRICT_OPTION(cx) ((cx)->options & JSOPTION_STRICT) + extern JSContext * js_NewContext(JSRuntime *rt, size_t stacksize); diff --git a/mozilla/js/src/jsconfig.h b/mozilla/js/src/jsconfig.h index 8424b43176d..bcf5d274ae2 100644 --- a/mozilla/js/src/jsconfig.h +++ b/mozilla/js/src/jsconfig.h @@ -92,6 +92,7 @@ #define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ #elif JS_VERSION == 110 @@ -146,6 +147,7 @@ #define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ #elif JS_VERSION == 120 @@ -200,6 +202,7 @@ #define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ #elif JS_VERSION == 130 @@ -254,6 +257,7 @@ #define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ #elif JS_VERSION == 140 @@ -308,6 +312,7 @@ #define JS_HAS_NUMBER_FORMATS 0 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 0 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 0 /* has uneval() top-level function */ +#define JS_HAS_CONST 0 /* has JS2 const as alternative var */ #elif JS_VERSION == 150 @@ -362,6 +367,7 @@ #define JS_HAS_NUMBER_FORMATS 1 /* numbers have formatting methods */ #define JS_HAS_GETTER_SETTER 1 /* has JS2 getter/setter functions */ #define JS_HAS_UNEVAL 1 /* has uneval() top-level function */ +#define JS_HAS_CONST 1 /* has JS2 const as alternative var */ #else diff --git a/mozilla/js/src/jsemit.c b/mozilla/js/src/jsemit.c index 3f57ffaefbb..fcf45fee609 100644 --- a/mozilla/js/src/jsemit.c +++ b/mozilla/js/src/jsemit.c @@ -65,14 +65,9 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, { memset(cg, 0, sizeof *cg); cg->codeMark = JS_ARENA_MARK(&cx->codePool); + cg->noteMark = JS_ARENA_MARK(&cx->notePool); cg->tempMark = JS_ARENA_MARK(&cx->tempPool); - JS_ARENA_ALLOCATE(cg->base, &cx->codePool, CGINCR); - if (!cg->base) { - JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - cg->next = cg->base; - cg->limit = CG_CODE(cg, CGINCR); + cg->current = &cg->main; cg->filename = filename; cg->firstLine = cg->currentLine = lineno; cg->principals = principals; @@ -85,7 +80,9 @@ JS_FRIEND_API(void) js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg) { JS_ARENA_RELEASE(&cx->codePool, cg->codeMark); + JS_ARENA_RELEASE(&cx->notePool, cg->noteMark); JS_ARENA_RELEASE(&cx->tempPool, cg->tempMark); + TREE_CONTEXT_FREE(&cg->treeContext); } static ptrdiff_t @@ -96,16 +93,19 @@ EmitCheck(JSContext *cx, JSCodeGenerator *cg, JSOp op, ptrdiff_t delta) JS_ASSERT(delta < (ptrdiff_t)CGINCR); offset = CG_OFFSET(cg); - if ((jsuword)cg->next + delta >= (jsuword)cg->limit) { - length = PTRDIFF(cg->limit, cg->base, jsbytecode); + if ((jsuword)CG_NEXT(cg) + delta >= (jsuword)CG_LIMIT(cg)) { + length = PTRDIFF(CG_LIMIT(cg), CG_BASE(cg), jsbytecode); cgsize = length * sizeof(jsbytecode); - JS_ARENA_GROW(cg->base, &cx->codePool, cgsize, CGINCR); - if (!cg->base) { + if (CG_BASE(cg)) + JS_ARENA_GROW(CG_BASE(cg), &cx->codePool, cgsize, CGINCR); + else + JS_ARENA_ALLOCATE(CG_BASE(cg), &cx->codePool, CGINCR); + if (!CG_BASE(cg)) { JS_ReportOutOfMemory(cx); return -1; } - cg->limit = CG_CODE(cg, length + CGINCR); - cg->next = CG_CODE(cg, offset); + CG_LIMIT(cg) = CG_CODE(cg, length + CGINCR); + CG_NEXT(cg) = CG_CODE(cg, offset); } return offset; } @@ -141,7 +141,7 @@ js_Emit1(JSContext *cx, JSCodeGenerator *cg, JSOp op) ptrdiff_t offset = EmitCheck(cx, cg, op, 1); if (offset >= 0) { - *cg->next++ = (jsbytecode)op; + *CG_NEXT(cg)++ = (jsbytecode)op; UpdateDepth(cx, cg, offset); } return offset; @@ -153,9 +153,10 @@ js_Emit2(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1) ptrdiff_t offset = EmitCheck(cx, cg, op, 2); if (offset >= 0) { - cg->next[0] = (jsbytecode)op; - cg->next[1] = op1; - cg->next += 2; + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + CG_NEXT(cg) = next + 2; UpdateDepth(cx, cg, offset); } return offset; @@ -168,10 +169,11 @@ js_Emit3(JSContext *cx, JSCodeGenerator *cg, JSOp op, jsbytecode op1, ptrdiff_t offset = EmitCheck(cx, cg, op, 3); if (offset >= 0) { - cg->next[0] = (jsbytecode)op; - cg->next[1] = op1; - cg->next[2] = op2; - cg->next += 3; + jsbytecode *next = CG_NEXT(cg); + next[0] = (jsbytecode)op; + next[1] = op1; + next[2] = op2; + CG_NEXT(cg) = next + 3; UpdateDepth(cx, cg, offset); } return offset; @@ -184,8 +186,9 @@ js_EmitN(JSContext *cx, JSCodeGenerator *cg, JSOp op, size_t extra) ptrdiff_t offset = EmitCheck(cx, cg, op, length); if (offset >= 0) { - *cg->next = (jsbytecode)op; - cg->next += length; + jsbytecode *next = CG_NEXT(cg); + *next = (jsbytecode)op; + CG_NEXT(cg) = next + length; UpdateDepth(cx, cg, offset); } return offset; @@ -344,7 +347,7 @@ js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg) JSStmtInfo *stmt; stmt = cg->treeContext.topStmt; - if (!PatchGotos(cx, cg, stmt, stmt->breaks, cg->next)) + if (!PatchGotos(cx, cg, stmt, stmt->breaks, CG_NEXT(cg))) return JS_FALSE; if (!PatchGotos(cx, cg, stmt, stmt->continues, CG_CODE(cg, stmt->update))) return JS_FALSE; @@ -484,13 +487,13 @@ FixupFinallyJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart, { jsbytecode *pc; - pc = cg->base + tryStart; - BYTECODE_ITER(pc, cg->next, + pc = CG_BASE(cg) + tryStart; + BYTECODE_ITER(pc, CG_NEXT(cg), if (*pc == JSOP_GOSUB) { ptrdiff_t index = GET_JUMP_OFFSET(pc); if (index <= 0) { if (index == 0) - index = finallyIndex - (pc - cg->base); + index = finallyIndex - PTRDIFF(pc, CG_BASE(cg), jsbytecode); else index++; CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, index); @@ -506,10 +509,12 @@ FixupCatchJumps(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t tryStart, { jsbytecode *pc; - pc = cg->base + tryStart; - BYTECODE_ITER(pc, cg->next, + pc = CG_BASE(cg) + tryStart; + BYTECODE_ITER(pc, CG_NEXT(cg), if (*pc == JSOP_GOTO && !GET_JUMP_OFFSET(pc)) { - CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, postCatch - (pc - cg->base)); + CHECK_AND_SET_JUMP_OFFSET(cx, cg, pc, + postCatch - PTRDIFF(pc, CG_BASE(cg), + jsbytecode)); } ); return JS_TRUE; @@ -598,19 +603,28 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) ale = js_IndexAtom(cx, atom, &cg->atomList); if (!ale) return JS_FALSE; + atomIndex = ale->index; /* Emit a bytecode or srcnote naming the literal in its immediate. */ #if JS_HAS_LEXICAL_CLOSURE if (pn->pn_op != JSOP_NOP) { - EMIT_ATOM_INDEX_OP(pn->pn_op, ale->index); + EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex); break; } #endif - noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)ale->index); + + /* Top-level functions need a nop for decompilation. */ + noteIndex = js_NewSrcNote2(cx, cg, SRC_FUNCDEF, (ptrdiff_t)atomIndex); if (noteIndex < 0 || js_Emit1(cx, cg, JSOP_NOP) < 0) { return JS_FALSE; } + + /* Top-levels also need a prolog op to predefine their names. */ + JS_ASSERT(fun->atom); + CG_SWITCH_TO_PROLOG(cg); + EMIT_ATOM_INDEX_OP(JSOP_DEFFUN, atomIndex); + CG_SWITCH_TO_MAIN(cg); break; } @@ -730,7 +744,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } else { low = JSVAL_INT_MAX; high = JSVAL_INT_MIN; - cg2.base = NULL; + cg2.current = NULL; for (pn3 = pn2->pn_head; pn3; pn3 = pn3->pn_next) { if (pn3->pn_type == TOK_DEFAULT) { hasDefault = JS_TRUE; @@ -823,9 +837,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) high = i; } if (switchop == JSOP_CONDSWITCH) { - JS_ASSERT(!cg2.base); + JS_ASSERT(!cg2.current); } else { - if (cg2.base) + if (cg2.current) js_FinishCodeGenerator(cx, &cg2); if (switchop == JSOP_TABLESWITCH) { tablen = (uint32)(high - low + 1); @@ -1237,9 +1251,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) } else { /* - for 'for(x[i]...)' there's only the object on the stack, - so we need to hide the pop. - */ + * For 'for(x[i]...)' there's only the object on the stack, + * so we need to hide the pop. + */ if (js_NewSrcNote(cx, cg, SRC_HIDDEN) < 0) return JS_FALSE; if (js_Emit1(cx, cg, JSOP_POP) < 0) @@ -1592,15 +1606,25 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (!ale) return JS_FALSE; atomIndex = ale->index; + + /* Emit a prolog bytecode to predefine the var w/ void value. */ + CG_SWITCH_TO_PROLOG(cg); + EMIT_ATOM_INDEX_OP(pn->pn_op, atomIndex); + CG_SWITCH_TO_MAIN(cg); } if (pn2->pn_expr) { - if (op == JSOP_SETNAME2) + if (op == JSOP_SETNAME) EMIT_ATOM_INDEX_OP(JSOP_BINDNAME, atomIndex); if (!js_EmitTree(cx, cg, pn2->pn_expr)) return JS_FALSE; } - if (pn2 == pn->pn_head && js_NewSrcNote(cx, cg, SRC_VAR) < 0) - return JS_FALSE; + if (pn2 == pn->pn_head && + js_NewSrcNote(cx, cg, + (pn->pn_op == JSOP_DEFCONST) + ? SRC_CONST + : SRC_VAR) < 0) { + return JS_FALSE; + } EMIT_ATOM_INDEX_OP(op, atomIndex); tmp = CG_OFFSET(cg); if (noteIndex >= 0) { @@ -1761,7 +1785,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) if (op != JSOP_NOP) { switch (pn2->pn_type) { case TOK_NAME: - if (pn2->pn_op != JSOP_SETNAME2) { + if (pn2->pn_op != JSOP_SETNAME) { EMIT_ATOM_INDEX_OP((pn2->pn_op == JSOP_SETARG) ? JSOP_GETARG : JSOP_GETVAR, @@ -2219,7 +2243,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) case TOK_OBJECT: /* * The scanner and parser associate JSOP_NAME with TOK_NAME, although - * other bytecodes may result instead (JSOP_BINDNAME/JSOP_SETNAME2, + * other bytecodes may result instead (JSOP_BINDNAME/JSOP_SETNAME, * JSOP_FORNAME2, etc.). Among JSOP_*NAME* variants, only JSOP_NAME * may generate the first operand of a call or new expression, so only * it sets the "obj" virtual machine register to the object along the @@ -2271,6 +2295,10 @@ JS_FRIEND_DATA(const char *) js_SrcNoteName[] = { "funcdef", "tryfin", "catch", + "const", + "reserved1", + "reserved2", + "reserved3", "newline", "setline", "xdelta" @@ -2299,6 +2327,10 @@ uint8 js_SrcNoteArity[] = { 1, /* SRC_FUNCDEF */ 1, /* SRC_TRYFIN */ 1, /* SRC_CATCH */ + 0, /* SRC_CONST */ + 0, /* SRC_RESERVED1 */ + 0, /* SRC_RESERVED2 */ + 0, /* SRC_RESERVED3 */ 0, /* SRC_NEWLINE */ 1, /* SRC_SETLINE */ 0 /* SRC_XDELTA */ @@ -2312,8 +2344,8 @@ AllocSrcNote(JSContext *cx, JSCodeGenerator *cg) size_t incr, size; index = cg->noteCount; - if (index % SNINCR == 0) { - pool = &cx->tempPool; + if ((uintN)index % SNINCR == 0) { + pool = &cx->notePool; incr = SNINCR * sizeof(jssrcnote); if (!cg->notes) { JS_ARENA_ALLOCATE(cg->notes, pool, incr); @@ -2357,7 +2389,7 @@ js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) xdelta = JS_MIN(delta, SN_XDELTA_MASK); SN_MAKE_XDELTA(sn, xdelta); delta -= xdelta; - index = js_NewSrcNote(cx, cg, SRC_NULL); + index = AllocSrcNote(cx, cg); if (index < 0) return -1; sn = &cg->notes[index]; @@ -2371,7 +2403,7 @@ js_NewSrcNote(JSContext *cx, JSCodeGenerator *cg, JSSrcNoteType type) */ SN_MAKE_NOTE(sn, type, delta); for (n = (intN)js_SrcNoteArity[type]; n > 0; n--) { - if (js_NewSrcNote(cx, cg, SRC_NULL) < 0) + if (AllocSrcNote(cx, cg) < 0) return -1; } return index; @@ -2413,7 +2445,7 @@ GrowSrcNotes(JSContext *cx, JSCodeGenerator *cg) JSArenaPool *pool; size_t incr, size; - pool = &cx->tempPool; + pool = &cx->notePool; incr = SNINCR * sizeof(jssrcnote); size = cg->noteCount * sizeof(jssrcnote); JS_ARENA_GROW(cg->notes, pool, size, incr); @@ -2483,7 +2515,7 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, /* Maybe this offset was already set to a three-byte value. */ if (!(*sn & SN_3BYTE_OFFSET_FLAG)) { /* Losing, need to insert another two bytes for this offset. */ - index = sn - cg->notes; + index = PTRDIFF(sn, cg->notes, jssrcnote); cg->noteCount += 2; /* @@ -2534,6 +2566,11 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg) if (size <= cg->tryNoteSpace) return JS_TRUE; + /* + * Allocate trynotes from cx->tempPool. + * XXX too much growing and we bloat, as other tempPool allocators block + * in-place growth, and we never recycle old free space in an arena. + */ if (!cg->tryBase) { size = JS_ROUNDUP(size, TNINCR); JS_ARENA_ALLOCATE(cg->tryBase, &cx->tempPool, size); @@ -2542,7 +2579,7 @@ js_AllocTryNotes(JSContext *cx, JSCodeGenerator *cg) cg->tryNoteSpace = size; cg->tryNext = cg->tryBase; } else { - delta = (char *)cg->tryNext - (char *)cg->tryBase; + delta = PTRDIFF((char *)cg->tryNext, (char *)cg->tryBase, char); incr = size - cg->tryNoteSpace; incr = JS_ROUNDUP(incr, TNINCR); size = cg->tryNoteSpace; @@ -2576,7 +2613,7 @@ js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote **tryp) uintN count; JSTryNote *tmp, *final; - count = cg->tryNext - cg->tryBase; + count = PTRDIFF(cg->tryNext, cg->tryBase, JSTryNote); if (!count) { *tryp = NULL; return JS_TRUE; @@ -2590,7 +2627,7 @@ js_FinishTakingTryNotes(JSContext *cx, JSCodeGenerator *cg, JSTryNote **tryp) } memcpy(final, tmp, count * sizeof(JSTryNote)); final[count].start = 0; - final[count].length = CG_OFFSET(cg); + final[count].length = CG_PROLOG_OFFSET(cg) + CG_OFFSET(cg); final[count].catchStart = 0; *tryp = final; return JS_TRUE; diff --git a/mozilla/js/src/jsemit.h b/mozilla/js/src/jsemit.h index ed8f5d8b4e0..4922153d103 100644 --- a/mozilla/js/src/jsemit.h +++ b/mozilla/js/src/jsemit.h @@ -84,6 +84,7 @@ struct JSTreeContext { /* tree context for semantic checks */ uint32 flags; /* statement state flags, see below */ uint32 tryCount; /* total count of try statements parsed */ JSStmtInfo *topStmt; /* top of statement info stack */ + JSAtomList decls; /* const and var declaration atom list */ }; #define TCF_IN_FUNCTION 0x01 /* parsing inside function body */ @@ -92,14 +93,21 @@ struct JSTreeContext { /* tree context for semantic checks */ #define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */ #define TREE_CONTEXT_INIT(tc) \ - ((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL) + ((tc)->flags = 0, (tc)->tryCount = 0, (tc)->topStmt = NULL, \ + ATOM_LIST_INIT(&(tc)->decls)) + +#define TREE_CONTEXT_FREE(tc) \ + ((void)0) struct JSCodeGenerator { void *codeMark; /* low watermark in cx->codePool */ + void *noteMark; /* low watermark in cx->notePool */ void *tempMark; /* low watermark in cx->tempPool */ - jsbytecode *base; /* base of JS bytecode vector */ - jsbytecode *limit; /* one byte beyond end of bytecode */ - jsbytecode *next; /* pointer to next free bytecode */ + struct { + jsbytecode *base; /* base of JS bytecode vector */ + jsbytecode *limit; /* one byte beyond end of bytecode */ + jsbytecode *next; /* pointer to next free bytecode */ + } prolog, main, *current; const char *filename; /* null or weak link to source filename */ uintN firstLine; /* first line, for js_NewScriptFromCG */ uintN currentLine; /* line number for tree-based srcnote gen */ @@ -116,13 +124,27 @@ struct JSCodeGenerator { size_t tryNoteSpace; /* # of bytes allocated at tryBase */ }; -#define CG_CODE(cg,offset) ((cg)->base + (offset)) -#define CG_OFFSET(cg) PTRDIFF((cg)->next, (cg)->base, jsbytecode) +#define CG_BASE(cg) ((cg)->current->base) +#define CG_LIMIT(cg) ((cg)->current->limit) +#define CG_NEXT(cg) ((cg)->current->next) +#define CG_CODE(cg,offset) (CG_BASE(cg) + (offset)) +#define CG_OFFSET(cg) PTRDIFF(CG_NEXT(cg), CG_BASE(cg), jsbytecode) + +#define CG_PROLOG_BASE(cg) ((cg)->prolog.base) +#define CG_PROLOG_LIMIT(cg) ((cg)->prolog.limit) +#define CG_PROLOG_NEXT(cg) ((cg)->prolog.next) +#define CG_PROLOG_CODE(cg,poff) (CG_PROLOG_BASE(cg) + (poff)) +#define CG_PROLOG_OFFSET(cg) PTRDIFF(CG_PROLOG_NEXT(cg), CG_PROLOG_BASE(cg),\ + jsbytecode) + +#define CG_SWITCH_TO_MAIN(cg) ((cg)->current = &(cg)->main) +#define CG_SWITCH_TO_PROLOG(cg) ((cg)->current = &(cg)->prolog) /* - * Initialize cg to allocate bytecode space from cx->codePool, and srcnote - * space from cx->tempPool. Return true on success. Report an error and - * return false if the initial code segment can't be allocated. + * Initialize cg to allocate bytecode space from cx->codePool, source note + * space from cx->notePool, and all other arena-allocated temporaries from + * cx->tempPool. Return true on success. Report an error and return false + * if the initial code segment can't be allocated. */ extern JS_FRIEND_API(JSBool) js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, @@ -130,10 +152,11 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSPrincipals *principals); /* - * Release cx->codePool and cx->tempPool to marks set by js_InitCodeGenerator. - * Note that cgs are magic: they own tempPool and codePool "tops-of-stack" - * above their codeMark and tempMark points. This means you cannot alloc - * from tempPool and save the pointer beyond the next JS_FinishCodeGenerator. + * Release cx->codePool, cx->notePool, and cx->tempPool to marks set by + * js_InitCodeGenerator. Note that cgs are magic: they own the arena pool + * "tops-of-stack" space above their codeMark, noteMark, and tempMark points. + * This means you cannot alloc from tempPool and save the pointer beyond the + * next JS_FinishCodeGenerator. */ extern JS_FRIEND_API(void) js_FinishCodeGenerator(JSContext *cx, JSCodeGenerator *cg); @@ -232,10 +255,15 @@ js_EmitFunctionBody(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body, * Source notes generated along with bytecode for decompiling and debugging. * A source note is a uint8 with 5 bits of type and 3 of offset from the pc of * the previous note. If 3 bits of offset aren't enough, extended delta notes - * (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits + * (SRC_XDELTA) consisting of 3 set high order bits followed by 5 offset bits * are emitted before the next note. Some notes have operand offsets encoded * immediately after them, in note bytes or byte-triples. * + * Source Note Extended Delta + * +7-6-5-4-3+2-1-0+ +7-6-5+4-3-2-1-0+ + * |note-type|delta| |1 1 1|ext-delta| + * +---------+-----+ +-----+---------+ + * * At most one "gettable" note (i.e., a note of type other than SRC_NEWLINE, * SRC_SETLINE, and SRC_XDELTA) applies to a given bytecode. * @@ -251,7 +279,7 @@ typedef enum JSSrcNoteType { SRC_CONTINUE = 5, /* JSOP_GOTO is a continue, not a break; also used on JSOP_ENDINIT if extra comma at end of array literal: [1,2,,] */ - SRC_VAR = 6, /* JSOP_NAME/FORNAME with a var declaration */ + SRC_VAR = 6, /* JSOP_NAME/SETNAME/FORNAME in a var decl */ SRC_PCDELTA = 7, /* offset from comma-operator to next POP, or from CONDSWITCH to first CASE opcode */ SRC_ASSIGNOP = 8, /* += or another assign-op follows */ @@ -269,14 +297,18 @@ typedef enum JSSrcNoteType { SRC_FUNCDEF = 19, /* JSOP_NOP for function f() with atomid */ 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 */ + SRC_CONST = 22, /* JSOP_SETCONST in a const decl */ + SRC_RESERVED1 = 23, /* reserved for future use */ + SRC_RESERVED2 = 24, /* reserved for future use */ + SRC_RESERVED3 = 25, /* reserved for future use */ + SRC_NEWLINE = 26, /* bytecode follows a source newline */ + SRC_SETLINE = 27, /* a file-absolute source line number note */ + SRC_XDELTA = 28 /* 28-31 are for extended delta notes */ } JSSrcNoteType; #define SN_TYPE_BITS 5 #define SN_DELTA_BITS 3 -#define SN_XDELTA_BITS 6 +#define SN_XDELTA_BITS 5 #define SN_TYPE_MASK (JS_BITMASK(SN_TYPE_BITS) << SN_DELTA_BITS) #define SN_DELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_DELTA_BITS)) #define SN_XDELTA_MASK ((ptrdiff_t)JS_BITMASK(SN_XDELTA_BITS)) @@ -313,8 +345,8 @@ typedef enum JSSrcNoteType { #define SN_3BYTE_OFFSET_MASK 0x7f extern JS_FRIEND_DATA(const char *) js_SrcNoteName[]; -extern JS_FRIEND_DATA(uint8) js_SrcNoteArity[]; -extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); +extern JS_FRIEND_DATA(uint8) js_SrcNoteArity[]; +extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn); #define SN_LENGTH(sn) ((js_SrcNoteArity[SN_TYPE(sn)] == 0) ? 1 \ : js_SrcNoteLength(sn)) @@ -351,7 +383,7 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index, uintN which, ptrdiff_t offset); /* - * Finish taking source notes in cx's tempPool by copying them to new + * Finish taking source notes in cx's notePool by copying them to new * stable store allocated via JS_malloc. Return null on malloc failure, * which means this function reported an error. */ diff --git a/mozilla/js/src/jsfun.c b/mozilla/js/src/jsfun.c index d4c2beeda27..946ff0d91c0 100644 --- a/mozilla/js/src/jsfun.c +++ b/mozilla/js/src/jsfun.c @@ -1417,6 +1417,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) jschar *collected_args, *cp; size_t args_length; JSTokenType tt; + jsid oldArgId; JSBool ok; if (cx->fp && !cx->fp->constructing) { @@ -1540,20 +1541,22 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) goto bad_formal; } if (sprop && obj2 == obj) { -#ifdef CHECK_ARGUMENT_HIDING - JS_ASSERT(SPROP_GETTER(sprop, obj) == js_GetArgument); - OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop); - JS_ReportErrorNumber(cx, JSREPORT_WARNING, - JSMSG_SAME_FORMAL, ATOM_BYTES(atom)); - goto bad_formal; -#else + if (JS_HAS_STRICT_OPTION(cx)) { + JS_ASSERT(SPROP_GETTER(sprop, obj) == js_GetArgument); + OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop); + js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, + JSMSG_DUPLICATE_FORMAL, + ATOM_BYTES(atom)); + goto bad_formal; + } + /* * A duplicate parameter name. We create a dummy symbol * entry with property id of the parameter number and set * the id to the name of the parameter. See jsopcode.c: * the decompiler knows to treat this case specially. */ - jsid oldArgId = (jsid) sprop->id; + oldArgId = (jsid) sprop->id; OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop); sprop = NULL; if (!js_DefineProperty(cx, obj, oldArgId, JSVAL_VOID, @@ -1563,7 +1566,6 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) goto bad_formal; } sprop->id = (jsid) atom; -#endif } if (sprop) OBJ_DROP_PROPERTY(cx, obj2, (JSProperty *)sprop); diff --git a/mozilla/js/src/jsgc.c b/mozilla/js/src/jsgc.c index 95d3c3785df..13e3f0dfae0 100644 --- a/mozilla/js/src/jsgc.c +++ b/mozilla/js/src/jsgc.c @@ -541,12 +541,12 @@ gc_mark(JSRuntime *rt, void *thing) JSAtom *atom = sym_atom(sprop->symbols); const char *id = (atom && ATOM_IS_STRING(atom)) ? JS_GetStringBytes(ATOM_TO_STRING(atom)) - : "unknown", + : "unknown"; #endif if (sprop->attrs & JSPROP_GETTER) { #ifdef GC_MARK_DEBUG - PR_snprintf(buf, sizeof buf, "%s %s", + JS_snprintf(buf, sizeof buf, "%s %s", id, js_getter_str); #endif GC_MARK(rt, @@ -557,7 +557,7 @@ gc_mark(JSRuntime *rt, void *thing) } if (sprop->attrs & JSPROP_SETTER) { #ifdef GC_MARK_DEBUG - PR_snprintf(buf, sizeof buf, "%s %s", + JS_snprintf(buf, sizeof buf, "%s %s", id, js_setter_str); #endif GC_MARK(rt, diff --git a/mozilla/js/src/jsinterp.c b/mozilla/js/src/jsinterp.c index 8e7de345251..42a4f2f9e0f 100644 --- a/mozilla/js/src/jsinterp.c +++ b/mozilla/js/src/jsinterp.c @@ -992,6 +992,7 @@ js_Interpret(JSContext *cx, jsval *result) JSRuntime *rt; JSStackFrame *fp; JSScript *script; + JSVersion newvers, oldvers; JSObject *obj, *obj2, *proto, *parent; JSBranchCallback onbranch; JSBool ok, cond; @@ -1002,7 +1003,7 @@ js_Interpret(JSContext *cx, jsval *result) JSOp op, op2; JSCodeSpec *cs; JSAtom *atom; - uintN argc, slot; + uintN argc, slot, attrs; jsval *vp, lval, rval, ltmp, rtmp; jsid id; JSObject *withobj, *origobj, *propobj; @@ -1030,9 +1031,6 @@ js_Interpret(JSContext *cx, jsval *result) JSFunction *fun2; JSObject *closure; #endif -#if JS_HAS_EXPORT_IMPORT || JS_HAS_GETTER_SETTER - uintN attrs; -#endif #if JS_HAS_GETTER_SETTER JSPropertyOp getter, setter; #endif @@ -1056,6 +1054,14 @@ js_Interpret(JSContext *cx, jsval *result) script = fp->script; obj = fp->scopeChain; + /* + * Optimized Get and SetVersion for proper script language versioning. + */ + newvers = script->version; + oldvers = cx->version; + if (newvers != oldvers) + JS_SetVersion(cx, newvers); + /* * Prepare to call a user-supplied branch handler, and abort the script * if it returns false. @@ -1543,30 +1549,18 @@ js_Interpret(JSContext *cx, jsval *result) } \ } - case JSOP_SETNAME: - /* Get an immediate atom naming the variable to set. */ - atom = GET_ATOM(cx, script, pc); - id = (jsid)atom; - - SAVE_SP(fp); - ok = js_FindVariable(cx, id, &obj, &obj2, &prop); - if (!ok) - goto out; - JS_ASSERT(prop); - - OBJ_DROP_PROPERTY(cx, obj2, prop); - - /* Pop the right-hand side and set obj[id] to it. */ - rval = POP(); - - /* Try to hit the property cache, FindVariable primes it. */ - CACHED_SET(OBJ_SET_PROPERTY(cx, obj, id, &rval)); - if (!ok) - goto out; - - /* Push the right-hand side as our result. */ - PUSH_OPND(rval); - break; + case JSOP_SETCONST: + obj = js_FindVariableScope(cx, &fun); + atom = GET_ATOM(cx, script, pc); + rval = POP(); + ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, rval, NULL, NULL, + JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY, + NULL); + if (!ok) + goto out; + PUSH_OPND(rval); + break; case JSOP_BINDNAME: atom = GET_ATOM(cx, script, pc); @@ -1578,7 +1572,7 @@ js_Interpret(JSContext *cx, jsval *result) PUSH_OPND(OBJECT_TO_JSVAL(obj)); break; - case JSOP_SETNAME2: + case JSOP_SETNAME: atom = GET_ATOM(cx, script, pc); id = (jsid)atom; rval = POP(); @@ -2647,6 +2641,42 @@ js_Interpret(JSContext *cx, jsval *result) *vp = sp[-1]; break; + case JSOP_DEFFUN: + /* We must be at top-level ("box") scope, not inside a with. */ + JS_ASSERT(fp->scopeChain == js_FindVariableScope(cx, &fun)); + + atom = GET_ATOM(cx, script, pc); + obj = ATOM_TO_OBJECT(atom); + fun = JS_GetPrivate(cx, obj); + attrs = fun->flags & (JSFUN_GETTER | JSFUN_SETTER); + ok = OBJ_DEFINE_PROPERTY(cx, fp->scopeChain, (jsid)fun->atom, + attrs ? JSVAL_VOID : OBJECT_TO_JSVAL(obj), + (attrs & JSFUN_GETTER) + ? (JSPropertyOp) obj + : NULL, + (attrs & JSFUN_SETTER) + ? (JSPropertyOp) obj + : NULL, + attrs | JSPROP_ENUMERATE, + NULL); + if (!ok) + goto out; + break; + + case JSOP_DEFCONST: + case JSOP_DEFVAR: + atom = GET_ATOM(cx, script, pc); + obj = js_FindVariableScope(cx, &fun); + JS_ASSERT(!fun); + attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT; + if (op == JSOP_DEFCONST) + attrs |= JSPROP_READONLY; + ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, + NULL, NULL, attrs, NULL); + if (!ok) + goto out; + break; + #if JS_HAS_GETTER_SETTER case JSOP_GETTER: case JSOP_SETTER: @@ -2655,7 +2685,7 @@ js_Interpret(JSContext *cx, jsval *result) cs = &js_CodeSpec[op2]; len = cs->length; switch (op2) { - case JSOP_SETNAME2: + case JSOP_SETNAME: case JSOP_SETPROP: atom = GET_ATOM(cx, script, pc); id = (jsid)atom; @@ -2687,7 +2717,7 @@ js_Interpret(JSContext *cx, jsval *result) JS_ASSERT(JSVAL_IS_OBJECT(lval)); obj = JSVAL_TO_OBJECT(lval); break; -#endif +#endif /* JS_HAS_INITIALIZERS */ default: JS_ASSERT(0); @@ -2718,7 +2748,7 @@ js_Interpret(JSContext *cx, jsval *result) if (cs->ndefs) PUSH_OPND(rval); break; -#endif +#endif /* JS_HAS_GETTER_SETTER */ #if JS_HAS_INITIALIZERS case JSOP_NEWINIT: @@ -2997,6 +3027,8 @@ no_catch: * Restore the previous frame's execution state. */ js_FreeStack(cx, mark); + if (newvers != oldvers) + JS_SetVersion(cx, oldvers); cx->interpLevel--; return ok; } diff --git a/mozilla/js/src/jslock.c b/mozilla/js/src/jslock.c index 56c46f16d59..7ea1f1e93cb 100644 --- a/mozilla/js/src/jslock.c +++ b/mozilla/js/src/jslock.c @@ -618,23 +618,19 @@ js_Unlock(JSThinLock *tl, jsword me) void js_LockRuntime(JSRuntime *rt) { - jsword me = CurrentThreadId(); - JSThinLock *tl; - - JS_ASSERT(Thin_RemoveWait(ReadWord(rt->rtLock.owner)) != me); - tl = &rt->rtLock; - JS_LOCK0(tl,me); + PR_Lock(rt->rtLock); +#ifdef DEBUG + rt->rtLockOwner = CurrentThreadId(); +#endif } void js_UnlockRuntime(JSRuntime *rt) { - jsword me = CurrentThreadId(); - JSThinLock *tl; - - JS_ASSERT(Thin_RemoveWait(ReadWord(rt->rtLock.owner)) == me); - tl = &rt->rtLock; - JS_UNLOCK0(tl,me); +#ifdef DEBUG + rt->rtLockOwner = 0; +#endif + PR_Unlock(rt->rtLock); } static JS_INLINE void @@ -738,7 +734,7 @@ js_UnlockObj(JSContext *cx, JSObject *obj) JSBool js_IsRuntimeLocked(JSRuntime *rt) { - return CurrentThreadId() == Thin_RemoveWait(ReadWord(rt->rtLock.owner)); + return CurrentThreadId() == rt->rtLockOwner; } JSBool diff --git a/mozilla/js/src/jsobj.c b/mozilla/js/src/jsobj.c index 869cb69582d..f3b9e82ed4e 100644 --- a/mozilla/js/src/jsobj.c +++ b/mozilla/js/src/jsobj.c @@ -1758,6 +1758,12 @@ js_FindVariable(JSContext *cx, jsid id, JSObject **objp, JSObject **pobjp, /* * Make a top-level variable. */ + if (JS_HAS_STRICT_OPTION(cx)) { + JSString *str = JSVAL_TO_STRING(js_IdToValue(id)); + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_UNDECLARED_VAR, JS_GetStringBytes(str)); + return JS_FALSE; + } if (!OBJ_DEFINE_PROPERTY(cx, obj, id, JSVAL_VOID, NULL, NULL, JSPROP_ENUMERATE, &prop)) { return JS_FALSE; @@ -2037,9 +2043,10 @@ read_only: if (JSVERSION_IS_ECMA(cx->version)) return JS_TRUE; str = js_DecompileValueGenerator(cx, JS_FALSE, js_IdToValue(id), NULL); - if (str) - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_READ_ONLY, JS_GetStringBytes(str)); + if (str) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, + JSMSG_READ_ONLY, JS_GetStringBytes(str)); + } return JS_FALSE; } diff --git a/mozilla/js/src/jsopcode.c b/mozilla/js/src/jsopcode.c index cf77750da90..fcb5566db7d 100644 --- a/mozilla/js/src/jsopcode.c +++ b/mozilla/js/src/jsopcode.c @@ -63,6 +63,8 @@ #include "jsscript.h" #include "jsstr.h" +char js_const_str[] = "const"; +char js_var_str[] = "var"; char js_function_str[] = "function"; char js_in_str[] = "in"; char js_instanceof_str[] = "instanceof"; @@ -110,6 +112,8 @@ js_Disassemble(JSContext *cx, JSScript *script, JSBool lines, FILE *fp) pc = script->code; end = pc + script->length; while (pc < end) { + if (pc == script->main) + fputs("main:\n", fp); len = js_Disassemble1(cx, script, pc, pc - script->code, lines, fp); if (!len) return; @@ -757,6 +761,25 @@ GetSlotAtom(JSScope *scope, JSPropertyOp getter, uintN slot) return NULL; } +static const char * +VarPrefix(jssrcnote *sn) +{ + char *kw; + static char buf[8]; + + kw = NULL; + if (sn) { + if (SN_TYPE(sn) == SRC_VAR) + kw = js_var_str; + else if (SN_TYPE(sn) == SRC_CONST) + kw = js_const_str; + } + if (!kw) + return ""; + JS_snprintf(buf, sizeof buf, "%s ", kw); + return buf; +} + static JSBool Decompile(SprintStack *ss, jsbytecode *pc, intN nb) { @@ -1320,8 +1343,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) oplen = js_CodeSpec[JSOP_IFEQ].length; len = GET_JUMP_OFFSET(pc); do_forinbody: - js_printf(jp, "\tfor (%s%s", - (sn && SN_TYPE(sn) == SRC_VAR) ? "var " : "", lval); + js_printf(jp, "\tfor (%s%s", VarPrefix(sn), lval); if (atom) js_printf(jp, ".%s", ATOM_BYTES(atom)); else if (xval) @@ -1386,13 +1408,13 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) LOCAL_ASSERT(atom); goto do_setname; + case JSOP_SETCONST: case JSOP_SETNAME: - case JSOP_SETNAME2: atom = GET_ATOM(cx, jp->script, pc); do_setname: lval = ATOM_BYTES(atom); rval = POP_STR(); - if (op == JSOP_SETNAME2) + if (op == JSOP_SETNAME) (void) PopOff(ss, op); if ((sn = js_GetSrcNote(jp->script, pc - 1)) != NULL && SN_TYPE(sn) == SRC_ASSIGNOP) { @@ -1401,8 +1423,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) } else { sn = js_GetSrcNote(jp->script, pc); todo = Sprint(&ss->sprinter, "%s%s = %s", - (sn && SN_TYPE(sn) == SRC_VAR) ? "var " : "", - lval, rval); + VarPrefix(sn), lval, rval); } break; @@ -1640,9 +1661,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) atom = GET_ATOM(cx, jp->script, pc); do_name: sn = js_GetSrcNote(jp->script, pc); - todo = Sprint(&ss->sprinter, - (sn && SN_TYPE(sn) == SRC_VAR) ? "var %s" : "%s", - ATOM_BYTES(atom)); + todo = Sprint(&ss->sprinter, "%s%s", + VarPrefix(sn), ATOM_BYTES(atom)); break; case JSOP_UINT16: @@ -1885,7 +1905,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb) obj = ATOM_TO_OBJECT(atom); fun = JS_GetPrivate(cx, obj); jp2 = js_NewPrinter(cx, JS_GetFunctionName(fun), jp->indent, - jp->pretty); + JS_FALSE); if (!jp2) return JS_FALSE; jp2->scope = jp->scope; @@ -2068,9 +2088,10 @@ js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len) { SprintStack ss; JSContext *cx; - void *mark; - JSScript *oldscript; + void *mark, *space; + size_t offsetsz, opcodesz; JSBool ok; + JSScript *oldscript; char *last; /* Initialize a sprinter for use with the offset stack. */ @@ -2079,14 +2100,16 @@ js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len) mark = JS_ARENA_MARK(&cx->tempPool); INIT_SPRINTER(cx, &ss.sprinter, &cx->tempPool, PAREN_SLOP); - /* Initialize the offset and opcode stacks. */ - ss.offsets = JS_malloc(cx, script->depth * sizeof *ss.offsets); - ss.opcodes = JS_malloc(cx, script->depth * sizeof *ss.opcodes); - if (!ss.offsets || !ss.opcodes) { - if (ss.offsets) - JS_free(cx, ss.offsets); - return JS_FALSE; + /* Allocate the parallel (to avoid padding) offset and opcode stacks. */ + offsetsz = script->depth * sizeof(ptrdiff_t); + opcodesz = script->depth * sizeof(jsbytecode); + JS_ARENA_ALLOCATE(space, &cx->tempPool, offsetsz + opcodesz); + if (!space) { + ok = JS_FALSE; + goto out; } + ss.offsets = (ptrdiff_t *) space; + ss.opcodes = (jsbytecode *) ((char *)space + offsetsz); ss.top = 0; /* Call recursive subroutine to do the hard work. */ @@ -2103,9 +2126,8 @@ js_DecompileCode(JSPrinter *jp, JSScript *script, jsbytecode *pc, uintN len) js_printf(jp, "%s", last); } - /* Free and clear temporary stuff. */ - JS_free(cx, ss.offsets); - JS_free(cx, ss.opcodes); +out: + /* Free all temporary stuff allocated under this call. */ JS_ARENA_RELEASE(&cx->tempPool, mark); return ok; } diff --git a/mozilla/js/src/jsopcode.h b/mozilla/js/src/jsopcode.h index 04c1553f6c3..91add1a6ace 100644 --- a/mozilla/js/src/jsopcode.h +++ b/mozilla/js/src/jsopcode.h @@ -123,6 +123,8 @@ struct JSCodeSpec { uint32 format; /* immediate operand format */ }; +extern char js_const_str[]; +extern char js_var_str[]; extern char js_function_str[]; extern char js_in_str[]; extern char js_instanceof_str[]; diff --git a/mozilla/js/src/jsopcode.tbl b/mozilla/js/src/jsopcode.tbl index 77a7be3baee..1ee8cf631dd 100644 --- a/mozilla/js/src/jsopcode.tbl +++ b/mozilla/js/src/jsopcode.tbl @@ -75,7 +75,7 @@ OPDEF(JSOP_FORPROP, 10, "forprop", NULL, 3, 2, 1, 0, JOF_CONST| OPDEF(JSOP_FORELEM, 11, "forelem", NULL, 1, 3, 1, 0, JOF_BYTE |JOF_ELEM|JOF_SET) OPDEF(JSOP_DUP, 12, "dup", NULL, 1, 1, 2, 0, JOF_BYTE) OPDEF(JSOP_DUP2, 13, "dup2", NULL, 1, 2, 4, 0, JOF_BYTE) -OPDEF(JSOP_SETNAME, 14, "setname", NULL, 3, 1, 1, 1, JOF_CONST|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETCONST, 14, "setconst", NULL, 3, 1, 1, 1, JOF_CONST|JOF_NAME|JOF_SET) OPDEF(JSOP_BITOR, 15, "bitor", "|", 1, 2, 1, 2, JOF_BYTE) OPDEF(JSOP_BITXOR, 16, "bitxor", "^", 1, 2, 1, 3, JOF_BYTE) OPDEF(JSOP_BITAND, 17, "bitand", "&", 1, 2, 1, 4, JOF_BYTE) @@ -198,7 +198,7 @@ OPDEF(JSOP_POP2, 107,"pop2", NULL, 1, 2, 0, 0, JOF_BYTE) /* ECMA-complaint assignment ops. */ OPDEF(JSOP_BINDNAME, 108,"bindname", NULL, 3, 0, 1, 0, JOF_CONST|JOF_NAME) -OPDEF(JSOP_SETNAME2, 109,"setname2", NULL, 3, 2, 1, 1, JOF_CONST|JOF_NAME|JOF_SET) +OPDEF(JSOP_SETNAME, 109,"setname", NULL, 3, 2, 1, 1, JOF_CONST|JOF_NAME|JOF_SET) /* Exception handling ops. */ OPDEF(JSOP_THROW, 110,"throw", NULL, 1, 1, 0, 0, JOF_BYTE) @@ -244,3 +244,10 @@ OPDEF(JSOP_ENUMELEM, 122,"enumelem", NULL, 1, 3, 0, 1, JOF_BYTE | */ OPDEF(JSOP_GETTER, 123,js_getter_str,js_getter_str,1, 0, 0, 0, JOF_BYTE) OPDEF(JSOP_SETTER, 124,js_setter_str,js_setter_str,1, 0, 0, 0, JOF_BYTE) + +/* + * Prolog bytecodes for defining function, var, and const names. + */ +OPDEF(JSOP_DEFFUN, 125,"deffun", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME|JOF_SET) +OPDEF(JSOP_DEFCONST, 126,"defconst", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME|JOF_SET) +OPDEF(JSOP_DEFVAR, 127,"defvar", NULL, 3, 0, 0, 0, JOF_CONST|JOF_NAME) diff --git a/mozilla/js/src/jsparse.c b/mozilla/js/src/jsparse.c index 59c2276c8ca..613c52f3195 100644 --- a/mozilla/js/src/jsparse.c +++ b/mozilla/js/src/jsparse.c @@ -299,13 +299,11 @@ js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, out: JS_ENABLE_GC(cx->runtime); - ts->flags &= ~TSF_BADCOMPILE; + ts->flags &= ~TSF_ERROR; cx->fp = fp; return ok; } -#ifdef CHECK_RETURN_EXPR - /* * Insist on a final return before control flows out of pn, but don't be too * smart about loops (do {...; return e2;} while(0) at the end of a function @@ -351,8 +349,6 @@ CheckFinalReturn(JSParseNode *pn) } } -#endif /* CHECK_RETURN_EXPR */ - static JSParseNode * FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun, JSTreeContext *tc) @@ -374,16 +370,14 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun, tc->flags |= TCF_IN_FUNCTION; pn = Statements(cx, ts, tc); -#ifdef CHECK_RETURN_EXPR /* Check for falling off the end of a function that returns a value. */ - if (pn && (tc->flags & TCF_RETURN_EXPR)) { + if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) { if (!CheckFinalReturn(pn)) { js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, JSMSG_NO_RETURN_VALUE); pn = NULL; } } -#endif cx->fp = fp; tc->flags = oldflags; @@ -446,13 +440,10 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSAtom *funAtom, *argAtom; JSFunction *fun, *outerFun; JSObject *parent; - JSPropertyOp getter, setter; - uintN attrs; - JSBool named; - jsval fval; JSObject *pobj; JSScopeProperty *sprop; JSTreeContext funtc; + jsid oldArgId; /* Make a TOK_FUNCTION node. */ pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC); @@ -471,35 +462,14 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, if (!parent) return NULL; - /* Set up for ultimate OBJ_DEFINE_PROPERTY call, if not anonymous. */ - named = !lambda && funAtom && !InWithStatement(tc); - getter = setter = NULL; - attrs = JSPROP_ENUMERATE; - fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom); if (!fun) return NULL; #if JS_HAS_GETTER_SETTER - if (op != JSOP_NOP) { - uintN gsattr; - - if (op == JSOP_GETTER) { - getter = (JSPropertyOp) fun->object; - gsattr = JSPROP_GETTER; - } else { - setter = (JSPropertyOp) fun->object; - gsattr = JSPROP_SETTER; - } - fun->flags |= gsattr; - attrs |= gsattr; - - fval = JSVAL_VOID; - } else + if (op != JSOP_NOP) + fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER; #endif - { - fval = OBJECT_TO_JSVAL(fun->object); - } /* Now parse formal argument list and compute fun->nargs. */ MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL); @@ -514,20 +484,21 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } if (sprop && pobj == fun->object) { if (SPROP_GETTER(sprop, pobj) == js_GetArgument) { -#ifdef CHECK_ARGUMENT_HIDING - OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); - js_ReportCompileErrorNumber(cx, ts, JSREPORT_WARNING, - JSMSG_DUPLICATE_FORMAL, - ATOM_BYTES(argAtom)); - return NULL; -#else + if (JS_HAS_STRICT_OPTION(cx)) { + OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); + js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, + JSMSG_DUPLICATE_FORMAL, + ATOM_BYTES(argAtom)); + return NULL; + } + /* * A duplicate parameter name. We create a dummy symbol * entry with property id of the parameter number and set * the id to the name of the parameter. * The decompiler will know to treat this case specially. */ - jsid oldArgId = (jsid) sprop->id; + oldArgId = (jsid) sprop->id; OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); sprop = NULL; if (!js_DefineProperty(cx, fun->object, @@ -538,7 +509,6 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, return NULL; } sprop->id = (jsid) argAtom; -#endif } } if (sprop) { @@ -574,21 +544,14 @@ FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, pn->pn_fun = fun; pn->pn_body = pn2; pn->pn_tryCount = funtc.tryCount; + TREE_CONTEXT_FREE(&funtc); #if JS_HAS_LEXICAL_CLOSURE - if (outerFun || cx->fp->scopeChain != parent || InWithStatement(tc)) + if (lambda) pn->pn_op = JSOP_CLOSURE; - else if (lambda) - pn->pn_op = JSOP_OBJECT; else #endif pn->pn_op = JSOP_NOP; - - if (named && - !OBJ_DEFINE_PROPERTY(cx, parent, (jsid)funAtom, fval, getter, setter, - attrs, NULL)) { - return NULL; - } return pn; } @@ -651,12 +614,13 @@ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) * XXX not ECMA, but documented in several books -- need a compile option */ if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP) { + JSBool rewrite = JS_HAS_STRICT_OPTION(cx) || + !JSVERSION_IS_ECMA(cx->version); js_ReportCompileErrorNumber(cx, ts, JSREPORT_WARNING, JSMSG_EQUAL_AS_ASSIGN, - JSVERSION_IS_ECMA(cx->version) ? "" - : "\nAssuming equality test"); - if (JSVERSION_IS_ECMA(cx->version)) - goto no_rewrite; + rewrite ? "\nAssuming equality test" : ""); + if (!rewrite) + return pn; pn->pn_type = TOK_EQOP; pn->pn_op = (JSOp)cx->jsop_eq; pn2 = pn->pn_left; @@ -667,7 +631,7 @@ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) case JSOP_SETVAR: pn2->pn_op = JSOP_GETVAR; break; - case JSOP_SETNAME2: + case JSOP_SETNAME: pn2->pn_op = JSOP_NAME; break; case JSOP_SETPROP: @@ -680,7 +644,6 @@ Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JS_ASSERT(0); } } - no_rewrite: return pn; } @@ -1063,11 +1026,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) stmtInfo.type = STMT_FOR_IN_LOOP; /* Check that the left side of the 'in' is valid. */ - if ((pn1->pn_type == TOK_VAR) - ? pn1->pn_count > 1 + if ((pn1->pn_type == TOK_VAR) + ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST) : (pn1->pn_type != TOK_NAME && - pn1->pn_type != TOK_DOT && - pn1->pn_type != TOK_LB)) { + pn1->pn_type != TOK_DOT && + pn1->pn_type != TOK_LB)) { js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, JSMSG_BAD_FOR_LEFTSIDE); return NULL; @@ -1395,14 +1358,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) pn->pn_kid = NULL; } -#ifdef CHECK_RETURN_EXPR - if ((tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == + if (JS_HAS_STRICT_OPTION(cx) && + (tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == (TCF_RETURN_EXPR | TCF_RETURN_VOID)) { js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, JSMSG_NO_RETURN_VALUE); return NULL; } -#endif break; case TOK_LC: @@ -1503,6 +1465,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) JSClass *clasp; JSPropertyOp getter, setter, currentGetter, currentSetter; JSAtom *atom; + JSAtomListElement *ale; JSProperty *prop; JSScopeProperty *sprop; JSBool ok; @@ -1540,12 +1503,33 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) setter = clasp->setProperty; } + ok = JS_TRUE; do { currentGetter = getter; currentSetter = setter; MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME); atom = CURRENT_TOKEN(ts).t_atom; + ATOM_LIST_SEARCH(ale, &tc->decls, atom); + if (ale && + (JS_HAS_STRICT_OPTION(cx) || + pn->pn_op == JSOP_DEFCONST || + ale->index == JSOP_DEFCONST)) + { + js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, + JSMSG_REDECLARED_VAR, + (ale->index == JSOP_DEFCONST) + ? js_const_str + : js_var_str, + ATOM_BYTES(atom)); + return NULL; + } + + ale = js_IndexAtom(cx, atom, &tc->decls); + if (!ale) + return NULL; + ale->index = (jsatomid) pn->pn_op; + pn2 = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_NAME); if (!pn2) return NULL; @@ -1563,14 +1547,12 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) if (SPROP_GETTER(sprop, pobj) == js_GetArgument) { currentGetter = js_GetArgument; currentSetter = js_SetArgument; -#ifdef CHECK_ARGUMENT_HIDING - js_ReportCompileErrorNumber(cx, ts, JSREPORT_WARNING, - JSMSG_VAR_HIDES_ARG, - ATOM_BYTES(atom)); - ok = JS_FALSE; -#else - ok = JS_TRUE; -#endif + if (JS_HAS_STRICT_OPTION(cx)) { + js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR, + JSMSG_VAR_HIDES_ARG, + ATOM_BYTES(atom)); + ok = JS_FALSE; + } } else { ok = JS_TRUE; if (fun) { @@ -1624,17 +1606,18 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) currentGetter = clasp->getProperty; currentSetter = clasp->setProperty; } - ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, - currentGetter, currentSetter, - JSPROP_ENUMERATE | JSPROP_PERMANENT, - &prop); - if (ok && prop) { - pobj = obj; - if (currentGetter == js_GetLocalVariable) { + if (currentGetter == js_GetLocalVariable) { + ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID, + currentGetter, currentSetter, + JSPROP_ENUMERATE | JSPROP_PERMANENT, + &prop); + if (ok) { + pobj = obj; + /* - * Allocate more room for variables in the - * function's frame. We can do this only - * before the function is called. + * Allocate more room for variables in the function's + * frame. We can do this only before the function is + * first called. */ sprop = (JSScopeProperty *)prop; sprop->id = INT_TO_JSVAL(fun->nvars++); @@ -1649,10 +1632,12 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) ok = JS_FALSE; } else { pn2->pn_expr = AssignExpr(cx, ts, tc); - if (pn2->pn_expr) - pn2->pn_op = JSOP_SETNAME2; - else + if (!pn2->pn_expr) ok = JS_FALSE; + else if (pn->pn_op == JSOP_DEFCONST) + pn2->pn_op = JSOP_SETCONST; + else + pn2->pn_op = JSOP_SETNAME; } } @@ -1789,7 +1774,7 @@ AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc) else pn2->pn_op = JSOP_SETVAR; } else { - pn2->pn_op = JSOP_SETNAME2; + pn2->pn_op = JSOP_SETNAME; } break; case TOK_DOT: diff --git a/mozilla/js/src/jsscan.c b/mozilla/js/src/jsscan.c index ebbb76db776..4e369f828c5 100644 --- a/mozilla/js/src/jsscan.c +++ b/mozilla/js/src/jsscan.c @@ -77,7 +77,7 @@ static struct keyword { {js_delete_str, TOK_DELETE, JSOP_NOP, JSVERSION_DEFAULT}, {"do", TOK_DO, JSOP_NOP, JSVERSION_DEFAULT}, {"else", TOK_ELSE, JSOP_NOP, JSVERSION_DEFAULT}, - {"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2}, + {"export", TOK_EXPORT, JSOP_NOP, JSVERSION_1_2}, {js_false_str, TOK_PRIMARY, JSOP_FALSE, JSVERSION_DEFAULT}, {"for", TOK_FOR, JSOP_NOP, JSVERSION_DEFAULT}, {js_function_str, TOK_FUNCTION, JSOP_NOP, JSVERSION_DEFAULT}, @@ -90,11 +90,17 @@ static struct keyword { {js_this_str, TOK_PRIMARY, JSOP_THIS, JSVERSION_DEFAULT}, {js_true_str, TOK_PRIMARY, JSOP_TRUE, JSVERSION_DEFAULT}, {js_typeof_str, TOK_UNARYOP, JSOP_TYPEOF,JSVERSION_DEFAULT}, - {"var", TOK_VAR, JSOP_NOP, JSVERSION_DEFAULT}, + {"var", TOK_VAR, JSOP_DEFVAR,JSVERSION_DEFAULT}, {js_void_str, TOK_UNARYOP, JSOP_VOID, JSVERSION_DEFAULT}, {"while", TOK_WHILE, JSOP_NOP, JSVERSION_DEFAULT}, {"with", TOK_WITH, JSOP_NOP, JSVERSION_DEFAULT}, +#if JS_HAS_CONST + {js_const_str, TOK_VAR, JSOP_DEFCONST,JSVERSION_DEFAULT}, +#else + {js_const_str, TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, +#endif + #if JS_HAS_EXCEPTIONS {"try", TOK_TRY, JSOP_NOP, JSVERSION_DEFAULT}, {"catch", TOK_CATCH, JSOP_NOP, JSVERSION_DEFAULT}, @@ -110,7 +116,7 @@ static struct keyword { #if JS_HAS_INSTANCEOF {js_instanceof_str, TOK_INSTANCEOF, JSOP_INSTANCEOF,JSVERSION_1_4}, #else - {js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4}, + {js_instanceof_str, TOK_RESERVED, JSOP_NOP, JSVERSION_1_4}, #endif #ifdef RESERVE_JAVA_KEYWORDS @@ -119,7 +125,6 @@ static struct keyword { {"byte", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"char", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"class", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, - {"const", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"double", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"extends", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, {"final", TOK_RESERVED, JSOP_NOP, JSVERSION_DEFAULT}, @@ -145,13 +150,13 @@ static struct keyword { #endif #ifdef RESERVE_ECMA_KEYWORDS - {"enum", 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, JSVERSION_1_3}, + {"debugger", TOK_DEBUGGER, JSOP_NOP, JSVERSION_1_3}, #elif defined(RESERVE_ECMA_KEYWORDS) - {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, + {"debugger", TOK_RESERVED, JSOP_NOP, JSVERSION_1_3}, #endif {0,0,0,0} }; @@ -454,68 +459,6 @@ MatchChar(JSTokenStream *ts, int32 expect) return JS_FALSE; } -#if 0 -/* XXX js_ReportCompileError is unused */ -void -js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags, - const char *format, ...) -{ - va_list ap; - char *message; - jschar *limit, lastc; - JSErrorReporter onError; - JSErrorReport report; - jschar *tokenptr; - JSString *linestr; - - va_start(ap, format); - message = JS_vsmprintf(format, ap); - va_end(ap); - if (!message) { - JS_ReportOutOfMemory(cx); - return; - } - - JS_ASSERT(ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); - limit = ts->linebuf.limit; - lastc = limit[-1]; - if (lastc == '\n') - limit[-1] = 0; - onError = cx->errorReporter; - if (onError) { - report.filename = ts->filename; - report.lineno = ts->lineno; - linestr = js_NewStringCopyZ(cx, ts->linebuf.base, 0); - report.linebuf = linestr - ? JS_GetStringBytes(linestr) - : NULL; - tokenptr = CURRENT_TOKEN(ts).ptr; - report.tokenptr = linestr - ? report.linebuf + (tokenptr - ts->linebuf.base) - : NULL; - report.uclinebuf = ts->linebuf.base; - report.uctokenptr = tokenptr; - report.flags = flags; - report.errorNumber = 0; - - (*onError)(cx, message, &report); -#if !defined XP_PC || !defined _MSC_VER || _MSC_VER > 800 - } else { - if (ts->filename) - fprintf(stderr, "%s, ", ts->filename); - if (ts->lineno) - fprintf(stderr, "line %u: ", ts->lineno); - fprintf(stderr, "%s:\n%s\n",message, - js_DeflateString(cx, ts->linebuf.base, - ts->linebuf.limit - ts->linebuf.base)); -#endif - } - if (lastc == '\n') - limit[-1] = lastc; - free(message); -} -#endif - void js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, const uintN errorNumber, ...) @@ -536,8 +479,9 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, va_start(ap, errorNumber); if (!js_ExpandErrorArguments(cx, js_GetErrorMessage, NULL, errorNumber, &message, &report, - JS_TRUE, ap)) + JS_TRUE, ap)) { return; + } va_end(ap); JS_ASSERT(ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); @@ -546,8 +490,8 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, if (onError) { report.filename = ts->filename; report.lineno = ts->lineno; - linestr = js_NewStringCopyN(cx, ts->linebuf.base, - limit - ts->linebuf.base, 0); + linestr = js_NewStringCopyN(cx, ts->linebuf.base, + limit - ts->linebuf.base, 0); report.linebuf = linestr ? JS_GetStringBytes(linestr) : NULL; @@ -578,10 +522,8 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, * otherwise the exception will describe only the last compile error, * which is likely spurious. */ - if (!(ts->flags & TSF_BADCOMPILE)) { - if (js_ErrorToException(cx, message, &report)) - ts->flags |= TSF_BADCOMPILE; - } + if (!(ts->flags & TSF_ERROR)) + (void) js_ErrorToException(cx, message, &report); /* * Suppress any compiletime errors that don't occur at the top level. @@ -625,6 +567,11 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, } if (report.ucmessage) JS_free(cx, (void *)report.ucmessage); + + if (!JSREPORT_IS_WARNING(flags)) { + /* Set the error flag to suppress spurious reports. */ + ts->flags |= TSF_ERROR; + } } JSTokenType diff --git a/mozilla/js/src/jsscan.h b/mozilla/js/src/jsscan.h index e99adac348a..e916d8f67a0 100644 --- a/mozilla/js/src/jsscan.h +++ b/mozilla/js/src/jsscan.h @@ -171,13 +171,12 @@ struct JSTokenStream { #define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor]) /* JSTokenStream flags */ -#define TSF_ERROR 0x01 /* fatal error while scanning */ +#define TSF_ERROR 0x01 /* fatal error while compiling */ #define TSF_EOF 0x02 /* hit end of file */ #define TSF_NEWLINES 0x04 /* tokenize newlines */ #define TSF_REGEXP 0x08 /* looking for a regular expression */ #define TSF_NLFLAG 0x20 /* last linebuf ended with \n */ #define TSF_CRFLAG 0x40 /* linebuf would have ended with \r */ -#define TSF_BADCOMPILE 0x80 /* compile failed, stop throwing exns */ /* * Create a new token stream, either from an input buffer or from a file. @@ -213,17 +212,6 @@ js_InitScanner(JSContext *cx); extern JS_FRIEND_API(void) js_MapKeywords(void (*mapfun)(const char *)); -/* - * Report an error found while scanning ts to a window or other output device - * associated with cx. - */ -#if 0 -/* XXX js_ReportCompileError is unused */ -extern void -js_ReportCompileError(JSContext *cx, JSTokenStream *ts, uintN flags, - const char *format, ...); -#endif - void js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, uintN flags, const uintN errorNumber, ...); diff --git a/mozilla/js/src/jsscript.c b/mozilla/js/src/jsscript.c index f57d4535885..43abc014d7f 100644 --- a/mozilla/js/src/jsscript.c +++ b/mozilla/js/src/jsscript.c @@ -327,60 +327,87 @@ XDRAtomMap(JSXDRState *xdr, JSAtomMap *map) } JSBool -js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic) +js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *hasMagic) { - JSScript *script = *scriptp; - uint32 length, lineno, depth, magicval, notelen, numtrys = 0; + JSScript *script; + uint32 length, lineno, depth, magic, notelen, numtrys; + uint32 prologLength, version; + script = *scriptp; + numtrys = 0; + + /* + * Encode prologLength and version after script->length (_2), but decode + * both new (_2) and old, prolog&version-free (_1) scripts. + */ if (xdr->mode == JSXDR_ENCODE) - magicval = SCRIPT_XDRMAGIC; - if (!JS_XDRUint32(xdr, &magicval)) - return JS_FALSE; - if (magicval != SCRIPT_XDRMAGIC) { - *magic = JS_FALSE; - return JS_TRUE; + magic = JSXDR_MAGIC_SCRIPT_CURRENT; + if (!JS_XDRUint32(xdr, &magic)) + return JS_FALSE; + if (magic != JSXDR_MAGIC_SCRIPT_2 && magic != JSXDR_MAGIC_SCRIPT_1) { + *hasMagic = JS_FALSE; + return JS_TRUE; } - *magic = JS_TRUE; + *hasMagic = JS_TRUE; + if (xdr->mode == JSXDR_ENCODE) { jssrcnote *end = script->notes; - length = script->length; - lineno = (uint32)script->lineno; - depth = (uint32)script->depth; - /* count the trynotes */ + length = script->length; + prologLength = script->main - script->code; + version = (int32) script->version; + lineno = (uint32)script->lineno; + depth = (uint32)script->depth; + + /* Count the trynotes. */ if (script->trynotes) { for (; script->trynotes[numtrys].catchStart; numtrys++) - ; /* count the trynotes */ + continue; numtrys++; /* room for the end marker */ } - /* count the src notes */ + + /* Count the src notes. */ while (!SN_IS_TERMINATOR(end)) end = SN_NEXT(end); notelen = end - script->notes; } + if (!JS_XDRUint32(xdr, &length)) - return JS_FALSE; - if (xdr->mode == JSXDR_DECODE) { - script = js_NewScript(xdr->cx, length); - if (!script) - return JS_FALSE; - *scriptp = script; + return JS_FALSE; + if (magic == JSXDR_MAGIC_SCRIPT_2) { + if (!JS_XDRUint32(xdr, &prologLength)) + return JS_FALSE; + if (!JS_XDRUint32(xdr, (uint32 *) &version)) + return JS_FALSE; } + + if (xdr->mode == JSXDR_DECODE) { + script = js_NewScript(xdr->cx, length); + if (!script) + return JS_FALSE; + if (magic == JSXDR_MAGIC_SCRIPT_2) { + script->main += prologLength; + script->version = (JSVersion) version; + } + *scriptp = script; + } + if (!JS_XDRBytes(xdr, (char **)&script->code, length) || - !XDRAtomMap(xdr, &script->atomMap) || + !XDRAtomMap(xdr, &script->atomMap) || !JS_XDRUint32(xdr, ¬elen) || /* malloc on decode only */ (!(xdr->mode == JSXDR_ENCODE || (script->notes = JS_malloc(xdr->cx, notelen)) != NULL)) || !JS_XDRBytes(xdr, (char **)&script->notes, notelen) || - !JS_XDRCStringOrNull(xdr, (char **)&script->filename) || - !JS_XDRUint32(xdr, &lineno) || - !JS_XDRUint32(xdr, &depth) || + !JS_XDRCStringOrNull(xdr, (char **)&script->filename) || + !JS_XDRUint32(xdr, &lineno) || + !JS_XDRUint32(xdr, &depth) || !JS_XDRUint32(xdr, &numtrys)) { goto error; } + if (xdr->mode == JSXDR_DECODE) { - script->lineno = (uintN)lineno; - script->depth = (uintN)depth; + script->lineno = (uintN)lineno; + script->depth = (uintN)depth; if (numtrys) { script->trynotes = JS_malloc(xdr->cx, sizeof(JSTryNote) * (numtrys + 1)); @@ -394,11 +421,13 @@ js_XDRScript(JSXDRState *xdr, JSScript **scriptp, JSBool *magic) JSTryNote *tn = &script->trynotes[numtrys - 1]; if (!JS_XDRUint32(xdr, (uint32*)&tn->start) || !JS_XDRUint32(xdr, (uint32*)&tn->length) || - !JS_XDRUint32(xdr, (uint32*)&tn->catchStart)) + !JS_XDRUint32(xdr, (uint32*)&tn->catchStart)) { goto error; + } } return JS_TRUE; - error: + + error: if (xdr->mode == JSXDR_DECODE) { js_DestroyScript(xdr->cx, script); *scriptp = NULL; @@ -412,7 +441,7 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, { JSXDRState *xdr; JSScript *script; - JSBool ok, magic; + JSBool ok, hasMagic; uint32 len; void *buf; JSString *str; @@ -429,10 +458,10 @@ script_freeze(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, return JS_FALSE; /* write */ - ok = js_XDRScript(xdr, &script, &magic); + ok = js_XDRScript(xdr, &script, &hasMagic); if (!ok) goto out; - if (!magic) { + if (!hasMagic) { *rval = JSVAL_VOID; goto out; } @@ -478,7 +507,7 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, void *buf; uint32 len; JSScript *script, *oldscript; - JSBool ok, magic; + JSBool ok, hasMagic; if (!JS_InstanceOf(cx, obj, &js_ScriptClass, argv)) return JS_FALSE; @@ -515,10 +544,10 @@ script_thaw(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, JS_XDRMemSetData(xdr, buf, len); /* XXXbe should magic mismatch be error, or false return value? */ - ok = js_XDRScript(xdr, &script, &magic); + ok = js_XDRScript(xdr, &script, &hasMagic); if (!ok) goto out; - if (!magic) { + if (!hasMagic) { *rval = JSVAL_FALSE; goto out; } @@ -585,7 +614,7 @@ script_call(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) return script_exec(cx, JSVAL_TO_OBJECT(argv[-2]), argc, argv, rval); } -JSClass js_ScriptClass = { +JS_FRIEND_DATA(JSClass) js_ScriptClass = { "Script", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, @@ -652,23 +681,27 @@ js_NewScript(JSContext *cx, uint32 length) if (!script) return NULL; memset(script, 0, sizeof(JSScript)); - script->code = (jsbytecode *)(script + 1); + script->code = script->main = (jsbytecode *)(script + 1); script->length = length; + script->version = cx->version; return script; } JSScript * js_NewScriptFromParams(JSContext *cx, jsbytecode *code, uint32 length, + jsbytecode *prolog, uint32 prologLength, const char *filename, uintN lineno, uintN depth, jssrcnote *notes, JSTryNote *trynotes, JSPrincipals *principals) { JSScript *script; - script = js_NewScript(cx, length); + script = js_NewScript(cx, prologLength + length); if (!script) return NULL; - memcpy(script->code, code, length * sizeof(jsbytecode)); + script->main += prologLength; + memcpy(script->code, prolog, prologLength * sizeof(jsbytecode)); + memcpy(script->main, code, length * sizeof(jsbytecode)); if (filename) { script->filename = JS_strdup(cx, filename); if (!script->filename) { @@ -698,7 +731,8 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun) if (!js_FinishTakingTryNotes(cx, cg, &trynotes)) return NULL; notes = js_FinishTakingSrcNotes(cx, cg); - script = js_NewScriptFromParams(cx, cg->base, CG_OFFSET(cg), + script = js_NewScriptFromParams(cx, CG_BASE(cg), CG_OFFSET(cg), + CG_PROLOG_BASE(cg), CG_PROLOG_OFFSET(cg), cg->filename, cg->firstLine, cg->maxStackDepth, notes, trynotes, cg->principals); @@ -749,7 +783,7 @@ js_GetSrcNote(JSScript *script, jsbytecode *pc) sn = script->notes; if (!sn) return NULL; - target = PTRDIFF(pc, script->code, jsbytecode); + target = PTRDIFF(pc, script->main, jsbytecode); if ((uintN)target >= script->length) return NULL; for (offset = 0; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { @@ -771,7 +805,7 @@ js_PCToLineNumber(JSScript *script, jsbytecode *pc) sn = script->notes; if (!sn) return 0; - target = PTRDIFF(pc, script->code, jsbytecode); + target = PTRDIFF(pc, script->main, jsbytecode); lineno = script->lineno; for (offset = 0; !SN_IS_TERMINATOR(sn); sn = SN_NEXT(sn)) { offset += SN_DELTA(sn); @@ -812,7 +846,7 @@ js_LineNumberToPC(JSScript *script, uintN target) lineno++; } } - return script->code + offset; + return script->main + offset; } uintN diff --git a/mozilla/js/src/jsscript.h b/mozilla/js/src/jsscript.h index 6be923c18d6..10a60144a4c 100644 --- a/mozilla/js/src/jsscript.h +++ b/mozilla/js/src/jsscript.h @@ -58,6 +58,8 @@ struct JSTryNote { struct JSScript { jsbytecode *code; /* bytecodes and their immediate operands */ uint32 length; /* length of code vector */ + jsbytecode *main; /* main entry point, after predef'ing prolog */ + JSVersion version; /* JS version under which script was compiled */ JSAtomMap atomMap; /* maps immediate index to literal struct */ const char *filename; /* source filename or null */ uintN lineno; /* base line number of script */ @@ -68,7 +70,7 @@ struct JSScript { JSObject *object; /* optional Script-class object wrapper */ }; -extern JSClass js_ScriptClass; +extern JS_FRIEND_DATA(JSClass) js_ScriptClass; extern JSObject * js_InitScriptClass(JSContext *cx, JSObject *obj); @@ -78,6 +80,7 @@ js_NewScript(JSContext *cx, uint32 length); extern JSScript * js_NewScriptFromParams(JSContext *cx, jsbytecode *code, uint32 length, + jsbytecode *prolog, uint32 prologLength, const char *filename, uintN lineno, uintN depth, jssrcnote *notes, JSTryNote *trynotes, JSPrincipals *principals); diff --git a/mozilla/js/src/jsxdrapi.h b/mozilla/js/src/jsxdrapi.h index 231ee411f2c..593ad9c039d 100644 --- a/mozilla/js/src/jsxdrapi.h +++ b/mozilla/js/src/jsxdrapi.h @@ -165,10 +165,8 @@ JS_FindClassById(JSXDRState *xdr, uint32 id); /* Magic values */ -#define OBJ_XDRMAGIC 0xdead1000 -#define OBJ_XDRTYPE_OBJ 0xdead1001 -#define OBJ_XDRTYPE_FUN 0xdead1002 -#define OBJ_XDRTYPE_REGEXP 0xdead1003 -#define SCRIPT_XDRMAGIC 0xdead0001 +#define JSXDR_MAGIC_SCRIPT_1 0xdead0001 +#define JSXDR_MAGIC_SCRIPT_2 0xdead0002 +#define JSXDR_MAGIC_SCRIPT_CURRENT JSXDR_MAGIC_SCRIPT_2 #endif /* ! jsxdrapi_h___ */