Ignore:
Timestamp:
Feb 15, 2021, 2:40:26 PM (5 years ago)
Author:
Caio Lima
Message:

[ESNext] Implement private accessors
https://bugs.webkit.org/show_bug.cgi?id=194435

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/private-accesor-duplicate-name-early-errors.js: Added.
  • stress/private-getter-brand-check.js: Added.
  • stress/private-getter-inner-class.js: Added.
  • stress/private-members-get-and-set.js: Added.
  • stress/private-methods-and-accessors-postfix-node.js: Added.
  • stress/private-methods-and-accessors-prefix-node.js: Added.
  • stress/private-names-available-on-direct-eval.js:
  • stress/private-names-available-on-eval-during-field-initialization.js: Copied from JSTests/stress/private-names-available-on-direct-eval.js.
  • stress/private-setter-brand-check.js: Added.
  • stress/private-setter-inner-class.js: Added.
  • test262/config.yaml:
  • test262/expectations.yaml:

Source/JavaScriptCore:

This patch is implementing support for instance private getters and
setters following the proposal on https://tc39.es/proposal-private-methods.
Private accessors also use the private brand check mechanism of
private methods, which means that we are using both
op_set_private_brand and op_check_private_brand to perform brand
checks. Accessors are also stored on class lexical scope as a pair of
getter and setter. This is done creating a new JSObject and
storing the getter on get property, and setter on set
property. This is designed in such way that we can always hit IC fast
path on get_by_id_direct to access the property, and also to allow
constant folding of accessors on DFG/FTL, since acessors objects are
going to be constant once created.

For reference, we have the following bytecode for a private getter
access:

`
class C {

get #m() {...}
access() {

return this.#m;

}

}
`

Bytecode for class declaration:

`
...
new_object dst:loc12, inlineCapacity:2 this is the object to store getter and setter pair
new_func_exp dst:loc13, scope:loc4, functionDecl:"get #m() {...}"
put_by_id base:loc13, property:@homeObject, value:loc11, flags:Strict
put_by_id base:loc12, property:@get, value:loc13, flags:IsDirect|Strict
put_to_scope scope:loc4, var:#m, value:loc12
loc4 is the class lexical scope
...

`

Bytecode for access():

`
...
resolve_scope dst:loc7, scope:loc4, var:"#m", resolveType:GlobalProperty, localScopeDepth:0
get_from_scope dst:loc8, scope:loc7, var:@privateBrand
check_private_brand base:this, brand:loc8
get_from_scope dst:loc8, scope:loc7, var:"#m"
get_by_id_direct dst:loc9, base:loc8, property:@get
mov dst:loc10, src:this
call dst:loc6, callee:loc9, argc:1, argv:16
...

`

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::instantiateLexicalVariables):
(JSC::BytecodeGenerator::getPrivateTraits):
(JSC::BytecodeGenerator::getAvailablePrivateAccessNames):
(JSC::BytecodeGenerator::isPrivateMethod): Deleted.

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitBytecode):
(JSC::PropertyListNode::emitPutConstantProperty):
(JSC::BaseDotNode::emitGetPropertyValue):
(JSC::BaseDotNode::emitPutProperty):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitDot):

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

(JSC::Parser<LexerType>::parseClass):
(JSC::Parser<LexerType>::parseGetterSetter):

  • parser/Parser.h:

(JSC::Scope::declarePrivateSetter):
(JSC::Scope::declarePrivateGetter):

  • parser/VariableEnvironment.cpp:

(JSC::VariableEnvironment::declarePrivateAccessor):
(JSC::VariableEnvironment::declarePrivateSetter):
(JSC::VariableEnvironment::declarePrivateGetter):

  • parser/VariableEnvironment.h:

(JSC::VariableEnvironmentEntry::isPrivateSetter const):
(JSC::VariableEnvironmentEntry::isPrivateGetter const):
(JSC::VariableEnvironmentEntry::setIsPrivateSetter):
(JSC::VariableEnvironmentEntry::setIsPrivateGetter):
(JSC::PrivateNameEntry::isSetter const):
(JSC::PrivateNameEntry::isGetter const):
(JSC::PrivateNameEntry::isField const):
(JSC::PrivateNameEntry::isPrivateMethodOrAcessor const):
(JSC::VariableEnvironment::declarePrivateSetter):
(JSC::VariableEnvironment::declarePrivateGetter):

  • runtime/ExceptionHelpers.cpp:

(JSC::createPrivateMethodAccessError):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/parser/Nodes.h

    r272580 r272883  
    722722    class PropertyNode final : public ParserArenaFreeable {
    723723    public:
    724         enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, PrivateField = 64, PrivateMethod = 128 };
     724        enum Type : uint16_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, PrivateField = 64, PrivateMethod = 128, PrivateSetter = 256, PrivateGetter = 512 };
    725725
    726726        PropertyNode(const Identifier&, ExpressionNode*, Type, SuperBinding, ClassElementTag);
     
    741741        bool isStaticClassField() const { return isStaticClassProperty() && !needsSuperBinding(); }
    742742        bool isOverriddenByDuplicate() const { return m_isOverriddenByDuplicate; }
    743         bool isPrivate() const { return m_type & (PrivateField | PrivateMethod); }
     743        bool isPrivate() const { return m_type & (PrivateField | PrivateMethod | PrivateGetter | PrivateSetter); }
    744744        bool hasComputedName() const { return m_expression; }
    745745        bool isComputedClassField() const { return isClassField() && hasComputedName(); }
     
    761761        ExpressionNode* m_expression;
    762762        ExpressionNode* m_assign;
    763         unsigned m_type;
     763        unsigned m_type : 10;
    764764        unsigned m_needsSuperBinding : 1;
    765765        static_assert(1 << 2 > static_cast<unsigned>(ClassElementTag::LastTag), "ClassElementTag shouldn't use more than two bits");
     
    789789        }
    790790
     791        void setHasPrivateAccessors(bool hasPrivateAccessors)
     792        {
     793            m_hasPrivateAccessors = hasPrivateAccessors;
     794        }
     795
     796        bool hasPrivateAccessors() const
     797        {
     798            return m_hasPrivateAccessors;
     799        }
     800
    791801        static bool shouldCreateLexicalScopeForClass(PropertyListNode*);
    792802
     
    805815        PropertyNode* m_node;
    806816        PropertyListNode* m_next { nullptr };
     817        bool m_hasPrivateAccessors { false };
    807818    };
    808819
Note: See TracChangeset for help on using the changeset viewer.