XULDOMJS_19991106_BRANCH landing (15146, 18025, r=shaver@mozilla.org)

git-svn-id: svn://10.0.0.236/trunk@53326 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
brendan%mozilla.org 1999-11-12 06:03:40 +00:00
parent f7a4841081
commit 5d2eac8479
23 changed files with 766 additions and 454 deletions

View File

@ -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') {

View File

@ -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}")

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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.
*/

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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[];

View File

@ -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)

View File

@ -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:

View File

@ -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

View File

@ -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, ...);

View File

@ -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, &notelen) ||
/* 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

View File

@ -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);

View File

@ -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___ */