Changeset 254653 in webkit


Ignore:
Timestamp:
Jan 15, 2020 4:09:50 PM (4 years ago)
Author:
caitp@igalia.com
Message:

[JSC] Add support for public class fields
https://bugs.webkit.org/show_bug.cgi?id=174212

Reviewed by Yusuke Suzuki.

JSTests:

New syntax invalidates some test expectations:

"async <linefeed> MethodDefinition" is no longer an unexpected "async"
token. It is now an instance field named "async" with no initializer,
and an automatic semicolon, followed by MethodDefinition.

"get|set GeneratorMethodDefinition"'s error message has changed, due to "get"
being valid class field names.

Many class-syntax tests relating to automatic semicolon insertion are
no longer valid, as a line containing nothing but an identifier is now
a valid class element.

  • stress/async-await-syntax.js:
  • stress/class-fields-bytecode-cache.js: Added.
  • stress/class-fields-computed-to-property-key.js: Added.
  • stress/class-fields-function-name.js: Added.
  • stress/class-fields-harmony.js: Added.
  • stress/class-fields-proxy-define-property.js: Added.
  • stress/class-fields-stress-instance.js: Added.
  • stress/generator-syntax.js:
  • stress/method-name.js:
  • test262/config.yaml:

Source/JavaScriptCore:

Implements the instance class fields proposal (https://tc39.es/proposal-class-fields/),
minus support for private fields (split into a separate patch).

In summary, class fields are initialized by a synthetic JSFunction. In its unlinked state,
the UnlinkedFunctionExecutable for the function includes an ordered list of JSTokenLocations
pointing to the start of each class field in the class. Each of these fields are parsed and
included as DefineFieldNodes, which implement the appropriate DefineField behaviour in the
proposal. This synthetic function is only created, and only loaded, if there are class fields
present. The decision to use a synthetic function was for simplicity. There are a number of
factors which make inlining the initialization complicated, though we may opt to do this in
the future. For reference, the complexities are: instance fields and constructor in different
currently in different parsing arenas, distinct scopes between the 2 which require work to manage,
and complexity in doing to this work for child classes, where the location of initialization can
depend, and in some cases occur more than once.

Computed property fields require a new bytecode, op_to_property_key, as an implementation
detail. It is necessary in the proposal to convert computed properties to property keys
during class evaluation, rather than during field initialization. Additionally, we allocate
the class lexical scope when computed class fields are used (previously, only when there was
a class name), as a location to keep the computed property keys. They can be loaded from the
scope via indexed keys.

To illustrate computed field names in action, consider the following pseudocode:

<during class evaluation>
1) fieldName = emitNode({expr})
2) fieldName = emitToPropertyKey(fieldName)
3) classScope[numComputedNames++] = fieldName

<during class field initialization>
1) fieldName = emitGetFromScope(classScope, computedFieldNameIndex++)
2) value = emitNode({initializer})
3) instance[fieldName] = value

The feature is currently hidden behind the feature flag JSC::Options::useClassFields.

LayoutTests:

New syntax invalidates some test expectations:

"async <linefeed> MethodDefinition" is no longer an unexpected "async"
token. It is now an instance field named "async" with no initializer,
and an automatic semicolon, followed by MethodDefinition.

"get|set GeneratorMethodDefinition"'s error message has changed, due to "get"
being valid class field names.

Many class-syntax tests relating to automatic semicolon insertion are
no longer valid, as a line containing nothing but an identifier is now
a valid class element.

  • js/class-syntax-semicolon-expected.txt:
  • js/script-tests/class-syntax-semicolon.js:
