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/DFGFixupPhase.cpp

    r223318 r223523  
    16011601            fixEdge<Int32Use>(node->child1());
    16021602            fixEdge<Int32Use>(node->child2());
     1603            break;
     1604        }
     1605
     1606        case GetPrototypeOf: {
     1607            fixupGetPrototypeOf(node);
    16031608            break;
    16041609        }
     
    23032308    }
    23042309
     2310    void fixupGetPrototypeOf(Node* node)
     2311    {
     2312        // Reflect.getPrototypeOf only accepts Objects. For Reflect.getPrototypeOf, ByteCodeParser attaches ObjectUse edge filter before fixup phase.
     2313        if (node->child1().useKind() != ObjectUse) {
     2314            if (node->child1()->shouldSpeculateString()) {
     2315                insertCheck<StringUse>(node->child1().node());
     2316                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->stringPrototype()));
     2317                return;
     2318            }
     2319            if (node->child1()->shouldSpeculateInt32()) {
     2320                insertCheck<Int32Use>(node->child1().node());
     2321                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
     2322                return;
     2323            }
     2324            if (enableInt52() && node->child1()->shouldSpeculateAnyInt()) {
     2325                insertCheck<Int52RepUse>(node->child1().node());
     2326                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
     2327                return;
     2328            }
     2329            if (node->child1()->shouldSpeculateNumber()) {
     2330                insertCheck<NumberUse>(node->child1().node());
     2331                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->numberPrototype()));
     2332                return;
     2333            }
     2334            if (node->child1()->shouldSpeculateSymbol()) {
     2335                insertCheck<SymbolUse>(node->child1().node());
     2336                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->symbolPrototype()));
     2337                return;
     2338            }
     2339            if (node->child1()->shouldSpeculateBoolean()) {
     2340                insertCheck<BooleanUse>(node->child1().node());
     2341                m_graph.convertToConstant(node, m_graph.freeze(m_graph.globalObjectFor(node->origin.semantic)->booleanPrototype()));
     2342                return;
     2343            }
     2344        }
     2345
     2346        if (node->child1()->shouldSpeculateFinalObject()) {
     2347            fixEdge<FinalObjectUse>(node->child1());
     2348            node->clearFlags(NodeMustGenerate);
     2349            return;
     2350        }
     2351        if (node->child1()->shouldSpeculateArray()) {
     2352            fixEdge<ArrayUse>(node->child1());
     2353            node->clearFlags(NodeMustGenerate);
     2354            return;
     2355        }
     2356        if (node->child1()->shouldSpeculateFunction()) {
     2357            fixEdge<FunctionUse>(node->child1());
     2358            node->clearFlags(NodeMustGenerate);
     2359            return;
     2360        }
     2361    }
     2362
    23052363    void fixupToThis(Node* node)
    23062364    {
Note: See TracChangeset for help on using the changeset viewer.