Source/JavaScriptCore:
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Mar 2015 04:02:52 +0000 (04:02 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 17 Mar 2015 04:02:52 +0000 (04:02 +0000)
Add support for default constructor
https://bugs.webkit.org/show_bug.cgi?id=142388

Reviewed by Filip Pizlo.

Added the support for default constructors. They're generated by ClassExprNode::emitBytecode
via BuiltinExecutables::createDefaultConstructor.

UnlinkedFunctionExecutable now has the ability to override SourceCode provided by the owner
executable. We can't make store SourceCode in UnlinkedFunctionExecutable since CodeCache can use
the same UnlinkedFunctionExecutable to generate code blocks for multiple functions.

Parser now has the ability to treat any function expression as a constructor of the kind specified
by m_defaultConstructorKind member variable.

* builtins/BuiltinExecutables.cpp:
(JSC::BuiltinExecutables::createDefaultConstructor): Added.
(JSC::BuiltinExecutables::createExecutableInternal): Generalized from createBuiltinExecutable.
Parse default constructors as normal non-builtin functions. Override SourceCode in the unlinked
function executable since the Miranda function's code is definitely not in the owner executable's
source code. That's the whole point.
* builtins/BuiltinExecutables.h:
(UnlinkedFunctionExecutable::createBuiltinExecutable): Added. Wraps createExecutableInternal.
* bytecode/UnlinkedCodeBlock.cpp:
(JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
(JSC::UnlinkedFunctionExecutable::linkInsideExecutable):
(JSC::UnlinkedFunctionExecutable::linkGlobalCode):
* bytecode/UnlinkedCodeBlock.h:
(JSC::UnlinkedFunctionExecutable::create):
(JSC::UnlinkedFunctionExecutable::symbolTable): Deleted.
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitNewDefaultConstructor): Added.
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::ClassExprNode::emitBytecode): Generate the default constructor if needed.
* parser/Parser.cpp:
(JSC::Parser<LexerType>::Parser):
(JSC::Parser<LexerType>::parseFunctionInfo): Override ownerClassKind and assume the function as
a constructor if we're parsing a default constructor.
(JSC::Parser<LexerType>::parseClass): Allow omission of the class constructor.
* parser/Parser.h:
(JSC::parse):

LayoutTests:
Implement default constructor

Add support for default constructor
https://bugs.webkit.org/show_bug.cgi?id=142388

Reviewed by Filip Pizlo.

Added tests for default constructors.

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

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/TestExpectations
LayoutTests/js/class-syntax-default-constructor-expected.txt [new file with mode: 0644]
LayoutTests/js/class-syntax-default-constructor.html [new file with mode: 0644]
LayoutTests/js/script-tests/class-syntax-default-constructor.js [new file with mode: 0644]
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/builtins/BuiltinExecutables.cpp
Source/JavaScriptCore/builtins/BuiltinExecutables.h
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/Parser.cpp
Source/JavaScriptCore/parser/Parser.h

index 5b25452..7fbddaf 100644 (file)
@@ -1,3 +1,19 @@
+2015-03-16  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Implement default constructor
+
+        Add support for default constructor
+        https://bugs.webkit.org/show_bug.cgi?id=142388
+
+        Reviewed by Filip Pizlo.
+
+        Added tests for default constructors.
+
+        * TestExpectations: Skipped the test since ES6 class syntax isn't enabled by default.
+        * js/class-syntax-default-constructor-expected.txt: Added.
+        * js/class-syntax-default-constructor.html: Added.
+        * js/script-tests/class-syntax-default-constructor.js: Added.
+
 2015-03-16  Hunseop Jeong  <hs85.jeong@samsung.com>
 
         [EFL] fast/css/outline-auto-empty-rects.html is failing 
index 54a96b4..58f0146 100644 (file)
@@ -69,6 +69,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-default-constructor.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-expression.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-extends.html [ Failure ]
 webkit.org/b/140491 js/class-syntax-scoping.html [ Failure ]
