Bug 636224 - rm cx->interpLevel and TSF_ERROR (r=brendan)

--HG--
extra : rebase_source : 682e496d3fad9454b0279aff9bfd4c1bcf50055c
This commit is contained in:
Luke Wagner 2011-03-23 14:33:02 -07:00
parent a3cfafaa02
commit f37c253b7f
8 changed files with 81 additions and 147 deletions

View File

@ -0,0 +1,9 @@
var caught = false;
try {
Function("a, `", "");
} catch(e) {
assertEq(e.toString().search("SyntaxError: malformed formal parameter") == -1, true);
assertEq(e.toString().search("SyntaxError: illegal character") == -1, false);
caught = true;
}
assertEq(caught, true);

View File

@ -1703,9 +1703,6 @@ struct JSContext
/* Branch callback. */
JSOperationCallback operationCallback;
/* Interpreter activation count. */
uintN interpLevel;
/* Client opaque pointers. */
void *data;
void *data2;

View File

@ -2408,16 +2408,29 @@ static JSFunctionSpec function_methods[] = {
JS_FS_END
};
/*
* Report "malformed formal parameter" iff no illegal char or similar scanner
* error was already reported.
*/
static bool
OnBadFormal(JSContext *cx, TokenKind tt)
{
if (tt != TOK_ERROR)
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_FORMAL);
else
JS_ASSERT(cx->isExceptionPending());
return false;
}
static JSBool
Function(JSContext *cx, uintN argc, Value *vp)
{
JSObject *obj = NewFunction(cx, NULL);
if (!obj)
return JS_FALSE;
JS::Anchor<JSObject *> obj(NewFunction(cx, NULL));
if (!obj.get())
return false;
/* N.B. overwriting callee with return value */
JSObject *parent = vp[0].toObject().getParent();
vp[0].setObject(*obj);
JSObject &callee = JS_CALLEE(cx, vp).toObject();
JSObject &calleeParent = *callee.getParent();
/*
* NB: (new Function) is not lexically closed by its caller, it's just an
@ -2429,10 +2442,10 @@ Function(JSContext *cx, uintN argc, Value *vp)
* its running context's globalObject, which might be different from the
* top-level reachable from scopeChain (in HTML frames, e.g.).
*/
JSFunction *fun = js_NewFunction(cx, obj, NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
parent, cx->runtime->atomState.anonymousAtom);
JSFunction *fun = js_NewFunction(cx, obj.get(), NULL, 0, JSFUN_LAMBDA | JSFUN_INTERPRETED,
&calleeParent, cx->runtime->atomState.anonymousAtom);
if (!fun)
return JS_FALSE;
return false;
/*
* Function is static and not called directly by other functions in this
@ -2446,8 +2459,7 @@ Function(JSContext *cx, uintN argc, Value *vp)
const char *filename;
JSPrincipals *principals;
if (caller) {
JSObject *callee = &JS_CALLEE(cx, vp).toObject();
principals = js_EvalFramePrincipals(cx, callee, caller);
principals = js_EvalFramePrincipals(cx, &callee, caller);
filename = js_ComputeFilename(cx, caller, principals, &lineno);
} else {
filename = NULL;
@ -2456,9 +2468,9 @@ Function(JSContext *cx, uintN argc, Value *vp)
}
/* Belt-and-braces: check that the caller has access to parent. */
if (!js_CheckPrincipalsAccess(cx, parent, principals,
if (!js_CheckPrincipalsAccess(cx, &calleeParent, principals,
CLASS_ATOM(cx, Function))) {
return JS_FALSE;
return false;
}
/*
@ -2466,24 +2478,22 @@ Function(JSContext *cx, uintN argc, Value *vp)
* Report errors via CSP is done in the script security manager.
* js_CheckContentSecurityPolicy is defined in jsobj.cpp
*/
if (!js_CheckContentSecurityPolicy(cx, parent)) {
if (!js_CheckContentSecurityPolicy(cx, &calleeParent)) {
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CSP_BLOCKED_FUNCTION);
return JS_FALSE;
return false;
}
EmptyShape *emptyCallShape = EmptyShape::getEmptyCallShape(cx);
if (!emptyCallShape)
return JS_FALSE;
return false;
AutoShapeRooter shapeRoot(cx, emptyCallShape);
Bindings bindings(cx, emptyCallShape);
AutoBindingsRooter root(cx, bindings);
Value *argv = vp + 2;
Value *argv = JS_ARGV(cx, vp);
uintN 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
@ -2494,13 +2504,12 @@ Function(JSContext *cx, uintN argc, Value *vp)
* compiler, but doing it this way is less of a delta from the old
* code. See ECMA 15.3.2.1.
*/
state = BAD_FORMAL;
size_t args_length = 0;
for (uintN i = 0; i < n; i++) {
/* Collect the lengths for all the function-argument arguments. */
JSString *arg = js_ValueToString(cx, argv[i]);
if (!arg)
return JS_FALSE;
return false;
argv[i].setString(arg);
/*
@ -2511,7 +2520,7 @@ Function(JSContext *cx, uintN argc, Value *vp)
args_length = old_args_length + arg->length();
if (args_length < old_args_length) {
js_ReportAllocationOverflow(cx);
return JS_FALSE;
return false;
}
}
@ -2521,7 +2530,7 @@ Function(JSContext *cx, uintN argc, Value *vp)
if (args_length < old_args_length ||
args_length >= ~(size_t)0 / sizeof(jschar)) {
js_ReportAllocationOverflow(cx);
return JS_FALSE;
return false;
}
/*
@ -2529,13 +2538,11 @@ Function(JSContext *cx, uintN argc, Value *vp)
* for a terminating 0. Mark cx->tempPool for later release, to free
* collected_args and its tokenstream in one swoop.
*/
void *mark = JS_ARENA_MARK(&cx->tempPool);
jschar *cp;
JS_ARENA_ALLOCATE_CAST(cp, jschar *, &cx->tempPool,
(args_length+1) * sizeof(jschar));
AutoArenaAllocator aaa(&cx->tempPool);
jschar *cp = aaa.alloc<jschar>(args_length + 1);
if (!cp) {
js_ReportOutOfScriptQuota(cx);
return JS_FALSE;
return false;
}
jschar *collected_args = cp;
@ -2546,10 +2553,8 @@ Function(JSContext *cx, uintN argc, Value *vp)
JSString *arg = argv[i].toString();
size_t arg_length = arg->length();
const jschar *arg_chars = arg->getChars(cx);
if (!arg_chars) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
if (!arg_chars)
return false;
(void) js_strncpy(cp, arg_chars, arg_length);
cp += arg_length;
@ -2559,10 +2564,8 @@ Function(JSContext *cx, uintN argc, Value *vp)
/* Initialize a tokenstream that reads from the given string. */
TokenStream ts(cx);
if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion())) {
JS_ARENA_RELEASE(&cx->tempPool, mark);
return JS_FALSE;
}
if (!ts.init(collected_args, args_length, filename, lineno, cx->findVersion()))
return false;
/* The argument string may be empty or contain no tokens. */
TokenKind tt = ts.getToken();
@ -2573,7 +2576,7 @@ Function(JSContext *cx, uintN argc, Value *vp)
* TOK_ERROR, which was already reported.
*/
if (tt != TOK_NAME)
goto after_args;
return OnBadFormal(cx, tt);
/*
* Get the atom corresponding to the name from the token
@ -2585,23 +2588,18 @@ Function(JSContext *cx, uintN argc, Value *vp)
/* Check for a duplicate parameter name. */
if (bindings.hasBinding(cx, atom)) {
JSAutoByteString name;
if (!js_AtomToPrintableString(cx, atom, &name)) {
state = BAD;
goto after_args;
}
if (!js_AtomToPrintableString(cx, atom, &name))
return false;
if (!ReportCompileErrorNumber(cx, &ts, NULL,
JSREPORT_WARNING | JSREPORT_STRICT,
JSMSG_DUPLICATE_FORMAL, name.ptr())) {
state = BAD;
goto after_args;
return false;
}
}
uint16 dummy;
if (!bindings.addArgument(cx, atom, &dummy)) {
state = BAD;
goto after_args;
}
if (!bindings.addArgument(cx, atom, &dummy))
return false;
/*
* Get the next token. Stop on end of stream. Otherwise
@ -2611,44 +2609,32 @@ Function(JSContext *cx, uintN argc, Value *vp)
if (tt == TOK_EOF)
break;
if (tt != TOK_COMMA)
goto after_args;
return OnBadFormal(cx, tt);
tt = ts.getToken();
}
}
state = OK;
after_args:
if (state == BAD_FORMAL && !ts.isError()) {
/*
* Report "malformed formal parameter" iff no illegal char or
* similar scanner error was already reported.
*/
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
JSMSG_BAD_FORMAL);
}
ts.close();
JS_ARENA_RELEASE(&cx->tempPool, mark);
if (state != OK)
return JS_FALSE;
}
JSString *str;
JS::Anchor<JSString *> strAnchor(NULL);
const jschar *chars;
size_t length;
if (argc) {
str = js_ValueToString(cx, argv[argc - 1]);
JSString *str = js_ValueToString(cx, argv[argc - 1]);
if (!str)
return JS_FALSE;
argv[argc - 1].setString(str);
return false;
strAnchor.set(str);
chars = str->getChars(cx);
length = str->length();
} else {
str = cx->runtime->emptyString;
chars = cx->runtime->emptyString->chars();
length = 0;
}
size_t length = str->length();
const jschar *chars = str->getChars(cx);
if (!chars)
return JS_FALSE;
JS_SET_RVAL(cx, vp, ObjectValue(*obj.get()));
return Compiler::compileFunctionBody(cx, fun, principals, &bindings,
chars, length, filename, lineno, cx->findVersion());
chars, length, filename, lineno,
cx->findVersion());
}
namespace js {

View File

@ -614,8 +614,6 @@ RunScript(JSContext *cx, JSScript *script, JSStackFrame *fp)
JMCheckLogging();
#endif
AutoInterpPreparer prepareInterp(cx, script);
/* FIXME: Once bug 470510 is fixed, make this an assert. */
if (script->compileAndGo) {
int32 flags = fp->scopeChain().getGlobal()->getReservedSlot(JSRESERVED_GLOBAL_FLAGS).toInt32();
@ -2461,10 +2459,8 @@ Interpret(JSContext *cx, JSStackFrame *entryFrame, uintN inlineCallCount, JSInte
InterpExitGuard(JSContext *cx, JSFrameRegs &regs)
: cx(cx), regs(regs), prevContextRegs(cx->regs) {
cx->setCurrentRegs(&regs);
++cx->interpLevel;
}
~InterpExitGuard() {
--cx->interpLevel;
JS_ASSERT(cx->regs == &regs);
*prevContextRegs = regs;
cx->setCurrentRegs(prevContextRegs);

View File

@ -515,22 +515,6 @@ class AutoPreserveEnumerators {
}
};
struct AutoInterpPreparer {
JSContext *cx;
JSScript *script;
AutoInterpPreparer(JSContext *cx, JSScript *script)
: cx(cx), script(script)
{
cx->interpLevel++;
}
~AutoInterpPreparer()
{
--cx->interpLevel;
}
};
class InvokeSessionGuard
{
InvokeArgsGuard args_;
@ -601,7 +585,6 @@ InvokeSessionGuard::invoke(JSContext *cx) const
AutoPreserveEnumerators preserve(cx);
Probes::enterJSFun(cx, fp->fun(), script_);
#ifdef JS_METHODJIT
AutoInterpPreparer prepareInterp(cx, script_);
ok = mjit::EnterMethodJIT(cx, fp, code, stackLimit_);
cx->regs->pc = stop_;
#else

View File

@ -225,7 +225,6 @@ Parser::~Parser()
if (principals)
JSPRINCIPALS_DROP(cx, principals);
tokenStream.close();
JS_ARENA_RELEASE(&cx->tempPool, tempPoolMark);
}

View File

@ -227,8 +227,7 @@ TokenStream::init(const jschar *base, size_t length, const char *fn, uintN ln, J
return true;
}
void
TokenStream::close()
TokenStream::~TokenStream()
{
if (flags & TSF_OWNFILENAME)
cx->free((void *) filename);
@ -432,7 +431,6 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro
JSBool ok;
const TokenPos *tp;
uintN i;
JSErrorReporter onError;
if (JSREPORT_IS_STRICT(flags) && !cx->hasStrictOption())
return JS_TRUE;
@ -512,45 +510,20 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro
* as the non-top-level "load", "eval", or "compile" native function
* returns false, the top-level reporter will eventually receive the
* uncaught exception report.
*
* XXX it'd probably be best if there was only one call to this
* function, but there seem to be two error reporter call points.
*/
onError = cx->errorReporter;
/*
* Try to raise an exception only if there isn't one already set --
* otherwise the exception will describe the last compile-time error,
* which is likely spurious.
*/
if (!(flags & TSF_ERROR)) {
if (js_ErrorToException(cx, message, &report, NULL, NULL))
onError = NULL;
}
/*
* Suppress any compile-time errors that don't occur at the top level.
* This may still fail, as interplevel may be zero in contexts where we
* don't really want to call the error reporter, as when js is called
* by other code which could catch the error.
*/
if (cx->interpLevel != 0 && !JSREPORT_IS_WARNING(flags))
onError = NULL;
if (onError) {
JSDebugErrorHook hook = cx->debugHooks->debugErrorHook;
if (!js_ErrorToException(cx, message, &report, NULL, NULL)) {
/*
* If debugErrorHook is present then we give it a chance to veto
* sending the error on to the regular error reporter.
*/
if (hook && !hook(cx, message, &report,
cx->debugHooks->debugErrorHookData)) {
onError = NULL;
}
bool reportError = true;
if (JSDebugErrorHook hook = cx->debugHooks->debugErrorHook)
reportError = hook(cx, message, &report, cx->debugHooks->debugErrorHookData);
/* Report the error */
if (reportError && cx->errorReporter)
cx->errorReporter(cx, message, &report);
}
if (onError)
(*onError)(cx, message, &report);
out:
if (linebytes)
@ -571,11 +544,6 @@ TokenStream::reportCompileErrorNumberVA(JSParseNode *pn, uintN flags, uintN erro
cx->free((void *)report.messageArgs);
}
if (!JSREPORT_IS_WARNING(flags)) {
/* Set the error flag to suppress spurious reports. */
flags |= TSF_ERROR;
}
return warning;
}
@ -1899,13 +1867,14 @@ TokenStream::getTokenInternal()
return tt;
error:
JS_ASSERT(cx->isExceptionPending());
/*
* For erroneous multi-line tokens we won't have changed end.lineno (it'll
* still be equal to begin.lineno) so we revert end.index to be equal to
* begin.index + 1 (as if it's a 1-char token) to avoid having inconsistent
* begin/end positions. end.index isn't used in error messages anyway.
*/
flags |= TSF_ERROR;
flags |= TSF_DIRTYLINE;
tp->pos.end.index = tp->pos.begin.index + 1;
tp->type = TOK_ERROR;

View File

@ -252,7 +252,6 @@ struct Token {
enum TokenStreamFlags
{
TSF_ERROR = 0x01, /* fatal error while compiling */
TSF_EOF = 0x02, /* hit end of file */
TSF_EOL = 0x04, /* an EOL was hit in whitespace or a multi-line comment */
TSF_OPERAND = 0x08, /* looking for operand, not operator */
@ -327,8 +326,7 @@ class TokenStream
*/
bool init(const jschar *base, size_t length, const char *filename, uintN lineno,
JSVersion version);
void close();
~TokenStream() {}
~TokenStream();
/* Accessors. */
JSContext *getContext() const { return cx; }
@ -363,7 +361,6 @@ class TokenStream
bool isXMLOnlyMode() { return !!(flags & TSF_XMLONLYMODE); }
bool isUnexpectedEOF() { return !!(flags & TSF_UNEXPECTED_EOF); }
bool isEOF() const { return !!(flags & TSF_EOF); }
bool isError() const { return !!(flags & TSF_ERROR); }
bool hasOctalCharacterEscape() const { return flags & TSF_OCTAL_CHAR; }
/* Mutators. */
@ -418,8 +415,6 @@ class TokenStream
return tt;
}
JS_ASSERT(!(flags & TSF_ERROR));
return getTokenInternal();
}