Bug 1059908 - Merge FunctionType and FunctionSyntaxKind. r=efaust
authorTom Schuster <evilpies@gmail.com>
Fri, 15 May 2015 20:53:03 +0200
changeset 244121 2fd7da3aa49a
parent 244120 6e940b4892ee
child 244122 9f7b7d427d1c
push id28766
push userphilringnalda@gmail.com
push dateSat, 16 May 2015 15:50:57 +0000
treeherdermozilla-central@e00b8970afbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1059908
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1059908 - Merge FunctionType and FunctionSyntaxKind. r=efaust
js/src/asmjs/AsmJSValidate.cpp
js/src/frontend/BytecodeCompiler.cpp
js/src/frontend/ParseNode.h
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/frontend/SharedContext.h
js/src/jsfun.cpp
js/src/jsfun.h
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -7599,19 +7599,17 @@ ParseFunction(ModuleCompiler& m, ParseNo
 
     Directives newDirectives = directives;
     AsmJSParseContext funpc(&m.parser(), outerpc, fn, funbox, &newDirectives,
                             outerpc->staticLevel + 1, outerpc->blockidGen,
                             /* blockScopeDepth = */ 0);
     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;
 
         return m.fail(nullptr, "encountered new directive");
     }
 
     MOZ_ASSERT(!tokenStream.hadError());
     MOZ_ASSERT(directives == newDirectives);
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -277,17 +277,19 @@ frontend::CompileScript(ExclusiveContext
                                     canLazilyParse ? syntaxParser.ptr() : nullptr, nullptr);
     parser.sct = sct;
     parser.ss = ss;
 
     if (!parser.checkOptions())
         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);
 
     Rooted<JSScript*> script(cx, JSScript::Create(cx, evalStaticScope, savedCallerFun,
                                                   options, staticLevel, sourceObject, 0,
                                                   srcBuf.length()));
     if (!script)
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -1688,17 +1688,26 @@ class ObjectBox
 enum ParseReportKind
 {
     ParseError,
     ParseWarning,
     ParseExtraWarning,
     ParseStrictError
 };
 
-enum FunctionSyntaxKind { Expression, Statement, Arrow, Method };
+enum FunctionSyntaxKind
+{
+    Expression,
+    Statement,
+    Arrow,
+    Method,
+    ClassConstructor,
+    Getter,
+    Setter
+};
 
 static inline ParseNode*
 FunctionArgsList(ParseNode* fn, unsigned* numFormals)
 {
     MOZ_ASSERT(fn->isKind(PNK_FUNCTION));
     ParseNode* argsBody = fn->pn_body;
     MOZ_ASSERT(argsBody->isKind(PNK_ARGSBODY));
     *numFormals = argsBody->pn_count;
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -1209,36 +1209,46 @@ struct BindData
 
 template <typename ParseHandler>
 JSFunction*
 Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind, HandleObject proto)
 {
     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)
         return nullptr;
     if (options().selfHostingMode)
         fun->setIsSelfHostedBuiltin();
     return fun;
 }
