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:
parent
f7a4841081
commit
5d2eac8479
@ -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') {
|
||||
|
||||
@ -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}")
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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[];
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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, ...);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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___ */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user