Location:
trunk
Files:
6 added
57 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r254632 r254653  
     12020-01-15  Caitlin Potter <caitp@igalia.com>
     2
     3        [JSC] Add support for public class fields
     4        https://bugs.webkit.org/show_bug.cgi?id=174212
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        New syntax invalidates some test expectations:
     9
     10        "async <linefeed> MethodDefinition" is no longer an unexpected "async"
     11        token. It is now an instance field named "async" with no initializer,
     12        and an automatic semicolon, followed by MethodDefinition.
     13
     14        "get|set GeneratorMethodDefinition"'s error message has changed, due to "get"
     15        being valid class field names.
     16
     17        Many class-syntax tests relating to automatic semicolon insertion are
     18        no longer valid, as a line containing nothing but an identifier is now
     19        a valid class element.
     20
     21        * stress/async-await-syntax.js:
     22        * stress/class-fields-bytecode-cache.js: Added.
     23        * stress/class-fields-computed-to-property-key.js: Added.
     24        * stress/class-fields-function-name.js: Added.
     25        * stress/class-fields-harmony.js: Added.
     26        * stress/class-fields-proxy-define-property.js: Added.
     27        * stress/class-fields-stress-instance.js: Added.
     28        * stress/generator-syntax.js:
     29        * stress/method-name.js:
     30        * test262/config.yaml:
     31
    1322020-01-15  Keith Miller  <keith_miller@apple.com>
    233
  • trunk/JSTests/stress/async-await-syntax.js

    r249925 r254653  
    561561        { prefix: "({ async", suffix: "method() {} }).method" },
    562562
    563         // ClassLiteral AsyncMethodDefinition
    564         { prefix: "(class { async", suffix: "method() {} }).prototype.method" },
    565 
    566563        // AsyncArrowFunctions
    567564        { prefix: "(async", suffix: "param => 1)" },
     
    579576    }
    580577
     578    let testsClass = [
     579        // ClassLiteral AsyncMethodDefinition
     580        { prefix: "(class { async", suffix: "method() {} }).prototype.method" },
     581    ];
     582
     583    for (let { prefix, suffix } of testsClass) {
     584        testSyntax(`${prefix} ${suffix}`);
     585        testSyntax(`"use strict";${prefix} ${suffix}`);
     586        shouldBe("function", typeof eval(`${prefix} ${suffix}`));
     587        shouldBe("function", typeof eval(`"use strict";${prefix} ${suffix}`));
     588    }
     589
    581590    // AsyncFunctionDeclaration
    582591    testSyntax("async function foo() {}");
  • trunk/JSTests/stress/generator-syntax.js

    r208016 r254653  
     1//@ requireOptions("--useClassFields=1")
     2
    13function testSyntax(script) {
    24    try {
     
    2729    }
    2830}
    29 `, `SyntaxError: Unexpected token '*'. Expected an opening '(' before a method's parameter list.`);
     31`, `SyntaxError: Unexpected token '*'. Expected a ';' following a class field.`);
    3032
    3133
     
    3537    }
    3638}
    37 `, `SyntaxError: Unexpected token '*'. Expected an opening '(' before a method's parameter list.`);
     39`, `SyntaxError: Unexpected token '*'. Expected a ';' following a class field.`);
    3840
    3941testSyntaxError(`
  • trunk/JSTests/stress/method-name.js

    r204842 r254653  
     1//@ requireOptions("--useClassFields=1")
     2
    13function testSyntax(script) {
    24    try {
     
    2628    hello hello() { }
    2729}
    28 `, `SyntaxError: Unexpected identifier 'hello'. Expected an opening '(' before a method's parameter list.`);
     30`, `SyntaxError: Unexpected identifier 'hello'. Expected a ';' following a class field.`);
    2931
    3032testSyntaxError(`
  • trunk/JSTests/test262/config.yaml

    r252559 r254653  
    44  BigInt: useBigInt
    55  WeakRef: useWeakRefs
     6  class-fields-public: useClassFields
    67skip:
    78  features:
     
    1112    - regexp-lookbehind
    1213
    13     - class-fields-public
    1414    - class-fields-private
    1515    - class-methods-private
  • trunk/LayoutTests/ChangeLog

    r254652 r254653  
     12020-01-15  Caitlin Potter <caitp@igalia.com>
     2
     3        [JSC] Add support for public class fields
     4        https://bugs.webkit.org/show_bug.cgi?id=174212
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        New syntax invalidates some test expectations:
     9
     10        "async <linefeed> MethodDefinition" is no longer an unexpected "async"
     11        token. It is now an instance field named "async" with no initializer,
     12        and an automatic semicolon, followed by MethodDefinition.
     13
     14        "get|set GeneratorMethodDefinition"'s error message has changed, due to "get"
     15        being valid class field names.
     16
     17        Many class-syntax tests relating to automatic semicolon insertion are
     18        no longer valid, as a line containing nothing but an identifier is now
     19        a valid class element.
     20
     21        * js/class-syntax-semicolon-expected.txt:
     22        * js/script-tests/class-syntax-semicolon.js:
     23
    1242020-01-15  Chris Dumez  <cdumez@apple.com>
    225
  • trunk/LayoutTests/js/class-syntax-semicolon-expected.txt

    r188018 r254653  
    44
    55
    6 PASS class A { foo;() { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list..
    76PASS class A { foo() ; { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '{' at the start of a method body..
    8 PASS class A { get ; foo() { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list..
    9 PASS class A { get foo;() { } } threw exception SyntaxError: Unexpected token ';'. Expected a parameter list for getter definition..
    107PASS class A { get foo() ; { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '{' at the start of a getter body..
    11 PASS class A { set ; foo(x) { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '(' before a method's parameter list..
    12 PASS class A { set foo;(x) { } } threw exception SyntaxError: Unexpected token ';'. Expected a parameter list for setter definition..
    138PASS class A { set foo(x) ; { } } threw exception SyntaxError: Unexpected token ';'. Expected an opening '{' at the start of a setter body..
    149PASS class A { ; } did not throw exception.
  • trunk/LayoutTests/js/script-tests/class-syntax-semicolon.js

    r199236 r254653  
    11description('Tests for ES6 class syntax containing semicolon in the class body');
    22
    3 shouldThrow("class A { foo;() { } }", "'SyntaxError: Unexpected token \\';\\'. Expected an opening \\'(\\' before a method\\'s parameter list.'");
    43shouldThrow("class A { foo() ; { } }", "'SyntaxError: Unexpected token \\\';\\'. Expected an opening \\'{\\' at the start of a method body.'");
    5 shouldThrow("class A { get ; foo() { } }", "'SyntaxError: Unexpected token \\';\\'. Expected an opening \\'(\\' before a method\\'s parameter list.'");
    6 shouldThrow("class A { get foo;() { } }", "'SyntaxError: Unexpected token \\\';\\'. Expected a parameter list for getter definition.'");
    74shouldThrow("class A { get foo() ; { } }", "'SyntaxError: Unexpected token \\\';\\'. Expected an opening \\'{\\' at the start of a getter body.'");
    8 shouldThrow("class A { set ; foo(x) { } }", "'SyntaxError: Unexpected token \\';\\'. Expected an opening \\'(\\' before a method\\'s parameter list.'");
    9 shouldThrow("class A { set foo;(x) { } }", "'SyntaxError: Unexpected token \\\';\\'. Expected a parameter list for setter definition.'");
    105shouldThrow("class A { set foo(x) ; { } }", "'SyntaxError: Unexpected token \\\';\\'. Expected an opening \\'{\\' at the start of a setter body.'");
    116
  • trunk/Source/JavaScriptCore/ChangeLog

    r254637 r254653  
     12020-01-15  Caitlin Potter <caitp@igalia.com>
     2
     3        [JSC] Add support for public class fields
     4        https://bugs.webkit.org/show_bug.cgi?id=174212
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Implements the instance class fields proposal (https://tc39.es/proposal-class-fields/),
     9        minus support for private fields (split into a separate patch).
     10
     11        In summary, class fields are initialized by a synthetic JSFunction. In its unlinked state,
     12        the UnlinkedFunctionExecutable for the function includes an ordered list of JSTokenLocations
     13        pointing to the start of each class field in the class. Each of these fields are parsed and
     14        included as DefineFieldNodes, which implement the appropriate DefineField behaviour in the
     15        proposal. This synthetic function is only created, and only loaded, if there are class fields
     16        present. The decision to use a synthetic function was for simplicity. There are a number of
     17        factors which make inlining the initialization complicated, though we may opt to do this in
     18        the future. For reference, the complexities are: instance fields and constructor in different
     19        currently in different parsing arenas, distinct scopes between the 2 which require work to manage,
     20        and complexity in doing to this work for child classes, where the location of initialization can
     21        depend, and in some cases occur more than once.
     22
     23        Computed property fields require a new bytecode, op_to_property_key, as an implementation
     24        detail. It is necessary in the proposal to convert computed properties to property keys
     25        during class evaluation, rather than during field initialization. Additionally, we allocate
     26        the class lexical scope when computed class fields are used (previously, only when there was
     27        a class name), as a location to keep the computed property keys. They can be loaded from the
     28        scope via indexed keys.
     29
     30        To illustrate computed field names in action, consider the following pseudocode:
     31
     32            <during class evaluation>
     33            1) fieldName = emitNode({expr})
     34            2) fieldName = emitToPropertyKey(fieldName)
     35            3) classScope[numComputedNames++] = fieldName
     36
     37            <during class field initialization>
     38            1) fieldName = emitGetFromScope(classScope, computedFieldNameIndex++)
     39            2) value = emitNode({initializer})
     40            3) instance[fieldName] = value
     41
     42        The feature is currently hidden behind the feature flag JSC::Options::useClassFields.
     43
    1442020-01-15  Adrian Perez de Castro  <aperez@igalia.com>
    245
  • trunk/Source/JavaScriptCore/builtins/BuiltinExecutableCreator.cpp

    r230105 r254653  
    3333UnlinkedFunctionExecutable* createBuiltinExecutable(VM& vm, const SourceCode& source, const Identifier& ident, ConstructorKind kind, ConstructAbility ability)
    3434{
    35     return BuiltinExecutables::createExecutable(vm, source, ident, kind, ability);
     35    return BuiltinExecutables::createExecutable(vm, source, ident, kind, ability, NeedsClassFieldInitializer::No);
    3636}
    3737   
  • trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.cpp

    r254087 r254653  
    6060}
    6161
    62 UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name)
     62UnlinkedFunctionExecutable* BuiltinExecutables::createDefaultConstructor(ConstructorKind constructorKind, const Identifier& name, NeedsClassFieldInitializer needsClassFieldInitializer)
    6363{
    6464    switch (constructorKind) {
     
    6868    case ConstructorKind::Base:
    6969    case ConstructorKind::Extends:
    70         return createExecutable(m_vm, defaultConstructorSourceCode(constructorKind), name, constructorKind, ConstructAbility::CanConstruct);
     70        return createExecutable(m_vm, defaultConstructorSourceCode(constructorKind), name, constructorKind, ConstructAbility::CanConstruct, needsClassFieldInitializer);
    7171    }
    7272    ASSERT_NOT_REACHED();
     
    7676UnlinkedFunctionExecutable* BuiltinExecutables::createBuiltinExecutable(const SourceCode& code, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility)
    7777{
    78     return createExecutable(m_vm, code, name, constructorKind, constructAbility);
    79 }
    80 
    81 UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility)
     78    return createExecutable(m_vm, code, name, constructorKind, constructAbility, NeedsClassFieldInitializer::No);
     79}
     80
     81UnlinkedFunctionExecutable* BuiltinExecutables::createExecutable(VM& vm, const SourceCode& source, const Identifier& name, ConstructorKind constructorKind, ConstructAbility constructAbility, NeedsClassFieldInitializer needsClassFieldInitializer)
    8282{
    8383    // FIXME: Can we just make MetaData computation be constexpr and have the compiler do this for us?
     
    252252    }
    253253
    254     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, isBuiltinDefaultClassConstructor);
     254    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, &metadata, kind, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
    255255    return functionExecutable;
    256256}
  • trunk/Source/JavaScriptCore/builtins/BuiltinExecutables.h

    r249509 r254653  
    2626#pragma once
    2727
     28#include "ExecutableInfo.h"
    2829#include "JSCBuiltins.h"
    2930#include "ParserModes.h"
     
    5859
    5960    static SourceCode defaultConstructorSourceCode(ConstructorKind);
    60     UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name);
     61    UnlinkedFunctionExecutable* createDefaultConstructor(ConstructorKind, const Identifier& name, NeedsClassFieldInitializer);
    6162
    62     static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility);
     63    static UnlinkedFunctionExecutable* createExecutable(VM&, const SourceCode&, const Identifier&, ConstructorKind, ConstructAbility, NeedsClassFieldInitializer);
    6364
    6465    void finalizeUnconditionally();
  • trunk/Source/JavaScriptCore/builtins/BuiltinNames.h

    r254420 r254653  
    168168    macro(webAssemblyCompileStreamingInternal) \
    169169    macro(webAssemblyInstantiateStreamingInternal) \
     170    macro(instanceFieldInitializer)
    170171
    171172namespace Symbols {
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.rb

    r254632 r254653  
    866866
    867867op :to_primitive,
     868    args: {
     869        dst: VirtualRegister,
     870        src: VirtualRegister,
     871    }
     872
     873op :to_property_key,
    868874    args: {
    869875        dst: VirtualRegister,
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp

    r253867 r254653  
    164164    USES(OpGetFromScope, scope)
    165165    USES(OpToPrimitive, src)
     166    USES(OpToPropertyKey, src)
    166167    USES(OpTryGetById, base)
    167168    USES(OpGetById, base)
     
    382383    DEFS(OpStrcat, dst)
    383384    DEFS(OpToPrimitive, dst)
     385    DEFS(OpToPropertyKey, dst)
    384386    DEFS(OpCreateThis, dst)
    385387    DEFS(OpCreatePromise, dst)
  • trunk/Source/JavaScriptCore/bytecode/ExecutableInfo.h

    r206525 r254653  
    3131   
    3232enum class DerivedContextType : uint8_t { None, DerivedConstructorContext, DerivedMethodContext };
    33 enum class EvalContextType    : uint8_t { None, FunctionEvalContext };
     33enum class EvalContextType    : uint8_t { None, FunctionEvalContext, InstanceFieldEvalContext };
     34enum class NeedsClassFieldInitializer : uint8_t { No, Yes };
    3435
    3536// FIXME: These flags, ParserModes and propagation to XXXCodeBlocks should be reorganized.
    3637// https://bugs.webkit.org/show_bug.cgi?id=151547
    3738struct ExecutableInfo {
    38     ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, JSParserScriptMode scriptMode, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, bool isArrowFunctionContext, bool isClassContext, EvalContextType evalContextType)
     39    ExecutableInfo(bool usesEval, bool isStrictMode, bool isConstructor, bool isBuiltinFunction, ConstructorKind constructorKind, JSParserScriptMode scriptMode, SuperBinding superBinding, SourceParseMode parseMode, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isArrowFunctionContext, bool isClassContext, EvalContextType evalContextType)
    3940        : m_usesEval(usesEval)
    4041        , m_isStrictMode(isStrictMode)
     
    4647        , m_parseMode(parseMode)
    4748        , m_derivedContextType(static_cast<unsigned>(derivedContextType))
     49        , m_needsClassFieldInitializer(static_cast<unsigned>(needsClassFieldInitializer))
    4850        , m_isArrowFunctionContext(isArrowFunctionContext)
    4951        , m_isClassContext(isClassContext)
     
    6769    bool isArrowFunctionContext() const { return m_isArrowFunctionContext; }
    6870    bool isClassContext() const { return m_isClassContext; }
     71    NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
    6972
    7073private:
     
    7881    SourceParseMode m_parseMode;
    7982    unsigned m_derivedContextType : 2;
     83    unsigned m_needsClassFieldInitializer : 1;
    8084    unsigned m_isArrowFunctionContext : 1;
    8185    unsigned m_isClassContext : 1;
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.cpp

    r254632 r254653  
    8080    ASSERT(m_codeType == static_cast<unsigned>(codeType));
    8181    ASSERT(m_didOptimize == static_cast<unsigned>(MixedTriState));
     82    if (info.needsClassFieldInitializer() == NeedsClassFieldInitializer::Yes) {
     83        createRareDataIfNecessary();
     84        m_rareData->m_needsClassFieldInitializer = static_cast<unsigned>(NeedsClassFieldInitializer::Yes);
     85    }
    8286}
    8387
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedCodeBlock.h

    r254632 r254653  
    332332    void resetAge() { m_age = 0; }
    333333
     334    NeedsClassFieldInitializer needsClassFieldInitializer() const
     335    {
     336        if (m_rareData)
     337            return static_cast<NeedsClassFieldInitializer>(m_rareData->m_needsClassFieldInitializer);
     338        return NeedsClassFieldInitializer::No;
     339    }
     340
    334341    void dump(PrintStream&) const;
    335342
     
    475482        Vector<BitVector> m_bitVectors;
    476483        Vector<ConstantIdentifierSetEntry> m_constantIdentifierSets;
     484
     485        unsigned m_needsClassFieldInitializer : 1;
    477486    };
    478487
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

    r251425 r254653  
    5858    JSParserScriptMode scriptMode = executable->scriptMode();
    5959    ASSERT(isFunctionParseMode(executable->parseMode()));
     60    Vector<JSTextPosition>* instanceFieldLocations = executable->instanceFieldLocations();
    6061    std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
    61         vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr);
     62        vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, instanceFieldLocations);
    6263
    6364    if (!function) {
     
    7172    bool isClassContext = executable->superBinding() == SuperBinding::Needed;
    7273
    73     UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(vm, FunctionCode, ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), scriptMode, executable->superBinding(), parseMode, executable->derivedContextType(), false, isClassContext, EvalContextType::FunctionEvalContext), codeGenerationMode);
     74    UnlinkedFunctionCodeBlock* result = UnlinkedFunctionCodeBlock::create(vm, FunctionCode, ExecutableInfo(function->usesEval(), function->isStrictMode(), kind == CodeForConstruct, functionKind == UnlinkedBuiltinFunction, executable->constructorKind(), scriptMode, executable->superBinding(), parseMode, executable->derivedContextType(), executable->needsClassFieldInitializer(), false, isClassContext, EvalContextType::FunctionEvalContext), codeGenerationMode);
    7475
    7576    VariableEnvironment parentScopeTDZVariables = executable->parentScopeTDZVariables();
     
    8283}
    8384
    84 UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM& vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor)
     85UnlinkedFunctionExecutable::UnlinkedFunctionExecutable(VM& vm, Structure* structure, const SourceCode& parentSource, FunctionMetadataNode* node, UnlinkedFunctionKind kind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor)
    8586    : Base(vm, structure)
    8687    , m_firstLineOffset(node->firstLine() - parentSource.firstLine().oneBasedInt())
     
    109110    , m_derivedContextType(static_cast<unsigned>(derivedContextType))
    110111    , m_isGeneratedFromCache(false)
     112    , m_needsClassFieldInitializer(static_cast<unsigned>(needsClassFieldInitializer))
    111113    , m_unlinkedCodeBlockForCall()
    112114    , m_unlinkedCodeBlockForConstruct()
     
    122124    ASSERT(m_derivedContextType == static_cast<unsigned>(derivedContextType));
    123125    ASSERT(!(m_isBuiltinDefaultClassConstructor && constructorKind() == ConstructorKind::None));
     126    ASSERT(!m_needsClassFieldInitializer || (isClassConstructorFunction() || derivedContextType == DerivedContextType::DerivedConstructorContext));
    124127    if (!node->classSource().isNull())
    125128        setClassSource(node->classSource());
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h

    r252520 r254653  
    3535#include "JSCast.h"
    3636#include "ParserModes.h"
     37#include "ParserTokens.h"
    3738#include "RegExp.h"
    3839#include "SourceCode.h"
     
    7071    }
    7172
    72     static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, bool isBuiltinDefaultClassConstructor = false)
     73    static UnlinkedFunctionExecutable* create(VM& vm, const SourceCode& source, FunctionMetadataNode* node, UnlinkedFunctionKind unlinkedFunctionKind, ConstructAbility constructAbility, JSParserScriptMode scriptMode, Optional<CompactVariableMap::Handle> parentScopeTDZVariables, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isBuiltinDefaultClassConstructor = false)
    7374    {
    7475        UnlinkedFunctionExecutable* instance = new (NotNull, allocateCell<UnlinkedFunctionExecutable>(vm.heap))
    75             UnlinkedFunctionExecutable(vm, vm.unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, isBuiltinDefaultClassConstructor);
     76            UnlinkedFunctionExecutable(vm, vm.unlinkedFunctionExecutableStructure.get(), source, node, unlinkedFunctionKind, constructAbility, scriptMode, WTFMove(parentScopeTDZVariables), derivedContextType, needsClassFieldInitializer, isBuiltinDefaultClassConstructor);
    7677        instance->finishCreation(vm);
    7778        return instance;
     
    209210        String m_sourceMappingURLDirective;
    210211        CompactVariableMap::Handle m_parentScopeTDZVariables;
     212        Vector<JSTextPosition> m_instanceFieldLocations;
    211213    };
    212214
     215    NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
     216
     217    Vector<JSTextPosition>* instanceFieldLocations() const
     218    {
     219        if (m_rareData)
     220            return &m_rareData->m_instanceFieldLocations;
     221        return nullptr;
     222    }
     223
     224    void setInstanceFieldLocations(Vector<JSTextPosition>&& instanceFieldLocations)
     225    {
     226        if (instanceFieldLocations.isEmpty())
     227            return;
     228        ensureRareData().m_instanceFieldLocations = WTFMove(instanceFieldLocations);
     229    }
     230
    213231private:
    214     UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>,  JSC::DerivedContextType, bool isBuiltinDefaultClassConstructor);
     232    UnlinkedFunctionExecutable(VM&, Structure*, const SourceCode&, FunctionMetadataNode*, UnlinkedFunctionKind, ConstructAbility, JSParserScriptMode, Optional<CompactVariableMap::Handle>,  JSC::DerivedContextType, JSC::NeedsClassFieldInitializer, bool isBuiltinDefaultClassConstructor);
    215233    UnlinkedFunctionExecutable(Decoder&, const CachedFunctionExecutable&);
    216234
     
    249267    unsigned m_derivedContextType: 2;
    250268    unsigned m_isGeneratedFromCache : 1;
     269    unsigned m_needsClassFieldInitializer : 1;
    251270
    252271    union {
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r254632 r254653  
    377377
    378378    bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || codeBlock->usesEval();
    379     bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction()));
     379    bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::InstanceFieldInitializerMode;
    380380
    381381    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
     
    601601
    602602        bool shouldCreateArgumensVariable = !haveParameterNamedArguments
    603             && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode).contains(m_codeBlock->parseMode());
     603            && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::InstanceFieldInitializerMode).contains(m_codeBlock->parseMode());
    604604        shouldCreateArgumentsVariableInParameterScope = shouldCreateArgumensVariable && !isSimpleParameterList;
    605605        // Do not create arguments variable in case of Arrow function. Value will be loaded from parent scope
     
    696696                case ConstructorKind::Base:
    697697                    emitCreateThis(&m_thisRegister);
     698                    if (Options::useClassFields())
     699                        emitInstanceFieldInitializationIfNeeded(&m_thisRegister, &m_calleeRegister, m_scopeNode->position(), m_scopeNode->position(), m_scopeNode->position());
    698700                    break;
    699701                case ConstructorKind::Extends:
     
    27332735}
    27342736
     2737RegisterID* BytecodeGenerator::emitInstanceFieldInitializationIfNeeded(RegisterID* dst, RegisterID* constructor, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
     2738{
     2739    if (!(isConstructor() || isDerivedConstructorContext()) || needsClassFieldInitializer() == NeedsClassFieldInitializer::No)
     2740        return dst;
     2741
     2742    RefPtr<RegisterID> initializer = emitDirectGetById(newTemporary(), constructor, propertyNames().builtinNames().instanceFieldInitializerPrivateName());
     2743    CallArguments args(*this, nullptr);
     2744    emitMove(args.thisRegister(), dst);
     2745    emitCall(newTemporary(), initializer.get(), NoExpectedFunction, args, divot, divotStart, divotEnd, DebuggableCall::No);
     2746
     2747    return dst;
     2748}
     2749
    27352750void BytecodeGenerator::emitTDZCheck(RegisterID* target)
    27362751{
     
    30143029
    30153030RegisterID* BytecodeGenerator::emitNewDefaultConstructor(RegisterID* dst, ConstructorKind constructorKind, const Identifier& name,
    3016     const Identifier& ecmaName, const SourceCode& classSource)
    3017 {
    3018     UnlinkedFunctionExecutable* executable = m_vm.builtinExecutables()->createDefaultConstructor(constructorKind, name);
     3031    const Identifier& ecmaName, const SourceCode& classSource, NeedsClassFieldInitializer needsClassFieldInitializer)
     3032{
     3033    UnlinkedFunctionExecutable* executable = m_vm.builtinExecutables()->createDefaultConstructor(constructorKind, name, needsClassFieldInitializer);
    30193034    executable->setInvalidTypeProfilingOffsets();
    30203035    executable->setEcmaName(ecmaName);
     
    30233038    unsigned index = m_codeBlock->addFunctionExpr(executable);
    30243039
     3040    OpNewFuncExp::emit(this, dst, scopeRegister(), index);
     3041    return dst;
     3042}
     3043
     3044RegisterID* BytecodeGenerator::emitNewInstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived)
     3045{
     3046    DerivedContextType newDerivedContextType;
     3047    SuperBinding superBinding;
     3048    if (!isDerived) {
     3049        newDerivedContextType = DerivedContextType::None;
     3050        superBinding = SuperBinding::NotNeeded;
     3051    } else {
     3052        newDerivedContextType = DerivedContextType::DerivedMethodContext;
     3053        superBinding = SuperBinding::Needed;
     3054    }
     3055
     3056    Optional<CompactVariableMap::Handle> variablesUnderTDZ = getVariablesUnderTDZ();
     3057    SourceParseMode parseMode = SourceParseMode::InstanceFieldInitializerMode;
     3058    ConstructAbility constructAbility = ConstructAbility::CannotConstruct;
     3059
     3060    const bool alwaysStrictInClass = true;
     3061    FunctionMetadataNode metadata(parserArena(), JSTokenLocation(), JSTokenLocation(), 0, 0, 0, 0, 0, alwaysStrictInClass, ConstructorKind::None, superBinding, 0, parseMode, false);
     3062    metadata.finishParsing(m_scopeNode->source(), Identifier(), FunctionMode::MethodDefinition);
     3063    auto initializer = UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), &metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(variablesUnderTDZ), newDerivedContextType, NeedsClassFieldInitializer::No);
     3064    initializer->setInstanceFieldLocations(WTFMove(instanceFieldLocations));
     3065
     3066    unsigned index = m_codeBlock->addFunctionExpr(initializer);
    30253067    OpNewFuncExp::emit(this, dst, scopeRegister(), index);
    30263068    return dst;
     
    30413083}
    30423084
    3043 void BytecodeGenerator::emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name)
     3085template<typename LazyNameRegisterFn>
     3086void BytecodeGenerator::emitSetFunctionNameIfNeededImpl(ExpressionNode* valueNode, RegisterID* value, const LazyNameRegisterFn& lazyNameFn)
    30443087{
    30453088    if (valueNode->isBaseFuncExprNode()) {
     
    30563099        return;
    30573100
     3101    RegisterID* name = lazyNameFn();
     3102
    30583103    // FIXME: We should use an op_call to an internal function here instead.
    30593104    // https://bugs.webkit.org/show_bug.cgi?id=155547
    30603105    OpSetFunctionName::emit(this, value, name);
     3106}
     3107
     3108void BytecodeGenerator::emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, const Identifier& ident)
     3109{
     3110    emitSetFunctionNameIfNeededImpl(valueNode, value, [=]() { return emitLoad(newTemporary(), ident); });
     3111}
     3112
     3113void BytecodeGenerator::emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name)
     3114{
     3115    emitSetFunctionNameIfNeededImpl(valueNode, value, [=]() { return name; });
    30613116}
    30623117
     
    34023457{
    34033458    OpToPrimitive::emit(this, dst, src);
     3459}
     3460
     3461RegisterID* BytecodeGenerator::emitToPropertyKey(RegisterID* dst, RegisterID* src)
     3462{
     3463    OpToPropertyKey::emit(this, dst, src);
     3464    return dst;
    34043465}
    34053466
     
    42344295RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment(const Identifier& identifier)
    42354296{
    4236     ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode);
     4297    ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode || m_codeBlock->parseMode() == SourceParseMode::InstanceFieldInitializerMode);
    42374298
    42384299    return emitResolveScope(nullptr, variable(identifier, ThisResolutionType::Scoped));
     
    42564317    Variable protoScopeVar = variable(propertyNames().builtinNames().derivedConstructorPrivateName());
    42574318    return emitGetFromScope(newTemporary(), emitLoadArrowFunctionLexicalEnvironment(propertyNames().builtinNames().derivedConstructorPrivateName()), protoScopeVar, ThrowIfNotFound);
     4319}
     4320
     4321RegisterID* BytecodeGenerator::emitLoadDerivedConstructor()
     4322{
     4323    ASSERT(constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext());
     4324    if (constructorKind() == ConstructorKind::Extends)
     4325        return &m_calleeRegister;
     4326    return emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
    42584327}
    42594328
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r254632 r254653  
    403403        SuperBinding superBinding() const { return m_codeBlock->superBinding(); }
    404404        JSParserScriptMode scriptMode() const { return m_codeBlock->scriptMode(); }
     405        NeedsClassFieldInitializer needsClassFieldInitializer() const { return m_codeBlock->needsClassFieldInitializer(); }
    405406
    406407        template<typename Node, typename UnlinkedCodeBlock>
     
    555556        }
    556557
    557         RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype)
     558        RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype, Vector<JSTextPosition>& instanceFieldLocations)
    558559        {
    559560            ASSERT(constructor->refCount() && prototype->refCount());
     
    562563            if (UNLIKELY(n->needsDebugHook()))
    563564                emitDebugHook(n);
    564             return n->emitBytecode(*this, constructor, prototype);
     565            return n->emitBytecode(*this, constructor, prototype, &instanceFieldLocations);
    565566        }
    566567
     
    728729        RegisterID* emitCreateAsyncGenerator(RegisterID* dst, RegisterID* newTarget);
    729730        RegisterID* emitCreateArgumentsButterfly(RegisterID* dst);
     731        RegisterID* emitInstanceFieldInitializationIfNeeded(RegisterID* dst, RegisterID* constructor, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
    730732        void emitTDZCheck(RegisterID* target);
    731733        bool needsTDZCheck(const Variable&);
     
    743745        RegisterID* emitNewFunction(RegisterID* dst, FunctionMetadataNode*);
    744746        RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*);
    745         RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource);
     747        RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource, NeedsClassFieldInitializer);
     748        RegisterID* emitNewInstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived);
    746749        RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
    747750        RegisterID* emitNewMethodDefinition(RegisterID* dst, MethodDefinitionNode*);
     
    749752
    750753        void emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, RegisterID* name);
     754        void emitSetFunctionNameIfNeeded(ExpressionNode* valueNode, RegisterID* value, const Identifier&);
    751755
    752756        RegisterID* moveLinkTimeConstant(RegisterID* dst, LinkTimeConstant);
     
    832836        RegisterID* emitStrcat(RegisterID* dst, RegisterID* src, int count);
    833837        void emitToPrimitive(RegisterID* dst, RegisterID* src);
     838        RegisterID* emitToPropertyKey(RegisterID* dst, RegisterID* src);
    834839
    835840        ResolveType resolveType();
     
    952957        void emitPutDerivedConstructorToArrowFunctionContextScope();
    953958        RegisterID* emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
     959        RegisterID* emitLoadDerivedConstructor();
    954960
    955961        void emitDebugHook(DebugHookType, const JSTextPosition&);
     
    970976        bool emitReturnViaFinallyIfNeeded(RegisterID* returnRegister);
    971977        void emitFinallyCompletion(FinallyContext&, Label& normalCompletionLabel);
     978
     979        template<typename LazyNameRegisterFn>
     980        void emitSetFunctionNameIfNeededImpl(ExpressionNode*, RegisterID*, const LazyNameRegisterFn&);
    972981
    973982    public:
     
    11181127            DerivedContextType newDerivedContextType = DerivedContextType::None;
    11191128
     1129            NeedsClassFieldInitializer needsClassFieldInitializer = metadata->isConstructorAndNeedsClassFieldInitializer() ? NeedsClassFieldInitializer::Yes : NeedsClassFieldInitializer::No;
    11201130            if (SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::AsyncArrowFunctionBodyMode).contains(metadata->parseMode())) {
    1121                 if (constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext())
     1131                if (constructorKind() == ConstructorKind::Extends || isDerivedConstructorContext()) {
    11221132                    newDerivedContextType = DerivedContextType::DerivedConstructorContext;
     1133                    needsClassFieldInitializer = m_codeBlock->needsClassFieldInitializer();
     1134                }
    11231135                else if (m_codeBlock->isClassContext() || isDerivedClassContext())
    11241136                    newDerivedContextType = DerivedContextType::DerivedMethodContext;
     
    11341146                constructAbility = ConstructAbility::CanConstruct;
    11351147
    1136             return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType);
     1148            return UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(optionalVariablesUnderTDZ), newDerivedContextType, needsClassFieldInitializer);
    11371149        }
    11381150
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r254420 r254653  
    179179static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
    180180{
    181     if (generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) {
     181    if ((generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) && generator.parseMode() != SourceParseMode::InstanceFieldInitializerMode) {
    182182        RegisterID* derivedConstructor = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
    183183        return generator.emitGetById(generator.newTemporary(), derivedConstructor, generator.propertyNames().builtinNames().homeObjectPrivateName());
     
    543543}
    544544
    545 RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype)
     545RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations)
    546546{
    547547    // Fast case: this loop just handles regular value properties.
     
    550550    for (; p && (p->m_node->m_type & PropertyNode::Constant); p = p->m_next) {
    551551        dst = p->m_node->isInstanceClassProperty() ? prototype : dstOrConstructor;
     552
     553        if (p->isComputedClassField())
     554            emitSaveComputedFieldName(generator, *p->m_node);
     555
     556        if (p->isInstanceClassField()) {
     557            ASSERT(instanceFieldLocations);
     558            instanceFieldLocations->append(p->position());
     559            continue;
     560        }
     561
    552562        emitPutConstantProperty(generator, dst, *p->m_node);
    553563    }
     
    596606            PropertyNode* node = p->m_node;
    597607            dst = node->isInstanceClassProperty() ? prototype : dstOrConstructor;
     608
     609            if (p->isComputedClassField())
     610                emitSaveComputedFieldName(generator, *p->m_node);
     611
     612            if (p->isInstanceClassField()) {
     613                ASSERT(instanceFieldLocations);
     614                ASSERT(node->m_type & PropertyNode::Constant);
     615                instanceFieldLocations->append(p->position());
     616                continue;
     617            }
    598618
    599619            // Handle regular values.
     
    718738}
    719739
     740void PropertyListNode::emitSaveComputedFieldName(BytecodeGenerator& generator, PropertyNode& node)
     741{
     742    ASSERT(node.isComputedClassField());
     743    RefPtr<RegisterID> propertyExpr;
     744
     745    // The 'name' refers to a synthetic numeric variable name in the private name scope, where the property key is saved for later use.
     746    const Identifier& description = *node.name();
     747    Variable var = generator.variable(description);
     748    ASSERT(!var.local());
     749
     750    propertyExpr = generator.emitNode(node.m_expression);
     751    RegisterID* propertyName = generator.emitToPropertyKey(generator.newTemporary(), propertyExpr.get());
     752
     753    RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
     754    generator.emitPutToScope(scope.get(), var, propertyName, ThrowIfNotFound, InitializationMode::ConstInitialization);
     755}
     756
    720757// ------------------------------ BracketAccessorNode --------------------------------
    721758
     
    924961        if (generator.isDerivedConstructorContext() || doWeUseArrowFunctionInConstructor)
    925962            generator.emitPutThisToArrowFunctionContextScope();
    926        
     963
     964        // Initialize instance fields after super-call.
     965        if (Options::useClassFields() && generator.needsClassFieldInitializer() == NeedsClassFieldInitializer::Yes) {
     966            ASSERT(generator.isConstructor() || generator.isDerivedConstructorContext());
     967            func = generator.emitLoadDerivedConstructor();
     968            generator.emitInstanceFieldInitializationIfNeeded(generator.thisRegister(), func.get(), divot(), divotStart(), divotEnd());
     969        }
     970
    927971        return ret;
    928972    }
     
    42674311}
    42684312
     4313// ------------------------------ DefineFieldNode ---------------------------------
     4314
     4315void DefineFieldNode::emitBytecode(BytecodeGenerator& generator, RegisterID*)
     4316{
     4317    RefPtr<RegisterID> value = generator.newTemporary();
     4318
     4319    if (!m_assign)
     4320        generator.emitLoad(value.get(), jsUndefined());
     4321    else {
     4322        generator.emitNode(value.get(), m_assign);
     4323        if (m_ident)
     4324            generator.emitSetFunctionNameIfNeeded(m_assign, value.get(), *m_ident);
     4325    }
     4326
     4327    switch (m_type) {
     4328    case DefineFieldNode::Type::Name: {
     4329        // FIXME: Improve performance of public class fields
     4330        // https://bugs.webkit.org/show_bug.cgi?id=198330
     4331        RefPtr<RegisterID> propertyName = generator.emitLoad(nullptr, *m_ident);
     4332        generator.emitCallDefineProperty(generator.thisRegister(), propertyName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
     4333        break;
     4334    }
     4335    case DefineFieldNode::Type::ComputedName: {
     4336        // FIXME: Improve performance of public class fields
     4337        // https://bugs.webkit.org/show_bug.cgi?id=198330
     4338
     4339        // For ComputedNames, the expression has already been evaluated earlier during evaluation of a ClassExprNode.
     4340        // Here, `m_ident` refers to an integer ID in a class lexical scope, containing the value already converted to an Expression.
     4341        Variable var = generator.variable(*m_ident);
     4342        ASSERT_WITH_MESSAGE(!var.local(), "Computed names must be stored in captured variables");
     4343
     4344        generator.emitExpressionInfo(position(), position(), position() + 1);
     4345        RefPtr<RegisterID> scope = generator.emitResolveScope(generator.newTemporary(), var);
     4346        RefPtr<RegisterID> privateName = generator.newTemporary();
     4347        generator.emitGetFromScope(privateName.get(), scope.get(), var, ThrowIfNotFound);
     4348        generator.emitProfileType(privateName.get(), var, m_position, JSTextPosition(-1, m_position.offset + m_ident->length(), -1));
     4349        generator.emitCallDefineProperty(generator.thisRegister(), privateName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
     4350        break;
     4351    }
     4352    }
     4353}
     4354
    42694355// ------------------------------ ClassDeclNode ---------------------------------
    42704356
     
    42784364RegisterID* ClassExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst)
    42794365{
    4280     if (!m_name.isNull())
     4366    if (m_needsLexicalScope)
    42814367        generator.pushLexicalScope(this, BytecodeGenerator::TDZCheckOptimization::Optimize, BytecodeGenerator::NestedScopeType::IsNested);
    42824368
     
    42894375    RefPtr<RegisterID> constructor = generator.tempDestination(dst);
    42904376    bool needsHomeObject = false;
     4377
     4378    auto needsClassFieldInitializer = this->hasInstanceFields() ? NeedsClassFieldInitializer::Yes : NeedsClassFieldInitializer::No;
    42914379
    42924380    if (m_constructorExpression) {
     
    42954383        metadata->setEcmaName(ecmaName());
    42964384        metadata->setClassSource(m_classSource);
     4385        metadata->setNeedsClassFieldInitializer(needsClassFieldInitializer == NeedsClassFieldInitializer::Yes);
    42974386        constructor = generator.emitNode(constructor.get(), m_constructorExpression);
    42984387        needsHomeObject = m_classHeritage || metadata->superBinding() == SuperBinding::Needed;
    42994388    } else
    4300         constructor = generator.emitNewDefaultConstructor(constructor.get(), m_classHeritage ? ConstructorKind::Extends : ConstructorKind::Base, m_name, ecmaName(), m_classSource);
     4389        constructor = generator.emitNewDefaultConstructor(constructor.get(), m_classHeritage ? ConstructorKind::Extends : ConstructorKind::Base, m_name, ecmaName(), m_classSource, needsClassFieldInitializer);
    43014390
    43024391    const auto& propertyNames = generator.propertyNames();
     
    43444433    generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position);
    43454434
    4346     if (m_classElements)
    4347         generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get());
    4348 
    4349     if (!m_name.isNull()) {
    4350         Variable classNameVar = generator.variable(m_name);
    4351         RELEASE_ASSERT(classNameVar.isResolved());
    4352         RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar);
    4353         generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization);
     4435    if (m_classElements) {
     4436        Vector<JSTextPosition> instanceFieldLocations;
     4437        generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations);
     4438        if (!instanceFieldLocations.isEmpty()) {
     4439            RefPtr<RegisterID> instanceFieldInitializer = generator.emitNewInstanceFieldInitializerFunction(generator.newTemporary(), WTFMove(instanceFieldLocations), m_classHeritage);
     4440
     4441            // FIXME: Skip this if the initializer function isn't going to need a home object (no eval or super properties)
     4442            // https://bugs.webkit.org/show_bug.cgi?id=196867
     4443            emitPutHomeObject(generator, instanceFieldInitializer.get(), prototype.get());
     4444
     4445            generator.emitDirectPutById(constructor.get(), generator.propertyNames().builtinNames().instanceFieldInitializerPrivateName(), instanceFieldInitializer.get(), PropertyNode::Unknown);
     4446        }
     4447    }
     4448
     4449    if (m_needsLexicalScope) {
     4450        if (!m_name.isNull()) {
     4451            Variable classNameVar = generator.variable(m_name);
     4452            RELEASE_ASSERT(classNameVar.isResolved());
     4453            RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar);
     4454            generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization);
     4455        }
    43544456        generator.popLexicalScope(this);
    43554457    }
  • trunk/Source/JavaScriptCore/debugger/DebuggerCallFrame.cpp

    r252216 r254653  
    254254    JSScope::collectClosureVariablesUnderTDZ(scope()->jsScope(), variablesUnderTDZ);
    255255
    256     auto* eval = DirectEvalExecutable::create(globalObject, makeSource(script, callFrame->callerSourceOrigin(vm)), codeBlock->isStrictMode(), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
     256    auto* eval = DirectEvalExecutable::create(globalObject, makeSource(script, callFrame->callerSourceOrigin(vm)), codeBlock->isStrictMode(), codeBlock->unlinkedCodeBlock()->derivedContextType(), codeBlock->unlinkedCodeBlock()->needsClassFieldInitializer(), codeBlock->unlinkedCodeBlock()->isArrowFunction(), evalContextType, &variablesUnderTDZ);
    257257    if (UNLIKELY(catchScope.exception())) {
    258258        exception = catchScope.exception();
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.cpp

    r254632 r254653  
    294294    case op_yield:
    295295    case op_create_generator_frame_environment:
     296    case op_to_property_key: // FIXME: op_to_property_key will need DFG/FTL support to ship class fields.
    296297    case llint_program_prologue:
    297298    case llint_eval_prologue:
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r254632 r254653  
    137137
    138138    EvalContextType evalContextType;
    139     if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
     139    if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::InstanceFieldInitializerMode)
     140        evalContextType = EvalContextType::InstanceFieldEvalContext;
     141    else if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
    140142        evalContextType = EvalContextType::FunctionEvalContext;
    141143    else if (callerUnlinkedCodeBlock->codeType() == EvalCode)
     
    163165        VariableEnvironment variablesUnderTDZ;
    164166        JSScope::collectClosureVariablesUnderTDZ(callerScopeChain, variablesUnderTDZ);
    165         eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, isArrowFunctionContext, evalContextType, &variablesUnderTDZ);
     167        eval = DirectEvalExecutable::create(globalObject, makeSource(programSource, callerCodeBlock->source().provider()->sourceOrigin()), callerCodeBlock->isStrictMode(), derivedContextType, callerUnlinkedCodeBlock->needsClassFieldInitializer(), isArrowFunctionContext, evalContextType, &variablesUnderTDZ);
    166168        EXCEPTION_ASSERT(!!scope.exception() == !eval);
    167169        if (!eval)
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r254087 r254653  
    426426        DEFINE_OP(op_put_getter_by_val)
    427427        DEFINE_OP(op_put_setter_by_val)
     428        DEFINE_OP(op_to_property_key)
    428429
    429430        DEFINE_OP(op_get_internal_field)
     
    600601        DEFINE_SLOWCASE_SLOW_OP(resolve_scope)
    601602        DEFINE_SLOWCASE_SLOW_OP(check_tdz)
     603        DEFINE_SLOWCASE_SLOW_OP(to_property_key)
    602604
    603605        default:
  • trunk/Source/JavaScriptCore/jit/JIT.h

    r254632 r254653  
    622622        void emit_op_log_shadow_chicken_prologue(const Instruction*);
    623623        void emit_op_log_shadow_chicken_tail(const Instruction*);
     624        void emit_op_to_property_key(const Instruction*);
    624625
    625626        void emitSlow_op_add(const Instruction*, Vector<SlowCaseEntry>::iterator&);
  • trunk/Source/JavaScriptCore/jit/JITOpcodes.cpp

    r254632 r254653  
    358358}
    359359
     360void JIT::emit_op_to_property_key(const Instruction* currentInstruction)
     361{
     362    auto bytecode = currentInstruction->as<OpToPropertyKey>();
     363    VirtualRegister dst = bytecode.m_dst;
     364    VirtualRegister src = bytecode.m_src;
     365
     366    emitGetVirtualRegister(src, regT0);
     367
     368    addSlowCase(branchIfNotCell(regT0));
     369    Jump done = branchIfSymbol(regT0);
     370    addSlowCase(branchIfNotString(regT0));
     371
     372    done.link(this);
     373    if (src != dst)
     374        emitPutVirtualRegister(dst);
     375}
     376
    360377void JIT::emit_op_set_function_name(const Instruction* currentInstruction)
    361378{
  • trunk/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp

    r254632 r254653  
    344344}
    345345
     346void JIT::emit_op_to_property_key(const Instruction* currentInstruction)
     347{
     348    auto bytecode = currentInstruction->as<OpToPropertyKey>();
     349    VirtualRegister dst = bytecode.m_dst;
     350    VirtualRegister src = bytecode.m_src;
     351
     352    emitLoad(src, regT1, regT0);
     353
     354    addSlowCase(branchIfNotCell(regT1));
     355    Jump done = branchIfSymbol(regT0);
     356    addSlowCase(branchIfNotString(regT0));
     357
     358    done.link(this);
     359    if (src != dst)
     360        emitStore(dst, regT1, regT0);
     361}
     362
    346363void JIT::emit_op_set_function_name(const Instruction* currentInstruction)
    347364{
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r254632 r254653  
    19601960
    19611961
     1962llintOpWithReturn(op_to_property_key, OpToPropertyKey, macro (size, get, dispatch, return)
     1963    get(m_src, t2)
     1964    loadConstantOrVariable(size, t2, t1, t0)
     1965    bineq t1, CellTag, .opToPropertyKeySlow
     1966    bbeq JSCell::m_type[t0], SymbolType, .done
     1967    bbneq JSCell::m_type[t0], StringType, .opToPropertyKeySlow
     1968
     1969.done:
     1970    return(t1, t0)
     1971
     1972.opToPropertyKeySlow:
     1973    callSlowPath(_slow_path_to_property_key)
     1974    dispatch()
     1975end)
     1976
     1977
    19621978commonOp(llint_op_catch, macro() end, macro (size)
    19631979    # This is where we end up from the JIT's throw trampoline (because the
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r254632 r254653  
    20992099
    21002100
     2101llintOpWithReturn(op_to_property_key, OpToPropertyKey, macro (size, get, dispatch, return)
     2102    get(m_src, t2)
     2103    loadConstantOrVariable(size, t2, t0)
     2104
     2105    btqnz t0, notCellMask, .opToPropertyKeySlow
     2106    bbeq JSCell::m_type[t0], SymbolType, .done
     2107    bbneq JSCell::m_type[t0], StringType, .opToPropertyKeySlow
     2108
     2109.done:
     2110    return(t0)
     2111
     2112.opToPropertyKeySlow:
     2113    callSlowPath(_slow_path_to_property_key)
     2114    dispatch()
     2115end)
     2116
     2117
    21012118commonOp(llint_op_catch, macro() end, macro (size)
    21022119    # This is where we end up from the JIT's throw trampoline (because the
  • trunk/Source/JavaScriptCore/parser/ASTBuilder.h

    r252032 r254653  
    406406    }
    407407
     408    DefineFieldNode* createDefineField(const JSTokenLocation& location, const Identifier* ident, ExpressionNode* initializer, DefineFieldNode::Type type)
     409    {
     410        return new (m_parserArena) DefineFieldNode(location, ident, initializer, type);
     411    }
     412
    408413    ClassExprNode* createClassExpr(const JSTokenLocation& location, const ParserClassInfo<ASTBuilder>& classInfo, VariableEnvironment& classEnvironment, ExpressionNode* constructor,
    409414        ExpressionNode* parentClass, PropertyListNode* classElements)
     
    528533    }
    529534    PropertyNode* createProperty(ExpressionNode* propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool, SuperBinding superBinding, ClassElementTag tag) { return new (m_parserArena) PropertyNode(propertyName, node, type, putType, superBinding, tag); }
     535    PropertyNode* createProperty(const Identifier* identifier, ExpressionNode* propertyName, ExpressionNode* node, PropertyNode::Type type, PropertyNode::PutType putType, bool, SuperBinding superBinding, ClassElementTag tag) { return new (m_parserArena) PropertyNode(*identifier, propertyName, node, type, putType, superBinding, tag); }
    530536    PropertyListNode* createPropertyList(const JSTokenLocation& location, PropertyNode* property) { return new (m_parserArena) PropertyListNode(location, property); }
    531537    PropertyListNode* createPropertyList(const JSTokenLocation& location, PropertyNode* property, PropertyListNode* tail) { return new (m_parserArena) PropertyListNode(location, property, tail); }
  • trunk/Source/JavaScriptCore/parser/NodeConstructors.h

    r252032 r254653  
    249249    inline PropertyNode::PropertyNode(const Identifier& name, ExpressionNode* assign, Type type, PutType putType, SuperBinding superBinding, ClassElementTag tag)
    250250        : m_name(&name)
     251        , m_expression(nullptr)
    251252        , m_assign(assign)
    252253        , m_type(type)
     
    260261    inline PropertyNode::PropertyNode(ExpressionNode* assign, Type type, PutType putType, SuperBinding superBinding, ClassElementTag tag)
    261262        : m_name(nullptr)
     263        , m_expression(nullptr)
    262264        , m_assign(assign)
    263265        , m_type(type)
     
    281283    }
    282284
     285    inline PropertyNode::PropertyNode(const Identifier& ident, ExpressionNode* name, ExpressionNode* assign, Type type, PutType putType, SuperBinding superBinding, ClassElementTag tag)
     286        : m_name(&ident)
     287        , m_expression(name)
     288        , m_assign(assign)
     289        , m_type(type)
     290        , m_needsSuperBinding(superBinding == SuperBinding::Needed)
     291        , m_putType(putType)
     292        , m_classElementTag(static_cast<unsigned>(tag))
     293        , m_isOverriddenByDuplicate(false)
     294    {
     295    }
     296
    283297    inline PropertyListNode::PropertyListNode(const JSTokenLocation& location, PropertyNode* node)
    284298        : ExpressionNode(location)
     
    9991013    }
    10001014
     1015    inline DefineFieldNode::DefineFieldNode(const JSTokenLocation& location, const Identifier* ident, ExpressionNode* assign, Type type)
     1016        : StatementNode(location)
     1017        , m_ident(ident)
     1018        , m_assign(assign)
     1019        , m_type(type)
     1020    {
     1021    }
     1022
    10011023    inline ClassDeclNode::ClassDeclNode(const JSTokenLocation& location, ExpressionNode* classDeclaration)
    10021024        : StatementNode(location)
     
    10141036        , m_classHeritage(classHeritage)
    10151037        , m_classElements(classElements)
     1038        , m_needsLexicalScope(!name.isNull() || PropertyListNode::shouldCreateLexicalScopeForClass(classElements))
    10161039    {
    10171040    }
  • trunk/Source/JavaScriptCore/parser/Nodes.cpp

    r253987 r254653  
    201201        , m_superBinding(static_cast<unsigned>(superBinding))
    202202        , m_constructorKind(static_cast<unsigned>(constructorKind))
     203        , m_needsClassFieldInitializer(static_cast<unsigned>(NeedsClassFieldInitializer::No))
    203204        , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression)
    204205        , m_parseMode(mode)
     
    224225        , m_superBinding(static_cast<unsigned>(superBinding))
    225226        , m_constructorKind(static_cast<unsigned>(constructorKind))
     227        , m_needsClassFieldInitializer(static_cast<unsigned>(NeedsClassFieldInitializer::No))
    226228        , m_isArrowFunctionBodyExpression(isArrowFunctionBodyExpression)
    227229        , m_parseMode(mode)
     
    329331}
    330332
     333// FIXME: calculate this feature once when parsing the property list.
     334// https://bugs.webkit.org/show_bug.cgi?id=206174
     335bool PropertyListNode::shouldCreateLexicalScopeForClass(PropertyListNode* list)
     336{
     337    while (list) {
     338        if (list->m_node->isComputedClassField())
     339            return true;
     340        list = list->m_next;
     341    }
     342    return false;
     343}
     344
     345// ------------------------------ ClassExprNode -----------------------------
     346
     347// FIXME: calculate this feature once when parsing the property list.
     348// https://bugs.webkit.org/show_bug.cgi?id=206174
     349bool PropertyListNode::hasInstanceFields() const
     350{
     351    for (auto list = this; list; list = list->m_next) {
     352        if (list->m_node->isInstanceClassField())
     353            return true;
     354    }
     355    return false;
     356}
     357
    331358VariableEnvironmentNode::VariableEnvironmentNode(VariableEnvironment& lexicalVariables)
    332359{
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r253987 r254653  
    252252        virtual bool isModuleDeclarationNode() const { return false; }
    253253        virtual bool isForOfNode() const { return false; }
     254        virtual bool isDefineFieldNode() const { return false; }
    254255
    255256    protected:
     
    719720        PropertyNode(ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
    720721        PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
     722        PropertyNode(const Identifier&, ExpressionNode* propertyName, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
    721723
    722724        ExpressionNode* expressionName() const { return m_expression; }
     
    728730        bool isStaticClassProperty() const { return static_cast<ClassElementTag>(m_classElementTag) == ClassElementTag::Static; }
    729731        bool isInstanceClassProperty() const { return static_cast<ClassElementTag>(m_classElementTag) == ClassElementTag::Instance; }
     732        bool isClassField() const { return isClassProperty() && !needsSuperBinding(); }
     733        bool isInstanceClassField() const { return isInstanceClassProperty() && !needsSuperBinding(); }
    730734        bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; }
     735        bool hasComputedName() const { return m_expression; }
     736        bool isComputedClassField() const { return isClassField() && hasComputedName(); }
    731737        void setIsOverriddenByDuplicate() { m_isOverriddenByDuplicate = true; }
    732738        PutType putType() const { return static_cast<PutType>(m_putType); }
     
    742748        static_assert(1 << 2 > static_cast<unsigned>(ClassElementTag::LastTag), "ClassElementTag shouldn't use more than two bits");
    743749        unsigned m_classElementTag : 2;
    744         unsigned m_isOverriddenByDuplicate: 1;
     750        unsigned m_isOverriddenByDuplicate : 1;
    745751    };
    746752
     
    751757
    752758        bool hasStaticallyNamedProperty(const Identifier& propName);
    753 
    754         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*);
     759        bool isComputedClassField() const
     760        {
     761            return m_node->isComputedClassField();
     762        }
     763        bool isInstanceClassField() const
     764        {
     765            return m_node->isInstanceClassField();
     766        }
     767        bool hasInstanceFields() const;
     768
     769        static bool shouldCreateLexicalScopeForClass(PropertyListNode*);
     770
     771        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>*);
    755772
    756773    private:
    757774        RegisterID* emitBytecode(BytecodeGenerator& generator, RegisterID* dst = nullptr) override
    758775        {
    759             return emitBytecode(generator, dst, nullptr);
     776            return emitBytecode(generator, dst, nullptr, nullptr);
    760777        }
    761778        void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&);
     779        void emitSaveComputedFieldName(BytecodeGenerator&, PropertyNode&);
    762780
    763781        PropertyNode* m_node;
     
    20752093        SuperBinding superBinding() { return static_cast<SuperBinding>(m_superBinding); }
    20762094        ConstructorKind constructorKind() { return static_cast<ConstructorKind>(m_constructorKind); }
     2095        bool isConstructorAndNeedsClassFieldInitializer() const { return m_needsClassFieldInitializer; }
     2096        void setNeedsClassFieldInitializer(bool value)
     2097        {
     2098            ASSERT(!value || constructorKind() != ConstructorKind::None);
     2099            m_needsClassFieldInitializer = value;
     2100        }
    20772101        bool isArrowFunctionBodyExpression() const { return m_isArrowFunctionBodyExpression; }
    20782102
     
    20952119        unsigned m_superBinding : 1;
    20962120        unsigned m_constructorKind : 2;
     2121        unsigned m_needsClassFieldInitializer : 1;
    20972122        unsigned m_isArrowFunctionBodyExpression : 1;
    20982123        SourceParseMode m_parseMode;
     
    22112236    };
    22122237
     2238    class DefineFieldNode final : public StatementNode {
     2239    public:
     2240        enum class Type { Name, ComputedName };
     2241        DefineFieldNode(const JSTokenLocation&, const Identifier*, ExpressionNode*, Type);
     2242
     2243    private:
     2244        void emitBytecode(BytecodeGenerator&, RegisterID* destination = nullptr) override;
     2245
     2246        bool isDefineFieldNode() const override { return true; }
     2247
     2248        const Identifier* m_ident;
     2249        ExpressionNode* m_assign;
     2250        Type m_type;
     2251    };
     2252
    22132253    class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode {
    22142254        JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ClassExprNode);
     
    22232263
    22242264        bool hasStaticProperty(const Identifier& propName) { return m_classElements ? m_classElements->hasStaticallyNamedProperty(propName) : false; }
     2265        bool hasInstanceFields() const { return m_classElements ? m_classElements->hasInstanceFields() : false; }
    22252266
    22262267    private:
     
    22352276        ExpressionNode* m_classHeritage;
    22362277        PropertyListNode* m_classElements;
     2278        bool m_needsLexicalScope;
    22372279    };
    22382280
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r251684 r254653  
    209209
    210210template <typename LexerType>
    211 String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition)
     211String Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* instanceFieldLocations)
    212212{
    213213    String parseError = String();
     
    223223        if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
    224224            m_parameters = createGeneratorParameters(context, functionInfo.parameterCount);
     225        else if (parseMode == SourceParseMode::InstanceFieldInitializerMode)
     226            m_parameters = context.createFormalParameterList();
    225227        else
    226228            m_parameters = parseFunctionParameters(context, parseMode, functionInfo);
     
    255257        else if (parsingContext == ParsingContext::FunctionConstructor)
    256258            sourceElements = parseSingleFunction(context, functionConstructorParametersEndPosition);
    257         else
     259        else if (parseMode == SourceParseMode::InstanceFieldInitializerMode) {
     260            ASSERT(instanceFieldLocations && !instanceFieldLocations->isEmpty());
     261            sourceElements = parseInstanceFieldInitializerSourceElements(context, *instanceFieldLocations);
     262        } else
    258263            sourceElements = parseSourceElements(context, CheckForStrictMode);
    259264    }
     
    21142119    ConstructorKind constructorKind, SuperBinding superBinding, FunctionBodyType bodyType, unsigned parameterCount, SourceParseMode parseMode)
    21152120{
     2121    SetForScope<bool> overrideParsingClassFieldInitializer(m_parserState.isParsingClassFieldInitializer, bodyType == StandardFunctionBodyBlock ? false : m_parserState.isParsingClassFieldInitializer);
    21162122    bool isArrowFunctionBodyExpression = bodyType == ArrowFunctionBodyExpression;
    21172123    if (!isArrowFunctionBodyExpression) {
     
    21662172    case SourceParseMode::ModuleAnalyzeMode:
    21672173    case SourceParseMode::ModuleEvaluateMode:
     2174    case SourceParseMode::InstanceFieldInitializerMode:
    21682175        RELEASE_ASSERT_NOT_REACHED();
    21692176        return "";
     
    22072214    case SourceParseMode::ModuleAnalyzeMode:
    22082215    case SourceParseMode::ModuleEvaluateMode:
     2216    case SourceParseMode::InstanceFieldInitializerMode:
    22092217        RELEASE_ASSERT_NOT_REACHED();
    22102218        return "";
     
    28542862        failIfFalse(parentClass, "Cannot parse the parent class name");
    28552863    }
     2864    classScope->setIsClassScope();
    28562865    const ConstructorKind constructorKind = parentClass ? ConstructorKind::Extends : ConstructorKind::Base;
    28572866
     
    28612870    TreePropertyList classElements = 0;
    28622871    TreePropertyList classElementsTail = 0;
     2872    unsigned numComputedFields = 0;
    28632873    while (!match(CLOSEBRACE)) {
    28642874        if (match(SEMICOLON)) {
     
    28722882        // For backwards compatibility, "static" is a non-reserved keyword in non-strict mode.
    28732883        ClassElementTag tag = ClassElementTag::Instance;
     2884        auto type = PropertyNode::Constant;
    28742885        if (match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm.propertyNames->staticKeyword) {
    28752886            SavePoint savePoint = createSavePoint();
     
    29052916                    ident = m_token.m_data.ident;
    29062917                    next();
    2907                     if (match(OPENPAREN) || match(COLON) || match(EQUAL) || m_lexer->hasLineTerminatorBeforeToken())
     2918                    // We match SEMICOLON as a special case for a field called 'async' without initializer.
     2919                    if (match(OPENPAREN) || match(COLON) || match(SEMICOLON) || match(EQUAL) || m_lexer->hasLineTerminatorBeforeToken())
    29082920                        break;
    29092921                    if (UNLIKELY(consume(TIMES)))
     
    29332945            next();
    29342946            computedPropertyName = parseAssignmentExpression(context);
     2947            type = static_cast<PropertyNode::Type>(type | PropertyNode::Computed);
    29352948            failIfFalse(computedPropertyName, "Cannot parse computed property name");
    29362949            handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
     
    29452958        const bool alwaysStrictInsideClass = true;
    29462959        if (isGetter || isSetter) {
    2947             property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter,
    2948                 methodStart, ConstructorKind::None, tag);
     2960            type = static_cast<PropertyNode::Type>(type & ~PropertyNode::Constant);
     2961            type = static_cast<PropertyNode::Type>(type | (isGetter ? PropertyNode::Getter : PropertyNode::Setter));
     2962            property = parseGetterSetter(context, alwaysStrictInsideClass, type, methodStart, ConstructorKind::None, tag);
    29492963            failIfFalse(property, "Cannot parse this method");
     2964        } else if (Options::useClassFields() && !match(OPENPAREN) && tag == ClassElementTag::Instance && parseMode == SourceParseMode::MethodMode) {
     2965            ASSERT(!isGetter && !isSetter);
     2966            if (ident)
     2967                semanticFailIfTrue(*ident == propertyNames.constructor, "Cannot declare class field named 'constructor'");
     2968
     2969            if (computedPropertyName) {
     2970                ident = &m_parserArena.identifierArena().makeNumericIdentifier(m_vm, numComputedFields++);
     2971                DeclarationResultMask declarationResult = classScope->declareLexicalVariable(ident, true);
     2972                ASSERT_UNUSED(declarationResult, declarationResult == DeclarationResult::Valid);
     2973                classScope->useVariable(ident, false);
     2974                classScope->addClosedVariableCandidateUnconditionally(ident->impl());
     2975            }
     2976
     2977            TreeExpression initializer = 0;
     2978            if (consume(EQUAL)) {
     2979                SetForScope<bool> overrideParsingClassFieldInitializer(m_parserState.isParsingClassFieldInitializer, true);
     2980                classScope->setExpectedSuperBinding(SuperBinding::Needed);
     2981                initializer = parseAssignmentExpression(context);
     2982                classScope->setExpectedSuperBinding(SuperBinding::NotNeeded);
     2983                failIfFalse(initializer, "Cannot parse initializer for class field");
     2984                classScope->markLastUsedVariablesSetAsCaptured();
     2985            }
     2986            failIfFalse(autoSemiColon(), "Expected a ';' following a class field");
     2987            auto inferName = initializer ? InferName::Allowed : InferName::Disallowed;
     2988            if (computedPropertyName)
     2989                property = context.createProperty(ident, computedPropertyName, initializer, type, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::NotNeeded, tag);
     2990            else
     2991                property = context.createProperty(ident, initializer, type, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::NotNeeded, inferName, tag);
    29502992        } else {
    29512993            ParserFunctionInfo<TreeBuilder> methodInfo;
     
    29723014
    29733015            if (computedPropertyName) {
    2974                 property = context.createProperty(computedPropertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed),
    2975                     PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, tag);
     3016                property = context.createProperty(computedPropertyName, method, type, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, tag);
    29763017            } else {
    2977                 property = context.createProperty(methodInfo.name, method, PropertyNode::Constant,
    2978                     PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, InferName::Allowed, tag);
     3018                property = context.createProperty(methodInfo.name, method, type, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed, InferName::Allowed, tag);
    29793019            }
    29803020        }
     
    29923032    popScope(classScope, TreeBuilder::NeedsFreeVariableInfo);
    29933033    return classExpression;
     3034}
     3035
     3036template <typename LexerType>
     3037template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseInstanceFieldInitializerSourceElements(TreeBuilder& context, const Vector<JSTextPosition>& instanceFieldLocations)
     3038{
     3039    TreeSourceElements sourceElements = context.createSourceElements();
     3040    currentScope()->setIsClassScope();
     3041
     3042    unsigned numComputedFields = 0;
     3043    for (auto location : instanceFieldLocations) {
     3044        // We don't need to worry about hasLineTerminatorBeforeToken
     3045        // on class fields, so we set this value to false.
     3046        LexerState lexerState { location.offset, static_cast<unsigned>(location.lineStartOffset), static_cast<unsigned>(location.line), static_cast<unsigned>(location.line), false };
     3047        restoreLexerState(lexerState);
     3048
     3049        JSTokenLocation fieldLocation = tokenLocation();
     3050        const Identifier* ident = nullptr;
     3051        TreeExpression computedPropertyName = 0;
     3052        DefineFieldNode::Type type = DefineFieldNode::Type::Name;
     3053        switch (m_token.m_type) {
     3054        case STRING:
     3055        case IDENT:
     3056        namedKeyword:
     3057            ident = m_token.m_data.ident;
     3058            ASSERT(ident);
     3059            next();
     3060            break;
     3061        case DOUBLE:
     3062        case INTEGER:
     3063            ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM&>(m_vm), m_token.m_data.doubleValue);
     3064            ASSERT(ident);
     3065            next();
     3066            break;
     3067        case OPENBRACKET:
     3068            next();
     3069            computedPropertyName = parseAssignmentExpression(context);
     3070            failIfFalse(computedPropertyName, "Cannot parse computed property name");
     3071            handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
     3072            ident = &m_parserArena.identifierArena().makeNumericIdentifier(m_vm, numComputedFields++);
     3073            type = DefineFieldNode::Type::ComputedName;
     3074            break;
     3075        default:
     3076            if (m_token.m_type & KeywordTokenFlag)
     3077                goto namedKeyword;
     3078            failDueToUnexpectedToken();
     3079        }
     3080
     3081        // Only valid class fields are handled in this function.
     3082        ASSERT(match(EQUAL) || match(SEMICOLON) || match(CLOSEBRACE) || m_lexer->hasLineTerminatorBeforeToken());
     3083
     3084        TreeExpression initializer = 0;
     3085        if (consume(EQUAL))
     3086            initializer = parseAssignmentExpression(context);
     3087
     3088        TreeStatement defineField = context.createDefineField(fieldLocation, ident, initializer, type);
     3089        context.appendStatement(sourceElements, defineField);
     3090    }
     3091
     3092    ASSERT(!hasError());
     3093    // Trick parseInner() into believing we've parsed the entire SourceCode, in order to prevent it from producing an error.
     3094    m_token.m_type = EOFTOK;
     3095    return sourceElements;
    29943096}
    29953097
     
    44854587            return createResolveAndUseVariable(context, ident, isEval, start, location);
    44864588        }
     4589        if (UNLIKELY(m_parserState.isParsingClassFieldInitializer))
     4590            failIfTrue(*m_token.m_data.ident == m_vm.propertyNames->arguments, "Cannot reference 'arguments' in class field initializer");
    44874591    identifierExpression:
    44884592        JSTextPosition start = tokenStartPosition();
    44894593        const Identifier* ident = m_token.m_data.ident;
     4594        if (UNLIKELY(currentScope()->evalContextType() == EvalContextType::InstanceFieldEvalContext))
     4595            failIfTrue(*ident == m_vm.propertyNames->arguments, "arguments is not valid in this context");
    44904596        JSTokenLocation location(tokenLocation());
    44914597        next();
     
    46824788        if (matchContextualKeyword(m_vm.propertyNames->target)) {
    46834789            ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
    4684             semanticFailIfFalse(currentScope()->isFunction() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is only valid inside functions");
     4790            ScopeRef classScope = closestClassScopeOrTopLevelScope();
     4791            bool isClassFieldInitializer = classScope.index() > closestOrdinaryFunctionScope.index();
     4792            bool isFunctionEvalContextType = closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::InstanceFieldEvalContext;
     4793            semanticFailIfFalse(currentScope()->isFunction() || isFunctionEvalContextType || isClassFieldInitializer, "new.target is only valid inside functions");
    46854794            baseIsNewTarget = true;
    46864795            if (currentScope()->isArrowFunction()) {
    4687                 semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || closestOrdinaryFunctionScope->evalContextType() == EvalContextType::FunctionEvalContext, "new.target is not valid inside arrow functions in global code");
     4796                semanticFailIfFalse(!closestOrdinaryFunctionScope->isGlobalCodeScope() || isFunctionEvalContextType || isClassFieldInitializer, "new.target is not valid inside arrow functions in global code");
    46884797                currentScope()->setInnerArrowFunctionUsesNewTarget();
    46894798            }
     
    47024811    if (baseIsSuper) {
    47034812        ScopeRef closestOrdinaryFunctionScope = closestParentOrdinaryFunctionNonLexicalScope();
    4704         semanticFailIfFalse(currentScope()->isFunction() || (closestOrdinaryFunctionScope->isEvalContext() && closestOrdinaryFunctionScope->expectedSuperBinding() == SuperBinding::Needed), "super is not valid in this context");
     4813        ScopeRef classScope = closestClassScopeOrTopLevelScope();
     4814        bool isClassFieldInitializer = classScope.index() > closestOrdinaryFunctionScope.index();
     4815        semanticFailIfFalse(currentScope()->isFunction() || isClassFieldInitializer || (closestOrdinaryFunctionScope->isEvalContext() && closestOrdinaryFunctionScope->expectedSuperBinding() == SuperBinding::Needed), "super is not valid in this context");
    47054816        base = context.createSuperExpr(location);
    47064817        next();
     4818        failIfTrue(match(OPENPAREN) && currentScope()->evalContextType() == EvalContextType::InstanceFieldEvalContext, "super call is not valid in this context");
    47074819        ScopeRef functionScope = currentFunctionScope();
    47084820        if (!functionScope->setNeedsSuperBinding()) {
     
    47144826                    ? functionScope->expectedSuperBinding()
    47154827                    : closestOrdinaryFunctionScope->expectedSuperBinding();
    4716                 semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded, "super is not valid in this context");
     4828                semanticFailIfTrue(functionSuperBinding == SuperBinding::NotNeeded && !isClassFieldInitializer, "super is not valid in this context");
    47174829            }
    47184830        }
     
    47954907            }
    47964908            case OPENPAREN: {
     4909                if (baseIsSuper)
     4910                    failIfTrue(m_parserState.isParsingClassFieldInitializer, "super call is not valid in class field initializer context");
    47974911                m_parserState.nonTrivialExpressionCount++;
    47984912                int nonLHSCount = m_parserState.nonLHSCount;
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r251684 r254653  
    182182        , m_isEvalContext(false)
    183183        , m_hasNonSimpleParameterList(false)
     184        , m_isClassScope(false)
    184185        , m_evalContextType(EvalContextType::None)
    185186        , m_constructorKind(static_cast<unsigned>(ConstructorKind::None))
     
    259260        case SourceParseMode::SetterMode:
    260261        case SourceParseMode::MethodMode:
     262        case SourceParseMode::InstanceFieldInitializerMode:
    261263            setIsFunction();
    262264            break;
     
    288290    bool isAsyncFunction() const { return m_isAsyncFunction; }
    289291    bool isAsyncFunctionBoundary() const { return m_isAsyncFunctionBoundary; }
     292    bool isClassScope() const { return m_isClassScope; }
    290293
    291294    bool hasArguments() const { return m_hasArguments; }
     
    302305        m_allowsLexicalDeclarations = true;
    303306    }
     307
     308    void setIsClassScope()
     309    {
     310        m_isClassScope = true;
     311    }
     312
    304313    bool isLexicalScope() { return m_isLexicalScope; }
    305314    bool usesEval() { return m_usesEval; }
     
    581590    {
    582591        m_closedVariableCandidates.add(impl);
     592    }
     593
     594    void markLastUsedVariablesSetAsCaptured()
     595    {
     596        for (UniquedStringImpl* impl : m_usedVariables.last())
     597            m_closedVariableCandidates.add(impl);
    583598    }
    584599   
     
    820835    bool m_isEvalContext;
    821836    bool m_hasNonSimpleParameterList;
     837    bool m_isClassScope;
    822838    EvalContextType m_evalContextType;
    823839    unsigned m_constructorKind;
     
    890906
    891907    template <class ParsedNode>
    892     std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt);
     908    std::unique_ptr<ParsedNode> parse(ParserError&, const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt, const Vector<JSTextPosition>* = nullptr);
    893909
    894910    JSTextPosition positionBeforeLastNewline() const { return m_lexer->positionBeforeLastNewline(); }
     
    11721188        return ScopeRef(&m_scopeStack, i);
    11731189    }
    1174    
     1190
     1191    ScopeRef closestClassScopeOrTopLevelScope()
     1192    {
     1193        unsigned i = m_scopeStack.size() - 1;
     1194        ASSERT(i < m_scopeStack.size());
     1195        while (i && !m_scopeStack[i].isClassScope())
     1196            i--;
     1197        return ScopeRef(&m_scopeStack, i);
     1198    }
     1199
    11751200    ScopeRef pushScope()
    11761201    {
     
    13481373    Parser();
    13491374
    1350     String parseInner(const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt);
     1375    String parseInner(const Identifier&, SourceParseMode, ParsingContext, Optional<int> functionConstructorParametersEndPosition = WTF::nullopt, const Vector<JSTextPosition>* = nullptr);
    13511376
    13521377    void didFinishParsing(SourceElements*, DeclarationStacks::FunctionStack&&, VariableEnvironment&, UniquedStringImplPtrSet&&, CodeFeatures, int);
     
    15771602    template <class TreeBuilder> TreeSourceElements parseAsyncGeneratorFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
    15781603    template <class TreeBuilder> TreeSourceElements parseSingleFunction(TreeBuilder&, Optional<int> functionConstructorParametersEndPosition);
     1604    template <class TreeBuilder> TreeSourceElements parseInstanceFieldInitializerSourceElements(TreeBuilder&, const Vector<JSTextPosition>&);
    15791605    template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
    15801606    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
     
    17631789        const Identifier* lastFunctionName { nullptr };
    17641790        bool allowAwait { true };
     1791        bool isParsingClassFieldInitializer { false };
    17651792    };
    17661793
     
    19031930template <typename LexerType>
    19041931template <class ParsedNode>
    1905 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition)
     1932std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* instanceFieldLocations)
    19061933{
    19071934    int errLine;
     
    19201947    unsigned startColumn = m_source->startColumn().zeroBasedInt();
    19211948
    1922     String parseError = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition);
     1949    String parseError = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, instanceFieldLocations);
    19231950
    19241951    int lineNumber = m_lexer->lineNumber();
     
    20042031    DerivedContextType derivedContextType = DerivedContextType::None,
    20052032    EvalContextType evalContextType = EvalContextType::None,
    2006     DebuggerParseData* debuggerParseData = nullptr)
     2033    DebuggerParseData* debuggerParseData = nullptr,
     2034    const Vector<JSTextPosition>* instanceFieldLocations = nullptr)
    20072035{
    20082036    ASSERT(!source.provider()->source().isNull());
     
    20152043    if (source.provider()->source().is8Bit()) {
    20162044        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    2017         result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
     2045        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, instanceFieldLocations);
    20182046        if (positionBeforeLastNewline)
    20192047            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     
    20282056        ASSERT_WITH_MESSAGE(defaultConstructorKindForTopLevelFunction == ConstructorKind::None, "BuiltinExecutables's special constructors should always use a 8-bit string");
    20292057        Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData);
    2030         result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program);
     2058        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, instanceFieldLocations);
    20312059        if (positionBeforeLastNewline)
    20322060            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
  • trunk/Source/JavaScriptCore/parser/ParserModes.h

    r249509 r254653  
    6767    AsyncGeneratorWrapperMethodMode   = 17,
    6868    GeneratorWrapperMethodMode        = 18,
     69    InstanceFieldInitializerMode      = 19,
    6970};
    7071
     
    115116        SourceParseMode::AsyncGeneratorBodyMode,
    116117        SourceParseMode::AsyncGeneratorWrapperFunctionMode,
    117         SourceParseMode::AsyncGeneratorWrapperMethodMode).contains(parseMode);
     118        SourceParseMode::AsyncGeneratorWrapperMethodMode,
     119        SourceParseMode::InstanceFieldInitializerMode).contains(parseMode);
    118120}
    119121
  • trunk/Source/JavaScriptCore/parser/SyntaxChecker.h

    r251684 r254653  
    237237        return Property(type);
    238238    }
     239    Property createProperty(const Identifier*, int, int, PropertyNode::Type type, PropertyNode::PutType, bool, SuperBinding, ClassElementTag)
     240    {
     241        return Property(type);
     242    }
    239243    int createPropertyList(const JSTokenLocation&, Property) { return PropertyListResult; }
    240244    int createPropertyList(const JSTokenLocation&, Property, int) { return PropertyListResult; }
     
    248252    int createClauseList(int, int) { return ClauseListResult; }
    249253    int createFuncDeclStatement(const JSTokenLocation&, const ParserFunctionInfo<SyntaxChecker>&) { return StatementResult; }
     254    int createDefineField(const JSTokenLocation&, const Identifier*, int, DefineFieldNode::Type) { return 0; }
    250255    int createClassDeclStatement(const JSTokenLocation&, ClassExpression,
    251256        const JSTextPosition&, const JSTextPosition&, int, int) { return StatementResult; }
  • trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp

    r254632 r254653  
    938938        m_bitVectors.encode(encoder, rareData.m_bitVectors);
    939939        m_constantIdentifierSets.encode(encoder, rareData.m_constantIdentifierSets);
     940        m_needsClassFieldInitializer = rareData.m_needsClassFieldInitializer;
    940941    }
    941942
     
    951952        m_bitVectors.decode(decoder, rareData->m_bitVectors);
    952953        m_constantIdentifierSets.decode(decoder, rareData->m_constantIdentifierSets);
     954        rareData->m_needsClassFieldInitializer = m_needsClassFieldInitializer;
    953955        return rareData;
    954956    }
     
    963965    CachedVector<CachedBitVector> m_bitVectors;
    964966    CachedVector<CachedConstantIdentifierSetEntry> m_constantIdentifierSets;
     967    unsigned m_needsClassFieldInitializer : 1;
    965968};
    966969
     
    17021705    unsigned superBinding() const { return m_superBinding; }
    17031706    unsigned derivedContextType() const { return m_derivedContextType; }
     1707    unsigned needsClassFieldInitializer() const { return m_needsClassFieldInitializer; }
    17041708
    17051709    Identifier name(Decoder& decoder) const { return m_name.decode(decoder); }
     
    17351739    unsigned m_functionMode : 2; // FunctionMode
    17361740    unsigned m_derivedContextType: 2;
     1741    unsigned m_needsClassFieldInitializer : 1;
    17371742
    17381743    CachedPtr<CachedFunctionExecutableRareData> m_rareData;
     
    17871792    unsigned constructorKind() const { return m_constructorKind; }
    17881793    unsigned derivedContextType() const { return m_derivedContextType; }
     1794    unsigned needsClassFieldInitializer() const { return m_needsClassFieldInitializer; }
    17891795    unsigned evalContextType() const { return m_evalContextType; }
    17901796    unsigned hasTailCalls() const { return m_hasTailCalls; }
     
    18181824    unsigned m_constructorKind : 2;
    18191825    unsigned m_derivedContextType : 2;
     1826    unsigned m_needsClassFieldInitializer : 1;
    18201827    unsigned m_evalContextType : 2;
    18211828    unsigned m_hasTailCalls : 1;
     
    20962103    m_superBinding = executable.m_superBinding;
    20972104    m_derivedContextType = executable.m_derivedContextType;
     2105    m_needsClassFieldInitializer = executable.m_needsClassFieldInitializer;
    20982106
    20992107    m_rareData.encode(encoder, executable.m_rareData.get());
     
    21432151    , m_derivedContextType(cachedExecutable.derivedContextType())
    21442152    , m_isGeneratedFromCache(true)
     2153    , m_needsClassFieldInitializer(cachedExecutable.needsClassFieldInitializer())
    21452154    , m_unlinkedCodeBlockForCall()
    21462155    , m_unlinkedCodeBlockForConstruct()
  • trunk/Source/JavaScriptCore/runtime/CodeCache.cpp

    r251263 r254653  
    150150    // in the global lexical environment, which we always TDZ check accesses from.
    151151    ConstructAbility constructAbility = constructAbilityForParseMode(metadata->parseMode());
    152     UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None);
     152    UnlinkedFunctionExecutable* functionExecutable = UnlinkedFunctionExecutable::create(vm, source, metadata, UnlinkedNormalFunction, constructAbility, JSParserScriptMode::Classic, WTF::nullopt, DerivedContextType::None, NeedsClassFieldInitializer::No);
    153153
    154154    if (!source.provider()->sourceURLDirective().isNull())
  • trunk/Source/JavaScriptCore/runtime/CodeCache.h

    r251263 r254653  
    280280    bool usesEval = rootNode->features() & EvalFeature;
    281281    bool isStrictMode = rootNode->features() & StrictModeFeature;
    282     ExecutableInfo executableInfo(usesEval, isStrictMode, false, false, ConstructorKind::None, scriptMode, SuperBinding::NotNeeded, CacheTypes<UnlinkedCodeBlockType>::parseMode, derivedContextType, isArrowFunctionContext, false, evalContextType);
     282    NeedsClassFieldInitializer needsClassFieldInitializer = NeedsClassFieldInitializer::No;
     283    if constexpr (std::is_same_v<ExecutableType, DirectEvalExecutable>)
     284        needsClassFieldInitializer = executable->needsClassFieldInitializer();
     285    ExecutableInfo executableInfo(usesEval, isStrictMode, false, false, ConstructorKind::None, scriptMode, SuperBinding::NotNeeded, CacheTypes<UnlinkedCodeBlockType>::parseMode, derivedContextType, needsClassFieldInitializer, isArrowFunctionContext, false, evalContextType);
    283286
    284287    UnlinkedCodeBlockType* unlinkedCodeBlock = UnlinkedCodeBlockType::create(vm, executableInfo, codeGenerationMode);
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.cpp

    r254632 r254653  
    10161016}
    10171017
     1018SLOW_PATH_DECL(slow_path_to_property_key)
     1019{
     1020    BEGIN();
     1021    auto bytecode = pc->as<OpToPropertyKey>();
     1022    RETURN(GET_C(bytecode.m_src).jsValue().toPropertyKeyValue(globalObject));
     1023}
     1024
    10181025SLOW_PATH_DECL(slow_path_get_enumerable_length)
    10191026{
  • trunk/Source/JavaScriptCore/runtime/CommonSlowPaths.h

    r253867 r254653  
    368368SLOW_PATH_HIDDEN_DECL(slow_path_strcat);
    369369SLOW_PATH_HIDDEN_DECL(slow_path_to_primitive);
     370SLOW_PATH_HIDDEN_DECL(slow_path_to_property_key);
    370371SLOW_PATH_HIDDEN_DECL(slow_path_get_enumerable_length);
    371372SLOW_PATH_HIDDEN_DECL(slow_path_has_generic_property);
  • trunk/Source/JavaScriptCore/runtime/DirectEvalExecutable.cpp

    r251425 r254653  
    3636namespace JSC {
    3737
    38 DirectEvalExecutable* DirectEvalExecutable::create(JSGlobalObject* globalObject, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
     38DirectEvalExecutable* DirectEvalExecutable::create(JSGlobalObject* globalObject, const SourceCode& source, bool isInStrictContext, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isArrowFunctionContext, EvalContextType evalContextType, const VariableEnvironment* variablesUnderTDZ)
    3939{
    4040    VM& vm = globalObject->vm();
     
    4646    }
    4747
    48     auto* executable = new (NotNull, allocateCell<DirectEvalExecutable>(vm.heap)) DirectEvalExecutable(globalObject, source, isInStrictContext, derivedContextType, isArrowFunctionContext, evalContextType);
     48    auto* executable = new (NotNull, allocateCell<DirectEvalExecutable>(vm.heap)) DirectEvalExecutable(globalObject, source, isInStrictContext, derivedContextType, needsClassFieldInitializer, isArrowFunctionContext, evalContextType);
    4949    executable->finishCreation(vm);
    5050
     
    7070}
    7171
    72 DirectEvalExecutable::DirectEvalExecutable(JSGlobalObject* globalObject, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext, EvalContextType evalContextType)
    73     : EvalExecutable(globalObject, source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType)
     72DirectEvalExecutable::DirectEvalExecutable(JSGlobalObject* globalObject, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, NeedsClassFieldInitializer needsClassFieldInitializer, bool isArrowFunctionContext, EvalContextType evalContextType)
     73    : EvalExecutable(globalObject, source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType, needsClassFieldInitializer)
    7474{
     75    ASSERT(needsClassFieldInitializer == NeedsClassFieldInitializer::No || derivedContextType == DerivedContextType::DerivedConstructorContext);
    7576}
    7677
  • trunk/Source/JavaScriptCore/runtime/DirectEvalExecutable.h

    r251425 r254653  
    3232class DirectEvalExecutable final : public EvalExecutable {
    3333public:
    34     static DirectEvalExecutable* create(JSGlobalObject*, const SourceCode&, bool isInStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*);
     34    static DirectEvalExecutable* create(JSGlobalObject*, const SourceCode&, bool isInStrictContext, DerivedContextType, NeedsClassFieldInitializer, bool isArrowFunctionContext, EvalContextType, const VariableEnvironment*);
    3535private:
    36     DirectEvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType);
     36    DirectEvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, NeedsClassFieldInitializer, bool isArrowFunctionContext, EvalContextType);
    3737};
    3838
  • trunk/Source/JavaScriptCore/runtime/EvalExecutable.cpp

    r251425 r254653  
    3434const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(EvalExecutable) };
    3535
    36 EvalExecutable::EvalExecutable(JSGlobalObject* globalObject, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext, EvalContextType evalContextType)
     36EvalExecutable::EvalExecutable(JSGlobalObject* globalObject, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext, EvalContextType evalContextType, NeedsClassFieldInitializer needsClassFieldInitializer)
    3737    : Base(globalObject->vm().evalExecutableStructure.get(), globalObject->vm(), source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType, NoIntrinsic)
     38    , m_needsClassFieldInitializer(static_cast<unsigned>(needsClassFieldInitializer))
    3839{
    3940    ASSERT(source.provider()->sourceType() == SourceProviderSourceType::Program);
  • trunk/Source/JavaScriptCore/runtime/EvalExecutable.h

    r251425 r254653  
    6363    DECLARE_INFO;
    6464
    65     ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext(), false, evalContextType()); }
     65    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), needsClassFieldInitializer(), isArrowFunctionContext(), false, evalContextType()); }
    6666
    6767    unsigned numVariables() { return m_unlinkedEvalCodeBlock->numVariables(); }
     
    6969    unsigned numTopLevelFunctionDecls() { return m_unlinkedEvalCodeBlock->numberOfFunctionDecls(); }
    7070    bool allowDirectEvalCache() const { return m_unlinkedEvalCodeBlock->allowDirectEvalCache(); }
    71 
     71    NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
    7272    TemplateObjectMap& ensureTemplateObjectMap(VM&);
    7373
     
    7777
    7878    using Base::finishCreation;
    79     EvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType);
     79    EvalExecutable(JSGlobalObject*, const SourceCode&, bool inStrictContext, DerivedContextType, bool isArrowFunctionContext, EvalContextType, NeedsClassFieldInitializer);
    8080
    8181    static void visitChildren(JSCell*, SlotVisitor&);
     82
     83    unsigned m_needsClassFieldInitializer : 1;
    8284
    8385    WriteBarrier<ExecutableToCodeBlockEdge> m_evalCodeBlock;
  • trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp

    r252520 r254653  
    114114
    115115        case SourceParseMode::ArrowFunctionMode:
     116        case SourceParseMode::InstanceFieldInitializerMode:
    116117            functionHeader = "";
    117118            break;
  • trunk/Source/JavaScriptCore/runtime/IndirectEvalExecutable.cpp

    r251425 r254653  
    7070
    7171IndirectEvalExecutable::IndirectEvalExecutable(JSGlobalObject* globalObject, const SourceCode& source, bool inStrictContext, DerivedContextType derivedContextType, bool isArrowFunctionContext, EvalContextType evalContextType)
    72     : EvalExecutable(globalObject, source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType)
     72    : EvalExecutable(globalObject, source, inStrictContext, derivedContextType, isArrowFunctionContext, evalContextType, NeedsClassFieldInitializer::No)
    7373{
    7474}
  • trunk/Source/JavaScriptCore/runtime/JSCJSValue.h

    r252032 r254653  
    274274    JSString* toStringOrNull(JSGlobalObject*) const; // On exception, this returns null, to make exception checks faster.
    275275    Identifier toPropertyKey(JSGlobalObject*) const;
     276    JSValue toPropertyKeyValue(JSGlobalObject*) const;
    276277    WTF::String toWTFString(JSGlobalObject*) const;
    277278    JSObject* toObject(JSGlobalObject*) const;
  • trunk/Source/JavaScriptCore/runtime/JSCJSValueInlines.h

    r251425 r254653  
    692692}
    693693
     694ALWAYS_INLINE JSValue JSValue::toPropertyKeyValue(JSGlobalObject* globalObject) const
     695{
     696    VM& vm = getVM(globalObject);
     697    auto scope = DECLARE_THROW_SCOPE(vm);
     698
     699    if (isString() || isSymbol())
     700        return *this;
     701
     702    JSValue primitive = toPrimitive(globalObject, PreferString);
     703    RETURN_IF_EXCEPTION(scope, JSValue());
     704    if (primitive.isSymbol())
     705        return primitive;
     706
     707    RELEASE_AND_RETURN(scope, primitive.toString(globalObject));
     708}
     709
    694710inline JSValue JSValue::toPrimitive(JSGlobalObject* globalObject, PreferredPrimitiveType preferredType) const
    695711{
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r254087 r254653  
    430430    case SourceParseMode::AsyncGeneratorWrapperMethodMode:
    431431    case SourceParseMode::GeneratorWrapperMethodMode:
     432    case SourceParseMode::InstanceFieldInitializerMode:
    432433        if (!function->jsExecutable()->isStrictMode())
    433434            return JSValue::encode(caller);
  • trunk/Source/JavaScriptCore/runtime/ModuleProgramExecutable.h

    r251425 r254653  
    6464    DECLARE_INFO;
    6565
    66     ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Module, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), isArrowFunctionContext(), false, EvalContextType::None); }
     66    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Module, SuperBinding::NotNeeded, SourceParseMode::ModuleEvaluateMode, derivedContextType(), NeedsClassFieldInitializer::No, isArrowFunctionContext(), false, EvalContextType::None); }
    6767
    6868    UnlinkedModuleProgramCodeBlock* unlinkedModuleProgramCodeBlock() { return m_unlinkedModuleProgramCodeBlock.get(); }
  • trunk/Source/JavaScriptCore/runtime/OptionsList.h

    r254558 r254653  
    497497    v(Bool, forceOSRExitToLLInt, false, Normal, "If true, we always exit to the LLInt. If false, we exit to whatever is most convenient.") \
    498498    v(Unsigned, getByValICMaxNumberOfIdentifiers, 4, Normal, "Number of identifiers we see in the LLInt that could cause us to bail on generating an IC for get_by_val.") \
     499    v(Bool, useClassFields, false, Normal, "If true, the parser will understand data fields inside classes.") \
    499500
    500501enum OptionEquivalence {
  • trunk/Source/JavaScriptCore/runtime/ProgramExecutable.h

    r251425 r254653  
    7272    DECLARE_INFO;
    7373
    74     ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), isArrowFunctionContext(), false, EvalContextType::None); }
     74    ExecutableInfo executableInfo() const { return ExecutableInfo(usesEval(), isStrictMode(), false, false, ConstructorKind::None, JSParserScriptMode::Classic, SuperBinding::NotNeeded, SourceParseMode::ProgramMode, derivedContextType(), NeedsClassFieldInitializer::No, isArrowFunctionContext(), false, EvalContextType::None); }
    7575
    7676    TemplateObjectMap& ensureTemplateObjectMap(VM&);
Note: See TracChangeset for help on using the changeset viewer.