Title: [181490] trunk
Revision
181490
Author
[email protected]
Date
2015-03-13 16:01:51 -0700 (Fri, 13 Mar 2015)

Log Message

Class constructor should throw TypeError when "called"
https://bugs.webkit.org/show_bug.cgi?id=142566

Reviewed by Michael Saboff.

Source/_javascript_Core:

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.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (181489 => 181490)


--- trunk/LayoutTests/ChangeLog	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/LayoutTests/ChangeLog	2015-03-13 23:01:51 UTC (rev 181490)
@@ -1,3 +1,17 @@
+2015-03-13  Ryosuke Niwa  <[email protected]>
+
+        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  <[email protected]>
 
         AX: Provide API for assistive tech to ignore DOM key event handlers

Modified: trunk/LayoutTests/TestExpectations (181489 => 181490)


--- trunk/LayoutTests/TestExpectations	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/LayoutTests/TestExpectations	2015-03-13 23:01:51 UTC (rev 181490)
@@ -67,6 +67,7 @@
 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 ]

Added: trunk/LayoutTests/js/class-syntax-call-expected.txt (0 => 181490)


--- trunk/LayoutTests/js/class-syntax-call-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/js/class-syntax-call-expected.txt	2015-03-13 23:01:51 UTC (rev 181490)
@@ -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
+

Added: trunk/LayoutTests/js/class-syntax-call.html (0 => 181490)


--- trunk/LayoutTests/js/class-syntax-call.html	                        (rev 0)
+++ trunk/LayoutTests/js/class-syntax-call.html	2015-03-13 23:01:51 UTC (rev 181490)
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src=""
+<script src=""
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/js/script-tests/class-syntax-call.js (0 => 181490)


--- trunk/LayoutTests/js/script-tests/class-syntax-call.js	                        (rev 0)
+++ trunk/LayoutTests/js/script-tests/class-syntax-call.js	2015-03-13 23:01:51 UTC (rev 181490)
@@ -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;

Modified: trunk/Source/_javascript_Core/ChangeLog (181489 => 181490)


--- trunk/Source/_javascript_Core/ChangeLog	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/ChangeLog	2015-03-13 23:01:51 UTC (rev 181490)
@@ -1,3 +1,63 @@
+2015-03-13  Ryosuke Niwa  <[email protected]>
+
+        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  <[email protected]>
 
         DFG::PutStackSinkingPhase should eliminate GetStacks that have an obviously known source

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp (181489 => 181490)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.cpp	2015-03-13 23:01:51 UTC (rev 181490)
@@ -62,7 +62,7 @@
     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 @@
     , 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 @@
     , m_features(0)
     , m_functionMode(node->functionMode())
 {
+    ASSERT(m_constructorKind == static_cast<unsigned>(node->constructorKind()));
 }
 
 size_t UnlinkedFunctionExecutable::parameterCount() const
@@ -224,14 +225,14 @@
     , 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 @@
     , m_bytecodeCommentIterator(0)
 #endif
 {
-
+    ASSERT(m_constructorKind == static_cast<unsigned>(info.constructorKind()));
 }
 
 void UnlinkedCodeBlock::visitChildren(JSCell* cell, SlotVisitor& visitor)

Modified: trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h (181489 => 181490)


--- trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/bytecode/UnlinkedCodeBlock.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -65,21 +65,31 @@
 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 @@
             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 @@
     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 @@
 
     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 @@
     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;

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (181489 => 181490)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2015-03-13 23:01:51 UTC (rev 181490)
@@ -68,7 +68,9 @@
         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 @@
     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 @@
         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();

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h (181489 => 181490)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -271,9 +271,9 @@
 
         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();

Modified: trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp (181489 => 181490)


--- trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/bytecompiler/NodesCodegen.cpp	2015-03-13 23:01:51 UTC (rev 181490)
@@ -144,7 +144,7 @@
 
 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 @@
     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);

Modified: trunk/Source/_javascript_Core/parser/Nodes.cpp (181489 => 181490)


--- trunk/Source/_javascript_Core/parser/Nodes.cpp	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/parser/Nodes.cpp	2015-03-13 23:01:51 UTC (rev 181490)
@@ -173,8 +173,9 @@
     , 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)

Modified: trunk/Source/_javascript_Core/parser/Nodes.h (181489 => 181490)


--- trunk/Source/_javascript_Core/parser/Nodes.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/parser/Nodes.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -1587,7 +1587,7 @@
 
         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 @@
         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 {

Modified: trunk/Source/_javascript_Core/parser/Parser.cpp (181489 => 181490)


--- trunk/Source/_javascript_Core/parser/Parser.cpp	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/parser/Parser.cpp	2015-03-13 23:01:51 UTC (rev 181490)
@@ -1291,7 +1291,7 @@
 
 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 @@
     }
     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 @@
         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 @@
     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 @@
             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 @@
     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 @@
         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)

Modified: trunk/Source/_javascript_Core/parser/Parser.h (181489 => 181490)


--- trunk/Source/_javascript_Core/parser/Parser.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/parser/Parser.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -758,7 +758,7 @@
     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 };

Modified: trunk/Source/_javascript_Core/parser/ParserModes.h (181489 => 181490)


--- trunk/Source/_javascript_Core/parser/ParserModes.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/parser/ParserModes.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -34,7 +34,7 @@
 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 };

Modified: trunk/Source/_javascript_Core/runtime/Executable.h (181489 => 181490)


--- trunk/Source/_javascript_Core/runtime/Executable.h	2015-03-13 22:30:36 UTC (rev 181489)
+++ trunk/Source/_javascript_Core/runtime/Executable.h	2015-03-13 23:01:51 UTC (rev 181490)
@@ -467,7 +467,7 @@
 
     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 @@
 
     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;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to