Changeset 269922 in webkit


Ignore:
Timestamp:
Nov 17, 2020 1:37:39 PM (3 years ago)
Author:
commit-queue@webkit.org
Message:

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

Patch by Xan López <Xan Lopez> on 2020-11-17
Reviewed by Yusuke Suzuki.

JSTests:

Enable static public fields, and import new stress tests from the
V8 project. Also split the support code into a separate file
(harmony-support.js) to avoid duplication.

  • test262/config.yaml: enable static public fields.
  • stress/class-fields-harmony.js: use the new support file.
  • stress/class-fields-static-harmony.js: Added.
  • stress/resources/harmony-support.js: Added.

Source/JavaScriptCore:

Add support for static public class fields. We can reuse most of
the existing machinery available for instance fields. Like
instance fields, static fields are initialized with a synthetic
function. This is done to allow us to trivially follow the scoping
rules in the spec. As it happens with instance fields this could
be inlined in a future patch.

A lot of small changes in many files are just a matter of doing
s/instance/class/ for variables related to class fields, which
before were assuming there are only instance fields implemented.

  • bytecode/UnlinkedFunctionExecutable.cpp:

(JSC::generateUnlinkedFunctionCodeBlock): do s/instanceField/classField/.

  • bytecode/UnlinkedFunctionExecutable.h: ditto.
  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): ditto.

  • bytecompiler/BytecodeGenerator.h: ditto, plus add a parameter

for static field locations in emitDefineClassElements.

  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitBytecode): save static fields
locations when going through the property list.
(JSC::PropertyListNode::emitSaveComputedFieldName): consider
static fields here too.
(JSC::ClassExprNode::emitBytecode): call the initializer for
static fields as the very last action of the class creation.

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createDefineField): field nodes can be static
too now.

  • parser/NodeConstructors.h:

(JSC::DefineFieldNode::DefineFieldNode): ditto.

  • parser/Nodes.h: ditto.
  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseInner): s/instanceField/classField/
(JSC::Parser<LexerType>::parseClass): consider static fields.
(JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements):
s/instanceField/classField/, and consider static fields.

  • parser/Parser.h:

(JSC::Parser<LexerType>::parse): s/instanceField/classField/
(JSC::parse): ditto.

  • runtime/JSFunction.cpp:

(JSC::JSFunction::setFunctionName): s/instanceField/classField/

  • runtime/OptionsList.h: add option to enable/disable static public fields.
