⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 269801 in webkit


Ignore:
Timestamp:
Nov 13, 2020, 2:32:01 PM (6 years ago)
Author:
commit-queue@webkit.org
Message:

[JSC] Use symbols as identifiers for class fields computed names storage
https://bugs.webkit.org/show_bug.cgi?id=216172

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

Use private symbols for the property keys of the class fields with
computed names. This is cleaner than using raw numeric identifiers and
will be less cumbersome when we add static fields. It also prevents
potential collisions if other features want to store data in the class
scope.

JSTests:

  • stress/class-fields-harmony.js: new test, make sure

setFunctionName works properly with computed fields.

Source/JavaScriptCore:

  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitSaveComputedFieldName): adapt a comment.

  • parser/Parser.cpp:

(JSC::Parser<LexerType>::parseClass): use private identifiers for computed fields property keys.
(JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements): ditto.

  • parser/ParserArena.cpp:

(JSC::IdentifierArena::makePrivateIdentifier): method to create a private identifier.

  • parser/ParserArena.h:
  • runtime/CachedTypes.cpp:

(JSC::CachedUniquedStringImplBase::encode): consider registered symbols, they are used by the parser now.
(JSC::CachedUniquedStringImplBase::decode const): ditto.

  • runtime/VM.cpp:

(JSC::VM::VM):

  • runtime/VM.h:

(JSC::VM::privateSymbolRegistry): create a private symbol registry too.

Source/WTF:

  • wtf/text/SymbolImpl.cpp:

(WTF::RegisteredSymbolImpl::createPrivate): add a method to create a registered private symbol from a string key.

  • wtf/text/SymbolImpl.h:
  • wtf/text/SymbolRegistry.cpp:

(WTF::SymbolRegistry::symbolForKey): consider that we can hold private symbols now too.

  • wtf/text/SymbolRegistry.h:

(WTF::SymbolRegistry::SymbolRegistry): new enum type for public/private symbols.

