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

    r223318 r223523  
    91879187}
    91889188
     9189void SpeculativeJIT::speculateFunction(Edge edge, GPRReg cell)
     9190{
     9191    speculateCellType(edge, cell, SpecFunction, JSFunctionType);
     9192}
     9193
    91899194void SpeculativeJIT::speculateFunction(Edge edge)
    91909195{
     
    91939198   
    91949199    SpeculateCellOperand operand(this, edge);
    9195     speculateCellType(edge, operand.gpr(), SpecFunction, JSFunctionType);
     9200    speculateFunction(edge, operand.gpr());
     9201}
     9202
     9203void SpeculativeJIT::speculateFinalObject(Edge edge, GPRReg cell)
     9204{
     9205    speculateCellType(edge, cell, SpecFinalObject, FinalObjectType);
    91969206}
    91979207
     
    92029212   
    92039213    SpeculateCellOperand operand(this, edge);
    9204     speculateCellType(edge, operand.gpr(), SpecFinalObject, FinalObjectType);
     9214    speculateFinalObject(edge, operand.gpr());
    92059215}
    92069216
     
    1076810778}
    1076910779
     10780void SpeculativeJIT::compileGetPrototypeOf(Node* node)
     10781{
     10782    switch (node->child1().useKind()) {
     10783    case ArrayUse:
     10784    case FunctionUse:
     10785    case FinalObjectUse: {
     10786        SpeculateCellOperand object(this, node->child1());
     10787        GPRTemporary temp(this);
     10788        GPRTemporary temp2(this);
     10789
     10790        GPRReg objectGPR = object.gpr();
     10791        GPRReg tempGPR = temp.gpr();
     10792        GPRReg temp2GPR = temp2.gpr();
     10793
     10794        switch (node->child1().useKind()) {
     10795        case ArrayUse:
     10796            speculateArray(node->child1(), objectGPR);
     10797            break;
     10798        case FunctionUse:
     10799            speculateFunction(node->child1(), objectGPR);
     10800            break;
     10801        case FinalObjectUse:
     10802            speculateFinalObject(node->child1(), objectGPR);
     10803            break;
     10804        default:
     10805            RELEASE_ASSERT_NOT_REACHED();
     10806            break;
     10807        }
     10808
     10809        m_jit.emitLoadStructure(*m_jit.vm(), objectGPR, tempGPR, temp2GPR);
     10810
     10811        AbstractValue& value = m_state.forNode(node->child1());
     10812        if ((value.m_type && !(value.m_type & ~SpecObject)) && value.m_structure.isFinite()) {
     10813            bool hasPolyProto = false;
     10814            bool hasMonoProto = false;
     10815            value.m_structure.forEach([&] (RegisteredStructure structure) {
     10816                if (structure->hasPolyProto())
     10817                    hasPolyProto = true;
     10818                else
     10819                    hasMonoProto = true;
     10820            });
     10821
     10822            if (hasMonoProto && !hasPolyProto) {
     10823#if USE(JSVALUE64)
     10824                m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
     10825                jsValueResult(tempGPR, node);
     10826#else
     10827                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
     10828                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
     10829                jsValueResult(temp2GPR, tempGPR, node);
     10830#endif
     10831                return;
     10832            }
     10833
     10834            if (hasPolyProto && !hasMonoProto) {
     10835#if USE(JSVALUE64)
     10836                m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
     10837                m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
     10838                m_jit.load64(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage()), tempGPR);
     10839                jsValueResult(tempGPR, node);
     10840#else
     10841                m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
     10842                m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + TagOffset), temp2GPR);
     10843                m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + PayloadOffset), tempGPR);
     10844                jsValueResult(temp2GPR, tempGPR, node);
     10845#endif
     10846                return;
     10847            }
     10848        }
     10849
     10850#if USE(JSVALUE64)
     10851        m_jit.load64(MacroAssembler::Address(tempGPR, Structure::prototypeOffset()), tempGPR);
     10852        auto isMonoProto = m_jit.branchIfNotInt32(JSValueRegs(tempGPR));
     10853        m_jit.zeroExtend32ToPtr(tempGPR, tempGPR);
     10854        m_jit.load64(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage()), tempGPR);
     10855        isMonoProto.link(&m_jit);
     10856        jsValueResult(tempGPR, node);
     10857#else
     10858        m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + TagOffset), temp2GPR);
     10859        m_jit.load32(MacroAssembler::Address(tempGPR, Structure::prototypeOffset() + PayloadOffset), tempGPR);
     10860        auto isMonoProto = m_jit.branch32(CCallHelpers::NotEqual, temp2GPR, TrustedImm32(JSValue::Int32Tag));
     10861        m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + TagOffset), temp2GPR);
     10862        m_jit.load32(JITCompiler::BaseIndex(objectGPR, tempGPR, JITCompiler::TimesEight, JSObject::offsetOfInlineStorage() + PayloadOffset), tempGPR);
     10863        isMonoProto.link(&m_jit);
     10864        jsValueResult(temp2GPR, tempGPR, node);
     10865#endif
     10866        return;
     10867    }
     10868    case ObjectUse: {
     10869        SpeculateCellOperand value(this, node->child1());
     10870        JSValueRegsTemporary result(this);
     10871
     10872        GPRReg valueGPR = value.gpr();
     10873        JSValueRegs resultRegs = result.regs();
     10874
     10875        speculateObject(node->child1(), valueGPR);
     10876
     10877        flushRegisters();
     10878        callOperation(operationGetPrototypeOfObject, resultRegs, valueGPR);
     10879        m_jit.exceptionCheck();
     10880        jsValueResult(resultRegs, node);
     10881        return;
     10882    }
     10883    default: {
     10884        JSValueOperand value(this, node->child1());
     10885        JSValueRegsTemporary result(this);
     10886
     10887        JSValueRegs valueRegs = value.jsValueRegs();
     10888        JSValueRegs resultRegs = result.regs();
     10889
     10890        flushRegisters();
     10891        callOperation(operationGetPrototypeOf, resultRegs, valueRegs);
     10892        m_jit.exceptionCheck();
     10893        jsValueResult(resultRegs, node);
     10894        return;
     10895    }
     10896    }
     10897}
     10898
    1077010899} } // namespace JSC::DFG
    1077110900
Note: See TracChangeset for help on using the changeset viewer.