Ignore:
Timestamp:
Oct 17, 2017, 5:02:01 AM (8 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] proto getter should be fast
https://bugs.webkit.org/show_bug.cgi?id=178067

Reviewed by Saam Barati.

JSTests:

  • stress/dfg-object-proto-accessor.js: Added.

(shouldBe):
(shouldThrow):
(target):

  • stress/dfg-object-proto-getter.js: Added.

(shouldBe):
(shouldThrow):
(target):

  • stress/dfg-object-prototype-of.js: Added.

(shouldBe):
(shouldThrow):
(target):

  • stress/dfg-reflect-get-prototype-of.js: Added.

(shouldBe):
(shouldThrow):
(target):

  • stress/object-get-prototype-of-filtered.js: Added.

(shouldBe):
(shouldThrow):
(target):
(i.Cocoa):

  • stress/object-get-prototype-of-mono-proto.js: Added.

(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

  • stress/object-get-prototype-of-poly-mono-proto.js: Added.

(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

  • stress/object-get-prototype-of-poly-proto.js: Added.

(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

  • stress/object-proto-getter-filtered.js: Added.

(shouldBe):
(shouldThrow):
(target):
(i.Cocoa):

  • stress/object-proto-getter-poly-mono-proto.js: Added.

(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

  • stress/object-proto-getter-poly-proto.js: Added.

(shouldBe):
(makePolyProtoObject.foo.C):
(makePolyProtoObject.foo):
(makePolyProtoObject):
(target):

  • stress/object-prototype-proto-accessors-should-throw-on-undefined-this.js:
  • stress/string-proto.js: Added.

(shouldBe):
(target):

Source/JavaScriptCore:

In our ES6 class implementation, we access proto field to retrieve super constructor.
Currently, it is handled as an usual getter call to a generic function. And DFG just emits
Call node for this. It is inefficient since typically we know the prototype of the given
object when accessing object.__proto__ since we emit CheckStructure for this object.
If Structure has mono proto, we can immediately fold it to constant value. If it is poly proto,
we can still change this to efficient access to poly proto slot.

This patch implements GetPrototypeOf DFG node. This node efficiently accesses to prototype of
the given object. And in AI and ByteCodeParser phase, we attempt to fold it to constant.
ByteCodeParser's folding is a bit important since we have callee.__proto__ code to get super
constructor. If we can change this to constant, we can reify CallLinkInfo with this constant.
This paves the way to optimizing ArrayConstructor super calls[1], which is particularly important
for ARES-6 ML.

And we also optimize Reflect.getPrototypeOf and Object.getPrototypeOf with this GetPrototypeOf node.

Currently, proto access for poly proto object is not handled well in IC. But we add code handling
poly proto in GetPrototypeOf since Reflect.getPrototypeOf and Object.getPrototypeOf can use it.
Once IC starts handling poly proto & intrinsic getter well, this code will be used for that too.

This patch improves SixSpeed super.es6 by 3.42x.

baseline patched

super.es6 123.6666+-3.9917 36.1684+-1.0351 definitely 3.4192x faster

[1]: https://bugs.webkit.org/show_bug.cgi?id=178064

  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleIntrinsicCall):
(JSC::DFG::ByteCodeParser::handleIntrinsicGetter):
(JSC::DFG::ByteCodeParser::handleGetById):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupGetPrototypeOf):

  • dfg/DFGHeapLocation.cpp:

(WTF::printInternal):

  • dfg/DFGHeapLocation.h:
  • dfg/DFGNode.h:

(JSC::DFG::Node::hasHeapPrediction):
(JSC::DFG::Node::shouldSpeculateFunction):

  • dfg/DFGNodeType.h:
  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:
  • dfg/DFGSafeToExecute.h:

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::speculateFunction):
(JSC::DFG::SpeculativeJIT::speculateFinalObject):
(JSC::DFG::SpeculativeJIT::compileGetPrototypeOf):

  • dfg/DFGSpeculativeJIT.h:
  • dfg/DFGSpeculativeJIT32_64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetPrototypeOf):
(JSC::FTL::DFG::LowerDFGToB3::compileInstanceOf):

  • jit/IntrinsicEmitter.cpp:

(JSC::IntrinsicGetterAccessCase::canEmitIntrinsicGetter):
(JSC::IntrinsicGetterAccessCase::emitIntrinsicGetter):

  • runtime/Intrinsic.cpp:

(JSC::intrinsicName):

  • runtime/Intrinsic.h:
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::init):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncProtoGetter):

  • runtime/JSGlobalObjectFunctions.h:
  • runtime/ObjectConstructor.cpp:
  • runtime/ReflectObject.cpp:

LayoutTests:

  • js/object-literal-shorthand-construction-expected.txt:
  • js/script-tests/object-literal-shorthand-construction.js:

(set 2):
(get 1):

  • js/script-tests/sloppy-getter-setter-global-object.js:
  • js/sloppy-getter-setter-global-object-expected.txt:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r223318 r223523  
    11151115        def(HeapLocation(TypedArrayByteOffsetLoc, MiscFields, node->child1()), LazyNode(node));
    11161116        return;
     1117
     1118    case GetPrototypeOf: {
     1119        switch (node->child1().useKind()) {
     1120        case ArrayUse:
     1121        case FunctionUse:
     1122        case FinalObjectUse:
     1123            read(JSCell_structureID);
     1124            read(JSObject_butterfly);
     1125            read(NamedProperties); // Poly proto could load prototype from its slot.
     1126            def(HeapLocation(PrototypeLoc, NamedProperties, node->child1()), LazyNode(node));
     1127            return;
     1128        default:
     1129            read(World);
     1130            write(Heap);
     1131            return;
     1132        }
     1133    }
    11171134       
    11181135    case GetByOffset:
Note: See TracChangeset for help on using the changeset viewer.