Location:
trunk
Files:
2 added
17 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r269831 r269922  
     12020-11-17  Xan López  <xan@igalia.com>
     2
     3        [JSC] Add support for static public class fields
     4        https://bugs.webkit.org/show_bug.cgi?id=194095
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Enable static public fields, and import new stress tests from the
     9        V8 project. Also split the support code into a separate file
     10        (harmony-support.js) to avoid duplication.
     11
     12        * test262/config.yaml: enable static public fields.
     13        * stress/class-fields-harmony.js: use the new support file.
     14        * stress/class-fields-static-harmony.js: Added.
     15        * stress/resources/harmony-support.js: Added.
     16
    1172020-11-15  Sergey Rubanov  <chi187@gmail.com>
    218
  • trunk/JSTests/stress/class-fields-harmony.js

    r269801 r269922  
    3232"use strict";
    3333
    34 function classOf(object) {
    35    // Argument must not be null or undefined.
    36    var string = Object.prototype.toString.call(object);
    37    // String has format [object <ClassName>].
    38    return string.substring(8, string.length - 1);
    39 }
    40 
    41 /**
    42  * Compares two objects for key/value equality.
    43  * Returns true if they are equal, false otherwise.
    44  */
    45 function deepObjectEquals(a, b) {
    46   var aProps = Object.keys(a);
    47   aProps.sort();
    48   var bProps = Object.keys(b);
    49   bProps.sort();
    50   if (!deepEquals(aProps, bProps)) {
    51     return false;
    52   }
    53   for (var i = 0; i < aProps.length; i++) {
    54     if (!deepEquals(a[aProps[i]], b[aProps[i]])) {
    55       return false;
    56     }
    57   }
    58   return true;
    59 }
    60 
    61 /**
    62  * Compares two JavaScript values for type and value equality.
    63  * It checks internals of arrays and objects.
    64  */
    65 function deepEquals(a, b) {
    66   if (a === b) {
    67     // Check for -0.
    68     if (a === 0) return (1 / a) === (1 / b);
    69     return true;
    70   }
    71   if (typeof a != typeof b) return false;
    72   if (typeof a == 'number') return isNaN(a) && isNaN(b);
    73   if (typeof a !== 'object' && typeof a !== 'function') return false;
    74   // Neither a nor b is primitive.
    75   var objectClass = classOf(a);
    76   if (objectClass !== classOf(b)) return false;
    77   if (objectClass === 'RegExp') {
    78     // For RegExp, just compare pattern and flags using its toString.
    79     return (a.toString() === b.toString());
    80   }
    81   // Functions are only identical to themselves.
    82   if (objectClass === 'Function') return false;
    83   if (objectClass === 'Array') {
    84     var elementCount = 0;
    85     if (a.length != b.length) {
    86       return false;
    87     }
    88     for (var i = 0; i < a.length; i++) {
    89       if (!deepEquals(a[i], b[i])) return false;
    90     }
    91     return true;
    92   }
    93   if (objectClass == 'String' || objectClass == 'Number' ||
    94       objectClass == 'Boolean' || objectClass == 'Date') {
    95     if (a.valueOf() !== b.valueOf()) return false;
    96   }
    97   return deepObjectEquals(a, b);
    98 }
    99 
    100 /**
    101  * Throws an exception containing the user_message (if any) and the values.
    102  */
    103 function fail(expected, found, user_message = '') {
    104   // TODO(cira): Replace String with PrettyPrint for objects and arrays.
    105   var message = 'Failure' + (user_message ? ' (' + user_message + ')' : '') +
    106       ': expected <' + String(expected) + '>, found <' + String(found) + '>.';
    107   throw new Error(message);
    108 }
    109 
    110 /**
    111  * Throws if obj is not of given type.
    112  */
    113 function assertInstanceof(obj, type) {
    114   if (!(obj instanceof type)) {
    115     var actualTypeName = null;
    116     var actualConstructor = Object.getPrototypeOf(obj).constructor;
    117     if (typeof actualConstructor == "function") {
    118       actualTypeName = actualConstructor.name || String(actualConstructor);
    119     }
    120     throw new Error('Object <' + obj + '> is not an instance of <' +
    121                     (type.name || type) + '>' +
    122                     (actualTypeName ? ' but of < ' + actualTypeName + '>' : ''));
    123   }
    124 }
    125 
    126 /**
    127  * Throws if obj is not the same as expected.
    128  */
    129 function assertSame(expected, found, name_opt) {
    130   if (found === expected) {
    131     if (expected !== 0 || (1 / expected) === (1 / found))
    132       return;
    133   } else if ((expected !== expected) && (found !== found)) {
    134       return;
    135   }
    136   fail(expected, found, name_opt);
    137 }
    138 
    139 /**
    140  * Throws if two variables have different types or values.
    141  */
    142 
    143 function assertEquals(expected, found, user_message = '') {
    144   if (!deepEquals(expected, found)) {
    145     fail(expected, found, user_message);
    146   }
    147 }
    148 
    149 /**
    150  * Throws if two variables have equal types or values.
    151  */
    152 
    153 function assertNotEquals(expected, found, user_message = '') {
    154   if (deepEquals(expected, found)) {
    155     fail(expected, found, user_message);
    156   }
    157 }
    158 
    159 /**
    160  * Throws if value is false.
    161  */
    162 function assertTrue(value, user_message = '') {
    163   assertEquals(true, value, user_message);
    164 }
    165 
    166 
    167 /**
    168  * Throws if value is true.
    169  */
    170 function assertFalse(value, user_message = '') {
    171   assertEquals(false, value, user_message);
    172 }
    173 
    174 /**
    175  * Runs code() and asserts that it throws the specified exception.
    176  */
    177 function assertThrows(code, type_opt, cause_opt) {
    178   try {
    179     if (typeof code == 'function') {
    180       code();
    181     } else {
    182       eval(code);
    183     }
    184   } catch (e) {
    185     if (typeof type_opt == 'function') {
    186       assertInstanceof(e, type_opt);
    187     }
    188     if (arguments.length >= 3) {
    189       assertEquals(cause_opt, e.type, 'thrown exception type mismatch');
    190     }
    191     // Success.
    192     return;
    193   }
    194   var expected = arguments.length >= 3 ? cause_opt :
    195       typeof type_opt == 'function' ? type_opt : 'any exception';
    196   fail(expected, 'no exception', 'expected thrown exception');
    197 }
     34load("./resources/harmony-support.js");
    19835
    19936{
  • trunk/JSTests/test262/config.yaml

    r269720 r269922  
    66  class-fields-public: usePublicClassFields
    77  class-fields-private: usePrivateClassFields
     8  class-static-fields-public: usePublicStaticClassFields
    89  Intl.DateTimeFormat-dayPeriod: useIntlDateTimeFormatDayPeriod
    910  SharedArrayBuffer: useSharedArrayBuffer
     
    1819    - arbitrary-module-namespace-names
    1920    - class-methods-private
    20     - class-static-fields-public
    2121    - class-static-fields-private
    2222    - class-static-methods-private
  • trunk/Source/JavaScriptCore/ChangeLog

    r269832 r269922  
     12020-11-17  Xan López  <xan@igalia.com>
     2
     3        [JSC] Add support for static public class fields
     4        https://bugs.webkit.org/show_bug.cgi?id=194095
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Add support for static public class fields. We can reuse most of
     9        the existing machinery available for instance fields. Like
     10        instance fields, static fields are initialized with a synthetic
     11        function. This is done to allow us to trivially follow the scoping
     12        rules in the spec. As it happens with instance fields this could
     13        be inlined in a future patch.
     14
     15        A lot of small changes in many files are just a matter of doing
     16        s/instance/class/ for variables related to class fields, which
     17        before were assuming there are only instance fields implemented.
     18
     19        * bytecode/UnlinkedFunctionExecutable.cpp:
     20        (JSC::generateUnlinkedFunctionCodeBlock): do s/instanceField/classField/.
     21        * bytecode/UnlinkedFunctionExecutable.h: ditto.
     22        * bytecompiler/BytecodeGenerator.cpp:
     23        (JSC::BytecodeGenerator::emitNewClassFieldInitializerFunction): ditto.
     24        * bytecompiler/BytecodeGenerator.h: ditto, plus add a parameter
     25        for static field locations in emitDefineClassElements.
     26        * bytecompiler/NodesCodegen.cpp:
     27        (JSC::PropertyListNode::emitBytecode): save static fields
     28        locations when going through the property list.
     29        (JSC::PropertyListNode::emitSaveComputedFieldName): consider
     30        static fields here too.
     31        (JSC::ClassExprNode::emitBytecode): call the initializer for
     32        static fields as the very last action of the class creation.
     33        * parser/ASTBuilder.h:
     34        (JSC::ASTBuilder::createDefineField): field nodes can be static
     35        too now.
     36        * parser/NodeConstructors.h:
     37        (JSC::DefineFieldNode::DefineFieldNode): ditto.
     38        * parser/Nodes.h: ditto.
     39        * parser/Parser.cpp:
     40        (JSC::Parser<LexerType>::parseInner): s/instanceField/classField/
     41        (JSC::Parser<LexerType>::parseClass): consider static fields.
     42        (JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements):
     43        s/instanceField/classField/, and consider static fields.
     44        * parser/Parser.h:
     45        (JSC::Parser<LexerType>::parse): s/instanceField/classField/
     46        (JSC::parse): ditto.
     47        * runtime/JSFunction.cpp:
     48        (JSC::JSFunction::setFunctionName): s/instanceField/classField/
     49        * runtime/OptionsList.h: add option to enable/disable static public fields.
     50
    1512020-11-15  Yusuke Suzuki  <ysuzuki@apple.com>
    252
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.cpp

    r269115 r269922  
    5757    JSParserScriptMode scriptMode = executable->scriptMode();
    5858    ASSERT(isFunctionParseMode(executable->parseMode()));
    59     Vector<JSTextPosition>* instanceFieldLocations = executable->instanceFieldLocations();
     59    Vector<JSTextPosition>* classFieldLocations = executable->classFieldLocations();
    6060    std::unique_ptr<FunctionNode> function = parse<FunctionNode>(
    61         vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, nullptr, instanceFieldLocations);
     61        vm, source, executable->name(), builtinMode, strictMode, scriptMode, executable->parseMode(), executable->superBinding(), error, nullptr, ConstructorKind::None, DerivedContextType::None, EvalContextType::None, nullptr, nullptr, classFieldLocations);
    6262
    6363    if (!function) {
  • trunk/Source/JavaScriptCore/bytecode/UnlinkedFunctionExecutable.h

    r269115 r269922  
    210210        String m_sourceMappingURLDirective;
    211211        Vector<CompactTDZEnvironmentMap::Handle> m_parentScopeTDZVariables;
    212         Vector<JSTextPosition> m_instanceFieldLocations;
     212        Vector<JSTextPosition> m_classFieldLocations;
    213213    };
    214214
    215215    NeedsClassFieldInitializer needsClassFieldInitializer() const { return static_cast<NeedsClassFieldInitializer>(m_needsClassFieldInitializer); }
    216216
    217     Vector<JSTextPosition>* instanceFieldLocations() const
     217    Vector<JSTextPosition>* classFieldLocations() const
    218218    {
    219219        if (m_rareData)
    220             return &m_rareData->m_instanceFieldLocations;
     220            return &m_rareData->m_classFieldLocations;
    221221        return nullptr;
    222222    }
    223223
    224     void setInstanceFieldLocations(Vector<JSTextPosition>&& instanceFieldLocations)
    225     {
    226         if (instanceFieldLocations.isEmpty())
     224    void setClassFieldLocations(Vector<JSTextPosition>&& classFieldLocations)
     225    {
     226        if (classFieldLocations.isEmpty())
    227227            return;
    228         ensureRareData().m_instanceFieldLocations = WTFMove(instanceFieldLocations);
     228        ensureRareData().m_classFieldLocations = WTFMove(classFieldLocations);
    229229    }
    230230
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r269115 r269922  
    382382
    383383    bool shouldCaptureAllOfTheThings = shouldEmitDebugHooks() || codeBlock->usesEval();
    384     bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::InstanceFieldInitializerMode;
     384    bool needsArguments = ((functionNode->usesArguments() && !codeBlock->isArrowFunction()) || codeBlock->usesEval() || (functionNode->usesArrowFunction() && !codeBlock->isArrowFunction() && isArgumentsUsedInInnerArrowFunction())) && parseMode != SourceParseMode::ClassFieldInitializerMode;
    385385
    386386    if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode)) {
     
    614614
    615615        bool shouldCreateArgumensVariable = !haveParameterNamedArguments
    616             && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::InstanceFieldInitializerMode).contains(m_codeBlock->parseMode());
     616            && !SourceParseModeSet(SourceParseMode::ArrowFunctionMode, SourceParseMode::AsyncArrowFunctionMode, SourceParseMode::ClassFieldInitializerMode).contains(m_codeBlock->parseMode());
    617617        shouldCreateArgumentsVariableInParameterScope = shouldCreateArgumensVariable && !isSimpleParameterList;
    618618        // Do not create arguments variable in case of Arrow function. Value will be loaded from parent scope
     
    31343134}
    31353135
    3136 RegisterID* BytecodeGenerator::emitNewInstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived)
     3136RegisterID* BytecodeGenerator::emitNewClassFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& classFieldLocations, bool isDerived)
    31373137{
    31383138    DerivedContextType newDerivedContextType;
     
    31473147
    31483148    auto variablesUnderTDZ = getVariablesUnderTDZ();
    3149     SourceParseMode parseMode = SourceParseMode::InstanceFieldInitializerMode;
     3149    SourceParseMode parseMode = SourceParseMode::ClassFieldInitializerMode;
    31503150    ConstructAbility constructAbility = ConstructAbility::CannotConstruct;
    31513151
     
    31543154    metadata.finishParsing(m_scopeNode->source(), Identifier(), FunctionMode::MethodDefinition);
    31553155    auto initializer = UnlinkedFunctionExecutable::create(m_vm, m_scopeNode->source(), &metadata, isBuiltinFunction() ? UnlinkedBuiltinFunction : UnlinkedNormalFunction, constructAbility, scriptMode(), WTFMove(variablesUnderTDZ), newDerivedContextType, NeedsClassFieldInitializer::No);
    3156     initializer->setInstanceFieldLocations(WTFMove(instanceFieldLocations));
     3156    initializer->setClassFieldLocations(WTFMove(classFieldLocations));
    31573157
    31583158    unsigned index = m_codeBlock->addFunctionExpr(initializer);
     
    44754475RegisterID* BytecodeGenerator::emitLoadArrowFunctionLexicalEnvironment(const Identifier& identifier)
    44764476{
    4477     ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode || m_codeBlock->parseMode() == SourceParseMode::InstanceFieldInitializerMode);
     4477    ASSERT(m_codeBlock->isArrowFunction() || m_codeBlock->isArrowFunctionContext() || constructorKind() == ConstructorKind::Extends || m_codeType == EvalCode || m_codeBlock->parseMode() == SourceParseMode::ClassFieldInitializerMode);
    44784478
    44794479    return emitResolveScope(nullptr, variable(identifier, ThisResolutionType::Scoped));
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r269115 r269922  
    583583        }
    584584
    585         RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype, Vector<JSTextPosition>& instanceFieldLocations)
     585        RegisterID* emitDefineClassElements(PropertyListNode* n, RegisterID* constructor, RegisterID* prototype, Vector<JSTextPosition>& instanceFieldLocations, Vector<JSTextPosition>& staticFieldLocations)
    586586        {
    587587            ASSERT(constructor->refCount() && prototype->refCount());
     
    590590            if (UNLIKELY(n->needsDebugHook()))
    591591                emitDebugHook(n);
    592             return n->emitBytecode(*this, constructor, prototype, &instanceFieldLocations);
     592            return n->emitBytecode(*this, constructor, prototype, &instanceFieldLocations, &staticFieldLocations);
    593593        }
    594594
     
    777777        RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode*);
    778778        RegisterID* emitNewDefaultConstructor(RegisterID* dst, ConstructorKind, const Identifier& name, const Identifier& ecmaName, const SourceCode& classSource, NeedsClassFieldInitializer);
    779         RegisterID* emitNewInstanceFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& instanceFieldLocations, bool isDerived);
     779        RegisterID* emitNewClassFieldInitializerFunction(RegisterID* dst, Vector<JSTextPosition>&& classFieldLocations, bool isDerived);
    780780        RegisterID* emitNewArrowFunctionExpression(RegisterID*, ArrowFuncExprNode*);
    781781        RegisterID* emitNewMethodDefinition(RegisterID* dst, MethodDefinitionNode*);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r269801 r269922  
    187187static RegisterID* emitHomeObjectForCallee(BytecodeGenerator& generator)
    188188{
    189     if ((generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) && generator.parseMode() != SourceParseMode::InstanceFieldInitializerMode) {
     189    if ((generator.isDerivedClassContext() || generator.isDerivedConstructorContext()) && generator.parseMode() != SourceParseMode::ClassFieldInitializerMode) {
    190190        RegisterID* derivedConstructor = generator.emitLoadDerivedConstructorFromArrowFunctionLexicalEnvironment();
    191191        return generator.emitGetById(generator.newTemporary(), derivedConstructor, generator.propertyNames().builtinNames().homeObjectPrivateName());
     
    578578}
    579579
    580 RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations)
     580RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dstOrConstructor, RegisterID* prototype, Vector<JSTextPosition>* instanceFieldLocations, Vector<JSTextPosition>* staticFieldLocations)
    581581{
    582582    PropertyListNode* p = this;
     
    593593            ASSERT(instanceFieldLocations);
    594594            instanceFieldLocations->append(p->position());
     595            continue;
     596        }
     597
     598        if (p->isStaticClassField()) {
     599            ASSERT(staticFieldLocations);
     600            staticFieldLocations->append(p->position());
    595601            continue;
    596602        }
     
    650656                ASSERT(node->m_type & PropertyNode::Constant);
    651657                instanceFieldLocations->append(p->position());
     658                continue;
     659            }
     660
     661            if (p->isStaticClassField()) {
     662                ASSERT(staticFieldLocations);
     663                staticFieldLocations->append(p->position());
    652664                continue;
    653665            }
     
    745757void PropertyListNode::emitPutConstantProperty(BytecodeGenerator& generator, RegisterID* newObj, PropertyNode& node)
    746758{
    747     // Private fields are handled in the synthetic instanceFieldInitializer function, not here.
     759    // Private fields are handled in a synthetic classFieldInitializer function, not here.
    748760    ASSERT(!(node.type() & PropertyNode::Private));
    749761
     
    801813{
    802814    ASSERT(node.isComputedClassField());
    803     RefPtr<RegisterID> propertyExpr;
    804815
    805816    // The 'name' refers to a synthetic private name in the class scope, where the property key is saved for later use.
     
    808819    ASSERT(!var.local());
    809820
    810     propertyExpr = generator.emitNode(node.m_expression);
    811     RegisterID* propertyName = generator.emitToPropertyKey(generator.newTemporary(), propertyExpr.get());
     821    RefPtr<RegisterID> propertyExpr = generator.emitNode(node.m_expression);
     822    RefPtr<RegisterID> propertyName = generator.emitToPropertyKey(generator.newTemporary(), propertyExpr.get());
     823
     824    if (node.isStaticClassField()) {
     825        Ref<Label> validPropertyNameLabel = generator.newLabel();
     826        RefPtr<RegisterID> prototypeString = generator.emitLoad(nullptr, JSValue(generator.addStringConstant(generator.propertyNames().prototype)));
     827        generator.emitJumpIfFalse(generator.emitBinaryOp<OpStricteq>(generator.newTemporary(), prototypeString.get(), propertyName.get(), OperandTypes(ResultType::stringType(), ResultType::stringType())), validPropertyNameLabel.get());
     828        generator.emitThrowTypeError("Cannot declare a static field named 'prototype'");
     829        generator.emitLabel(validPropertyNameLabel.get());
     830    }
    812831
    813832    RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, var);
    814     generator.emitPutToScope(scope.get(), var, propertyName, ThrowIfNotFound, InitializationMode::ConstInitialization);
     833    generator.emitPutToScope(scope.get(), var, propertyName.get(), ThrowIfNotFound, InitializationMode::ConstInitialization);
    815834}
    816835
     
    49474966    generator.emitCallDefineProperty(constructor.get(), prototypeNameRegister.get(), prototype.get(), nullptr, nullptr, 0, m_position);
    49484967
     4968    Vector<JSTextPosition> staticFieldLocations;
    49494969    if (m_classElements) {
    49504970        m_classElements->emitDeclarePrivateFieldNames(generator, generator.scopeRegister());
    49514971
    49524972        Vector<JSTextPosition> instanceFieldLocations;
    4953         generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations);
     4973        generator.emitDefineClassElements(m_classElements, constructor.get(), prototype.get(), instanceFieldLocations, staticFieldLocations);
    49544974        if (!instanceFieldLocations.isEmpty()) {
    4955             RefPtr<RegisterID> instanceFieldInitializer = generator.emitNewInstanceFieldInitializerFunction(generator.newTemporary(), WTFMove(instanceFieldLocations), m_classHeritage);
     4975            RefPtr<RegisterID> instanceFieldInitializer = generator.emitNewClassFieldInitializerFunction(generator.newTemporary(), WTFMove(instanceFieldLocations), m_classHeritage);
    49564976
    49574977            // FIXME: Skip this if the initializer function isn't going to need a home object (no eval or super properties)
     
    49634983    }
    49644984
    4965     if (m_needsLexicalScope) {
    4966         if (!m_name.isNull()) {
    4967             Variable classNameVar = generator.variable(m_name);
    4968             RELEASE_ASSERT(classNameVar.isResolved());
    4969             RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar);
    4970             generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization);
    4971         }
     4985    if (m_needsLexicalScope && !m_name.isNull()) {
     4986        Variable classNameVar = generator.variable(m_name);
     4987        RELEASE_ASSERT(classNameVar.isResolved());
     4988        RefPtr<RegisterID> scope = generator.emitResolveScope(nullptr, classNameVar);
     4989        generator.emitPutToScope(scope.get(), classNameVar, constructor.get(), ThrowIfNotFound, InitializationMode::Initialization);
     4990    }
     4991
     4992    if (!staticFieldLocations.isEmpty()) {
     4993        RefPtr<RegisterID> staticFieldInitializer = generator.emitNewClassFieldInitializerFunction(generator.newTemporary(), WTFMove(staticFieldLocations), m_classHeritage);
     4994        // FIXME: Skip this if the initializer function isn't going to need a home object (no eval or super properties)
     4995        // https://bugs.webkit.org/show_bug.cgi?id=196867
     4996        emitPutHomeObject(generator, staticFieldInitializer.get(), constructor.get());
     4997
     4998        CallArguments args(generator, nullptr);
     4999        generator.move(args.thisRegister(), constructor.get());
     5000        generator.emitCall(generator.newTemporary(), staticFieldInitializer.get(), NoExpectedFunction, args, position(), position(), position(), DebuggableCall::No);
     5001    }
     5002
     5003    if (m_needsLexicalScope)
    49725004        generator.popLexicalScope(this);
    4973     }
    49745005
    49755006    return generator.move(generator.finalDestination(dst, constructor.get()), constructor.get());
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r269115 r269922  
    118118
    119119    EvalContextType evalContextType;
    120     if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::InstanceFieldInitializerMode)
     120    if (callerUnlinkedCodeBlock->parseMode() == SourceParseMode::ClassFieldInitializerMode)
    121121        evalContextType = EvalContextType::InstanceFieldEvalContext;
    122122    else if (isFunctionParseMode(callerUnlinkedCodeBlock->parseMode()))
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r268323 r269922  
    739739        bool isClassField() const { return isClassProperty() && !needsSuperBinding(); }
    740740        bool isInstanceClassField() const { return isInstanceClassProperty() && !needsSuperBinding(); }
     741        bool isStaticClassField() const { return isStaticClassProperty() && !needsSuperBinding(); }
    741742        bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; }
    742743        bool isPrivate() const { return m_type & Private; }
     
    783784        bool hasInstanceFields() const;
    784785
     786        bool isStaticClassField() const
     787        {
     788            return m_node->isStaticClassField();
     789        }
     790
    785791        static bool shouldCreateLexicalScopeForClass(PropertyListNode*);
    786792
    787         RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>*);
     793        RegisterID* emitBytecode(BytecodeGenerator&, RegisterID*, RegisterID*, Vector<JSTextPosition>*, Vector<JSTextPosition>*);
    788794
    789795        void emitDeclarePrivateFieldNames(BytecodeGenerator&, RegisterID* scope);
     
    792798        RegisterID* emitBytecode(BytecodeGenerator& generator, RegisterID* dst = nullptr) final
    793799        {
    794             return emitBytecode(generator, dst, nullptr, nullptr);
     800            return emitBytecode(generator, dst, nullptr, nullptr, nullptr);
    795801        }
    796802        void emitPutConstantProperty(BytecodeGenerator&, RegisterID*, PropertyNode&);
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r269801 r269922  
    210210
    211211template <typename LexerType>
    212 Expected<typename Parser<LexerType>::ParseInnerResult, String> Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* instanceFieldLocations)
     212Expected<typename Parser<LexerType>::ParseInnerResult, String> Parser<LexerType>::parseInner(const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const Vector<JSTextPosition>* classFieldLocations)
    213213{
    214214    ASTBuilder context(const_cast<VM&>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source));
     
    223223        if (isGeneratorOrAsyncFunctionBodyParseMode(parseMode))
    224224            parameters = createGeneratorParameters(context, functionInfo.parameterCount);
    225         else if (parseMode == SourceParseMode::InstanceFieldInitializerMode)
     225        else if (parseMode == SourceParseMode::ClassFieldInitializerMode)
    226226            parameters = context.createFormalParameterList();
    227227        else
     
    257257        else if (parsingContext == ParsingContext::FunctionConstructor)
    258258            sourceElements = parseSingleFunction(context, functionConstructorParametersEndPosition);
    259         else if (parseMode == SourceParseMode::InstanceFieldInitializerMode) {
    260             ASSERT(instanceFieldLocations && !instanceFieldLocations->isEmpty());
    261             sourceElements = parseInstanceFieldInitializerSourceElements(context, *instanceFieldLocations);
     259        else if (parseMode == SourceParseMode::ClassFieldInitializerMode) {
     260            ASSERT(classFieldLocations && !classFieldLocations->isEmpty());
     261            sourceElements = parseClassFieldInitializerSourceElements(context, *classFieldLocations);
    262262        } else
    263263            sourceElements = parseSourceElements(context, CheckForStrictMode);
     
    21792179    case SourceParseMode::ModuleAnalyzeMode:
    21802180    case SourceParseMode::ModuleEvaluateMode:
    2181     case SourceParseMode::InstanceFieldInitializerMode:
     2181    case SourceParseMode::ClassFieldInitializerMode:
    21822182        RELEASE_ASSERT_NOT_REACHED();
    21832183        return "";
     
    22212221    case SourceParseMode::ModuleAnalyzeMode:
    22222222    case SourceParseMode::ModuleEvaluateMode:
    2223     case SourceParseMode::InstanceFieldInitializerMode:
     2223    case SourceParseMode::ClassFieldInitializerMode:
    22242224        RELEASE_ASSERT_NOT_REACHED();
    22252225        return "";
     
    28392839
    28402840static constexpr ASCIILiteral instanceComputedNamePrefix { "instanceComputedName"_s };
     2841static constexpr ASCIILiteral staticComputedNamePrefix { "staticComputedName"_s };
    28412842
    28422843template <typename LexerType>
     
    28822883    TreePropertyList classElements = 0;
    28832884    TreePropertyList classElementsTail = 0;
    2884     unsigned numComputedFields = 0;
     2885    unsigned nextInstanceComputedFieldID = 0;
     2886    unsigned nextStaticComputedFieldID = 0;
    28852887    while (!match(CLOSEBRACE)) {
    28862888        if (match(SEMICOLON)) {
     
    29912993            property = parseGetterSetter(context, type, methodStart, ConstructorKind::None, tag);
    29922994            failIfFalse(property, "Cannot parse this method");
    2993         } else if (Options::usePublicClassFields() && !match(OPENPAREN) && tag == ClassElementTag::Instance && parseMode == SourceParseMode::MethodMode) {
     2995        } else if (Options::usePublicClassFields() && !match(OPENPAREN) && (tag == ClassElementTag::Instance || Options::usePublicStaticClassFields()) && parseMode == SourceParseMode::MethodMode) {
    29942996            ASSERT(!isGetter && !isSetter);
    29952997            if (ident) {
    29962998                semanticFailIfTrue(*ident == propertyNames.constructor, "Cannot declare class field named 'constructor'");
    29972999                semanticFailIfTrue(*ident == propertyNames.constructorPrivateField, "Cannot declare private class field named '#constructor'");
     3000                if (tag == ClassElementTag::Static)
     3001                    semanticFailIfTrue(*ident == propertyNames.prototype, "Cannot declare a static field named 'prototype'");
    29983002            }
    29993003
    30003004            if (computedPropertyName) {
    3001                 ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++);
     3005                if (tag == ClassElementTag::Instance)
     3006                    ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, nextInstanceComputedFieldID++);
     3007                else
     3008                    ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, staticComputedNamePrefix, nextStaticComputedFieldID++);
    30023009                DeclarationResultMask declarationResult = classScope->declareLexicalVariable(ident, true);
    30033010                ASSERT_UNUSED(declarationResult, declarationResult == DeclarationResult::Valid);
     
    30663073
    30673074template <typename LexerType>
    3068 template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseInstanceFieldInitializerSourceElements(TreeBuilder& context, const Vector<JSTextPosition>& instanceFieldLocations)
     3075template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseClassFieldInitializerSourceElements(TreeBuilder& context, const Vector<JSTextPosition>& classFieldLocations)
    30693076{
    30703077    TreeSourceElements sourceElements = context.createSourceElements();
     
    30723079
    30733080    unsigned numComputedFields = 0;
    3074     for (auto location : instanceFieldLocations) {
     3081    for (auto location : classFieldLocations) {
     3082        // This loop will either parse only static fields or only
     3083        // instance fields, but never a mix; we could make it slightly
     3084        // smarter about parsing given that fact, but it's probably
     3085        // not worth the hassle, so begin each iteration without
     3086        // knowing which kind the next field will be.
     3087        bool isStaticField = false;
    30753088        // We don't need to worry about hasLineTerminatorBeforeToken
    30763089        // on class fields, so we set this value to false.
     
    30813094        const Identifier* ident = nullptr;
    30823095        DefineFieldNode::Type type = DefineFieldNode::Type::Name;
    3083         switch (m_token.m_type) {
    3084         case PRIVATENAME:
    3085             type = DefineFieldNode::Type::PrivateName;
    3086             FALLTHROUGH;
    3087         case STRING:
    3088         case IDENT:
    3089         namedKeyword:
    3090             ident = m_token.m_data.ident;
    3091             ASSERT(ident);
     3096
     3097        if (match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm.propertyNames->staticKeyword) {
     3098            auto* staticIdentifier = m_token.m_data.ident;
     3099            ASSERT(staticIdentifier);
    30923100            next();
    3093             break;
    3094         case BIGINT:
    3095             ident = &m_parserArena.identifierArena().makeBigIntDecimalIdentifier(const_cast<VM&>(m_vm), *m_token.m_data.bigIntString, m_token.m_data.radix);
    3096             ASSERT(ident);
    3097             next();
    3098             break;
    3099         case DOUBLE:
    3100         case INTEGER:
    3101             ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM&>(m_vm), m_token.m_data.doubleValue);
    3102             ASSERT(ident);
    3103             next();
    3104             break;
    3105         case OPENBRACKET: {
    3106             next();
    3107             TreeExpression computedPropertyName = parseAssignmentExpression(context);
    3108             failIfFalse(computedPropertyName, "Cannot parse computed property name");
    3109             handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
    3110             ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++);
    3111             type = DefineFieldNode::Type::ComputedName;
    3112             break;
    3113         }
    3114         default:
    3115             if (m_token.m_type & KeywordTokenFlag)
    3116                 goto namedKeyword;
    3117             failDueToUnexpectedToken();
     3101            if (match(SEMICOLON) || match (EQUAL) || match(CLOSEBRACE) || m_lexer->hasLineTerminatorBeforeToken())
     3102                ident = staticIdentifier;
     3103            else
     3104                isStaticField = true;
     3105        }
     3106
     3107        if (!ident) {
     3108            switch (m_token.m_type) {
     3109            case PRIVATENAME:
     3110                type = DefineFieldNode::Type::PrivateName;
     3111                FALLTHROUGH;
     3112            case STRING:
     3113            case IDENT:
     3114            namedKeyword:
     3115                ident = m_token.m_data.ident;
     3116                ASSERT(ident);
     3117                next();
     3118                break;
     3119            case BIGINT:
     3120                ident = &m_parserArena.identifierArena().makeBigIntDecimalIdentifier(const_cast<VM&>(m_vm), *m_token.m_data.bigIntString, m_token.m_data.radix);
     3121                ASSERT(ident);
     3122                next();
     3123                break;
     3124            case DOUBLE:
     3125            case INTEGER:
     3126                ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM&>(m_vm), m_token.m_data.doubleValue);
     3127                ASSERT(ident);
     3128                next();
     3129                break;
     3130            case OPENBRACKET: {
     3131                next();
     3132                TreeExpression computedPropertyName = parseAssignmentExpression(context);
     3133                failIfFalse(computedPropertyName, "Cannot parse computed property name");
     3134                handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
     3135                ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm,
     3136                    isStaticField ? staticComputedNamePrefix : instanceComputedNamePrefix,
     3137                    numComputedFields++);
     3138                type = DefineFieldNode::Type::ComputedName;
     3139                break;
     3140            }
     3141            default:
     3142                if (m_token.m_type & KeywordTokenFlag)
     3143                    goto namedKeyword;
     3144                failDueToUnexpectedToken();
     3145            }
    31183146        }
    31193147
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r269115 r269922  
    261261        case SourceParseMode::SetterMode:
    262262        case SourceParseMode::MethodMode:
    263         case SourceParseMode::InstanceFieldInitializerMode:
     263        case SourceParseMode::ClassFieldInitializerMode:
    264264            setIsFunction();
    265265            break;
     
    17131713    template <class TreeBuilder> TreeSourceElements parseAsyncGeneratorFunctionSourceElements(TreeBuilder&, SourceParseMode, bool isArrowFunctionBodyExpression, SourceElementsMode);
    17141714    template <class TreeBuilder> TreeSourceElements parseSingleFunction(TreeBuilder&, Optional<int> functionConstructorParametersEndPosition);
    1715     template <class TreeBuilder> TreeSourceElements parseInstanceFieldInitializerSourceElements(TreeBuilder&, const Vector<JSTextPosition>&);
     1715    template <class TreeBuilder> TreeSourceElements parseClassFieldInitializerSourceElements(TreeBuilder&, const Vector<JSTextPosition>&);
    17161716    template <class TreeBuilder> TreeStatement parseStatementListItem(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength);
    17171717    template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = nullptr);
     
    20542054template <typename LexerType>
    20552055template <class ParsedNode>
    2056 std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* parentScopePrivateNames, const Vector<JSTextPosition>* instanceFieldLocations)
     2056std::unique_ptr<ParsedNode> Parser<LexerType>::parse(ParserError& error, const Identifier& calleeName, SourceParseMode parseMode, ParsingContext parsingContext, Optional<int> functionConstructorParametersEndPosition, const VariableEnvironment* parentScopePrivateNames, const Vector<JSTextPosition>* classFieldLocations)
    20572057{
    20582058    int errLine;
     
    20742074    }
    20752075
    2076     auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, instanceFieldLocations);
     2076    auto parseResult = parseInner(calleeName, parseMode, parsingContext, functionConstructorParametersEndPosition, classFieldLocations);
    20772077
    20782078    int lineNumber = m_lexer->lineNumber();
     
    21592159    DebuggerParseData* debuggerParseData = nullptr,
    21602160    const VariableEnvironment* parentScopePrivateNames = nullptr,
    2161     const Vector<JSTextPosition>* instanceFieldLocations = nullptr,
     2161    const Vector<JSTextPosition>* classFieldLocations = nullptr,
    21622162    bool isInsideOrdinaryFunction = false)
    21632163{
     
    21712171    if (source.provider()->source().is8Bit()) {
    21722172        Parser<Lexer<LChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
    2173         result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);
     2173        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, classFieldLocations);
    21742174        if (positionBeforeLastNewline)
    21752175            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
     
    21842184        ASSERT_WITH_MESSAGE(defaultConstructorKindForTopLevelFunction == ConstructorKind::None, "BuiltinExecutables's special constructors should always use a 8-bit string");
    21852185        Parser<Lexer<UChar>> parser(vm, source, builtinMode, strictMode, scriptMode, parseMode, superBinding, defaultConstructorKindForTopLevelFunction, derivedContextType, isEvalNode<ParsedNode>(), evalContextType, debuggerParseData, isInsideOrdinaryFunction);
    2186         result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, instanceFieldLocations);
     2186        result = parser.parse<ParsedNode>(error, name, parseMode, isEvalNode<ParsedNode>() ? ParsingContext::Eval : ParsingContext::Program, WTF::nullopt, parentScopePrivateNames, classFieldLocations);
    21872187        if (positionBeforeLastNewline)
    21882188            *positionBeforeLastNewline = parser.positionBeforeLastNewline();
  • trunk/Source/JavaScriptCore/parser/ParserModes.h

    r268323 r269922  
    6767    AsyncGeneratorWrapperMethodMode   = 17,
    6868    GeneratorWrapperMethodMode        = 18,
    69     InstanceFieldInitializerMode      = 19,
     69    ClassFieldInitializerMode         = 19,
    7070};
    7171
     
    117117        SourceParseMode::AsyncGeneratorWrapperFunctionMode,
    118118        SourceParseMode::AsyncGeneratorWrapperMethodMode,
    119         SourceParseMode::InstanceFieldInitializerMode).contains(parseMode);
     119        SourceParseMode::ClassFieldInitializerMode).contains(parseMode);
    120120}
    121121
  • trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp

    r267594 r269922  
    111111
    112112        case SourceParseMode::ArrowFunctionMode:
    113         case SourceParseMode::InstanceFieldInitializerMode:
     113        case SourceParseMode::ClassFieldInitializerMode:
    114114            functionHeader = "";
    115115            break;
  • trunk/Source/JavaScriptCore/runtime/JSFunction.cpp

    r267727 r269922  
    422422    case SourceParseMode::AsyncGeneratorWrapperMethodMode:
    423423    case SourceParseMode::GeneratorWrapperMethodMode:
    424     case SourceParseMode::InstanceFieldInitializerMode:
     424    case SourceParseMode::ClassFieldInitializerMode:
    425425        if (!function->jsExecutable()->isInStrictContext())
    426426            return JSValue::encode(caller);
  • trunk/Source/JavaScriptCore/runtime/OptionsList.h

    r269706 r269922  
    526526    v(Bool, exposeCustomSettersOnGlobalObjectForTesting, false, Normal, nullptr) \
    527527    v(Bool, useJITCage, canUseJITCage(), Normal, nullptr) \
     528    v(Bool, usePublicStaticClassFields, false, Normal, "If true, the parser will understand public static data fields inside classes.") \
    528529
    529530enum OptionEquivalence {
Note: See TracChangeset for help on using the changeset viewer.