From d554d804426cb812c3615b37234337de986a0006 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Fri, 15 May 2015 20:53:03 +0200 Subject: [PATCH] Bug 1059908 - Merge FunctionType and FunctionSyntaxKind. r=efaust --- js/src/asmjs/AsmJSValidate.cpp | 4 +- js/src/frontend/BytecodeCompiler.cpp | 4 +- js/src/frontend/ParseNode.h | 11 +++- js/src/frontend/Parser.cpp | 96 +++++++++++++++++----------- js/src/frontend/Parser.h | 14 ++-- js/src/frontend/SharedContext.h | 4 +- js/src/jsfun.cpp | 5 +- js/src/jsfun.h | 25 +++++++- 8 files changed, 106 insertions(+), 57 deletions(-) diff --git a/js/src/asmjs/AsmJSValidate.cpp b/js/src/asmjs/AsmJSValidate.cpp index 829b0489d84f..6c73bc0c7424 100644 --- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -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; diff --git a/js/src/frontend/BytecodeCompiler.cpp b/js/src/frontend/BytecodeCompiler.cpp index c01e03159a42..d7d10829a4bf 100644 --- a/js/src/frontend/BytecodeCompiler.cpp +++ b/js/src/frontend/BytecodeCompiler.cpp @@ -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); diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index 4c6c341f9456..5653c854f6a8 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -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) diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index d48ac3d6647b..d646f31a231f 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -1214,26 +1214,36 @@ Parser::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::bindDestructuringArg(BindData* data, template bool Parser::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::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::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::functionArguments(YieldHandling yieldHandling, FunctionSyn return false; } - if (parenFreeArrow || type == Setter) + if (parenFreeArrow || kind == Setter) break; bool matched; @@ -1781,7 +1791,7 @@ Parser::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::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::templateLiteral(YieldHandling yieldHandling) template typename ParseHandler::Node Parser::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::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::finishFunctionDefinition(Node pn, FunctionBox* funbo template <> bool Parser::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::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::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::functionArgsAndBody(InHandling inHandling, ParseNode* template <> bool Parser::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun, - FunctionType type, FunctionSyntaxKind kind, + FunctionSyntaxKind kind, GeneratorKind generatorKind, Directives inheritedDirectives, Directives* newDirectives) @@ -2424,7 +2432,7 @@ Parser::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::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 bool Parser::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::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::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::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 @@ -2680,7 +2698,7 @@ Parser::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::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::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::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::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::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::propertyList(YieldHandling yieldHandling, PropListType typ template bool Parser::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; diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index 33b75b81be92..0a03356a1c9b 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -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); diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h index 0d69d19ac7a0..807778a3672c 100644 --- a/js/src/frontend/SharedContext.h +++ b/js/src/frontend/SharedContext.h @@ -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(); } }; diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 1dfab4c64237..e0cb5e38e216 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -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) { diff --git a/js/src/jsfun.h b/js/src/jsfun.h index 599037f74492..f2ab2a7851a2 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -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; }