diff --git a/LayoutTests/js/class-syntax-default-constructor-expected.txt b/LayoutTests/js/class-syntax-default-constructor-expected.txt
new file mode 100644 (file)
index 0000000..5d01d85
--- /dev/null
@@ -0,0 +1,19 @@
+Tests for ES6 class syntax default constructor
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS class A { }; window.A = A; new A instanceof A is true
+PASS A() threw exception TypeError: Cannot call a class constructor.
+PASS A.prototype.constructor instanceof Function is true
+PASS A.prototype.constructor.name is "A"
+PASS class B extends A { }; new B instanceof A; new B instanceof A is true
+PASS B() threw exception TypeError: Cannot call a class constructor.
+PASS B.prototype.constructor.name is "B"
+PASS A is not B
+FAIL A.prototype.constructor should be function B() { super(...arguments); }. Was function A() { }.
+PASS new (class extends (class { constructor(a, b) { return [a, b]; } }) {})(1, 2) is [1, 2]
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/js/class-syntax-default-constructor.html b/LayoutTests/js/class-syntax-default-constructor.html
new file mode 100644 (file)
index 0000000..3b71746
--- /dev/null
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<body>
+<script src="../resources/js-test-pre.js"></script>
+<script src="script-tests/class-syntax-default-constructor.js"></script>
+<script src="../resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/js/script-tests/class-syntax-default-constructor.js b/LayoutTests/js/script-tests/class-syntax-default-constructor.js
new file mode 100644 (file)
index 0000000..76d2983
--- /dev/null
@@ -0,0 +1,16 @@
+//@ skip
+
+description('Tests for ES6 class syntax default constructor');
+
+shouldBeTrue('class A { }; window.A = A; new A instanceof A');
+shouldThrow('A()', '"TypeError: Cannot call a class constructor"');
+shouldBeTrue('A.prototype.constructor instanceof Function');
+shouldBe('A.prototype.constructor.name', '"A"');
+shouldBeTrue('class B extends A { }; new B instanceof A; new B instanceof A');
+shouldThrow('B()', '"TypeError: Cannot call a class constructor"');
+shouldBe('B.prototype.constructor.name', '"B"');
+shouldNotBe('A', 'B');
+shouldBe('A.prototype.constructor', 'B.prototype.constructor');
+shouldBe('new (class extends (class { constructor(a, b) { return [a, b]; } }) {})(1, 2)', '[1, 2]');
+
+var successfullyParsed = true;
index fb7ba48..f17088a 100644 (file)
@@ -1,3 +1,48 @@
+2015-03-16  Ryosuke Niwa  <rniwa@webkit.org>
+
+        Add support for default constructor
+        https://bugs.webkit.org/show_bug.cgi?id=142388
+
+        Reviewed by Filip Pizlo.
+
+        Added the support for default constructors. They're generated by ClassExprNode::emitBytecode
+        via BuiltinExecutables::createDefaultConstructor.
+
+        UnlinkedFunctionExecutable now has the ability to override SourceCode provided by the owner
+        executable. We can't make store SourceCode in UnlinkedFunctionExecutable since CodeCache can use
+        the same UnlinkedFunctionExecutable to generate code blocks for multiple functions.
+
+        Parser now has the ability to treat any function expression as a constructor of the kind specified
+        by m_defaultConstructorKind member variable.
+
+        * builtins/BuiltinExecutables.cpp:
+        (JSC::BuiltinExecutables::createDefaultConstructor): Added.
+        (JSC::BuiltinExecutables::createExecutableInternal): Generalized from createBuiltinExecutable.
+        Parse default constructors as normal non-builtin functions. Override SourceCode in the unlinked
+        function executable since the Miranda function's code is definitely not in the owner executable's
+        source code. That's the whole point.
+        * builtins/BuiltinExecutables.h:
+        (UnlinkedFunctionExecutable::createBuiltinExecutable): Added. Wraps createExecutableInternal.
+        * bytecode/UnlinkedCodeBlock.cpp:
+        (JSC::UnlinkedFunctionExecutable::UnlinkedFunctionExecutable):
+        (JSC::UnlinkedFunctionExecutable::linkInsideExecutable):
+        (JSC::UnlinkedFunctionExecutable::linkGlobalCode):
+        * bytecode/UnlinkedCodeBlock.h:
+        (JSC::UnlinkedFunctionExecutable::create):
+        (JSC::UnlinkedFunctionExecutable::symbolTable): Deleted.
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::emitNewDefaultConstructor): Added.
+        * bytecompiler/BytecodeGenerator.h:
+        * bytecompiler/NodesCodegen.cpp:
+        (JSC::ClassExprNode::emitBytecode): Generate the default constructor if needed.
+        * parser/Parser.cpp:
+        (JSC::Parser<LexerType>::Parser):
+        (JSC::Parser<LexerType>::parseFunctionInfo): Override ownerClassKind and assume the function as
+        a constructor if we're parsing a default constructor.
+        (JSC::Parser<LexerType>::parseClass): Allow omission of the class constructor.
+        * parser/Parser.h:
+        (JSC::parse):
+
 2015-03-16  Alex Christensen  <achristensen@webkit.org>
 
         Progress towards CMake on Mac
