зеркало из https://github.com/mozilla/pjs.git
Backing out the patch 397210.
This commit is contained in:
Родитель
b9983456d9
Коммит
8abbdb13fe
172
js/src/jsapi.c
172
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;
|
||||
}
|
||||
|
|
|
@ -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 *
|
||||
|
|
198
js/src/jsparse.c
198
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 <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(¬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)
|
||||
|
|
|
@ -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.
|
||||
|
|
143
js/src/jsscan.c
143
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче