Class constructor should throw TypeError when "called"
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Mar 2015 23:01:51 +0000 (23:01 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 13 Mar 2015 23:01:51 +0000 (23:01 +0000)
https://bugs.webkit.org/show_bug.cgi?id=142566

Reviewed by Michael Saboff.

Source/JavaScriptCore:

Added ConstructorKind::None to denote code that doesn't belong to an ES6 class.
This allows BytecodeGenerator to emit code to throw TypeError when generating code block
to call ES6 class constructors.

Most of changes are about increasing the number of bits to store ConstructorKind from one
bit to two bits.

* bytecode/UnlinkedCodeBlock.cpp:
(JSC::generateFunctionCodeBlock):
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
* bytecode/UnlinkedCodeBlock.h:
(JSC::ExecutableInfo::ExecutableInfo):
(JSC::ExecutableInfo::needsActivation):
(JSC::ExecutableInfo::usesEval):
(JSC::ExecutableInfo::isStrictMode):
(JSC::ExecutableInfo::isConstructor):
(JSC::ExecutableInfo::isBuiltinFunction):
(JSC::ExecutableInfo::constructorKind):
(JSC::UnlinkedFunctionExecutable::constructorKind):
(JSC::UnlinkedCodeBlock::constructorKind):
(JSC::UnlinkedFunctionExecutable::constructorKindIsDerived): Deleted.
(JSC::UnlinkedCodeBlock::constructorKindIsDerived): Deleted.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate): Don't emit bytecode when we had already emitted code
to throw TypeError.
(JSC::BytecodeGenerator::BytecodeGenerator): Emit code to throw TypeError when generating
code to call.
(JSC::BytecodeGenerator::emitReturn):
* bytecompiler/BytecodeGenerator.h:
(JSC::BytecodeGenerator::constructorKind):
(JSC::BytecodeGenerator::constructorKindIsDerived): Deleted.
* bytecompiler/NodesCodegen.cpp:
(JSC::ThisNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
* parser/Nodes.cpp:
(JSC::FunctionBodyNode::FunctionBodyNode):
* parser/Nodes.h:
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseFunctionInfo): Renamed the incoming function argument to
ownerClassKind. Set constructorKind to Base or Derived only if we're parsing a constructor.
(JSC::Parser<LexerType>::parseFunctionDeclaration):
(JSC::Parser<LexerType>::parseClass): Don't parse static methods using MethodMode since that
would result in BytecodeGenerator erroneously treating static method named "constructor" as
a class constructor.
(JSC::Parser<LexerType>::parsePropertyMethod):
(JSC::Parser<LexerType>::parsePrimaryExpression):
* parser/Parser.h:
* parser/ParserModes.h:
* runtime/Executable.h:
(JSC::EvalExecutable::executableInfo):
(JSC::ProgramExecutable::executableInfo):

LayoutTests:

Added tests for calling class constructors.

* TestExpectations: Skipped the test since ES6 class syntax isn't enabled by default.
* js/class-syntax-call-expected.txt: Added.
* js/class-syntax-call.html: Added.
* js/script-tests/class-syntax-call.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@181490 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/js/class-syntax-call-expected.txt [new file with mode: 0644]
LayoutTests/js/class-syntax-call.html [new file with mode: 0644]
LayoutTests/js/script-tests/class-syntax-call.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp
Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
Source/JavaScriptCore/parser/Nodes.cpp
Source/JavaScriptCore/parser/Nodes.h
Source/JavaScriptCore/parser/Parser.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/parser/ParserModes.h
Source/JavaScriptCore/runtime/Executable.h

index bbd4678..6aecbc1 100644 (file)
@@ -1,3 +1,17 @@
+2015-03-13  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Class constructor should throw TypeError when "called"
+        https://bugs.webkit.org/show_bug.cgi?id=142566
+
+        Reviewed by Michael Saboff.
+
+        Added tests for calling class constructors.
+
+        * TestExpectations: Skipped the test since ES6 class syntax isn't enabled by default.
+        * js/class-syntax-call-expected.txt: Added.
+        * js/class-syntax-call.html: Added.
+        * js/script-tests/class-syntax-call.js: Added.
+
 2015-03-13  Doug Russell  <d_russell@apple.com>
 
         AX: Provide API for assistive tech to ignore DOM key event handlers