index 3c8dac5..fb3fd4e 100644 (file)
@@ -31,6 +31,7 @@
 #include "Executable.h"
 #include "JSCInlines.h"
 #include "Parser.h"
+#include <wtf/NeverDestroyed.h>
 
 namespace JSC {
 
@@ -42,11 +43,33 @@ BuiltinExecutables::BuiltinExecutables(VM& vm)
 {
 }
 
-UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& source, const Identifier& name)
+UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name)
+{
+    static NeverDestroyed<const String> baseConstructorCode(ASCIILiteral("(function () { })"));
+    static NeverDestroyed<const String> derivedConstructorCode(ASCIILiteral("(function () { super(...arguments); })"));
+
+    switch (constructorKind) {
+    case ConstructorKind::None:
+        break;
+    case ConstructorKind::Base:
+        return createExecutableInternal(makeSource(baseConstructorCode), name, constructorKind);
+    case ConstructorKind::Derived:
+        return createExecutableInternal(makeSource(derivedConstructorCode), name, constructorKind);
+    }
+    ASSERT_NOT_REACHED();
+    return nullptr;
+}
+
+UnlinkedFunctionExecutable* BuiltinExecutables::createExecutableInternal(const SourceCode& source, const Identifier& name, ConstructorKind constructorKind)
 {
     JSTextPosition positionBeforeLastNewline;
     ParserError error;
-    std::unique_ptr<ProgramNode> program = parse<ProgramNode>(&m_vm, source, 0, Identifier(), JSParseBuiltin, JSParseProgramCode, error, &positionBeforeLastNewline);
+    bool isParsingDefaultConstructor = constructorKind != ConstructorKind::None;
+    JSParserStrictness strictness = isParsingDefaultConstructor ? JSParseNormal : JSParseBuiltin;
+    UnlinkedFunctionKind kind = isParsingDefaultConstructor ? UnlinkedNormalFunction : UnlinkedBuiltinFunction;
+    RefPtr<SourceProvider> sourceOverride = isParsingDefaultConstructor ? source.provider() : nullptr;
+    std::unique_ptr<ProgramNode> program = parse<ProgramNode>(&m_vm, source, 0, Identifier(), strictness, JSParseProgramCode,
+        error, &positionBeforeLastNewline, false, constructorKind);
 
     if (!program) {
         dataLog("Fatal error compiling builtin function '", name.string(), "': ", error.message());
@@ -78,7 +101,7 @@ UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const So
         RELEASE_ASSERT(closedVariable->isUnique());
     }
     body->overrideName(name);
-    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, UnlinkedBuiltinFunction);
+    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(&m_vm, source, body, kind, WTF::move(sourceOverride));
     functionExecutable->m_nameValue.set(m_vm, functionExecutable, jsString(&m_vm, name.string()));
     return functionExecutable;
 }
index c330e9d..f0d5f4e 100644 (file)
@@ -27,6 +27,7 @@
 #define BuiltinExecutables_h
 
 #include "JSCBuiltins.h"
+#include "ParserModes.h"
 #include "SourceCode.h"
 #include "Weak.h"
 #include "WeakHandleOwner.h"
@@ -48,12 +49,20 @@ const SourceCode& name##Source() { return m_##name##Source; }
     
     JSC_FOREACH_BUILTIN(EXPOSE_BUILTIN_EXECUTABLES)
 #undef EXPOSE_BUILTIN_SOURCES
-    
+
+    UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name);
+
 private:
     void finalize(Handle<Unknown>, void* context) override;
 
     VM& m_vm;
-    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode&, const Identifier&);
+
+    UnlinkedFunctionExecutable* createBuiltinExecutable(const SourceCode& code, const Identifier& name)
+    {
+        return createExecutableInternal(code, name, ConstructorKind::None);
+    }
+    UnlinkedFunctionExecutable* createExecutableInternal(const SourceCode&, const Identifier&, ConstructorKind);
+
 #define DECLARE_BUILTIN_SOURCE_MEMBERS(name, functionName, length)\
     SourceCode m_##name##Source; \
     Weak<UnlinkedFunctionExecutable> m_##name##Executable;
index 58033bd..09f078e 100644 (file)
@@ -80,7 +80,7 @@ unsigned UnlinkedCodeBlock::addOrFindConstant(JSValue v)
     return addConstant(v);
 }
 
-UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind kind)
+UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* structure, const SourceCode& source, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode* node, UnlinkedFunctionKind kind)
     : Base(*vm, structure)
     , m_isInStrictContext(node->isInStrictContext())
     , m_hasCapturedVariables(false)
