Bug 1059908 - Merge FunctionType and FunctionSyntaxKind. r=efaust

This commit is contained in:
Tom Schuster 2015-05-15 20:53:03 +02:00
parent 8444c671f4
commit d554d80442
8 changed files with 106 additions and 57 deletions

View File

@ -7604,9 +7604,7 @@ ParseFunction(ModuleCompiler& m, ParseNode** fnOut)
if (!funpc.init(tokenStream))
return false;
if (!m.parser().functionArgsAndBodyGeneric(InAllowed, YieldIsName, fn, fun, Normal,
Statement))
{
if (!m.parser().functionArgsAndBodyGeneric(InAllowed, YieldIsName, fn, fun, Statement)) {
if (tokenStream.hadError() || directives == newDirectives)
return false;

View File

@ -282,7 +282,9 @@ frontend::CompileScript(ExclusiveContext* cx, LifoAlloc* alloc, HandleObject sco
return nullptr;
bool savedCallerFun = evalCaller && evalCaller->functionOrCallerFunction();
bool allowSuperProperty = savedCallerFun && evalCaller->functionOrCallerFunction()->isMethod();
bool allowSuperProperty = savedCallerFun && (evalCaller->functionOrCallerFunction()->isMethod() ||
evalCaller->functionOrCallerFunction()->isGetter() ||
evalCaller->functionOrCallerFunction()->isSetter());
Directives directives(options.strictOption);
GlobalSharedContext globalsc(cx, directives, options.extraWarningsOption, allowSuperProperty);

View File

@ -1693,7 +1693,16 @@ enum ParseReportKind
ParseStrictError
};
enum FunctionSyntaxKind { Expression, Statement, Arrow, Method };
enum FunctionSyntaxKind
{
Expression,
Statement,
Arrow,
Method,
ClassConstructor,
Getter,
Setter
};
static inline ParseNode*
FunctionArgsList(ParseNode* fn, unsigned* numFormals)

View File

@ -1214,26 +1214,36 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, Hand
MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
RootedFunction fun(context);
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
JSFunction::Flags flags;
switch(kind) {
switch (kind) {
case Expression:
flags = JSFunction::INTERPRETED_LAMBDA;
break;
case Arrow:
flags = JSFunction::INTERPRETED_LAMBDA_ARROW;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case Method:
flags = JSFunction::INTERPRETED_METHOD;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case ClassConstructor:
flags = JSFunction::INTERPRETED_CLASS_CONSTRUCTOR;
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
break;
case Getter:
flags = JSFunction::INTERPRETED_GETTER;
break;
case Setter:
flags = JSFunction::INTERPRETED_SETTER;
break;
default:
flags = JSFunction::INTERPRETED;
break;
}
gc::AllocKind allocKind = gc::AllocKind::FUNCTION;
if (kind == Arrow || kind == Method)
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
fun = NewFunctionWithProto(context, nullptr, 0, flags, NullPtr(), atom, proto,
allocKind, TenuredObject);
if (!fun)
@ -1556,7 +1566,7 @@ Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler>* data,
template <typename ParseHandler>
bool
Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
FunctionType type, Node* listp, Node funcpn, bool* hasRest)
Node* listp, Node funcpn, bool* hasRest)
{
FunctionBox* funbox = pc->sc->asFunctionBox();
@ -1604,9 +1614,9 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
bool hasDefaults = false;
Node duplicatedArg = null();
Node list = null();
bool disallowDuplicateArgs = kind == Arrow || kind == Method;
bool disallowDuplicateArgs = kind == Arrow || kind == Method || kind == ClassConstructor;
if (type == Getter) {
if (kind == Getter) {
report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
return false;
}
@ -1689,7 +1699,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
case TOK_TRIPLEDOT:
{
if (type == Setter) {
if (kind == Setter) {
report(ParseError, false, null(),
JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
@ -1766,7 +1776,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
return false;
}
if (parenFreeArrow || type == Setter)
if (parenFreeArrow || kind == Setter)
break;
bool matched;
@ -1781,7 +1791,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!tokenStream.getToken(&tt))
return false;
if (tt != TOK_RP) {
if (type == Setter) {
if (kind == Setter) {
report(ParseError, false, null(),
JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
@ -1794,7 +1804,7 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
if (!hasDefaults)
funbox->length = pc->numArgs() - *hasRest;
} else if (type == Setter) {
} else if (kind == Setter) {
report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
return false;
}
@ -2149,9 +2159,8 @@ Parser<ParseHandler>::templateLiteral(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHandling,
HandlePropertyName funName, FunctionType type,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
InvokedPrediction invoked)
HandlePropertyName funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, InvokedPrediction invoked)
{
MOZ_ASSERT_IF(kind == Statement, funName);
@ -2195,7 +2204,7 @@ Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHand
tokenStream.tell(&start);
while (true) {
if (functionArgsAndBody(inHandling, pn, fun, type, kind, generatorKind, directives,
if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives,
&newDirectives))
{
break;
@ -2303,8 +2312,8 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
template <>
bool
Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode* pn,
HandleFunction fun, FunctionType type,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
HandleFunction fun, FunctionSyntaxKind kind,
GeneratorKind generatorKind,
Directives inheritedDirectives,
Directives* newDirectives)
{
@ -2344,8 +2353,7 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
return false;
if (!parser->functionArgsAndBodyGeneric(inHandling, yieldHandling,
SyntaxParseHandler::NodeGeneric, fun, type,
kind))
SyntaxParseHandler::NodeGeneric, fun, kind))
{
if (parser->hadAbortedSyntaxParse()) {
// Try again with a full parse.
@ -2383,7 +2391,7 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
if (!funpc.init(tokenStream))
return false;
if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, type, kind))
if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
return false;
if (!leaveFunction(pn, outerpc, kind))
@ -2404,7 +2412,7 @@ Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode*
template <>
bool
Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
FunctionType type, FunctionSyntaxKind kind,
FunctionSyntaxKind kind,
GeneratorKind generatorKind,
Directives inheritedDirectives,
Directives* newDirectives)
@ -2424,7 +2432,7 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn,
return false;
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, type, kind))
if (!functionArgsAndBodyGeneric(inHandling, yieldHandling, pn, fun, kind))
return false;
if (!leaveFunction(pn, outerpc, kind))
@ -2486,8 +2494,16 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
return null();
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
FunctionSyntaxKind syntaxKind = fun->isMethod() ? Method : Statement;
if (!functionArgsAndBodyGeneric(InAllowed, yieldHandling, pn, fun, Normal, syntaxKind)) {
FunctionSyntaxKind syntaxKind = Statement;
if (fun->isClassConstructor())
syntaxKind = ClassConstructor;
else if (fun->isMethod())
syntaxKind = Method;
else if (fun->isGetter())
syntaxKind = Getter;
else if (fun->isSetter())
syntaxKind = Setter;
if (!functionArgsAndBodyGeneric(InAllowed, yieldHandling, pn, fun, syntaxKind)) {
MOZ_ASSERT(directives == newDirectives);
return null();
}
@ -2515,8 +2531,7 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
YieldHandling yieldHandling, Node pn,
HandleFunction fun, FunctionType type,
FunctionSyntaxKind kind)
HandleFunction fun, FunctionSyntaxKind kind)
{
// Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy
@ -2524,7 +2539,7 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
Node prelude = null();
bool hasRest;
if (!functionArguments(yieldHandling, kind, type, &prelude, pn, &hasRest))
if (!functionArguments(yieldHandling, kind, &prelude, pn, &hasRest))
return false;
FunctionBox* funbox = pc->sc->asFunctionBox();
@ -2574,8 +2589,11 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
if (!body)
return false;
if (kind != Method && fun->name() && !checkStrictBinding(fun->name(), pn))
if ((kind != Method && kind != ClassConstructor) && fun->name() &&
!checkStrictBinding(fun->name(), pn))
{
return false;
}
if (bodyType == StatementListBody) {
bool matched;
@ -2648,7 +2666,7 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling)
!report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
return null();
return functionDef(InAllowed, yieldHandling, name, Normal, Statement, generatorKind);
return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind);
}
template <typename ParseHandler>
@ -2680,7 +2698,7 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
}
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
return functionDef(InAllowed, yieldHandling, name, Normal, Expression, generatorKind, invoked);
return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked);
}
/*
@ -6575,7 +6593,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
if (!tokenStream.peekToken(&ignored))
return null();
return functionDef(inHandling, yieldHandling, NullPtr(), Normal, Arrow, NotGenerator);
return functionDef(inHandling, yieldHandling, NullPtr(), Arrow, NotGenerator);
}
default:
@ -7806,7 +7824,7 @@ Parser<ParseHandler>::checkAndMarkSuperScope()
sc->asFunctionBox()->setNeedsHomeObject();
return true;
} else if (sc->isFunctionBox() && !sc->asFunctionBox()->function()->isArrow()) {
// super is not legal is normal functions.
// super is not legal in normal functions.
break;
}
}
@ -8297,6 +8315,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
JSOp op = JSOP_INITPROP;
Node propname;
bool isConstructor = false;
switch (ltok) {
case TOK_NUMBER:
atom = DoubleToAtom(context, tokenStream.currentToken().number());
@ -8423,6 +8442,7 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
return null();
}
seenConstructor = true;
isConstructor = true;
} else if (isStatic && atom == context->names().prototype) {
report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF);
return null();
@ -8498,7 +8518,8 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
return null();
} else if (tt == TOK_LP) {
tokenStream.ungetToken();
if (!methodDefinition(yieldHandling, type, propList, propname, Normal,
if (!methodDefinition(yieldHandling, type, propList, propname,
isConstructor ? ClassConstructor : Method,
isGenerator ? StarGenerator : NotGenerator, isStatic, op))
{
return null();
@ -8542,17 +8563,18 @@ Parser<ParseHandler>::propertyList(YieldHandling yieldHandling, PropListType typ
template <typename ParseHandler>
bool
Parser<ParseHandler>::methodDefinition(YieldHandling yieldHandling, PropListType listType,
Node propList, Node propname, FunctionType type,
Node propList, Node propname, FunctionSyntaxKind kind,
GeneratorKind generatorKind, bool isStatic, JSOp op)
{
MOZ_ASSERT(kind == Method || kind == ClassConstructor || kind == Getter || kind == Setter);
/* NB: Getter function in { get x(){} } is unnamed. */
RootedPropertyName funName(context);
if (type == Normal && tokenStream.isCurrentTokenType(TOK_NAME))
if ((kind == Method || kind == ClassConstructor) && tokenStream.isCurrentTokenType(TOK_NAME))
funName = tokenStream.currentName();
else
funName = nullptr;
Node fn = functionDef(InAllowed, yieldHandling, funName, type, Method, generatorKind);
Node fn = functionDef(InAllowed, yieldHandling, funName, kind, generatorKind);
if (!fn)
return false;