index f400fc1..b76e3ce 100644 (file)
@@ -67,6 +67,7 @@ webkit.org/b/126166 [ Debug ] js/dfg-uint32array-overflow-values.html [ Skip ]
 webkit.org/b/127860 [ Debug ] js/function-apply-aliased.html [ Skip ]
 
 # ES6 class syntax hasn't been enabled yet.
+webkit.org/b/140491 js/class-syntax-call.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-declaration.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-expression.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-extends.html [ Failure ]
diff --git a/LayoutTests/js/class-syntax-call-expected.txt b/LayoutTests/js/class-syntax-call-expected.txt
new file mode 100644 (file)
index 0000000..3109ee1
--- /dev/null
@@ -0,0 +1,12 @@
+PASS class A { constructor() {} }; window.A = A; new A did not throw exception.
+PASS A() threw exception TypeError: Cannot call a class constructor.
+PASS class B extends A { constructor() { super() } }; window.B = B; new A did not throw exception.
+PASS B() threw exception TypeError: Cannot call a class constructor.
+PASS new (class { constructor() {} })() did not throw exception.
+PASS (class { constructor() {} })() threw exception TypeError: Cannot call a class constructor.
+PASS new (class extends null { constructor() { super() } })() did not throw exception.
+PASS (class extends null { constructor() { super() } })() threw exception TypeError: Cannot call a class constructor.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/class-syntax-call.html b/LayoutTests/js/class-syntax-call.html
new file mode 100644 (file)
index 0000000..eb229a5
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../resources/js-test-pre.js"></script>
+<script src="script-tests/class-syntax-call.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/class-syntax-call.js b/LayoutTests/js/script-tests/class-syntax-call.js
new file mode 100644 (file)
index 0000000..e4b1b99
--- /dev/null
@@ -0,0 +1,12 @@
+//@ skip
+
+shouldNotThrow('class A { constructor() {} }; window.A = A; new A');
+shouldThrow('A()', '"TypeError: Cannot call a class constructor"');
+shouldNotThrow('class B extends A { constructor() { super() } }; window.B = B; new A');
+shouldThrow('B()', '"TypeError: Cannot call a class constructor"');
+shouldNotThrow('new (class { constructor() {} })()');
+shouldThrow('(class { constructor() {} })()', '"TypeError: Cannot call a class constructor"');
+shouldNotThrow('new (class extends null { constructor() { super() } })()');
+shouldThrow('(class extends null { constructor() { super() } })()', '"TypeError: Cannot call a class constructor"');
+
+var successfullyParsed = true;
index 5745548..4970e5f 100644 (file)
@@ -1,3 +1,63 @@
+2015-03-13  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Class constructor should throw TypeError when "called"
+        https://bugs.webkit.org/show_bug.cgi?id=142566
+
+        Reviewed by Michael Saboff.
+
+        Added ConstructorKind::None to denote code that doesn't belong to an ES6 class.
+        This allows BytecodeGenerator to emit code to throw TypeError when generating code block
+        to call ES6 class constructors.
+
+        Most of changes are about increasing the number of bits to store ConstructorKind from one
+        bit to two bits.
+
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::generateFunctionCodeBlock):
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        (JSC::UnlinkedCodeBlock::UnlinkedCodeBlock):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::ExecutableInfo::ExecutableInfo):
+        (JSC::ExecutableInfo::needsActivation):
+        (JSC::ExecutableInfo::usesEval):
+        (JSC::ExecutableInfo::isStrictMode):
+        (JSC::ExecutableInfo::isConstructor):
+        (JSC::ExecutableInfo::isBuiltinFunction):
+        (JSC::ExecutableInfo::constructorKind):
+        (JSC::UnlinkedFunctionExecutable::constructorKind):
+        (JSC::UnlinkedCodeBlock::constructorKind):
+        (JSC::UnlinkedFunctionExecutable::constructorKindIsDerived): Deleted.
+        (JSC::UnlinkedCodeBlock::constructorKindIsDerived): Deleted.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::generate): Don't emit bytecode when we had already emitted code
+        to throw TypeError.
+        (JSC::BytecodeGenerator::BytecodeGenerator): Emit code to throw TypeError when generating
+        code to call.
+        (JSC::BytecodeGenerator::emitReturn):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC::BytecodeGenerator::constructorKind):
+        (JSC::BytecodeGenerator::constructorKindIsDerived): Deleted.
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ThisNode::emitBytecode):
+        (JSC::FunctionCallValueNode::emitBytecode):
+        * parser/Nodes.cpp:
+        (JSC::FunctionBodyNode::FunctionBodyNode):
+        * parser/Nodes.h:
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::parseFunctionInfo): Renamed the incoming function argument to
+        ownerClassKind. Set constructorKind to Base or Derived only if we're parsing a constructor.
+        (JSC::Parser<LexerType>::parseFunctionDeclaration):
+        (JSC::Parser<LexerType>::parseClass): Don't parse static methods using MethodMode since that
+        would result in BytecodeGenerator erroneously treating static method named "constructor" as
+        a class constructor.
+        (JSC::Parser<LexerType>::parsePropertyMethod):
+        (JSC::Parser<LexerType>::parsePrimaryExpression):
+        * parser/Parser.h:
+        * parser/ParserModes.h:
+        * runtime/Executable.h:
+        (JSC::EvalExecutable::executableInfo):
+        (JSC::ProgramExecutable::executableInfo):
+
 2015-03-13  Filip Pizlo  <fpizlo@apple.com>
 
         DFG::PutStackSinkingPhase should eliminate GetStacks that have an obviously known source