@@ -1551,17 +1561,17 @@ Parser<ParseHandler>::bindDestructuringA
         return false;
 
     return pc->define(parser->tokenStream, name, data->pn, Definition::VAR);
 }
 
 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();
 
     *hasRest = false;
 
     bool parenFreeArrow = false;
     if (kind == Arrow) {
         TokenKind tt;
@@ -1599,19 +1609,19 @@ Parser<ParseHandler>::functionArguments(
             return false;
         if (!matched)
             hasArguments = true;
     }
     if (hasArguments) {
         bool hasDefaults = false;
         Node duplicatedArg = null();
         Node list = null();
-        bool disallowDuplicateArgs = kind == Arrow || kind == Method;
-
-        if (type == Getter) {
+        bool disallowDuplicateArgs = kind == Arrow || kind == Method || kind == ClassConstructor;
+
+        if (kind == Getter) {
             report(ParseError, false, null(), JSMSG_ACCESSOR_WRONG_ARGS, "getter", "no", "s");
             return false;
         }
 
         while (true) {
             if (*hasRest) {
                 report(ParseError, false, null(), JSMSG_PARAMETER_AFTER_REST);
                 return false;
@@ -1684,17 +1694,17 @@ Parser<ParseHandler>::functionArguments(
               case TOK_YIELD:
                 if (!checkYieldNameValidity())
                     return false;
                 MOZ_ASSERT(yieldHandling == YieldIsName);
                 goto TOK_NAME;
 
               case TOK_TRIPLEDOT:
               {
-                if (type == Setter) {
+                if (kind == Setter) {
                     report(ParseError, false, null(),
                            JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
                     return false;
                 }
                 *hasRest = true;
                 if (!tokenStream.getToken(&tt))
                     return false;
                 // FIXME: This fails to handle a rest parameter named |yield|
@@ -1761,45 +1771,45 @@ Parser<ParseHandler>::functionArguments(
                 break;
               }
 
               default:
                 report(ParseError, false, null(), JSMSG_MISSING_FORMAL);
                 return false;
             }
 
-            if (parenFreeArrow || type == Setter)
+            if (parenFreeArrow || kind == Setter)
                 break;
 
             bool matched;
             if (!tokenStream.matchToken(&matched, TOK_COMMA))
                 return false;
             if (!matched)
                 break;
         }
 
         if (!parenFreeArrow) {
             TokenKind tt;
             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;
                 }
 
                 report(ParseError, false, null(), JSMSG_PAREN_AFTER_FORMAL);
                 return false;
             }
         }
 
         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;
     }
 
     return true;
 }
 
 template <>
@@ -2144,19 +2154,18 @@ Parser<ParseHandler>::templateLiteral(Yi
         handler.addList(nodeList, pn);
     } while (tt == TOK_TEMPLATE_HEAD);
     return nodeList;
 }
 
 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);
 
     /* Make a TOK_FUNCTION node. */
     Node pn = handler.newFunctionDefinition();
     if (!pn)
         return null();
 
@@ -2190,17 +2199,17 @@ Parser<ParseHandler>::functionDef(InHand
     // of directives.
     Directives directives(pc);
     Directives newDirectives = directives;
 
     TokenStream::Position start(keepAtoms);
     tokenStream.tell(&start);
 
     while (true) {
-        if (functionArgsAndBody(inHandling, pn, fun, type, kind, generatorKind, directives,
+        if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives,
                                 &newDirectives))
         {
             break;
         }
         if (tokenStream.hadError() || directives == newDirectives)
             return null();
 
         // Assignment must be monotonic to prevent reparsing iloops
@@ -2298,18 +2307,18 @@ Parser<SyntaxParseHandler>::finishFuncti
 
     fun->initLazyScript(lazy);
     return true;
 }
 
 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)
 {
     ParseContext<FullParseHandler>* outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
     if (!funbox)
@@ -2339,18 +2348,17 @@ Parser<FullParseHandler>::functionArgsAn
 
             ParseContext<SyntaxParseHandler> funpc(parser, outerpc, SyntaxParseHandler::null(), funbox,
                                                    newDirectives, outerpc->staticLevel + 1,
                                                    outerpc->blockidGen, /* blockScopeDepth = */ 0);
             if (!funpc.init(tokenStream))
                 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.
                     parser->clearAbortedSyntaxParse();
                     MOZ_ASSERT_IF(parser->context->isJSContext(),
                                   !parser->context->asJSContext()->isExceptionPending());
                     break;
                 }
@@ -2378,17 +2386,17 @@ Parser<FullParseHandler>::functionArgsAn
 
     // Continue doing a full parse for this inner function.
     ParseContext<FullParseHandler> funpc(this, pc, pn, funbox, newDirectives,
                                          outerpc->staticLevel + 1, outerpc->blockidGen,
                                          /* blockScopeDepth = */ 0);
     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))
         return false;
 
     pn->pn_blockid = outerpc->blockid();
 
     /*
@@ -2399,17 +2407,17 @@ Parser<FullParseHandler>::functionArgsAn
      */
     PropagateTransitiveParseFlags(funbox, outerpc->sc);
     return true;
 }
 
 template <>
 bool
 Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
