From 8abbdb13fe20c978890c88d15371ed4a21531eee Mon Sep 17 00:00:00 2001 From: "igor%mir2.org" Date: Mon, 1 Oct 2007 20:46:10 +0000 Subject: [PATCH] Backing out the patch 397210. --- js/src/jsapi.c | 172 ++++++++++++++++++++++++++-------------- js/src/jsemit.c | 53 +++++++------ js/src/jsemit.h | 9 ++- js/src/jsfun.c | 88 ++++++++++++--------- js/src/jsparse.c | 198 +++++++++++++++++----------------------------- js/src/jsparse.h | 44 +++-------- js/src/jsscan.c | 143 ++++++++++++++++++++++++--------- js/src/jsscan.h | 40 ++++++---- js/src/jsscript.c | 8 +- js/src/jsxml.c | 25 +++--- 10 files changed, 434 insertions(+), 346 deletions(-) diff --git a/js/src/jsapi.c b/js/src/jsapi.c index 14a557f42d2..fd2b2e41bd1 100644 --- a/js/src/jsapi.c +++ b/js/src/jsapi.c @@ -4318,6 +4318,51 @@ JS_DefineUCFunction(JSContext *cx, JSObject *obj, return js_DefineFunction(cx, obj, atom, call, nargs, attrs); } +static JSScript * +CompileTokenStream(JSContext *cx, JSObject *obj, JSTokenStream *ts, + void *tempMark, JSBool *eofp) +{ + JSBool eof; + JSArenaPool codePool, notePool; + JSParseContext pc; + JSCodeGenerator cg; + JSScript *script; + + eof = JS_FALSE; + JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode), + &cx->scriptStackQuota); + JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote), + &cx->scriptStackQuota); + js_InitParseContext(cx, &pc); + JS_ASSERT(!ts->parseContext); + ts->parseContext = &pc; + if (!js_InitCodeGenerator(cx, &cg, &pc, &codePool, ¬ePool, + ts->filename, ts->lineno, + ts->principals)) { + script = NULL; + } else if (!js_CompileTokenStream(cx, obj, ts, &cg)) { + script = NULL; + eof = (ts->flags & TSF_EOF) != 0; + } else { + script = js_NewScriptFromCG(cx, &cg, NULL); + } + if (eofp) + *eofp = eof; + if (!js_CloseTokenStream(cx, ts)) { + if (script) + js_DestroyScript(cx, script); + script = NULL; + } + + js_FinishCodeGenerator(cx, &cg); + JS_ASSERT(ts->parseContext == &pc); + js_FinishParseContext(cx, &pc); + JS_FinishArenaPool(&codePool); + JS_FinishArenaPool(¬ePool); + JS_ARENA_RELEASE(&cx->tempPool, tempMark); + return script; +} + JS_PUBLIC_API(JSScript *) JS_CompileScript(JSContext *cx, JSObject *obj, const char *bytes, size_t length, @@ -4384,15 +4429,16 @@ JS_CompileUCScriptForPrincipals(JSContext *cx, JSObject *obj, const jschar *chars, size_t length, const char *filename, uintN lineno) { - JSParseContext pc; + void *mark; + JSTokenStream *ts; JSScript *script; CHECK_REQUEST(cx); - if (!js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno)) + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals); + if (!ts) return NULL; - js_InitCompilePrincipals(cx, &pc, principals); - script = js_CompileScript(cx, obj, &pc); - js_FinishParseContext(cx, &pc); + script = CompileTokenStream(cx, obj, ts, mark, NULL); LAST_FRAME_CHECKS(cx, script); return script; } @@ -4404,6 +4450,8 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, jschar *chars; JSBool result; JSExceptionState *exnState; + void *tempMark; + JSTokenStream *ts; JSParseContext pc; JSErrorReporter older; @@ -4418,10 +4466,15 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, */ result = JS_TRUE; exnState = JS_SaveExceptionState(cx); - if (js_InitParseContext(cx, &pc, chars, length, NULL, NULL, 1)) { + tempMark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewTokenStream(cx, chars, length, NULL, 0, NULL); + if (ts) { older = JS_SetErrorReporter(cx, NULL); - if (!js_ParseScript(cx, obj, &pc) && - (pc.tokenStream.flags & TSF_UNEXPECTED_EOF)) { + js_InitParseContext(cx, &pc); + JS_ASSERT(!ts->parseContext); + ts->parseContext = &pc; + if (!js_ParseTokenStream(cx, obj, ts) && + (ts->flags & TSF_UNEXPECTED_EOF)) { /* * We ran into an error. If it was because we ran out of source, * we return false, so our caller will know to try to collect more @@ -4429,9 +4482,14 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, */ result = JS_FALSE; } - JS_SetErrorReporter(cx, older); + + JS_ASSERT(ts->parseContext == &pc); js_FinishParseContext(cx, &pc); + JS_SetErrorReporter(cx, older); + js_CloseTokenStream(cx, ts); } + + JS_ARENA_RELEASE(&cx->tempPool, tempMark); JS_free(cx, chars); JS_RestoreExceptionState(cx, exnState); return result; @@ -4440,30 +4498,16 @@ JS_BufferIsCompilableUnit(JSContext *cx, JSObject *obj, JS_PUBLIC_API(JSScript *) JS_CompileFile(JSContext *cx, JSObject *obj, const char *filename) { - FILE *fp; - JSParseContext pc; + void *mark; + JSTokenStream *ts; JSScript *script; CHECK_REQUEST(cx); - if (!filename || strcmp(filename, "-") == 0) { - fp = stdin; - } else { - fp = fopen(filename, "r"); - if (!fp) { - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, - filename, "No such file or directory"); - return NULL; - } - } - - if (!js_InitParseContext(cx, &pc, NULL, 0, fp, filename, 1)) { - script = NULL; - } else { - script = js_CompileScript(cx, obj, &pc); - js_FinishParseContext(cx, &pc); - } - if (fp != stdin) - fclose(fp); + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewFileTokenStream(cx, filename, stdin); + if (!ts) + return NULL; + script = CompileTokenStream(cx, obj, ts, mark, NULL); LAST_FRAME_CHECKS(cx, script); return script; } @@ -4480,15 +4524,22 @@ JS_CompileFileHandleForPrincipals(JSContext *cx, JSObject *obj, const char *filename, FILE *file, JSPrincipals *principals) { - JSParseContext pc; + void *mark; + JSTokenStream *ts; JSScript *script; CHECK_REQUEST(cx); - if (!js_InitParseContext(cx, &pc, NULL, 0, file, filename, 1)) + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewFileTokenStream(cx, NULL, file); + if (!ts) return NULL; - js_InitCompilePrincipals(cx, &pc, principals); - script = js_CompileScript(cx, obj, &pc); - js_FinishParseContext(cx, &pc); + ts->filename = filename; + /* XXXshaver js_NewFileTokenStream should do this, because it drops */ + if (principals) { + ts->principals = principals; + JSPRINCIPALS_HOLD(cx, ts->principals); + } + script = CompileTokenStream(cx, obj, ts, mark, NULL); LAST_FRAME_CHECKS(cx, script); return script; } @@ -4583,13 +4634,19 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, const jschar *chars, size_t length, const char *filename, uintN lineno) { + void *mark; + JSTokenStream *ts; JSFunction *fun; JSAtom *funAtom, *argAtom; uintN i; - JSParseContext pc; - JSBool ok; CHECK_REQUEST(cx); + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewTokenStream(cx, chars, length, filename, lineno, principals); + if (!ts) { + fun = NULL; + goto out; + } if (!name) { funAtom = NULL; } else { @@ -4605,41 +4662,36 @@ JS_CompileUCFunctionForPrincipals(JSContext *cx, JSObject *obj, if (nargs) { for (i = 0; i < nargs; i++) { argAtom = js_Atomize(cx, argnames[i], strlen(argnames[i]), 0); - if (!argAtom) { - fun = NULL; - goto out; - } + if (!argAtom) + break; if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom), js_GetArgument, js_SetArgument, SPROP_INVALID_SLOT, JSPROP_PERMANENT | JSPROP_SHARED, SPROP_HAS_SHORTID, i)) { - fun = NULL; - goto out; + break; } } + if (i < nargs) { + fun = NULL; + goto out; + } } - - ok = js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno); - if (ok) { - js_InitCompilePrincipals(cx, &pc, principals); - ok = js_CompileFunctionBody(cx, &pc, fun); - js_FinishParseContext(cx, &pc); - } - if (!ok) { + if (!js_CompileFunctionBody(cx, ts, fun)) { fun = NULL; goto out; } - - if (obj && - funAtom && - !OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom), - OBJECT_TO_JSVAL(fun->object), - NULL, NULL, JSPROP_ENUMERATE, NULL)) { - fun = NULL; + if (obj && funAtom) { + if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(funAtom), + OBJECT_TO_JSVAL(fun->object), + NULL, NULL, JSPROP_ENUMERATE, NULL)) { + return NULL; + } } - - out: +out: + if (ts) + js_CloseTokenStream(cx, ts); + JS_ARENA_RELEASE(&cx->tempPool, mark); LAST_FRAME_CHECKS(cx, fun); return fun; } diff --git a/js/src/jsemit.c b/js/src/jsemit.c index 0f6fd66c8fd..098cd9145d8 100644 --- a/js/src/jsemit.c +++ b/js/src/jsemit.c @@ -79,10 +79,11 @@ static JSBool NewTryNote(JSContext *cx, JSCodeGenerator *cg, JSTryNoteKind kind, uintN stackDepth, size_t start, size_t end); -JS_FRIEND_API(void) +JS_FRIEND_API(JSBool) js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, JSArenaPool *codePool, JSArenaPool *notePool, - uintN lineno) + const char *filename, uintN lineno, + JSPrincipals *principals) { memset(cg, 0, sizeof *cg); TREE_CONTEXT_INIT(&cg->treeContext, pc); @@ -92,10 +93,13 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, cg->codeMark = JS_ARENA_MARK(codePool); cg->noteMark = JS_ARENA_MARK(notePool); cg->current = &cg->main; + cg->filename = filename; cg->firstLine = cg->prolog.currentLine = cg->main.currentLine = lineno; + cg->principals = principals; ATOM_LIST_INIT(&cg->atomList); cg->prolog.noteMask = cg->main.noteMask = SRCNOTE_CHUNK - 1; ATOM_LIST_INIT(&cg->constList); + return JS_TRUE; } JS_FRIEND_API(void) @@ -176,14 +180,11 @@ UpdateDepth(JSContext *cx, JSCodeGenerator *cg, ptrdiff_t target) JS_ASSERT(cg->stackDepth >= 0); if (cg->stackDepth < 0) { char numBuf[12]; - JSTokenStream *ts; - JS_snprintf(numBuf, sizeof numBuf, "%d", target); - ts = &cg->treeContext.parseContext->tokenStream; JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, NULL, JSMSG_STACK_UNDERFLOW, - ts->filename ? ts->filename : "stdin", + cg->filename ? cg->filename : "stdin", numBuf); } cg->stackDepth += cs->ndefs; @@ -4020,9 +4021,12 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) JS_ReportOutOfMemory(cx); return JS_FALSE; } - js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext, - cg->codePool, cg->notePool, - pn->pn_pos.begin.lineno); + if (!js_InitCodeGenerator(cx, cg2, cg->treeContext.parseContext, + cg->codePool, cg->notePool, + cg->filename, pn->pn_pos.begin.lineno, + cg->principals)) { + return JS_FALSE; + } cg2->treeContext.flags = (uint16) (pn->pn_flags | TCF_IN_FUNCTION); cg2->parent = cg; fun = (JSFunction *) OBJ_GET_PRIVATE(cx, pn->pn_funpob->object); @@ -5271,8 +5275,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) cg->treeContext.topStmt->type != STMT_LABEL || cg->treeContext.topStmt->update < CG_OFFSET(cg))) { CG_CURRENT_LINE(cg) = pn2->pn_pos.begin.lineno; - if (!js_ReportCompileErrorNumber(cx, pn2, - JSREPORT_PN | + if (!js_ReportCompileErrorNumber(cx, cg, + JSREPORT_CG | JSREPORT_WARNING | JSREPORT_STRICT, JSMSG_USELESS_EXPR)) { @@ -6294,21 +6298,22 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn) ok = EmitNumberOp(cx, pn->pn_dval, cg); break; - case TOK_REGEXP: - /* - * If the regexp's script is one-shot, we can avoid the extra - * fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT. - * Otherwise, to avoid incorrect proto, parent, and lastIndex - * sharing among threads and sequentially across re-execution, - * select JSOP_REGEXP. - */ - JS_ASSERT(pn->pn_op == JSOP_REGEXP); - if (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)) { - ok = EmitObjectOp(cx, pn->pn_pob, JSOP_OBJECT, cg); - } else { - ok = EmitIndexOp(cx, JSOP_REGEXP, + case TOK_OBJECT: + if (pn->pn_op == JSOP_REGEXP) { + /* + * cx->fp->varobj cannot be a Call object here, because that + * implies we are compiling eval code, in which case + * (cx->fp->flags & JSFRAME_EVAL) is true, and js_GetToken will + * have already selected JSOP_OBJECT instead of JSOP_REGEXP, to + * avoid all this RegExp object cloning business. + */ + JS_ASSERT(!(cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))); + ok = EmitIndexOp(cx, PN_OP(pn), IndexParsedObject(pn->pn_pob, &cg->regexpList), cg); + } else { + JS_ASSERT(pn->pn_op == JSOP_OBJECT); + ok = EmitObjectOp(cx, pn->pn_pob, PN_OP(pn), cg); } break; diff --git a/js/src/jsemit.h b/js/src/jsemit.h index 9efc3df1efb..27ee5da8f92 100644 --- a/js/src/jsemit.h +++ b/js/src/jsemit.h @@ -295,7 +295,9 @@ struct JSCodeGenerator { uintN currentLine; /* line number for tree-based srcnote gen */ } prolog, main, *current; + const char *filename; /* null or weak link to source filename */ uintN firstLine; /* first line, for js_NewScriptFromCG */ + JSPrincipals *principals; /* principals for constant folding eval */ JSAtomList atomList; /* literals indexed for mapping */ intN stackDepth; /* current stack depth in script frame */ @@ -349,11 +351,14 @@ struct JSCodeGenerator { /* * Initialize cg to allocate bytecode space from codePool, source note space * from 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(void) +extern JS_FRIEND_API(JSBool) js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc, JSArenaPool *codePool, JSArenaPool *notePool, - uintN lineno); + const char *filename, uintN lineno, + JSPrincipals *principals); /* * Release cg->codePool, cg->notePool, and cx->tempPool to marks set by diff --git a/js/src/jsfun.c b/js/src/jsfun.c index 227f8395a02..8f02424e9d2 100644 --- a/js/src/jsfun.c +++ b/js/src/jsfun.c @@ -1805,10 +1805,10 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSProperty *prop; JSScopeProperty *sprop; JSString *str, *arg; - JSParseContext pc; + void *mark; + JSTokenStream *ts; JSPrincipals *principals; jschar *collected_args, *cp; - void *mark; size_t arg_length, args_length, old_args_length; JSTokenType tt; JSBool ok; @@ -1869,8 +1869,6 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) n = argc ? argc - 1 : 0; if (n > 0) { - enum { OK, BAD, BAD_FORMAL } state; - /* * Collect the function-argument arguments into one string, separated * by commas, then make a tokenstream from that string, and scan it to @@ -1881,7 +1879,6 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * compiler, but doing it this way is less of a delta from the old * code. See ECMA 15.3.2.1. */ - state = BAD_FORMAL; args_length = 0; for (i = 0; i < n; i++) { /* Collect the lengths for all the function-argument arguments. */ @@ -1938,15 +1935,19 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) *cp++ = (i + 1 < n) ? ',' : 0; } - /* Initialize a tokenstream that reads from the given string. */ - if (!js_InitTokenStream(cx, &pc.tokenStream, collected_args, - args_length, NULL, filename, lineno)) { + /* + * Make a tokenstream (allocated from cx->tempPool) that reads from + * the given string. + */ + ts = js_NewTokenStream(cx, collected_args, args_length, filename, + lineno, principals); + if (!ts) { JS_ARENA_RELEASE(&cx->tempPool, mark); return JS_FALSE; } /* The argument string may be empty or contain no tokens. */ - tt = js_GetToken(cx, &pc.tokenStream); + tt = js_GetToken(cx, ts); if (tt != TOK_EOF) { for (;;) { /* @@ -1954,16 +1955,16 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * TOK_ERROR, which was already reported. */ if (tt != TOK_NAME) - goto after_args; + goto bad_formal; /* * Get the atom corresponding to the name from the tokenstream; * we're assured at this point that it's a valid identifier. */ - atom = CURRENT_TOKEN(&pc.tokenStream).t_atom; + atom = CURRENT_TOKEN(ts).t_atom; if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom), &obj2, &prop)) { - goto after_args; + goto bad_formal; } sprop = (JSScopeProperty *) prop; dupflag = 0; @@ -1980,7 +1981,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) */ JS_ASSERT(sprop->getter == js_GetArgument); ok = name && - js_ReportCompileErrorNumber(cx, &pc.tokenStream, + js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_WARNING | JSREPORT_STRICT, @@ -1991,7 +1992,7 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) } OBJ_DROP_PROPERTY(cx, obj2, prop); if (!ok) - goto after_args; + goto bad_formal; sprop = NULL; } if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(atom), @@ -2000,13 +2001,12 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) JSPROP_PERMANENT | JSPROP_SHARED, dupflag | SPROP_HAS_SHORTID, fun->nargs)) { - goto after_args; + goto bad_formal; } if (fun->nargs == JS_BITMASK(16)) { JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_TOO_MANY_FUN_ARGS); - state = BAD; - goto after_args; + goto bad; } fun->nargs++; @@ -2014,28 +2014,19 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) * Get the next token. Stop on end of stream. Otherwise * insist on a comma, get another name, and iterate. */ - tt = js_GetToken(cx, &pc.tokenStream); + tt = js_GetToken(cx, ts); if (tt == TOK_EOF) break; if (tt != TOK_COMMA) - goto after_args; - tt = js_GetToken(cx, &pc.tokenStream); + goto bad_formal; + tt = js_GetToken(cx, ts); } } - state = OK; - after_args: - if (state == BAD_FORMAL && !(pc.tokenStream.flags & TSF_ERROR)) { - /* - * Report "malformed formal parameter" iff no illegal char or - * similar scanner error was already reported. - */ - JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, - JSMSG_BAD_FORMAL); - } - js_CloseTokenStream(cx, &pc.tokenStream); + /* Clean up. */ + ok = js_CloseTokenStream(cx, ts); JS_ARENA_RELEASE(&cx->tempPool, mark); - if (state != OK) + if (!ok) return JS_FALSE; } @@ -2048,14 +2039,35 @@ Function(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval) str = cx->runtime->emptyString; } - ok = js_InitParseContext(cx, &pc, JSSTRING_CHARS(str), JSSTRING_LENGTH(str), - NULL, filename, lineno); - if (ok) { - js_InitCompilePrincipals(cx, &pc, principals); - ok = js_CompileFunctionBody(cx, &pc, fun); - js_FinishParseContext(cx, &pc); + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewTokenStream(cx, JSSTRING_CHARS(str), JSSTRING_LENGTH(str), + filename, lineno, principals); + if (!ts) { + ok = JS_FALSE; + } else { + /* Note: We must *always* close ts. */ + ok = js_CompileFunctionBody(cx, ts, fun); + ok &= js_CloseTokenStream(cx, ts); } + JS_ARENA_RELEASE(&cx->tempPool, mark); return ok; + +bad_formal: + /* + * Report "malformed formal parameter" iff no illegal char or similar + * scanner error was already reported. + */ + if (!(ts->flags & TSF_ERROR)) + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL); + +bad: + /* + * Clean up the arguments string and tokenstream if we failed to parse + * the arguments. + */ + (void)js_CloseTokenStream(cx, ts); + JS_ARENA_RELEASE(&cx->tempPool, mark); + return JS_FALSE; } JSObject * diff --git a/js/src/jsparse.c b/js/src/jsparse.c index 322080a439f..5dafc0ce8a3 100644 --- a/js/src/jsparse.c +++ b/js/src/jsparse.c @@ -158,46 +158,23 @@ static uint32 maxparsenodes = 0; static uint32 recyclednodes = 0; #endif -JS_FRIEND_API(JSBool) -js_InitParseContext(JSContext *cx, JSParseContext *pc, - const jschar *base, size_t length, - FILE *fp, const char *filename, uintN lineno) +void +js_InitParseContext(JSContext *cx, JSParseContext *pc) { - pc->tempPoolMark = JS_ARENA_MARK(&cx->tempPool); - if (!js_InitTokenStream(cx, TS(pc), base, length, fp, filename, lineno)) { - JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark); - return JS_FALSE; - } - pc->principals = NULL; pc->nodeList = NULL; pc->traceListHead = NULL; /* Root atoms and objects allocated for the parsed tree. */ JS_KEEP_ATOMS(cx->runtime); JS_PUSH_TEMP_ROOT_PARSE_CONTEXT(cx, pc, &pc->tempRoot); - return JS_TRUE; -} - -JS_FRIEND_API(void) -js_FinishParseContext(JSContext *cx, JSParseContext *pc) -{ - if (pc->principals) - JSPRINCIPALS_DROP(cx, pc->principals); - JS_ASSERT(pc->tempRoot.u.parseContext == pc); - JS_POP_TEMP_ROOT(cx, &pc->tempRoot); - JS_UNKEEP_ATOMS(cx->runtime); - js_CloseTokenStream(cx, TS(pc)); - JS_ARENA_RELEASE(&cx->tempPool, pc->tempPoolMark); } void -js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc, - JSPrincipals *principals) +js_FinishParseContext(JSContext *cx, JSParseContext *pc) { - JS_ASSERT(!pc->principals); - if (principals) - JSPRINCIPALS_HOLD(cx, principals); - pc->principals = principals; + JS_ASSERT(pc->tempRoot.u.parseContext == pc); + JS_POP_TEMP_ROOT(cx, &pc->tempRoot); + JS_UNKEEP_ATOMS(cx->runtime); } JSParsedObjectBox * @@ -519,7 +496,7 @@ MaybeSetupFrame(JSContext *cx, JSObject *chain, JSStackFrame *oldfp, * Parse a top-level JS script. */ JS_FRIEND_API(JSParseNode *) -js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc) +js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts) { JSStackFrame *fp, frame; JSTreeContext tc; @@ -541,12 +518,11 @@ js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc) * an object lock before it finishes generating bytecode into a script * protected from the GC by a root or a stack frame reference. */ - TREE_CONTEXT_INIT(&tc, pc); - pn = Statements(cx, TS(pc), &tc); + TREE_CONTEXT_INIT(&tc, ts->parseContext); + pn = Statements(cx, ts, &tc); if (pn) { - if (!js_MatchToken(cx, TS(pc), TOK_EOF)) { - js_ReportCompileErrorNumber(cx, TS(pc), - JSREPORT_TS | JSREPORT_ERROR, + if (!js_MatchToken(cx, ts, TOK_EOF)) { + js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; } else { @@ -564,15 +540,14 @@ js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc) /* * Compile a top-level script. */ -JS_FRIEND_API(JSScript *) -js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc) +JS_FRIEND_API(JSBool) +js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, + JSCodeGenerator *cg) { JSStackFrame *fp, frame; uint32 flags; - JSArenaPool codePool, notePool; - JSCodeGenerator cg; JSParseNode *pn; - JSScript *script; + JSBool ok; #ifdef METER_PARSENODES void *sbrk(ptrdiff_t), *before = sbrk(0); #endif @@ -590,48 +565,40 @@ js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc) ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO : JSFRAME_COMPILING); - JS_INIT_ARENA_POOL(&codePool, "code", 1024, sizeof(jsbytecode), - &cx->scriptStackQuota); - JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote), - &cx->scriptStackQuota); - js_InitCodeGenerator(cx, &cg, pc, &codePool, ¬ePool, TS(pc)->lineno); + /* Prevent GC activation while compiling. */ + JS_KEEP_ATOMS(cx->runtime); - /* From this point the control must flow via the label out. */ - pn = Statements(cx, TS(pc), &cg.treeContext); + pn = Statements(cx, ts, &cg->treeContext); if (!pn) { - script = NULL; - goto out; - } - if (!js_MatchToken(cx, TS(pc), TOK_EOF)) { - js_ReportCompileErrorNumber(cx, TS(pc), JSREPORT_TS | JSREPORT_ERROR, + ok = JS_FALSE; + } else if (!js_MatchToken(cx, ts, TOK_EOF)) { + js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); - script = NULL; - goto out; - } + ok = JS_FALSE; + } else { #ifdef METER_PARSENODES - printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n", - (char *)sbrk(0) - (char *)before, - parsenodes, - maxparsenodes, - parsenodes - recyclednodes); - before = sbrk(0); + printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n", + (char *)sbrk(0) - (char *)before, + parsenodes, + maxparsenodes, + parsenodes - recyclednodes); + before = sbrk(0); #endif - /* - * No need to emit bytecode here -- Statements already has, for each - * statement in turn. Search for TCF_COMPILING in Statements, below. - * That flag is set for every tc == &cg->treeContext, and it implies - * that the tc can be downcast to a cg and used to emit code during - * parsing, rather than at the end of the parse phase. - * - * Nowadays the threaded interpreter needs a stop instruction, so we - * do have to emit that here. - */ - JS_ASSERT(cg.treeContext.flags & TCF_COMPILING); - if (js_Emit1(cx, &cg, JSOP_STOP) < 0) { - script = NULL; - goto out; + /* + * No need to emit bytecode here -- Statements already has, for each + * statement in turn. Search for TCF_COMPILING in Statements, below. + * That flag is set for every tc == &cg->treeContext, and it implies + * that the tc can be downcast to a cg and used to emit code during + * parsing, rather than at the end of the parse phase. + * + * Nowadays the threaded interpreter needs a stop instruction, so we + * do have to emit that here. + */ + JS_ASSERT(cg->treeContext.flags & TCF_COMPILING); + ok = js_Emit1(cx, cg, JSOP_STOP) >= 0; } + #ifdef METER_PARSENODES printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n", (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount); @@ -639,16 +606,10 @@ js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc) #ifdef JS_ARENAMETER JS_DumpArenaStats(stdout); #endif - script = js_NewScriptFromCG(cx, &cg, NULL); - - out: - js_FinishCodeGenerator(cx, &cg); - JS_FinishArenaPool(&codePool); - JS_FinishArenaPool(¬ePool); - + JS_UNKEEP_ATOMS(cx->runtime); cx->fp->flags = flags; cx->fp = fp; - return script; + return ok; } /* @@ -909,9 +870,10 @@ FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun, * handler attribute in an HTML tag. */ JSBool -js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun) +js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun) { JSArenaPool codePool, notePool; + JSParseContext pc; JSCodeGenerator funcg; JSStackFrame *fp, frame; JSObject *funobj; @@ -921,7 +883,14 @@ js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun) &cx->scriptStackQuota); JS_INIT_ARENA_POOL(¬ePool, "note", 1024, sizeof(jssrcnote), &cx->scriptStackQuota); - js_InitCodeGenerator(cx, &funcg, pc, &codePool, ¬ePool, TS(pc)->lineno); + js_InitParseContext(cx, &pc); + JS_ASSERT(!ts->parseContext); + ts->parseContext = &pc; + if (!js_InitCodeGenerator(cx, &funcg, &pc, &codePool, ¬ePool, + ts->filename, ts->lineno, + ts->principals)) { + return JS_FALSE; + } /* Push a JSStackFrame for use by FunctionBody. */ fp = cx->fp; @@ -949,12 +918,11 @@ js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun) * Therefore we must fold constants, allocate try notes, and generate code * for this function, including a stop opcode at the end. */ - CURRENT_TOKEN(TS(pc)).type = TOK_LC; - pn = FunctionBody(cx, TS(pc), fun, &funcg.treeContext); + CURRENT_TOKEN(ts).type = TOK_LC; + pn = FunctionBody(cx, ts, fun, &funcg.treeContext); if (pn) { - if (!js_MatchToken(cx, TS(pc), TOK_EOF)) { - js_ReportCompileErrorNumber(cx, TS(pc), - JSREPORT_TS | JSREPORT_ERROR, + if (!js_MatchToken(cx, ts, TOK_EOF)) { + js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_SYNTAX_ERROR); pn = NULL; } else { @@ -966,6 +934,7 @@ js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun) /* Restore saved state and release code generation arenas. */ cx->fp = fp; js_FinishCodeGenerator(cx, &funcg); + js_FinishParseContext(cx, &pc); JS_FinishArenaPool(&codePool); JS_FinishArenaPool(¬ePool); return pn != NULL; @@ -5483,8 +5452,8 @@ XMLElementOrListRoot(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } JS_FRIEND_API(JSParseNode *) -js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc, - JSBool allowList) +js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, + JSBool allowList) { JSStackFrame *fp, frame; JSParseNode *pn; @@ -5498,22 +5467,22 @@ js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc, */ fp = cx->fp; MaybeSetupFrame(cx, chain, fp, &frame); - TREE_CONTEXT_INIT(&tc, pc); + TREE_CONTEXT_INIT(&tc, ts->parseContext); /* Set XML-only mode to turn off special treatment of {expr} in XML. */ - TS(pc)->flags |= TSF_OPERAND | TSF_XMLONLYMODE; - tt = js_GetToken(cx, TS(pc)); - TS(pc)->flags &= ~TSF_OPERAND; + ts->flags |= TSF_OPERAND | TSF_XMLONLYMODE; + tt = js_GetToken(cx, ts); + ts->flags &= ~TSF_OPERAND; if (tt != TOK_XMLSTAGO) { - js_ReportCompileErrorNumber(cx, TS(pc), JSREPORT_TS | JSREPORT_ERROR, + js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, JSMSG_BAD_XML_MARKUP); pn = NULL; } else { - pn = XMLElementOrListRoot(cx, TS(pc), &tc, allowList); + pn = XMLElementOrListRoot(cx, ts, &tc, allowList); } - TS(pc)->flags &= ~TSF_XMLONLYMODE; + ts->flags &= ~TSF_XMLONLYMODE; TREE_CONTEXT_FINISH(&tc); cx->fp = fp; return pn; @@ -5938,10 +5907,14 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, case TOK_XMLPI: #endif case TOK_NAME: + case TOK_OBJECT: pn = NewParseNode(cx, ts, PN_NULLARY, tc); if (!pn) return NULL; - pn->pn_atom = CURRENT_TOKEN(ts).t_atom; + if (tt == TOK_OBJECT) + pn->pn_pob = CURRENT_TOKEN(ts).t_pob; + else + pn->pn_atom = CURRENT_TOKEN(ts).t_atom; #if JS_HAS_XML_SUPPORT if (tt == TOK_XMLPI) pn->pn_atom2 = CURRENT_TOKEN(ts).t_atom2; @@ -6006,31 +5979,6 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, } break; - case TOK_REGEXP: - { - JSObject *obj; - - pn = NewParseNode(cx, ts, PN_NULLARY, tc); - if (!pn) - return NULL; - - /* Token stream ensures that tokenbuf is NUL-terminated. */ - JS_ASSERT(*ts->tokenbuf.ptr == (jschar) 0); - obj = js_NewRegExpObject(cx, ts, - ts->tokenbuf.base, - ts->tokenbuf.ptr - ts->tokenbuf.base, - CURRENT_TOKEN(ts).t_reflags); - if (!obj) - return NULL; - - pn->pn_pob = js_NewParsedObjectBox(cx, tc->parseContext, obj); - if (!pn->pn_pob) - return NULL; - - pn->pn_op = JSOP_REGEXP; - break; - } - case TOK_NUMBER: pn = NewParseNode(cx, ts, PN_NULLARY, tc); if (!pn) diff --git a/js/src/jsparse.h b/js/src/jsparse.h index c8334db4155..212abcf129b 100644 --- a/js/src/jsparse.h +++ b/js/src/jsparse.h @@ -185,7 +185,7 @@ JS_BEGIN_EXTERN_C * TOK_NAME, name pn_atom: name, string, or object atom * TOK_STRING, pn_op: JSOP_NAME, JSOP_STRING, or JSOP_OBJECT, or * JSOP_REGEXP - * TOK_REGEXP If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR + * TOK_OBJECT If JSOP_NAME, pn_op may be JSOP_*ARG or JSOP_*VAR * with pn_slot >= 0 and pn_attrs telling const-ness * TOK_NUMBER dval pn_dval: double value of numeric literal * TOK_PRIMARY nullary pn_op: JSOp bytecode @@ -425,10 +425,8 @@ struct JSParsedObjectBox { JSObject *object; }; + struct JSParseContext { - JSTokenStream tokenStream; - void *tempPoolMark; /* initial JSContext.tempPool mark */ - JSPrincipals *principals; /* principals associated with source */ JSParseNode *nodeList; /* list of recyclable parse-node structs */ JSParsedObjectBox *traceListHead; /* list of parsed object for GC @@ -444,51 +442,33 @@ struct JSParseContext { #endif }; -/* - * Convenience macro to access JSParseContext.tokenStream as a pointer. - */ -#define TS(pc) (&(pc)->tokenStream) - /* * Parse a top-level JS script. */ extern JS_FRIEND_API(JSParseNode *) -js_ParseScript(JSContext *cx, JSObject *chain, JSParseContext *pc); +js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts); -extern JS_FRIEND_API(JSScript *) -js_CompileScript(JSContext *cx, JSObject *chain, JSParseContext *pc); +extern JS_FRIEND_API(JSBool) +js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, + JSCodeGenerator *cg); extern JSBool -js_CompileFunctionBody(JSContext *cx, JSParseContext *pc, JSFunction *fun); +js_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun); extern JSBool js_FoldConstants(JSContext *cx, JSParseNode *pn, JSTreeContext *tc); #if JS_HAS_XML_SUPPORT JS_FRIEND_API(JSParseNode *) -js_ParseXMLText(JSContext *cx, JSObject *chain, JSParseContext *pc, - JSBool allowList); +js_ParseXMLTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts, + JSBool allowList); #endif -/* - * Initialize a parse context. All parameters after pc are passed to - * js_InitTokenStream. - * - * The parse context owns the arena pool "tops-of-stack" space above the - * current JSContext.tempPool mark. This means you cannot allocate from - * tempPool and save the pointer beyond the next js_FinishParseContext. - */ -extern JS_FRIEND_API(JSBool) -js_InitParseContext(JSContext *cx, JSParseContext *pc, - const jschar *base, size_t length, FILE *fp, - const char *filename, uintN lineno); - -extern JS_FRIEND_API(void) -js_FinishParseContext(JSContext *cx, JSParseContext *pc); +extern void +js_InitParseContext(JSContext *cx, JSParseContext *pc); extern void -js_InitCompilePrincipals(JSContext *cx, JSParseContext *pc, - JSPrincipals *principals); +js_FinishParseContext(JSContext *cx, JSParseContext *pc); /* * Allocate a new parseed object node from cx->tempPool. diff --git a/js/src/jsscan.c b/js/src/jsscan.c index 133c01efd45..8bc756273bb 100644 --- a/js/src/jsscan.c +++ b/js/src/jsscan.c @@ -172,6 +172,24 @@ js_IsIdentifier(JSString *str) return JS_TRUE; } +JSTokenStream * +js_NewTokenStream(JSContext *cx, const jschar *base, size_t length, + const char *filename, uintN lineno, + JSPrincipals *principals) +{ + JSTokenStream *ts; + + ts = js_NewBufferTokenStream(cx, base, length); + if (!ts) + return NULL; + ts->filename = filename; + ts->lineno = lineno; + if (principals) + JSPRINCIPALS_HOLD(cx, principals); + ts->principals = principals; + return ts; +} + #define TBMIN 64 static JSBool @@ -212,50 +230,69 @@ GrowTokenBuf(JSStringBuffer *sb, size_t newlength) return JS_TRUE; } -JS_FRIEND_API(JSBool) -js_InitTokenStream(JSContext *cx, JSTokenStream *ts, - const jschar *base, size_t length, - FILE *fp, const char *filename, uintN lineno) +JS_FRIEND_API(JSTokenStream *) +js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length) { - jschar *buf; size_t nb; + JSTokenStream *ts; - JS_ASSERT_IF(fp, !base); - JS_ASSERT_IF(!base, length == 0); - nb = fp - ? 2 * JS_LINE_LIMIT * sizeof(jschar) - : JS_LINE_LIMIT * sizeof(jschar); - JS_ARENA_ALLOCATE_CAST(buf, jschar *, &cx->tempPool, nb); + nb = sizeof(JSTokenStream) + JS_LINE_LIMIT * sizeof(jschar); + JS_ARENA_ALLOCATE_CAST(ts, JSTokenStream *, &cx->tempPool, nb); if (!ts) { JS_ReportOutOfMemory(cx); - return JS_FALSE; - } - memset(buf, 0, nb); - memset(ts, 0, sizeof(*ts)); - ts->filename = filename; - ts->lineno = lineno; - ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = buf; - if (fp) { - ts->file = fp; - ts->userbuf.base = buf + JS_LINE_LIMIT; - ts->userbuf.ptr = ts->userbuf.limit = ts->userbuf.base + JS_LINE_LIMIT; - } else { - ts->userbuf.base = (jschar *)base; - ts->userbuf.limit = (jschar *)base + length; - ts->userbuf.ptr = (jschar *)base; + return NULL; } + memset(ts, 0, nb); + ts->lineno = 1; + ts->linebuf.base = ts->linebuf.limit = ts->linebuf.ptr = (jschar *)(ts + 1); + ts->userbuf.base = (jschar *)base; + ts->userbuf.limit = (jschar *)base + length; + ts->userbuf.ptr = (jschar *)base; ts->tokenbuf.grow = GrowTokenBuf; ts->tokenbuf.data = cx; ts->listener = cx->debugHooks->sourceHandler; ts->listenerData = cx->debugHooks->sourceHandlerData; - return JS_TRUE; + return ts; } -JS_FRIEND_API(void) +JS_FRIEND_API(JSTokenStream *) +js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp) +{ + jschar *base; + JSTokenStream *ts; + FILE *file; + + JS_ARENA_ALLOCATE_CAST(base, jschar *, &cx->tempPool, + JS_LINE_LIMIT * sizeof(jschar)); + if (!base) + return NULL; + ts = js_NewBufferTokenStream(cx, base, JS_LINE_LIMIT); + if (!ts) + return NULL; + if (!filename || strcmp(filename, "-") == 0) { + file = defaultfp; + } else { + file = fopen(filename, "r"); + if (!file) { + JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_OPEN, + filename, "No such file or directory"); + return NULL; + } + } + ts->userbuf.ptr = ts->userbuf.limit; + ts->file = file; + ts->filename = filename; + return ts; +} + +JS_FRIEND_API(JSBool) js_CloseTokenStream(JSContext *cx, JSTokenStream *ts) { if (ts->flags & TSF_OWNFILENAME) JS_free(cx, (void *) ts->filename); + if (ts->principals) + JSPRINCIPALS_DROP(cx, ts->principals); + return !ts->file || fclose(ts->file) == 0; } JS_FRIEND_API(int) @@ -517,6 +554,7 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags, jschar *linechars = NULL; char *linebytes = NULL; JSTokenStream *ts = NULL; + JSCodeGenerator *cg = NULL; JSParseNode *pn = NULL; JSErrorReporter onError; JSTokenPos *tp; @@ -536,20 +574,27 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags, return JS_FALSE; } - if ((flags & JSREPORT_HANDLE) == JSREPORT_TS) { + switch (flags & JSREPORT_HANDLE) { + case JSREPORT_TS: ts = (JSTokenStream *) handle; - } else { - JS_ASSERT((flags & JSREPORT_HANDLE) == JSREPORT_PN); + break; + case JSREPORT_CG: + cg = (JSCodeGenerator *) handle; + break; + case JSREPORT_PN: pn = (JSParseNode *) handle; ts = pn->pn_ts; + break; } + JS_ASSERT(!ts || ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); + /* - * The regexp parser calls us with null ts when the regexp is constructed - * at runtime and does not come from a literal embedded in a script. + * We are typically called with non-null ts and null cg from jsparse.c. + * We can be called with null ts from the regexp compilation functions. + * The code generator (jsemit.c) may pass null ts and non-null cg. */ if (ts) { - JS_ASSERT(ts->linebuf.limit < ts->linebuf.base + JS_LINE_LIMIT); report->filename = ts->filename; if (pn) { report->lineno = pn->pn_pos.begin.lineno; @@ -594,6 +639,9 @@ ReportCompileErrorNumber(JSContext *cx, void *handle, uintN flags, report->tokenptr = report->linebuf + index; report->uclinebuf = linechars; report->uctokenptr = report->uclinebuf + index; + } else if (cg) { + report->filename = cg->filename; + report->lineno = CG_CURRENT_LINE(cg); } else { /* * If we can't find out where the error was based on the current @@ -1860,8 +1908,10 @@ skipline: } if (ts->flags & TSF_OPERAND) { + JSObject *obj; uintN flags; JSBool inCharClass = JS_FALSE; + JSParsedObjectBox *regexpPob; INIT_TOKENBUF(); for (;;) { @@ -1913,8 +1963,29 @@ skipline: if (!TOKENBUF_OK()) goto error; NUL_TERM_TOKENBUF(); - tp->t_reflags = flags; - tt = TOK_REGEXP; + obj = js_NewRegExpObject(cx, ts, + TOKENBUF_BASE(), + TOKENBUF_LENGTH(), + flags); + if (!obj) + goto error; + + regexpPob = js_NewParsedObjectBox(cx, ts->parseContext, obj); + if (!regexpPob) + goto error; + + /* + * If the regexp's script is one-shot, we can avoid the extra + * fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT. + * Otherwise, to avoid incorrect proto, parent, and lastIndex + * sharing among threads and sequentially across re-execution, + * select JSOP_REGEXP. + */ + tp->t_op = (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)) + ? JSOP_OBJECT + : JSOP_REGEXP; + tp->t_pob = regexpPob; + tt = TOK_OBJECT; break; } diff --git a/js/src/jsscan.h b/js/src/jsscan.h index de349d610c1..152b2de33b8 100644 --- a/js/src/jsscan.h +++ b/js/src/jsscan.h @@ -84,7 +84,7 @@ typedef enum JSTokenType { TOK_NAME = 29, /* identifier */ TOK_NUMBER = 30, /* numeric constant */ TOK_STRING = 31, /* string constant */ - TOK_REGEXP = 32, /* RegExp constant */ + TOK_OBJECT = 32, /* RegExp or other object constant */ TOK_PRIMARY = 33, /* true, false, null, this, super */ TOK_FUNCTION = 34, /* function keyword */ TOK_EXPORT = 35, /* export keyword */ @@ -204,8 +204,10 @@ struct JSToken { JSOp op; /* operator, for minimal parser */ JSAtom *atom; /* atom table entry */ } s; - uintN reflags; /* regexp flags, use tokenbuf to access - regexp chars */ + struct { /* object literal */ + JSOp op; /* operator, for minimal parser */ + JSParsedObjectBox *pob; /* object literal node */ + } o; struct { /* atom pair, for XML PIs */ JSAtom *atom2; /* auxiliary atom table entry */ JSAtom *atom; /* main atom table entry */ @@ -215,7 +217,7 @@ struct JSToken { }; #define t_op u.s.op -#define t_reflags u.reflags +#define t_pob u.o.pob #define t_atom u.s.atom #define t_atom2 u.p.atom2 #define t_dval u.dval @@ -246,11 +248,13 @@ struct JSTokenStream { JSStringBuffer tokenbuf; /* current token string buffer */ const char *filename; /* input filename or null */ FILE *file; /* stdio stream if reading from file */ + JSPrincipals *principals; /* principals associated with source */ JSSourceHandler listener; /* callback for source; eg debugger */ void *listenerData; /* listener 'this' data */ void *listenerTSData;/* listener data for this TokenStream */ jschar *saveEOL; /* save next end of line in userbuf, to optimize for very long lines */ + JSParseContext *parseContext; }; #define CURRENT_TOKEN(ts) ((ts)->tokens[(ts)->cursor]) @@ -304,16 +308,21 @@ struct JSTokenStream { * Create a new token stream, either from an input buffer or from a file. * Return null on file-open or memory-allocation failure. * - * The function uses JSContext.tempPool to allocate internal buffers. The - * caller should release them using JS_ARENA_RELEASE after it has finished - * with the token stream and has called js_CloseTokenStream. + * NB: All of js_New{,Buffer,File}TokenStream() return a pointer to transient + * memory in the current context's temp pool. This memory is deallocated via + * JS_ARENA_RELEASE() after parsing is finished. */ -extern JSBool -js_InitTokenStream(JSContext *cx, JSTokenStream *ts, - const jschar *base, size_t length, - FILE *fp, const char *filename, uintN lineno); +extern JSTokenStream * +js_NewTokenStream(JSContext *cx, const jschar *base, size_t length, + const char *filename, uintN lineno, JSPrincipals *principals); -extern void +extern JS_FRIEND_API(JSTokenStream *) +js_NewBufferTokenStream(JSContext *cx, const jschar *base, size_t length); + +extern JS_FRIEND_API(JSTokenStream *) +js_NewFileTokenStream(JSContext *cx, const char *filename, FILE *defaultfp); + +extern JS_FRIEND_API(JSBool) js_CloseTokenStream(JSContext *cx, JSTokenStream *ts); extern JS_FRIEND_API(int) @@ -352,10 +361,11 @@ extern JSBool js_ReportCompileErrorNumberUC(JSContext *cx, void *handle, uintN flags, uintN errorNumber, ...); -/* Steal one JSREPORT_* bit (see jsapi.h) to tell handle's type. */ -#define JSREPORT_HANDLE 0x100 +/* Steal some JSREPORT_* bits (see jsapi.h) to tell handle's type. */ +#define JSREPORT_HANDLE 0x300 #define JSREPORT_TS 0x000 -#define JSREPORT_PN 0x100 +#define JSREPORT_CG 0x100 +#define JSREPORT_PN 0x200 /* * Look ahead one token and return its type. diff --git a/js/src/jsscript.c b/js/src/jsscript.c index 32a72f1a96c..5719f4715af 100644 --- a/js/src/jsscript.c +++ b/js/src/jsscript.c @@ -57,7 +57,6 @@ #include "jslock.h" #include "jsnum.h" #include "jsopcode.h" -#include "jsparse.h" #include "jsscript.h" #if JS_HAS_XDR #include "jsxdrapi.h" @@ -1416,7 +1415,7 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun) js_InitAtomMap(cx, &script->atomMap, &cg->atomList); - filename = cg->treeContext.parseContext->tokenStream.filename; + filename = cg->filename; if (filename) { script->filename = js_SaveScriptFilename(cx, filename); if (!script->filename) @@ -1424,9 +1423,10 @@ js_NewScriptFromCG(JSContext *cx, JSCodeGenerator *cg, JSFunction *fun) } script->lineno = cg->firstLine; script->depth = cg->maxStackDepth; - script->principals = cg->treeContext.parseContext->principals; - if (script->principals) + if (cg->principals) { + script->principals = cg->principals; JSPRINCIPALS_HOLD(cx, script->principals); + } if (!js_FinishTakingSrcNotes(cx, cg, SCRIPT_NOTES(script))) goto bad; diff --git a/js/src/jsxml.c b/js/src/jsxml.c index 9230b8e9046..bdf5b584ca7 100644 --- a/js/src/jsxml.c +++ b/js/src/jsxml.c @@ -1956,11 +1956,12 @@ ParseXMLSource(JSContext *cx, JSString *src) jschar *chars; const jschar *srcp, *endp; JSXML *xml; - JSParseContext pc; - const char *filename; + void *mark; + JSTokenStream *ts; uintN lineno; JSStackFrame *fp; JSOp op; + JSParseContext pc; JSParseNode *pn; JSXMLArray nsarray; uintN flags; @@ -2002,25 +2003,28 @@ ParseXMLSource(JSContext *cx, JSString *src) chars [offset + dstlen] = 0; xml = NULL; + mark = JS_ARENA_MARK(&cx->tempPool); + ts = js_NewBufferTokenStream(cx, chars, length); + if (!ts) + goto out; for (fp = cx->fp; fp && !fp->pc; fp = fp->down) JS_ASSERT(!fp->script); - filename = NULL; - lineno = 1; if (fp) { op = (JSOp) *fp->pc; if (op == JSOP_TOXML || op == JSOP_TOXMLLIST) { - filename = fp->script->filename; + ts->filename = fp->script->filename; lineno = js_PCToLineNumber(cx, fp->script, fp->pc); - for (endp = srcp + srclen; srcp < endp; srcp++) { + for (endp = srcp + srclen; srcp < endp; srcp++) if (*srcp == '\n') --lineno; - } + ts->lineno = lineno; } } - if (!js_InitParseContext(cx, &pc, chars, length, NULL, filename, lineno)) - goto out; - pn = js_ParseXMLText(cx, cx->fp->scopeChain, &pc, JS_FALSE); + js_InitParseContext(cx, &pc); + JS_ASSERT(!ts->parseContext); + ts->parseContext = &pc; + pn = js_ParseXMLTokenStream(cx, cx->fp->scopeChain, ts, JS_FALSE); if (pn && XMLArrayInit(cx, &nsarray, 1)) { if (GetXMLSettingFlags(cx, &flags)) xml = ParseNodeToXML(cx, pn, &nsarray, flags); @@ -2030,6 +2034,7 @@ ParseXMLSource(JSContext *cx, JSString *src) js_FinishParseContext(cx, &pc); out: + JS_ARENA_RELEASE(&cx->tempPool, mark); JS_free(cx, chars); return xml;