index 22601dc..58033bd 100644 (file)
@@ -62,7 +62,7 @@ static UnlinkedFunctionCodeBlock* generateFunctionCodeBlock(VM& vm, UnlinkedFunc
     executable->recordParse(function->features(), function->hasCapturedVariables());
     
     UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(&vm, FunctionCode,
-        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKindIsDerived()));
+        ExecutableInfo(function->needsActivation(), function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind()));
     auto generator(std::make_unique<BytecodeGenerator>(vm, function.get(), result, debuggerMode, profilerMode));
     error = generator->generate();
     if (error.isValid())
@@ -85,7 +85,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_isInStrictContext(node->isInStrictContext())
     , m_hasCapturedVariables(false)
     , m_isBuiltinFunction(kind == UnlinkedBuiltinFunction)
-    , m_constructorKindIsDerived(node->constructorKindIsDerived())
+    , m_constructorKind(static_cast<unsigned>(node->constructorKind()))
     , m_name(node->ident())
     , m_inferredName(node->inferredName())
     , m_parameters(node->parameters())
@@ -101,6 +101,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_features(0)
     , m_functionMode(node->functionMode())
 {
+    ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
 }
 
 size_t UnlinkedFunctionExecutable::parameterCount() const
@@ -224,14 +225,14 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_vm(vm)
     , m_argumentsRegister(VirtualRegister())
     , m_globalObjectRegister(VirtualRegister())
-    , m_needsFullScopeChain(info.m_needsActivation)
-    , m_usesEval(info.m_usesEval)
+    , m_needsFullScopeChain(info.needsActivation())
+    , m_usesEval(info.usesEval())
     , m_isNumericCompareFunction(false)
-    , m_isStrictMode(info.m_isStrictMode)
-    , m_isConstructor(info.m_isConstructor)
+    , m_isStrictMode(info.isStrictMode())
+    , m_isConstructor(info.isConstructor())
     , m_hasCapturedVariables(false)
