This commit is contained in:
igor%mir2.org 2007-10-01 20:46:10 +00:00
Родитель b9983456d9
Коммит 8abbdb13fe
10 изменённых файлов: 434 добавлений и 346 удалений

Просмотреть файл

@ -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(&notePool, "note", 1024, sizeof(jssrcnote),
&cx->scriptStackQuota);
js_InitParseContext(cx, &pc);
JS_ASSERT(!ts->parseContext);
ts->parseContext = &pc;
if (!js_InitCodeGenerator(cx, &cg, &pc, &codePool, &notePool,
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(&notePool);
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;
}

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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(&notePool, "note", 1024, sizeof(jssrcnote),
&cx->scriptStackQuota);
js_InitCodeGenerator(cx, &cg, pc, &codePool, &notePool, 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(&notePool);
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 <INPUT> 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(&notePool, "note", 1024, sizeof(jssrcnote),
&cx->scriptStackQuota);
js_InitCodeGenerator(cx, &funcg, pc, &codePool, &notePool, TS(pc)->lineno);
js_InitParseContext(cx, &pc);
JS_ASSERT(!ts->parseContext);
ts->parseContext = &pc;
if (!js_InitCodeGenerator(cx, &funcg, &pc, &codePool, &notePool,
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(&notePool);
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)

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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