-                                                FunctionType type, FunctionSyntaxKind kind,
+                                                FunctionSyntaxKind kind,
                                                 GeneratorKind generatorKind,
                                                 Directives inheritedDirectives,
                                                 Directives* newDirectives)
 {
     ParseContext<SyntaxParseHandler>* outerpc = pc;
 
     // Create box for fun->object early to protect against last-ditch GC.
     FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
@@ -2419,17 +2427,17 @@ Parser<SyntaxParseHandler>::functionArgs
     // Initialize early for possible flags mutation via destructuringExpr.
     ParseContext<SyntaxParseHandler> funpc(this, pc, handler.null(), funbox, newDirectives,
                                            outerpc->staticLevel + 1, outerpc->blockidGen,
                                            /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         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))
         return false;
 
     // This is a lazy function inner to another lazy function. Remember the
     // inner function so that if the outer function is eventually parsed we do
     // not need any further parsing or processing of the inner function.
@@ -2481,18 +2489,26 @@ Parser<FullParseHandler>::standaloneLazy
     Directives newDirectives = directives;
     ParseContext<FullParseHandler> funpc(this, /* parent = */ nullptr, pn, funbox,
                                          &newDirectives, staticLevel, /* bodyid = */ 0,
                                          /* blockScopeDepth = */ 0);
     if (!funpc.init(tokenStream))
         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();
     }
 
     if (fun->isNamedLambda()) {
         if (AtomDefnPtr p = pc->lexdeps->lookup(fun->name())) {
             Definition* dn = p.value().get<FullParseHandler>();
             if (!ConvertDefinitionToNamedLambdaUse(tokenStream, pc, funbox, dn))
@@ -2510,26 +2526,25 @@ Parser<FullParseHandler>::standaloneLazy
 
     return pn;
 }
 
 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
     // parsing and such.
 
     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();
 
     fun->setArgCount(pc->numArgs());
     if (hasRest)
         fun->setHasRest();
 
@@ -2569,18 +2584,21 @@ Parser<ParseHandler>::functionArgsAndBod
         fun->setIsExprBody();
 #endif
     }
 
     Node body = functionBody(inHandling, yieldHandling, kind, bodyType);
     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;
         if (!tokenStream.matchToken(&matched, TOK_RC))
             return false;
         if (!matched) {
             report(ParseError, false, null(), JSMSG_CURLY_AFTER_BODY);
             return false;
@@ -2643,17 +2661,17 @@ Parser<ParseHandler>::functionStmt(Yield
         return null();
     }
 
     /* We forbid function statements in strict mode code. */
     if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
         !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>
 typename ParseHandler::Node
 Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
 {
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
@@ -2675,17 +2693,17 @@ Parser<ParseHandler>::functionExpr(Invok
         if (!checkYieldNameValidity())
             return null();
         name = tokenStream.currentName();
     } else {
         tokenStream.ungetToken();
     }
 
     YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
-    return functionDef(InAllowed, yieldHandling, name, Normal, Expression, generatorKind, invoked);
+    return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked);
 }
 
 /*
  * Return true if this node, known to be an unparenthesized string literal,
  * could be the string of a directive in a Directive Prologue. Directive
  * strings never contain escape sequences or line continuations.
  * isEscapeFreeStringLiteral, below, checks whether the node itself could be
  * a directive.
@@ -6570,17 +6588,17 @@ Parser<ParseHandler>::assignExpr(InHandl
         tokenStream.seek(start);
         if (!abortIfSyntaxParser())
             return null();
 
         TokenKind ignored;
         if (!tokenStream.peekToken(&ignored))
             return null();
 
-        return functionDef(inHandling, yieldHandling, NullPtr(), Normal, Arrow, NotGenerator);
+        return functionDef(inHandling, yieldHandling, NullPtr(), Arrow, NotGenerator);
       }
 
       default:
         MOZ_ASSERT(!tokenStream.isCurrentTokenAssignment());
         tokenStream.ungetToken();
         return lhs;
     }
 
@@ -7801,17 +7819,17 @@ Parser<ParseHandler>::checkAndMarkSuperS
 {
     for (GenericParseContext* gpc = pc; gpc; gpc = gpc->parent) {
         SharedContext* sc = gpc->sc;
         if (sc->allowSuperProperty()) {
             if (sc->isFunctionBox())
                 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;
         }
     }
     return false;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
@@ -8292,16 +8310,17 @@ Parser<ParseHandler>::propertyList(Yield
             if (!tokenStream.getToken(&ltok, TokenStream::KeywordIsName))
                 return null();
         }
 
         atom = nullptr;
 
         JSOp op = JSOP_INITPROP;
         Node propname;
+        bool isConstructor = false;
         switch (ltok) {
           case TOK_NUMBER:
             atom = DoubleToAtom(context, tokenStream.currentToken().number());
             if (!atom)
                 return null();
             propname = newNumber(tokenStream.currentToken());
             if (!propname)
                 return null();
@@ -8418,16 +8437,17 @@ Parser<ParseHandler>::propertyList(Yield
                     report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF);
                     return null();
                 }
                 if (seenConstructor) {
                     report(ParseError, false, propname, JSMSG_DUPLICATE_PROPERTY, "constructor");
                     return null();
                 }
                 seenConstructor = true;
+                isConstructor = true;
             } else if (isStatic && atom == context->names().prototype) {
                 report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF);
                 return null();
             }
         }
 
         if (op == JSOP_INITPROP) {
             TokenKind tt;
@@ -8493,17 +8513,18 @@ Parser<ParseHandler>::propertyList(Yield
                 Node nameExpr = identifierName(yieldHandling);
                 if (!nameExpr)
                     return null();
 
                 if (!handler.addShorthand(propList, propname, nameExpr))
                     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();
                 }
             } else {
                 report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
                 return null();
             }
@@ -8537,27 +8558,28 @@ Parser<ParseHandler>::propertyList(Yield
 
     handler.setEndPosition(propList, pos().end);
     return propList;
 }
 
 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;
 
     if (listType == ClassBody)
         return handler.addClassMethodDefinition(propList, propname, fn, op, isStatic);
 
     MOZ_ASSERT(listType == ObjectLiteral);
     return handler.addObjectMethodDefinition(propList, propname, fn, op);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -323,17 +323,16 @@ Directives::Directives(ParseContext<Pars
 
 template <typename ParseHandler>
 struct BindData;
 
 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
 // [Return] because its behavior is exactly equivalent to checking whether
 // we're in a function box -- easier and simpler than passing an extra
 // parameter everywhere.
 enum YieldHandling { YieldIsName, YieldIsKeyword };
 enum InHandling { InAllowed, InProhibited };
@@ -499,18 +498,17 @@ class Parser : private JS::AutoGCRooter,
      * Parse a function body.  Pass StatementListBody if the body is a list of
      * statements; pass ExpressionBody if the body is a single expression.
      */
     enum FunctionBodyType { StatementListBody, ExpressionBody };
     Node functionBody(InHandling inHandling, YieldHandling yieldHandling, FunctionSyntaxKind kind,
                       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
     // inside a star generator.
     bool checkYieldNameValidity();
     bool yieldExpressionsSupported() {
         return versionNumber() >= JSVERSION_1_7 || pc->isGenerator();
     }
@@ -589,29 +587,29 @@ class Parser : private JS::AutoGCRooter,
     Node primaryExpr(YieldHandling yieldHandling, TokenKind tt,
                      InvokedPrediction invoked = PredictUninvoked);
     Node parenExprOrGeneratorComprehension(YieldHandling yieldHandling);
     Node exprInParens(InHandling inHandling, YieldHandling yieldHandling);
 
     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);
 
     Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
 
     Node condition(InHandling inHandling, YieldHandling yieldHandling);
 
     Node generatorComprehensionLambda(GeneratorKind comprehensionKind, unsigned begin,
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -301,17 +301,17 @@ class FunctionBox : public ObjectBox, pu
     bool needsHomeObject()          const { return funCxFlags.needsHomeObject; }
 
     void setMightAliasLocals()             { funCxFlags.mightAliasLocals         = true; }
     void setHasExtensibleScope()           { funCxFlags.hasExtensibleScope       = true; }
     void setNeedsDeclEnvObject()           { funCxFlags.needsDeclEnvObject       = true; }
     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 {
         return length != function()->nargs() - function()->hasRest();
     }
 
     // Return whether this or an enclosing function is being parsed and
     // validated as asm.js. Note: if asm.js validation fails, this will be false
@@ -334,17 +334,17 @@ class FunctionBox : public ObjectBox, pu
         return bindings.hasAnyAliasedBindings() ||
                hasExtensibleScope() ||
                needsDeclEnvObject() ||
                needsHomeObject()    ||
                isGenerator();
     }
 
     bool allowSuperProperty() const {
-        return function()->isMethod();
+        return function()->isMethod() || function()->isGetter() || function()->isSetter();
     }
 };
 
 inline FunctionBox*
 SharedContext::asFunctionBox()
 {
     MOZ_ASSERT(isFunctionBox());
     return static_cast<FunctionBox*>(this);
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -975,18 +975,19 @@ js::FunctionToString(JSContext* cx, Hand
                 !out.append("\n    [generator expression]\n") ||
                 (!bodyOnly && !out.append("}")))
             {
                 return nullptr;
             }
             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) {
             if (!out.append("("))
                 return nullptr;
         }
         if (!fun->isArrow()) {
             if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function ")))
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -27,17 +27,20 @@ class JSFunction : public js::NativeObje
 {
   public:
     static const js::Class class_;
 
     enum FunctionKind {
         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 {
         INTERPRETED      = 0x0001,  /* function has a JSScript and environment. */
         NATIVE_CTOR      = 0x0002,  /* native that can be called as a constructor */
         EXTENDED         = 0x0004,  /* structure is FunctionExtended */
         IS_FUN_PROTO     = 0x0008,  /* function is Function.prototype for some global object */
         EXPR_BODY        = 0x0010,  /* arrow function with expression body or
@@ -52,35 +55,43 @@ class JSFunction : public js::NativeObje
         SELF_HOSTED_CTOR = 0x0100,  /* function is self-hosted builtin constructor and
                                        must be constructible but not decompilable. */
         HAS_REST         = 0x0200,  /* function has a rest (...) parameter */
         INTERPRETED_LAZY = 0x0400,  /* function is interpreted but doesn't have a script yet */
         RESOLVED_LENGTH  = 0x0800,  /* f.length has been resolved (see fun_resolve). */
         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 |
                                LAMBDA | SELF_HOSTED | SELF_HOSTED_CTOR | HAS_REST |
                                FUNCTION_KIND_MASK
     };
 
     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
                                      (including defaults and the rest parameter unlike f.length) */
     uint16_t        flags_;       /* bitfield composed of the above Flags enum, as well as the kind */
     union U {
         class Native {
             friend class JSFunction;
@@ -147,18 +158,26 @@ class JSFunction : public js::NativeObje
     bool isSelfHostedBuiltin()      const { return flags() & SELF_HOSTED; }
     bool isSelfHostedConstructor()  const { return flags() & SELF_HOSTED_CTOR; }
     bool hasRest()                  const { return flags() & HAS_REST; }
     bool isInterpretedLazy()        const { return flags() & INTERPRETED_LAZY; }
     bool hasScript()                const { return flags() & INTERPRETED; }
 
     // 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; }
 
     bool hasJITCode() const {
         if (!hasScript())
             return false;
 
         return nonLazyScript()->hasBaselineScript() || nonLazyScript()->hasIonScript();