-    , m_isBuiltinFunction(info.m_isBuiltinFunction)
-    , m_constructorKindIsDerived(info.m_constructorKindIsDerived)
+    , m_isBuiltinFunction(info.isBuiltinFunction())
+    , m_constructorKind(static_cast<unsigned>(info.constructorKind()))
     , m_firstLine(0)
     , m_lineCount(0)
     , m_endColumn(UINT_MAX)
@@ -246,7 +247,7 @@ UnlinkedCodeBlock::UnlinkedCodeBlock(VM* vm, Structure* structure, CodeType code
     , m_bytecodeCommentIterator(0)
 #endif
 {
-
+    ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
 }
 
 void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)
index 6463394..5dd2523 100644 (file)
@@ -65,21 +65,31 @@ typedef unsigned UnlinkedObjectAllocationProfile;
 typedef unsigned UnlinkedLLIntCallLinkInfo;
 
 struct ExecutableInfo {
-    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, bool constructorKindIsDerived)
+    ExecutableInfo(bool needsActivation, bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind)
         : m_needsActivation(needsActivation)
         , m_usesEval(usesEval)
         , m_isStrictMode(isStrictMode)
         , m_isConstructor(isConstructor)
         , m_isBuiltinFunction(isBuiltinFunction)
-        , m_constructorKindIsDerived(constructorKindIsDerived)
+        , m_constructorKind(static_cast<unsigned>(constructorKind))
     {
+        ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
     }
-    bool m_needsActivation : 1;
-    bool m_usesEval : 1;
-    bool m_isStrictMode : 1;
-    bool m_isConstructor : 1;
-    bool m_isBuiltinFunction : 1;
-    bool m_constructorKindIsDerived : 1;
+
+    bool needsActivation() const { return m_needsActivation; }
+    bool usesEval() const { return m_usesEval; }
+    bool isStrictMode() const { return m_isStrictMode; }
+    bool isConstructor() const { return m_isConstructor; }
+    bool isBuiltinFunction() const { return m_isBuiltinFunction; }
+    ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
+
+private:
+    unsigned m_needsActivation : 1;
+    unsigned m_usesEval : 1;
+    unsigned m_isStrictMode : 1;
+    unsigned m_isConstructor : 1;
+    unsigned m_isBuiltinFunction : 1;
+    unsigned m_constructorKind : 2;
 };
 
 enum UnlinkedFunctionKind {
@@ -118,7 +128,7 @@ public:
             return JSParseStrict;
         return JSParseNormal;
     }
-    bool constructorKindIsDerived() const { return m_constructorKindIsDerived; }
+    ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
 
     unsigned unlinkedFunctionNameStart() const { return m_unlinkedFunctionNameStart; }
     unsigned unlinkedBodyStartColumn() const { return m_unlinkedBodyStartColumn; }
@@ -167,10 +177,10 @@ private:
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
 
-    bool m_isInStrictContext : 1;
-    bool m_hasCapturedVariables : 1;
-    bool m_isBuiltinFunction : 1;
-    bool m_constructorKindIsDerived : 1;
+    unsigned m_isInStrictContext : 1;
+    unsigned m_hasCapturedVariables : 1;
+    unsigned m_isBuiltinFunction : 1;
+    unsigned m_constructorKind : 2;
 
     Identifier m_name;
     Identifier m_inferredName;
@@ -346,7 +356,7 @@ public:
 
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
 
-    bool constructorKindIsDerived() const { return m_constructorKindIsDerived; }
+    ConstructorKind constructorKind() const { return static_cast<ConstructorKind>(m_constructorKind); }
 
     void shrinkToFit()
     {
@@ -532,14 +542,15 @@ private:
     VirtualRegister m_lexicalEnvironmentRegister;
     VirtualRegister m_globalObjectRegister;
 
-    bool m_needsFullScopeChain : 1;
-    bool m_usesEval : 1;
-    bool m_isNumericCompareFunction : 1;
-    bool m_isStrictMode : 1;
-    bool m_isConstructor : 1;
-    bool m_hasCapturedVariables : 1;
-    bool m_isBuiltinFunction : 1;
-    bool m_constructorKindIsDerived : 1;
+    unsigned m_needsFullScopeChain : 1;
+    unsigned m_usesEval : 1;
+    unsigned m_isNumericCompareFunction : 1;
+    unsigned m_isStrictMode : 1;
+    unsigned m_isConstructor : 1;
+    unsigned m_hasCapturedVariables : 1;
+    unsigned m_isBuiltinFunction : 1;
+    unsigned m_constructorKind : 2;
+
     unsigned m_firstLine;
     unsigned m_lineCount;
     unsigned m_endColumn;
index 6cfe830..faf5fd9 100644 (file)
@@ -68,7 +68,9 @@ ParserError BytecodeGenerator::generate()
         entry.second->bindValue(*this, entry.first.get());
     }
 