@@ -98,6 +98,7 @@ UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM* vm, Structure* struct
     , m_sourceLength(node->source().length())
     , m_typeProfilingStartOffset(node->functionKeywordStart())
     , m_typeProfilingEndOffset(node->startStartOffset() + node->source().length() - 1)
+    , m_sourceOverride(sourceOverride)
     , m_features(0)
     , m_functionMode(node->functionMode())
 {
@@ -121,8 +122,9 @@ void UnlinkedFunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visito
     visitor.append(&thisObject->m_symbolTableForConstruct);
 }
 
-FunctionExecutable* UnlinkedFunctionExecutable::linkInsideExecutable(VM& vm, const SourceCode& source)
+FunctionExecutable* UnlinkedFunctionExecutable::linkInsideExecutable(VM& vm, const SourceCode& ownerSource)
 {
+    SourceCode source = m_sourceOverride ? SourceCode(m_sourceOverride) : ownerSource;
     unsigned firstLine = source.firstLine() + m_firstLineOffset;
     unsigned startOffset = source.startOffset() + m_startOffset;
 
@@ -137,6 +139,7 @@ FunctionExecutable* UnlinkedFunctionExecutable::linkInsideExecutable(VM& vm, con
 
 FunctionExecutable* UnlinkedFunctionExecutable::linkGlobalCode(VM& vm, const SourceCode& source)
 {
+    ASSERT(!m_sourceOverride);
     unsigned firstLine = source.firstLine() + m_firstLineOffset;
     unsigned startOffset = source.startOffset() + m_startOffset;
 
index 5dd2523..cde0ae3 100644 (file)
@@ -103,9 +103,10 @@ public:
     friend class CodeCache;
     friend class VM;
     typedef JSCell Base;
-    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind)
+    static UnlinkedFunctionExecutable* create(VM* vm, const SourceCode& source, FunctionBodyNode* node, UnlinkedFunctionKind unlinkedFunctionKind, RefPtr<SourceProvider>&& sourceOverride = nullptr)
     {
-        UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap)) UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind);
+        UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm->heap))
+            UnlinkedFunctionExecutable(vm, vm->unlinkedFunctionExecutableStructure.get(), source, WTF::move(sourceOverride), node, unlinkedFunctionKind);
         instance->finishCreation(*vm);
         return instance;
     }
@@ -173,7 +174,7 @@ public:
     bool isBuiltinFunction() const { return m_isBuiltinFunction; }
 
 private:
-    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, FunctionBodyNode*, UnlinkedFunctionKind);
+    UnlinkedFunctionExecutable(VM*, Structure*, const SourceCode&, RefPtr<SourceProvider>&& sourceOverride, FunctionBodyNode*, UnlinkedFunctionKind);
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForCall;
     WriteBarrier<UnlinkedFunctionCodeBlock> m_codeBlockForConstruct;
 
@@ -197,6 +198,7 @@ private:
     unsigned m_sourceLength;
     unsigned m_typeProfilingStartOffset;
     unsigned m_typeProfilingEndOffset;
+    RefPtr<SourceProvider> m_sourceOverride;
 
     CodeFeatures m_features;
 
index faf5fd9..f44d970 100644 (file)
@@ -31,6 +31,7 @@
 #include "config.h"
 #include "BytecodeGenerator.h"
 
+#include "BuiltinExecutables.h"
 #include "Interpreter.h"
 #include "JSFunction.h"
 #include "JSLexicalEnvironment.h"
@@ -1692,6 +1693,19 @@ RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExp
     return r0;
 }
 
+RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name)
+{
+    UnlinkedFunctionExecutable* executable = m_vm->builtinExecutables()->createDefaultConstructor(constructorKind, name);
+
+    unsigned index = m_codeBlock->addFunctionExpr(executable);
+
+    emitOpcode(op_new_func_exp);
+    instructions().append(dst->index());
+    instructions().append(scopeRegister()->index());
+    instructions().append(index);
+    return dst;
+}
+
 RegisterID* BytecodeGenerator::emitCall(RegisterID* dst, RegisterID* func, ExpectedFunction expectedFunction, CallArguments& callArguments, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
 {
     return emitCall(op_call, dst, func, expectedFunction, callArguments, divot, divotStart, divotEnd);
index 6252f32..5f21b5a 100644 (file)
@@ -466,6 +466,7 @@ namespace JSC {
         RegisterID* emitLazyNewFunction(RegisterID* dst, FunctionBodyNode* body);
         RegisterID* emitNewFunctionInternal(RegisterID* dst, unsigned index, bool shouldNullCheck);
         RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func);
+        RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name);
         RegisterID* emitNewRegExp(RegisterID* dst, RegExp*);
 
         RegisterID* emitMove(RegisterID* dst, RegisterID* src);
index 65f3a12..d562917 100644 (file)
@@ -2885,9 +2885,18 @@ RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID
         generator.emitNode(superclass.get(), m_classHeritage);
     }
 
