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 bbd4678dad5b498a57e99342c922a640da3a3d34..6aecbc1b4947837038d5cff599c26679d49c003b 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 f400fc1dcf1253179092db8c9e4fd4aa916021e1..b76e3ce108ed70db229fb03ac16677d62e083dcd 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 57455481cfe4a1b9ae87cd3f3197210601f604ae..4970e5fb372dc932fcc5122bd44560437ee21466 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 22601dcc6a086c1ef58c4ec2de75fe54ae848efe..58033bd511c8a26344ed1444636733a1829abf51 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 64633946b2129f2a2727d748fc7b988963810650..5dd25230511f13fdb911bab13473d62696483f47 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 6cfe830d0346160e88c5f2ede4272b36b331b27a..faf5fd9a2140cf45ee5c191bb270ceb2d07c5e64 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 dd994c0aa9a7ca0f350d853959fb9a1b30df4543..6252f32317f0e87db120b561ee930f705e9fd844 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 2e41ae650a964620246ce83eb8e2b87707a85238..65f3a1220749c052b69aadc9d95e2810e9fd0b3f 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 123921487532694c75dc42878ac7cd83a35bff3f..1eeb6494ce604e68d4f9212c239a308c7f7c9319 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 40bc1bed8c1c6afee8262954d43e56f405938cbd..d0bbe807c132e2f902d1d33236af1330ddde4df4 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 9b7224cc8296746e4a29185870d51d64eacc842c..78fc37a77ebde429d0aca4fa349827a29ec8c134 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 7a8f4b02471940ef0609b927c1151c2c1190f5c7..1c6ef9cbe0889c7fe067b6e29e3de5c26f632246 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 e209748265b2cf03741d8b10353c31044a157dd5..14d819d356f12d5876de9c8663a63b3ae608a5ad 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 bf94a1d7024078adb0819fbcf3f7e2d61c3ce94f..3e03bccd109870d15f6f6cb402ae6a71b5743009 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;