View File

@ -328,7 +328,6 @@ class CompExprTransplanter;
enum LetContext { LetExpression, LetStatement };
enum VarContext { HoistVars, DontHoistVars };
enum FunctionType { Getter, Setter, Normal };
enum PropListType { ObjectLiteral, ClassBody };
// Specify a value for an ES6 grammar parametrization. We have no enum for
@ -504,8 +503,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
FunctionBodyType type);
bool functionArgsAndBodyGeneric(InHandling inHandling, YieldHandling yieldHandling, Node pn,
HandleFunction fun, FunctionType type,
FunctionSyntaxKind kind);
HandleFunction fun, FunctionSyntaxKind kind);
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
@ -594,19 +592,19 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
bool checkAndMarkSuperScope();
bool methodDefinition(YieldHandling yieldHandling, PropListType listType, Node propList,
Node propname, FunctionType type, GeneratorKind generatorKind,
Node propname, FunctionSyntaxKind kind, GeneratorKind generatorKind,
bool isStatic, JSOp Op);
/*
* Additional JS parsers.
*/
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, FunctionType type,
Node* list, Node funcpn, bool* hasRest);
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind, Node* list,
Node funcpn, bool* hasRest);
Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
FunctionType type, FunctionSyntaxKind kind, GeneratorKind generatorKind,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
InvokedPrediction invoked = PredictUninvoked);
bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, FunctionType type,
bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
Directives inheritedDirectives, Directives* newDirectives);