-    RefPtr<RegisterID> constructor = generator.emitNode(dst, m_constructorExpression);
+    RefPtr<RegisterID> constructor;
+    RefPtr<RegisterID> prototype;
+
     // FIXME: Make the prototype non-configurable & non-writable.
-    RefPtr<RegisterID> prototype = generator.emitGetById(generator.newTemporary(), constructor.get(), generator.propertyNames().prototype);
+    if (m_constructorExpression)
+        constructor = generator.emitNode(dst, m_constructorExpression);
+    else {
+        constructor = generator.emitNewDefaultConstructor(generator.finalDestination(dst),
+            m_classHeritage ? ConstructorKind::Derived : ConstructorKind::Base, m_name);
+    }
+
+    prototype = generator.emitGetById(generator.newTemporary(), constructor.get(), generator.propertyNames().prototype);
 
     if (superclass) {
         RefPtr<RegisterID> tempRegister = generator.newTemporary();
index d800afb..3175c04 100644 (file)
@@ -190,7 +190,7 @@ void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B
 }
 
 template <typename LexerType>
-Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode)
+Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ConstructorKind defaultConstructorKind)
     : m_vm(vm)
     , m_source(&source)
     , m_hasStackOverflow(false)
@@ -204,6 +204,7 @@ Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters*
     , m_lastFunctionName(nullptr)
     , m_sourceElements(0)
     , m_parsingBuiltin(strictness == JSParseBuiltin)
+    , m_defaultConstructorKind(defaultConstructorKind)
 {
     m_lexer = std::make_unique<LexerType>(vm, strictness);
     m_lexer->setCode(source, &m_parserArena);
@@ -1325,6 +1326,10 @@ template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuild
     // 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;
+    if (m_defaultConstructorKind != ConstructorKind::None) {
+        ownerClassKind = m_defaultConstructorKind;
+        isClassConstructor = true;
+    }
     ConstructorKind constructorKind = isClassConstructor ? ownerClassKind : ConstructorKind::None;
 
     info.openBraceOffset = m_token.m_data.offset;
@@ -1549,9 +1554,6 @@ template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(T
         }
     }
 
-    // FIXME: Create a Miranda function instead.
-    semanticFailIfFalse(constructor, "Class declaration without a constructor is not supported yet");
-
     failIfFalse(popScope(classScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error");
     consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body");
 
index 1c6ef9c..26b00f8 100644 (file)
@@ -426,7 +426,8 @@ class Parser {
     WTF_MAKE_FAST_ALLOCATED;
 
 public:
-    Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode);
+    Parser(VM*, const SourceCode&, FunctionParameters*, const Identifier&, JSParserStrictness, JSParserMode,
+        ConstructorKind defaultConstructorKind = ConstructorKind::None);
     ~Parser();
 
     template <class ParsedNode>
@@ -872,6 +873,7 @@ private:
     RefPtr<SourceProviderCache> m_functionCache;
     SourceElements* m_sourceElements;
     bool m_parsingBuiltin;
+    ConstructorKind m_defaultConstructorKind;
     DeclarationStacks::VarStack m_varDeclarations;
     DeclarationStacks::FunctionStack m_funcDeclarations;
     IdentifierSet m_capturedVariables;
@@ -979,13 +981,15 @@ std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, bool ne
 }
 
 template <class ParsedNode>
-std::unique_ptr<ParsedNode> parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode, ParserError& error, JSTextPosition* positionBeforeLastNewline = 0, bool needReparsingAdjustment = false)
+std::unique_ptr<ParsedNode> parse(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name,
+    JSParserStrictness strictness, JSParserMode parserMode, ParserError& error, JSTextPosition* positionBeforeLastNewline = 0,
+    bool needReparsingAdjustment = false, ConstructorKind defaultConstructorKind = ConstructorKind::None)
 {
     SamplingRegion samplingRegion("Parsing");
 
     ASSERT(!source.provider()->source().isNull());
     if (source.provider()->source().is8Bit()) {
-        Parser<Lexer<LChar>> parser(vm, source, parameters, name, strictness, parserMode);
+        Parser<Lexer<LChar>> parser(vm, source, parameters, name, strictness, parserMode, defaultConstructorKind);
         std::unique_ptr<ParsedNode> result = parser.parse<ParsedNode>(error, needReparsingAdjustment);
         if (positionBeforeLastNewline)
             *positionBeforeLastNewline = parser.positionBeforeLastNewline();