Location:
trunk
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r269791 r269801  
     12020-11-13  Xan López  <xan@igalia.com>
     2
     3        [JSC] Use symbols as identifiers for class fields computed names storage
     4        https://bugs.webkit.org/show_bug.cgi?id=216172
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Use private symbols for the property keys of the class fields with
     9        computed names. This is cleaner than using raw numeric identifiers and
     10        will be less cumbersome when we add static fields. It also prevents
     11        potential collisions if other features want to store data in the class
     12        scope.
     13
     14        * stress/class-fields-harmony.js: new test, make sure
     15        setFunctionName works properly with computed fields.
     16
    1172020-11-13  Yusuke Suzuki  <ysuzuki@apple.com>
    218
  • trunk/JSTests/stress/class-fields-harmony.js

    r258071 r269801  
    907907}
    908908
     909// Additional tests by the WebKit project.
     910
     911{
     912  let x = 0;
     913  let y = 'foo';
     914  let z = { name: 'test' };
     915
     916  let C = class {
     917    [x] = () => {
     918      return 2;
     919    };
     920    [y] = class {};
     921    [z] = class D {};
     922  }
     923
     924  let c = new C();
     925  assertSame(c[x](), 2);
     926  assertSame(c[x].name, '0');
     927  assertSame(c[y].name, 'foo');
     928  assertSame(c[z].name, 'D');
     929}
  • trunk/Source/JavaScriptCore/ChangeLog

    r269790 r269801  
     12020-11-13  Xan López  <xan@igalia.com>
     2
     3        [JSC] Use symbols as identifiers for class fields computed names storage
     4        https://bugs.webkit.org/show_bug.cgi?id=216172
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Use private symbols for the property keys of the class fields with
     9        computed names. This is cleaner than using raw numeric identifiers and
     10        will be less cumbersome when we add static fields. It also prevents
     11        potential collisions if other features want to store data in the class
     12        scope.
     13
     14        * bytecompiler/NodesCodegen.cpp:
     15        (JSC::PropertyListNode::emitSaveComputedFieldName): adapt a comment.
     16        * parser/Parser.cpp:
     17        (JSC::Parser<LexerType>::parseClass): use private identifiers for computed fields property keys.
     18        (JSC::Parser<LexerType>::parseInstanceFieldInitializerSourceElements): ditto.
     19        * parser/ParserArena.cpp:
     20        (JSC::IdentifierArena::makePrivateIdentifier): method to create a private identifier.
     21        * parser/ParserArena.h:
     22        * runtime/CachedTypes.cpp:
     23        (JSC::CachedUniquedStringImplBase::encode): consider registered symbols, they are used by the parser now.
     24        (JSC::CachedUniquedStringImplBase::decode const): ditto.
     25        * runtime/VM.cpp:
     26        (JSC::VM::VM):
     27        * runtime/VM.h:
     28        (JSC::VM::privateSymbolRegistry): create a private symbol registry too.
     29
    1302020-11-13  Sergey Rubanov  <chi187@gmail.com>
    231
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r268489 r269801  
    803803    RefPtr<RegisterID> propertyExpr;
    804804
    805     // The 'name' refers to a synthetic numeric variable name in the private name scope, where the property key is saved for later use.
     805    // The 'name' refers to a synthetic private name in the class scope, where the property key is saved for later use.
    806806    const Identifier& description = *node.name();
    807807    Variable var = generator.variable(description);
     
    48184818{
    48194819    RefPtr<RegisterID> value = generator.newTemporary();
     4820    bool shouldSetFunctionName = false;
    48204821
    48214822    if (!m_assign)
     
    48234824    else {
    48244825        generator.emitNode(value.get(), m_assign);
    4825         if (m_ident && generator.shouldSetFunctionName(m_assign))
     4826        shouldSetFunctionName = generator.shouldSetFunctionName(m_assign);
     4827        if (m_ident && shouldSetFunctionName && m_type != DefineFieldNode::Type::ComputedName)
    48264828            generator.emitSetFunctionName(value.get(), *m_ident);
    48274829    }
     
    48514853
    48524854        // For ComputedNames, the expression has already been evaluated earlier during evaluation of a ClassExprNode.
    4853         // Here, `m_ident` refers to an integer ID in a class lexical scope, containing the value already converted to an Expression.
     4855        // Here, `m_ident` refers to private symbol ID in a class lexical scope, containing the value already converted to an Expression.
    48544856        Variable var = generator.variable(*m_ident);
    48554857        ASSERT_WITH_MESSAGE(!var.local(), "Computed names must be stored in captured variables");
     
    48594861        RefPtr<RegisterID> privateName = generator.newTemporary();
    48604862        generator.emitGetFromScope(privateName.get(), scope.get(), var, ThrowIfNotFound);
     4863        if (shouldSetFunctionName)
     4864            generator.emitSetFunctionName(value.get(), privateName.get());
    48614865        generator.emitProfileType(privateName.get(), var, m_position, m_position + m_ident->length());
    48624866        generator.emitCallDefineProperty(generator.thisRegister(), privateName.get(), value.get(), nullptr, nullptr, BytecodeGenerator::PropertyConfigurable | BytecodeGenerator::PropertyWritable | BytecodeGenerator::PropertyEnumerable, m_position);
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r268688 r269801  
    28382838}
    28392839
     2840static constexpr ASCIILiteral instanceComputedNamePrefix { "instanceComputedName"_s };
     2841
    28402842template <typename LexerType>
    28412843template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionNameRequirements requirements, ParserClassInfo<TreeBuilder>& info)
     
    29972999
    29983000            if (computedPropertyName) {
    2999                 ident = &m_parserArena.identifierArena().makeNumericIdentifier(m_vm, numComputedFields++);
     3001                ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++);
    30003002                DeclarationResultMask declarationResult = classScope->declareLexicalVariable(ident, true);
    30013003                ASSERT_UNUSED(declarationResult, declarationResult == DeclarationResult::Valid);
     
    30783080        JSTokenLocation fieldLocation = tokenLocation();
    30793081        const Identifier* ident = nullptr;
    3080         TreeExpression computedPropertyName = 0;
    30813082        DefineFieldNode::Type type = DefineFieldNode::Type::Name;
    30823083        switch (m_token.m_type) {
     
    31023103            next();
    31033104            break;
    3104         case OPENBRACKET:
     3105        case OPENBRACKET: {
    31053106            next();
    3106             computedPropertyName = parseAssignmentExpression(context);
     3107            TreeExpression computedPropertyName = parseAssignmentExpression(context);
    31073108            failIfFalse(computedPropertyName, "Cannot parse computed property name");
    31083109            handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name");
    3109             ident = &m_parserArena.identifierArena().makeNumericIdentifier(m_vm, numComputedFields++);
     3110            ident = &m_parserArena.identifierArena().makePrivateIdentifier(m_vm, instanceComputedNamePrefix, numComputedFields++);
    31103111            type = DefineFieldNode::Type::ComputedName;
    31113112            break;
     3113        }
    31123114        default:
    31133115            if (m_token.m_type & KeywordTokenFlag)
  • trunk/Source/JavaScriptCore/parser/ParserArena.cpp

    r262342 r269801  
    108108}
    109109
     110const Identifier& IdentifierArena::makePrivateIdentifier(VM& vm, ASCIILiteral prefix, unsigned identifier)
     111{
     112    String symbolName = makeString(prefix, identifier);
     113    auto symbol = vm.privateSymbolRegistry().symbolForKey(symbolName);
     114    m_identifiers.append(Identifier::fromUid(symbol));
     115    return m_identifiers.last();
    110116}
     117
     118}
  • trunk/Source/JavaScriptCore/parser/ParserArena.h

    r261464 r269801  
    5353        const Identifier& makeBigIntDecimalIdentifier(VM&, const Identifier&, uint8_t radix);
    5454        const Identifier& makeNumericIdentifier(VM&, double number);
     55        const Identifier& makePrivateIdentifier(VM&, ASCIILiteral, unsigned);
    5556
    5657    public:
  • trunk/Source/JavaScriptCore/runtime/CachedTypes.cpp

    r269115 r269801  
    703703        m_isAtomic = string.isAtom();
    704704        m_isSymbol = string.isSymbol();
     705        m_isRegistered = false;
    705706        m_isWellKnownSymbol = false;
     707        m_isPrivate = false;
    706708        RefPtr<StringImpl> impl = const_cast<StringImpl*>(&string);
    707709
    708710        if (m_isSymbol) {
    709711            SymbolImpl* symbol = static_cast<SymbolImpl*>(impl.get());
     712            m_isRegistered = symbol->isRegistered();
     713            m_isPrivate = symbol->isPrivate();
    710714            if (!symbol->isNullSymbol()) {
    711715                // We have special handling for well-known symbols.
    712                 if (!symbol->isPrivate()) {
     716                if (!m_isPrivate) {
    713717                    m_isWellKnownSymbol = true;
    714718                    impl = symbol->substring(strlen("Symbol."));
     
    743747
    744748            SymbolImpl* symbol;
    745             if (m_isWellKnownSymbol)
    746                 symbol = decoder.vm().propertyNames->builtinNames().lookUpWellKnownSymbol(buffer, m_length);
     749            VM& vm = decoder.vm();
     750            if (m_isRegistered) {
     751                String str(buffer, m_length);
     752                if (m_isPrivate)
     753                    symbol = static_cast<SymbolImpl*>(&vm.privateSymbolRegistry().symbolForKey(str).leakRef());
     754                else
     755                    symbol = static_cast<SymbolImpl*>(&vm.symbolRegistry().symbolForKey(str).leakRef());
     756            } else if (m_isWellKnownSymbol)
     757                symbol = vm.propertyNames->builtinNames().lookUpWellKnownSymbol(buffer, m_length);
    747758            else
    748                 symbol = decoder.vm().propertyNames->builtinNames().lookUpPrivateName(buffer, m_length);
     759                symbol = vm.propertyNames->builtinNames().lookUpPrivateName(buffer, m_length);
    749760            RELEASE_ASSERT(symbol);
    750761            String str = symbol;
     
    774785    bool m_isWellKnownSymbol : 1;
    775786    bool m_isAtomic : 1;
     787    bool m_isRegistered : 1;
     788    bool m_isPrivate : 1;
    776789    unsigned m_length;
    777790};
  • trunk/Source/JavaScriptCore/runtime/VM.cpp

    r269320 r269801  
    383383    , deferredWorkTimer(DeferredWorkTimer::create(*this))
    384384    , m_atomStringTable(vmType == Default ? Thread::current().atomStringTable() : new AtomStringTable)
     385    , m_privateSymbolRegistry(WTF::SymbolRegistry::Type::PrivateSymbol)
    385386    , propertyNames(nullptr)
    386387    , emptyList(new ArgList)
  • trunk/Source/JavaScriptCore/runtime/VM.h

    r269576 r269801  
    715715    AtomStringTable* m_atomStringTable;
    716716    WTF::SymbolRegistry m_symbolRegistry;
     717    WTF::SymbolRegistry m_privateSymbolRegistry;
    717718    CommonIdentifiers* propertyNames;
    718719    const ArgList* emptyList;
     
    726727    AtomStringTable* atomStringTable() const { return m_atomStringTable; }
    727728    WTF::SymbolRegistry& symbolRegistry() { return m_symbolRegistry; }
     729    WTF::SymbolRegistry& privateSymbolRegistry() { return m_privateSymbolRegistry; }
    728730
    729731    Strong<JSBigInt> heapBigIntConstantOne;
  • trunk/Source/WTF/ChangeLog

    r269785 r269801  
     12020-11-13  Xan López  <xan@igalia.com>
     2
     3        [JSC] Use symbols as identifiers for class fields computed names storage
     4        https://bugs.webkit.org/show_bug.cgi?id=216172
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Use private symbols for the property keys of the class fields with
     9        computed names. This is cleaner than using raw numeric identifiers and
     10        will be less cumbersome when we add static fields. It also prevents
     11        potential collisions if other features want to store data in the class
     12        scope.
     13
     14        * wtf/text/SymbolImpl.cpp:
     15        (WTF::RegisteredSymbolImpl::createPrivate): add a method to create a registered private symbol from a string key.
     16        * wtf/text/SymbolImpl.h:
     17        * wtf/text/SymbolRegistry.cpp:
     18        (WTF::SymbolRegistry::symbolForKey): consider that we can hold private symbols now too.
     19        * wtf/text/SymbolRegistry.h:
     20        (WTF::SymbolRegistry::SymbolRegistry): new enum type for public/private symbols.
     21
    1222020-11-12  Darin Adler  <darin@apple.com>
    223
  • trunk/Source/WTF/wtf/text/SymbolImpl.cpp

    r237099 r269801  
    8080}
    8181
     82Ref<RegisteredSymbolImpl> RegisteredSymbolImpl::createPrivate(StringImpl& rep, SymbolRegistry& symbolRegistry)
     83{
     84    auto* ownerRep = (rep.bufferOwnership() == BufferSubstring) ? rep.substringBuffer() : &rep;
     85    ASSERT(ownerRep->bufferOwnership() != BufferSubstring);
     86    if (rep.is8Bit())
     87        return adoptRef(*new RegisteredSymbolImpl(rep.m_data8, rep.length(), *ownerRep, symbolRegistry, s_flagIsRegistered | s_flagIsPrivate));
     88    return adoptRef(*new RegisteredSymbolImpl(rep.m_data16, rep.length(), *ownerRep, symbolRegistry, s_flagIsRegistered | s_flagIsPrivate));
     89}
     90
    8291} // namespace WTF
  • trunk/Source/WTF/wtf/text/SymbolImpl.h

    r257201 r269801  
    157157
    158158    static Ref<RegisteredSymbolImpl> create(StringImpl& rep, SymbolRegistry&);
    159 
    160     RegisteredSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
    161         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
     159    static Ref<RegisteredSymbolImpl> createPrivate(StringImpl& rep, SymbolRegistry&);
     160
     161    RegisteredSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry, Flags flags = s_flagIsRegistered)
     162        : SymbolImpl(characters, length, WTFMove(base), flags)
    162163        , m_symbolRegistry(&registry)
    163164    {
    164165    }
    165166
    166     RegisteredSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
    167         : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
     167    RegisteredSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry, Flags flags = s_flagIsRegistered)
     168        : SymbolImpl(characters, length, WTFMove(base), flags)
    168169        , m_symbolRegistry(&registry)
    169170    {
  • trunk/Source/WTF/wtf/text/SymbolRegistry.cpp

    r237099 r269801  
    2929namespace WTF {
    3030
     31SymbolRegistry::SymbolRegistry(Type type)
     32    : m_symbolType(type)
     33{
     34}
     35
    3136SymbolRegistry::~SymbolRegistry()
    3237{
     
    4550    }
    4651
    47     auto symbol = RegisteredSymbolImpl::create(*rep.impl(), *this);
    48     *addResult.iterator = SymbolRegistryKey(&symbol.get());
    49     return symbol;
     52    RefPtr<RegisteredSymbolImpl> symbol;
     53    if (m_symbolType == Type::PrivateSymbol)
     54        symbol = RegisteredSymbolImpl::createPrivate(*rep.impl(), *this);
     55    else
     56        symbol = RegisteredSymbolImpl::create(*rep.impl(), *this);
     57
     58    *addResult.iterator = SymbolRegistryKey(symbol.get());
     59    return symbol.releaseNonNull();
    5060}
    5161
  • trunk/Source/WTF/wtf/text/SymbolRegistry.h

    r264488 r269801  
    7979    WTF_MAKE_NONCOPYABLE(SymbolRegistry);
    8080public:
    81     SymbolRegistry() = default;
     81    enum class Type : uint8_t { PublicSymbol, PrivateSymbol };
     82    WTF_EXPORT_PRIVATE SymbolRegistry(Type = Type::PublicSymbol);
    8283    WTF_EXPORT_PRIVATE ~SymbolRegistry();
    8384
     
    8889private:
    8990    HashSet<SymbolRegistryKey> m_table;
     91    Type m_symbolType;
    9092};
    9193
Note: See TracChangeset for help on using the changeset viewer.