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:
Location:
trunk/Source/JavaScriptCore/bytecompiler
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp

    r266106 r266264  
    25772577}
    25782578
    2579 RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType putType)
     2579RegisterID* BytecodeGenerator::emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value)
    25802580{
    25812581    ASSERT_WITH_MESSAGE(!parseIndex(property), "Indexed properties should be handled with put_by_val(direct).");
     
    25852585    m_staticPropertyAnalyzer.putById(base, propertyIndex);
    25862586
    2587     PutByIdFlags type = (putType == PropertyNode::KnownDirect || property != m_vm.propertyNames->underscoreProto) ? PutByIdFlags::createDirect(ecmaMode()) : PutByIdFlags::create(ecmaMode());
     2587    PutByIdFlags type = PutByIdFlags::createDirect(ecmaMode());
    25882588    OpPutById::emit(this, base, propertyIndex, value, type);
    25892589    return value;
     
    26932693}
    26942694
    2695 RegisterID* BytecodeGenerator::emitDirectSetPrototypeOf(RegisterID* dst, RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd)
     2695RegisterID* BytecodeGenerator::emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype)
    26962696{
    26972697    RefPtr<RegisterID> setPrototypeDirect = moveLinkTimeConstant(nullptr, LinkTimeConstant::setPrototypeDirect);
     
    27012701    move(args.argumentRegister(0), prototype);
    27022702
    2703     emitCall(newTemporary(), setPrototypeDirect.get(), NoExpectedFunction, args, divot, divotStart, divotEnd, DebuggableCall::No);
    2704     return dst;
     2703    JSTextPosition position;
     2704    emitCall(newTemporary(), setPrototypeDirect.get(), NoExpectedFunction, args, position, position, position, DebuggableCall::No);
     2705    return base;
    27052706}
    27062707
  • trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h

    r266106 r266264  
    808808        RegisterID* emitPutById(RegisterID* base, const Identifier& property, RegisterID* value);
    809809        RegisterID* emitPutById(RegisterID* base, RegisterID* thisValue, const Identifier& property, RegisterID* value);
    810         RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value, PropertyNode::PutType);
     810        RegisterID* emitDirectPutById(RegisterID* base, const Identifier& property, RegisterID* value);
    811811        RegisterID* emitDeleteById(RegisterID* dst, RegisterID* base, const Identifier&);
    812812        RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property);
    813813        RegisterID* emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* thisValue, RegisterID* property);
    814814        RegisterID* emitGetPrototypeOf(RegisterID* dst, RegisterID* value);
    815         RegisterID* emitDirectSetPrototypeOf(RegisterID* dst, RegisterID* base, RegisterID* prototype, const JSTextPosition& divot, const JSTextPosition& divotStart, const JSTextPosition& divotEnd);
     815        RegisterID* emitDirectSetPrototypeOf(RegisterID* base, RegisterID* prototype);
    816816        RegisterID* emitPutByVal(RegisterID* base, RegisterID* property, RegisterID* value);
    817817        RegisterID* emitPutByVal(RegisterID* base, RegisterID* thisValue, RegisterID* property, RegisterID* value);
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r266106 r266264  
    748748    ASSERT(!(node.type() & PropertyNode::Private));
    749749
     750    if (PropertyNode::isUnderscoreProtoSetter(generator.vm(), node)) {
     751        RefPtr<RegisterID> prototype = generator.emitNode(node.m_assign);
     752        generator.emitDirectSetPrototypeOf(newObj, prototype.get());
     753        return;
     754    }
     755
    750756    bool shouldSetFunctionName = generator.shouldSetFunctionName(node.m_assign);
    751757
     
    778784        Optional<uint32_t> optionalIndex = parseIndex(*identifier);
    779785        if (!optionalIndex) {
    780             generator.emitDirectPutById(newObj, *identifier, value.get(), node.putType());
     786            generator.emitDirectPutById(newObj, *identifier, value.get());
    781787            return;
    782788        }
     
    13951401    ASSERT(!node->m_next);
    13961402
    1397     return generator.move(dst, generator.emitDirectPutById(base.get(), ident, value.get(), PropertyNode::KnownDirect));
     1403    return generator.move(dst, generator.emitDirectPutById(base.get(), ident, value.get()));
    13981404}
    13991405
     
    14111417    ASSERT(!node->m_next);
    14121418
    1413     return generator.move(dst, generator.emitDirectPutById(base.get(), generator.parserArena().identifierArena().makeIdentifier(generator.vm(), symbol), value.get(), PropertyNode::KnownDirect));
     1419    return generator.move(dst, generator.emitDirectPutById(base.get(), generator.parserArena().identifierArena().makeIdentifier(generator.vm(), symbol), value.get()));
    14141420}
    14151421
     
    49094915        generator.emitLabel(protoParentIsObjectOrNullLabel.get());
    49104916
    4911         generator.emitDirectSetPrototypeOf(tempRegister.get(), constructor.get(), superclass.get(), divot(), divotStart(), divotEnd());
     4917        generator.emitDirectSetPrototypeOf(constructor.get(), superclass.get());
    49124918        generator.emitLabel(superclassIsNullLabel.get());
    4913         generator.emitDirectSetPrototypeOf(tempRegister.get(), prototype.get(), protoParent.get(), divot(), divotStart(), divotEnd());
     4919        generator.emitDirectSetPrototypeOf(prototype.get(), protoParent.get());
    49144920    }
    49154921
     
    49364942            emitPutHomeObject(generator, instanceFieldInitializer.get(), prototype.get());
    49374943
    4938             generator.emitDirectPutById(constructor.get(), generator.propertyNames().builtinNames().instanceFieldInitializerPrivateName(), instanceFieldInitializer.get(), PropertyNode::Unknown);
     4944            generator.emitDirectPutById(constructor.get(), generator.propertyNames().builtinNames().instanceFieldInitializerPrivateName(), instanceFieldInitializer.get());
    49394945        }
    49404946    }
Note: See TracChangeset for help on using the changeset viewer.