Ignore:
Timestamp:
Aug 27, 2020, 5:27:19 PM (5 years ago)
Author:
Alexey Shvayka
Message:

proto in object literal should perform SetPrototypeOf directly
https://bugs.webkit.org/show_bug.cgi?id=215769

Reviewed by Ross Kirsling.

JSTests:

  • microbenchmarks/object-literal-underscore-proto-setter.js: Added.
  • stress/syntax-checker-duplicate-underscore-proto.js:

Rewrite the test to ensure each eval() call throws a SyntaxError.

Source/JavaScriptCore:

To fix proto usage in object literals if Object.prototype.proto is overridden
or removed, this patch sets the Prototype directly, aligning JSC with V8 and
SpiderMonkey. We are safe to skip method table lookups and cycle checks, as the
spec [1] calls SetPrototypeOf on newly created (unreferenced) ordinary objects.

This change removes PropertyNode::PutType because its only purpose was to accomodate
proto in object literals. Since emitPutConstantProperty() handles static public
class fields, which don't need super binding, PropertyNode::isUnderscoreProtoSetter()
is extended to reject class properties.

This patch speeds up creating object literals with proto by 25%.

[1]: https://tc39.es/ecma262/#sec-__proto__-property-names-in-object-initializers (step 7.a)

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitDirectSetPrototypeOf):

  1. Remove unused dst parameter to align with other put methods.
  2. Remove divot* parameters as it's cumbersome to pass them through, and globalFuncSetPrototypeDirect() never throws anyway.
  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::PropertyListNode::emitPutConstantProperty):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_putByIdDirect):
(JSC::BytecodeIntrinsicNode::emit_intrinsic_putByIdDirectPrivate):
(JSC::ClassExprNode::emitBytecode):

  • parser/ASTBuilder.h:

(JSC::ASTBuilder::createGetterOrSetterProperty):
(JSC::ASTBuilder::createProperty):
(JSC::ASTBuilder::isUnderscoreProtoSetter const):

  • parser/NodeConstructors.h:

(JSC::PropertyNode::PropertyNode):

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

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

  • parser/SyntaxChecker.h:

(JSC::SyntaxChecker::createProperty):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncSetPrototypeDirect):

  1. Ignore a prototype value of incorrect type as per spec [1], which is unobservable for call sites in ClassExprNode::emitBytecode().
  2. Assert that JSObject::setPrototypeDirect() doesn't throw.

LayoutTests:

  • js/script-tests/object-literal-direct-put.js:
File:
1 edited

Legend:

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

    r266117 r266264  
    723723    public:
    724724        enum Type : uint8_t { Constant = 1, Getter = 2, Setter = 4, Computed = 8, Shorthand = 16, Spread = 32, Private = 64 };
    725         enum PutType : uint8_t { Unknown, KnownDirect };
    726 
    727         PropertyNode(const Identifier&, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
    728         PropertyNode(ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
    729         PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
    730         PropertyNode(const Identifier&, ExpressionNode* propertyName, ExpressionNode*, Type, PutType, SuperBinding, ClassElementTag);
     725
     726        PropertyNode(const Identifier&, ExpressionNode*, Type, SuperBinding, ClassElementTag);
     727        PropertyNode(ExpressionNode*, Type, SuperBinding, ClassElementTag);
     728        PropertyNode(ExpressionNode* propertyName, ExpressionNode*, Type, SuperBinding, ClassElementTag);
     729        PropertyNode(const Identifier&, ExpressionNode* propertyName, ExpressionNode*, Type, SuperBinding, ClassElementTag);
    731730
    732731        ExpressionNode* expressionName() const { return m_expression; }
     
    745744        bool isComputedClassField() const { return isClassField() && hasComputedName(); }
    746745        void setIsOverriddenByDuplicate() { m_isOverriddenByDuplicate = true; }
    747         PutType putType() const { return static_cast<PutType>(m_putType); }
    748 
    749         ALWAYS_INLINE static bool isUnderscoreProtoSetter(VM& vm, const Identifier* name, Type type, bool needsSuperBinding)
    750         {
    751             return name && *name == vm.propertyNames->underscoreProto && type == Type::Constant && !needsSuperBinding;
     746
     747        ALWAYS_INLINE static bool isUnderscoreProtoSetter(VM& vm, const PropertyNode& node)
     748        {
     749            return isUnderscoreProtoSetter(vm, node.name(), node.type(), node.needsSuperBinding(), node.isClassProperty());
     750        }
     751
     752        ALWAYS_INLINE static bool isUnderscoreProtoSetter(VM& vm, const Identifier* name, Type type, bool needsSuperBinding, bool isClassProperty)
     753        {
     754            return name && *name == vm.propertyNames->underscoreProto && type == Type::Constant && !needsSuperBinding && !isClassProperty;
    752755        }
    753756
     
    759762        unsigned m_type : 7;
    760763        unsigned m_needsSuperBinding : 1;
    761         unsigned m_putType : 1;
    762764        static_assert(1 << 2 > static_cast<unsigned>(ClassElementTag::LastTag), "ClassElementTag shouldn't use more than two bits");
    763765        unsigned m_classElementTag : 2;
     
    23292331    };
    23302332
    2331     class ClassExprNode final : public ExpressionNode, public ThrowableExpressionData, public VariableEnvironmentNode {
     2333    class ClassExprNode final : public ExpressionNode, public VariableEnvironmentNode {
    23322334        JSC_MAKE_PARSER_ARENA_DELETABLE_ALLOCATED(ClassExprNode);
    23332335    public:
Note: See TracChangeset for help on using the changeset viewer.