-    m_scopeNode->emitBytecode(*this);
+    bool callingClassConstructor = constructorKind() != ConstructorKind::None && !isConstructor();
+    if (!callingClassConstructor)
+        m_scopeNode->emitBytecode(*this);
 
     m_staticPropertyAnalyzer.kill();
 
@@ -401,12 +403,14 @@ BytecodeGenerator::BytecodeGenerator(VM& vm, FunctionNode* functionNode, Unlinke
     addCallee(functionNode, calleeRegister);
 
     if (isConstructor()) {
-        if (constructorKindIsDerived()) {
+        if (constructorKind() == ConstructorKind::Derived) {
             m_newTargetRegister = addVar();
             emitMove(m_newTargetRegister, &m_thisRegister);
             emitMove(&m_thisRegister, addConstantEmptyValue());
         } else
             emitCreateThis(&m_thisRegister);
+    } else if (constructorKind() != ConstructorKind::None) {
+        emitThrowTypeError("Cannot call a class constructor");
     } else if (functionNode->usesThis() || codeBlock->usesEval()) {
         m_codeBlock->addPropertyAccessInstruction(instructions().size());
         emitOpcode(op_to_this);
@@ -1912,7 +1916,7 @@ RegisterID* BytecodeGenerator::emitReturn(RegisterID* src)
         instructions().append(m_lexicalEnvironmentRegister ? m_lexicalEnvironmentRegister->index() : emitLoad(0, JSValue())->index());
     }
 
-    bool thisMightBeUninitialized = constructorKindIsDerived();
+    bool thisMightBeUninitialized = constructorKind() == ConstructorKind::Derived;
     bool srcIsThis = src->index() == m_thisRegister.index();
     if (isConstructor() && (!srcIsThis || thisMightBeUninitialized)) {
         RefPtr<Label> isObjectOrUndefinedLabel = newLabel();
index dd994c0..6252f32 100644 (file)
@@ -271,9 +271,9 @@ namespace JSC {
 
         bool isConstructor() const { return m_codeBlock->isConstructor(); }
 #if ENABLE(ES6_CLASS_SYNTAX)
-        bool constructorKindIsDerived() const { return m_codeBlock->constructorKindIsDerived(); }
+        ConstructorKind constructorKind() const { return m_codeBlock->constructorKind(); }
 #else
-        bool constructorKindIsDerived() const { return false; }
+        ConstructorKind constructorKind() const { return ConstructorKind::None; }
 #endif
 
         ParserError generate();
index 2e41ae6..65f3a12 100644 (file)
@@ -144,7 +144,7 @@ RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* d
 
 RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
 {
-    if (generator.constructorKindIsDerived())
+    if (generator.constructorKind() == ConstructorKind::Derived)
         generator.emitTDZCheck(generator.thisRegister());
 
     if (dst == generator.ignoredResult())
@@ -574,7 +574,8 @@ RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, Re
     RefPtr<RegisterID> returnValue = generator.finalDestination(dst, func.get());
     CallArguments callArguments(generator, m_args);
     if (m_expr->isSuperNode()) {
-        ASSERT(generator.constructorKindIsDerived());
+        ASSERT(generator.isConstructor());
+        ASSERT(generator.constructorKind() == ConstructorKind::Derived);
         generator.emitMove(callArguments.thisRegister(), generator.newTarget());
         RegisterID* ret = generator.emitConstruct(returnValue.get(), func.get(), NoExpectedFunction, callArguments, divot(), divotStart(), divotEnd());
         generator.emitMove(generator.thisRegister(), ret);
index 1239214..1eeb649 100644 (file)
@@ -173,8 +173,9 @@ FunctionBodyNode::FunctionBodyNode(ParserArena&, const JSTokenLocation& startLoc
     , m_endColumn(endColumn)
     , m_startStartOffset(startLocation.startOffset)
     , m_isInStrictContext(isInStrictContext)
-    , m_constructorKindIsDerived(constructorKind == ConstructorKind::Derived)
+    , m_constructorKind(static_cast<unsigned>(constructorKind))
 {
+    ASSERT(m_constructorKind == static_cast<unsigned>(constructorKind));
 }
 
 void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter, const Identifier& ident, enum FunctionMode functionMode)
index 40bc1be..d0bbe80 100644 (file)
@@ -1587,7 +1587,7 @@ namespace JSC {
 
         int startStartOffset() const { return m_startStartOffset; }
         bool isInStrictContext() const { return m_isInStrictContext; }
-        bool constructorKindIsDerived() { return m_constructorKindIsDerived; }
+        ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
 
     protected:
         Identifier m_ident;
@@ -1600,8 +1600,8 @@ namespace JSC {
         unsigned m_endColumn;
         SourceCode m_source;
         int m_startStartOffset;
-        bool m_isInStrictContext : 1;
-        bool m_constructorKindIsDerived : 1;
+        unsigned m_isInStrictContext : 1;
+        unsigned m_constructorKind : 2;
     };
 
     class FunctionNode final : public ScopeNode {
index 9b7224c..78fc37a 100644 (file)
@@ -1291,7 +1291,7 @@ static const char* stringForFunctionMode(FunctionParseMode mode)
 
 template <typename LexerType>
 template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, FunctionParseMode mode,
-    bool nameIsInContainingScope, ConstructorKind constructorKind, ParserFunctionInfo<TreeBuilder>& info)
+    bool nameIsInContainingScope, ConstructorKind ownerClassKind, ParserFunctionInfo<TreeBuilder>& info)
 {
     AutoPopScopeRef functionScope(this, pushScope());
     functionScope->setIsFunction();
@@ -1321,7 +1321,12 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     }
     consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration");
     matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body");
-    
+
+    // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed.
+    // Set ConstructorKind to None for non-constructor methods of classes.
+    bool isClassConstructor = mode == MethodMode && info.name && *info.name == m_vm->propertyNames->constructor;
+    ConstructorKind constructorKind = isClassConstructor ? ownerClassKind : ConstructorKind::None;
+
     info.openBraceOffset = m_token.m_data.offset;
     info.bodyStartLine = tokenLine();
     info.bodyStartColumn = m_token.m_data.offset - m_token.m_data.lineStartOffset;
@@ -1377,12 +1382,11 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
         semanticFailIfTrue(m_vm->propertyNames->eval == *info.name, "'", info.name->impl(), "' is not a valid function name in strict mode");
     }
     if (functionScope->hasDirectSuper()) {
-        bool isClassConstructor = mode == MethodMode && info.name && *info.name == m_vm->propertyNames->constructor;
         semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor");
-        semanticFailIfTrue(constructorKind == ConstructorKind::Base, "Cannot call super() in a base class constructor");
+        semanticFailIfTrue(ownerClassKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor");
     }
     if (functionScope->needsSuperBinding())
-        semanticFailIfTrue(constructorKind == ConstructorKind::Base, "super can only be used in a method of a derived class");
+        semanticFailIfTrue(ownerClassKind != ConstructorKind::Derived, "super can only be used in a method of a derived class");
 
     info.closeBraceOffset = m_token.m_data.offset;
     unsigned closeBraceLine = m_token.m_data.line;
@@ -1424,7 +1428,7 @@ template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDecla
     unsigned functionKeywordStart = tokenStart();
     next();
     ParserFunctionInfo<TreeBuilder> info;
-    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::Base, info)), "Cannot parse this function");
+    failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::None, info)), "Cannot parse this function");
     failIfFalse(info.name, "Function statements must have a name");
     failIfFalseIfStrict(declareVariable(info.name), "Cannot declare a function named '", info.name->impl(), "' in strict mode");
     return context.createFuncDeclStatement(location, info, functionKeywordStart);