View File

@ -306,7 +306,7 @@ class FunctionBox : public ObjectBox, public SharedContext
void setArgumentsHasLocalBinding() { funCxFlags.argumentsHasLocalBinding = true; }
void setDefinitelyNeedsArgsObj() { MOZ_ASSERT(funCxFlags.argumentsHasLocalBinding);
funCxFlags.definitelyNeedsArgsObj = true; }
void setNeedsHomeObject() { MOZ_ASSERT(function()->isMethod());
void setNeedsHomeObject() { MOZ_ASSERT(allowSuperProperty());
funCxFlags.needsHomeObject = true; }
bool hasDefaults() const {
@ -339,7 +339,7 @@ class FunctionBox : public ObjectBox, public SharedContext
}
bool allowSuperProperty() const {
return function()->isMethod();
return function()->isMethod() || function()->isGetter() || function()->isSetter();
}
};

View File

@ -980,8 +980,9 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb
return out.finishString();
}
}
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod();
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
if (!bodyOnly) {
// If we're not in pretty mode, put parentheses around lambda functions and methods.
if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda) {

View File

@ -32,7 +32,10 @@ class JSFunction : public js::NativeObject
NormalFunction = 0,
Arrow, /* ES6 '(args) => body' syntax */
Method, /* ES6 MethodDefinition */
AsmJS /* function is an asm.js module or exported function */
Getter,
Setter,
AsmJS, /* function is an asm.js module or exported function */
FunctionKindLimit
};
enum Flags {
@ -57,16 +60,22 @@ class JSFunction : public js::NativeObject
RESOLVED_NAME = 0x1000, /* f.name has been resolved (see fun_resolve). */
FUNCTION_KIND_SHIFT = 13,
FUNCTION_KIND_MASK = 0x3 << FUNCTION_KIND_SHIFT,
FUNCTION_KIND_MASK = 0x7 << FUNCTION_KIND_SHIFT,
ASMJS_KIND = AsmJS << FUNCTION_KIND_SHIFT,
ARROW_KIND = Arrow << FUNCTION_KIND_SHIFT,
METHOD_KIND = Method << FUNCTION_KIND_SHIFT,
GETTER_KIND = Getter << FUNCTION_KIND_SHIFT,
SETTER_KIND = Setter << FUNCTION_KIND_SHIFT,
/* Derived Flags values for convenience: */
NATIVE_FUN = 0,
ASMJS_CTOR = ASMJS_KIND | NATIVE_CTOR,
ASMJS_LAMBDA_CTOR = ASMJS_KIND | NATIVE_CTOR | LAMBDA,
INTERPRETED_METHOD = INTERPRETED | (Method << FUNCTION_KIND_SHIFT),
INTERPRETED_METHOD = INTERPRETED | METHOD_KIND,
INTERPRETED_CLASS_CONSTRUCTOR = INTERPRETED | METHOD_KIND,
INTERPRETED_GETTER = INTERPRETED | GETTER_KIND,
INTERPRETED_SETTER = INTERPRETED | SETTER_KIND,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW_KIND,
STABLE_ACROSS_CLONES = NATIVE_CTOR | IS_FUN_PROTO | EXPR_BODY | HAS_GUESSED_ATOM |
@ -76,6 +85,8 @@ class JSFunction : public js::NativeObject
static_assert((INTERPRETED | INTERPRETED_LAZY) == js::JS_FUNCTION_INTERPRETED_BITS,
"jsfriendapi.h's JSFunction::INTERPRETED-alike is wrong");
static_assert(((FunctionKindLimit - 1) << FUNCTION_KIND_SHIFT) <= FUNCTION_KIND_MASK,
"FunctionKind doesn't fit into flags_");
private:
uint16_t nargs_; /* number of formal arguments
@ -152,8 +163,16 @@ class JSFunction : public js::NativeObject
// Arrow functions store their lexical |this| in the first extended slot.
bool isArrow() const { return kind() == Arrow; }
// Every class-constructor is also a method.
bool isMethod() const { return kind() == Method; }
bool isGetter() const { return kind() == Getter; }
bool isSetter() const { return kind() == Setter; }
bool isClassConstructor() const {
return kind() == Method && isInterpretedConstructor();
}
bool hasResolvedLength() const { return flags() & RESOLVED_LENGTH; }
bool hasResolvedName() const { return flags() & RESOLVED_NAME; }