Ignore:
Timestamp:
Jan 15, 2020, 4:09:50 PM (5 years ago)
Author:
[email protected]
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:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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; }
Note: See TracChangeset for help on using the changeset viewer.