@@ -1512,7 +1516,7 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
             failIfFalse(property, "Cannot parse this method");
         } else {
             ParserFunctionInfo<TreeBuilder> methodInfo;
-            failIfFalse((parseFunctionInfo(context, FunctionNeedsName, MethodMode, false, constructorKind, methodInfo)), "Cannot parse this method");
+            failIfFalse((parseFunctionInfo(context, FunctionNeedsName, isStaticMethod ? FunctionMode : MethodMode, false, constructorKind, methodInfo)), "Cannot parse this method");
             failIfFalse(methodInfo.name, "method must have a name");
             failIfFalse(declareVariable(methodInfo.name), "Cannot declare a method named '", methodInfo.name->impl(), "'");
 
@@ -2017,7 +2021,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMeth
     JSTokenLocation methodLocation(tokenLocation());
     unsigned methodStart = tokenStart();
     ParserFunctionInfo<TreeBuilder> methodInfo;
-    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::Base, methodInfo)), "Cannot parse this method");
+    failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::None, methodInfo)), "Cannot parse this method");
     methodInfo.name = methodName;
     return context.createFunctionExpr(methodLocation, methodInfo, methodStart);
 }
@@ -2231,7 +2235,7 @@ template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpre
         next();
         ParserFunctionInfo<TreeBuilder> info;
         info.name = &m_vm->propertyNames->nullIdentifier;
-        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::Base, info)), "Cannot parse function expression");
+        failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::None, info)), "Cannot parse function expression");
         return context.createFunctionExpr(location, info, functionKeywordStart);
     }
 #if ENABLE(ES6_CLASS_SYNTAX)
index 7a8f4b0..1c6ef9c 100644 (file)
@@ -758,7 +758,7 @@ private:
     template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&, SpreadMode);
     template <class TreeBuilder> TreeProperty parseProperty(TreeBuilder&, bool strict);
     template <class TreeBuilder> TreeExpression parsePropertyMethod(TreeBuilder& context, const Identifier* methodName);
-    template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::Base, SuperBinding = SuperBinding::NotNeeded);
+    template <class TreeBuilder> TreeProperty parseGetterSetter(TreeBuilder&, bool strict, PropertyNode::Type, unsigned getterOrSetterStartOffset, ConstructorKind = ConstructorKind::None, SuperBinding = SuperBinding::NotNeeded);
     template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&, ConstructorKind);
     template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
     enum VarDeclarationListContext { ForLoopContext, VarDeclarationContext };
index e209748..14d819d 100644 (file)
@@ -34,7 +34,7 @@ namespace JSC {
 enum JSParserStrictness { JSParseNormal, JSParseBuiltin, JSParseStrict };
 enum JSParserMode { JSParseProgramCode, JSParseFunctionCode };
 
-enum class ConstructorKind { Base, Derived };
+enum class ConstructorKind { None, Base, Derived };
 enum class SuperBinding { Needed, NotNeeded };
 
 enum ProfilerMode { ProfilerOff, ProfilerOn };
index bf94a1d..3e03bcc 100644 (file)
@@ -467,7 +467,7 @@ public:
 
     void clearCode();
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
 
     unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     unsigned numberOfFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
@@ -522,7 +522,7 @@ public:
 
     void clearCode();
 
-    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, false); }
+    ExecutableInfo executableInfo() const { return ExecutableInfo(needsActivation(), usesEval(), isStrictMode(), false, false, ConstructorKind::None); }
 
 private:
     friend class ScriptExecutable;