Changeset 208117 in webkit


Ignore:
Timestamp:
Oct 29, 2016 6:38:22 PM (7 years ago)
Author:
sbarati@apple.com
Message:

We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
https://bugs.webkit.org/show_bug.cgi?id=163305

Reviewed by Keith Miller.

JSTests:

  • microbenchmarks/pure-get-by-id-cse-2.js: Added.

(foo):

  • microbenchmarks/pure-get-by-id-cse.js: Added.

(foo):

  • stress/pure-get-by-id-cse-correctness.js: Added.

(assert):
(foo):

  • stress/pure-get-by-id-on-non-object.js: Added.

(assert):
(foo):

Source/JavaScriptCore:

This creates a new GetById node in the DFG called PureGetById. We emit a
PureGetById when we profile that a get_by_id in the baseline never does
side effects. PureGetById speculates on the fact that it won't do side
effects. If it realizes that it must perform side effects, it will perform
the side effect, but also invalidate the CodeBlock that compiled it,
which will cause us to exit once we return back to the compiled code.
This allows us to have stricter clobberize rules for PureGetById which
model how getOwnPropertySlot(VMInquiry) behaves. This means that PureGetByIds
can be CSEd with each other, and that other things are more likely to
be CSEd around a PureGetById. To profile if a get_by_id does side
effects, I've added an extra bit into StructureStubInfo that we write
to when performing a get_by_id slow path call. If we notice that we
never do effects, inside the ByteCodeParser, we will emit a PureGetById
instead of a GetById.

To justify the performance benefit of this patch, I ran the suite of
benchmarks with useAccessInlining=false. This meant that we don't compile
any (Multi)GetByOffset/(Multi)PutByOffset. This was just to try to see if
this patch is worth anything at all in a world where we emit many
PureGetByIds. Running the benchmarks under this mode showed a 3.5% octane
improvement and a 15% kraken improvement. However, when running benchmarks
with useAccessInlining=true (the default JSC state), this patch is neutral.
I think the main reason for this is that the DFG is good at knowing when to
emit (Multi)GetByOffset, and most benchmarks that would benefit from
PureGetById are already emitting (Multi)GetByOffset. However, PureGetById can be
profitable when we encounter code that is too polymorphic for (Multi)GetByOffset.
It's reasonable to expect that JS code in the wild will fall into this use
case even though it might not be represented in some of the major JS benchmarks.
I wrote some microbenchmarks to demonstrate the benefits of PureGetById CSE,
and they were 30% (eliminating a few PureGetById from an add expression)
to 10x faster (eliminating a PureGetById in a loop).

  • bytecode/StructureStubInfo.cpp:

(JSC::StructureStubInfo::StructureStubInfo):
(JSC::StructureStubInfo::reset):

  • bytecode/StructureStubInfo.h:
  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGArrayMode.cpp:

(JSC::DFG::canBecomeGetArrayLength):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleGetById):
(JSC::DFG::ByteCodeParser::parseBlock):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

  • dfg/DFGNode.h:

(JSC::DFG::Node::convertToGetByOffset):
(JSC::DFG::Node::convertToMultiGetByOffset):
(JSC::DFG::Node::hasIdentifier):
(JSC::DFG::Node::hasHeapPrediction):

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileTryGetById):
(JSC::DFG::SpeculativeJIT::compilePureGetById):

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

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • ftl/FTLCapabilities.cpp:

(JSC::FTL::canCompile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileNode):
(JSC::FTL::DFG::LowerDFGToB3::compileGetById):
(JSC::FTL::DFG::LowerDFGToB3::getById):

  • jit/JITOperations.cpp:

(JSC::pureGetByIdCommon):

  • jit/JITOperations.h:
  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_try_get_by_id):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_try_get_by_id):

  • jit/Repatch.cpp:

(JSC::appropriateOptimizingGetByIdFunction):
(JSC::appropriateGenericGetByIdFunction):
(JSC::tryCacheGetByID):

  • jit/Repatch.h:
  • profiler/ProfilerJettisonReason.cpp:

(WTF::printInternal):

  • profiler/ProfilerJettisonReason.h:
Location:
trunk
Files:
4 added
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r208053 r208117  
     12016-10-29  Saam Barati  <sbarati@apple.com>
     2
     3        We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
     4        https://bugs.webkit.org/show_bug.cgi?id=163305
     5
     6        Reviewed by Keith Miller.
     7
     8        * microbenchmarks/pure-get-by-id-cse-2.js: Added.
     9        (foo):
     10        * microbenchmarks/pure-get-by-id-cse.js: Added.
     11        (foo):
     12        * stress/pure-get-by-id-cse-correctness.js: Added.
     13        (assert):
     14        (foo):
     15        * stress/pure-get-by-id-on-non-object.js: Added.
     16        (assert):
     17        (foo):
     18
    1192016-10-28  Csaba Osztrogonác  <ossy@webkit.org>
    220
  • trunk/Source/JavaScriptCore/ChangeLog

    r208097 r208117  
     12016-10-29  Saam Barati  <sbarati@apple.com>
     2
     3        We should have a way of profiling when a get_by_id is pure and to emit a PureGetById in the DFG/FTL
     4        https://bugs.webkit.org/show_bug.cgi?id=163305
     5
     6        Reviewed by Keith Miller.
     7
     8        This creates a new GetById node in the DFG called PureGetById. We emit a
     9        PureGetById when we profile that a get_by_id in the baseline never does
     10        side effects. PureGetById speculates on the fact that it won't do side
     11        effects. If it realizes that it must perform side effects, it will perform
     12        the side effect, but also invalidate the CodeBlock that compiled it,
     13        which will cause us to exit once we return back to the compiled code.
     14        This allows us to have stricter clobberize rules for PureGetById which
     15        model how getOwnPropertySlot(VMInquiry) behaves. This means that PureGetByIds
     16        can be CSEd with each other, and that other things are more likely to
     17        be CSEd around a PureGetById. To profile if a get_by_id does side
     18        effects, I've added an extra bit into StructureStubInfo that we write
     19        to when performing a get_by_id slow path call. If we notice that we
     20        never do effects, inside the ByteCodeParser, we will emit a PureGetById
     21        instead of a GetById.
     22
     23        To justify the performance benefit of this patch, I ran the suite of
     24        benchmarks with useAccessInlining=false. This meant that we don't compile
     25        any (Multi)GetByOffset/(Multi)PutByOffset. This was just to try to see if
     26        this patch is worth anything at all in a world where we emit many
     27        PureGetByIds. Running the benchmarks under this mode showed a 3.5% octane
     28        improvement and a 15% kraken improvement. However, when running benchmarks
     29        with useAccessInlining=true (the default JSC state), this patch is neutral.
     30        I think the main reason for this is that the DFG is good at knowing when to
     31        emit (Multi)GetByOffset, and most benchmarks that would benefit from
     32        PureGetById are already emitting (Multi)GetByOffset. However, PureGetById can be
     33        profitable when we encounter code that is too polymorphic for (Multi)GetByOffset.
     34        It's reasonable to expect that JS code in the wild will fall into this use
     35        case even though it might not be represented in some of the major JS benchmarks.
     36        I wrote some microbenchmarks to demonstrate the benefits of PureGetById CSE,
     37        and they were 30% (eliminating a few PureGetById from an add expression)
     38        to 10x faster (eliminating a PureGetById in a loop).
     39
     40        * bytecode/StructureStubInfo.cpp:
     41        (JSC::StructureStubInfo::StructureStubInfo):
     42        (JSC::StructureStubInfo::reset):
     43        * bytecode/StructureStubInfo.h:
     44        * dfg/DFGAbstractInterpreterInlines.h:
     45        (JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):
     46        * dfg/DFGArrayMode.cpp:
     47        (JSC::DFG::canBecomeGetArrayLength):
     48        * dfg/DFGByteCodeParser.cpp:
     49        (JSC::DFG::ByteCodeParser::handleGetById):
     50        (JSC::DFG::ByteCodeParser::parseBlock):
     51        * dfg/DFGClobberize.h:
     52        (JSC::DFG::clobberize):
     53        * dfg/DFGConstantFoldingPhase.cpp:
     54        (JSC::DFG::ConstantFoldingPhase::foldConstants):
     55        * dfg/DFGDoesGC.cpp:
     56        (JSC::DFG::doesGC):
     57        * dfg/DFGFixupPhase.cpp:
     58        (JSC::DFG::FixupPhase::fixupNode):
     59        * dfg/DFGNode.h:
     60        (JSC::DFG::Node::convertToGetByOffset):
     61        (JSC::DFG::Node::convertToMultiGetByOffset):
     62        (JSC::DFG::Node::hasIdentifier):
     63        (JSC::DFG::Node::hasHeapPrediction):
     64        * dfg/DFGNodeType.h:
     65        * dfg/DFGPredictionPropagationPhase.cpp:
     66        * dfg/DFGSafeToExecute.h:
     67        (JSC::DFG::safeToExecute):
     68        * dfg/DFGSpeculativeJIT.cpp:
     69        (JSC::DFG::SpeculativeJIT::compileTryGetById):
     70        (JSC::DFG::SpeculativeJIT::compilePureGetById):
     71        * dfg/DFGSpeculativeJIT.h:
     72        * dfg/DFGSpeculativeJIT32_64.cpp:
     73        (JSC::DFG::SpeculativeJIT::cachedGetById):
     74        (JSC::DFG::SpeculativeJIT::compile):
     75        * dfg/DFGSpeculativeJIT64.cpp:
     76        (JSC::DFG::SpeculativeJIT::cachedGetById):
     77        (JSC::DFG::SpeculativeJIT::compile):
     78        * ftl/FTLCapabilities.cpp:
     79        (JSC::FTL::canCompile):
     80        * ftl/FTLLowerDFGToB3.cpp:
     81        (JSC::FTL::DFG::LowerDFGToB3::compileNode):
     82        (JSC::FTL::DFG::LowerDFGToB3::compileGetById):
     83        (JSC::FTL::DFG::LowerDFGToB3::getById):
     84        * jit/JITOperations.cpp:
     85        (JSC::pureGetByIdCommon):
     86        * jit/JITOperations.h:
     87        * jit/JITPropertyAccess.cpp:
     88        (JSC::JIT::emit_op_try_get_by_id):
     89        * jit/JITPropertyAccess32_64.cpp:
     90        (JSC::JIT::emit_op_try_get_by_id):
     91        * jit/Repatch.cpp:
     92        (JSC::appropriateOptimizingGetByIdFunction):
     93        (JSC::appropriateGenericGetByIdFunction):
     94        (JSC::tryCacheGetByID):
     95        * jit/Repatch.h:
     96        * profiler/ProfilerJettisonReason.cpp:
     97        (WTF::printInternal):
     98        * profiler/ProfilerJettisonReason.h:
     99
    11002016-10-28  Joseph Pecoraro  <pecoraro@apple.com>
    2101
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.cpp

    r205462 r208117  
    4949    , tookSlowPath(false)
    5050    , everConsidered(false)
     51    , didSideEffects(false)
    5152{
    5253}
     
    217218
    218219    switch (accessType) {
    219     case AccessType::GetPure:
     220    case AccessType::TryGet:
     221        resetGetByID(codeBlock, *this, GetByIDKind::Try);
     222        break;
     223    case AccessType::PureGet:
    220224        resetGetByID(codeBlock, *this, GetByIDKind::Pure);
    221225        break;
  • trunk/Source/JavaScriptCore/bytecode/StructureStubInfo.h

    r206525 r208117  
    4747enum class AccessType : int8_t {
    4848    Get,
    49     GetPure,
     49    TryGet,
     50    PureGet,
    5051    Put,
    5152    In
     
    206207    bool tookSlowPath : 1;
    207208    bool everConsidered : 1;
     209    bool didSideEffects : 1;
    208210};
    209211
  • trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.h

    r208077 r208117  
    21202120        break;
    21212121
     2122    case PureGetById:
    21222123    case GetById:
    21232124    case GetByIdFlush: {
     
    21512152        }
    21522153
    2153         clobberWorld(node->origin.semantic, clobberLimit);
     2154        if (node->op() == PureGetById)
     2155            clobberStructures(clobberLimit);
     2156        else
     2157            clobberWorld(node->origin.semantic, clobberLimit);
    21542158        forNode(node).makeHeapTop();
    21552159        break;
  • trunk/Source/JavaScriptCore/dfg/DFGArrayMode.cpp

    r205830 r208117  
    153153static bool canBecomeGetArrayLength(Graph& graph, Node* node)
    154154{
    155     if (node->op() != GetById)
    156         return false;
    157     auto uid = graph.identifiers()[node->identifierNumber()];
    158     return uid == graph.m_vm.propertyNames->length.impl();
     155    if (node->op() == GetById || node->op() == PureGetById) {
     156        auto uid = graph.identifiers()[node->identifierNumber()];
     157        return uid == graph.m_vm.propertyNames->length.impl();
     158    }
     159    return false;
    159160}
    160161
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r208078 r208117  
    33083308   
    33093309    NodeType getById;
    3310     if (type == AccessType::Get)
     3310    switch (type) {
     3311    case AccessType::Get:
    33113312        getById = getByIdStatus.makesCalls() ? GetByIdFlush : GetById;
    3312     else
     3313        break;
     3314    case AccessType::TryGet:
    33133315        getById = TryGetById;
     3316        break;
     3317    case AccessType::PureGet:
     3318        getById = PureGetById;
     3319        break;
     3320    default:
     3321        RELEASE_ASSERT_NOT_REACHED();
     3322    }
    33143323
    33153324    // Special path for custom accessors since custom's offset does not have any meanings.
     
    41994208            Node* base = get(VirtualRegister(currentInstruction[2].u.operand));
    42004209            Node* property = get(VirtualRegister(currentInstruction[3].u.operand));
    4201             bool compiledAsGetById = false;
     4210            bool compileAsGetById = false;
     4211            bool compileAsPureGetById = false;
    42024212            GetByIdStatus getByIdStatus;
    42034213            unsigned identifierNumber = 0;
     
    42084218                // At that time, there is no information.
    42094219                if (byValInfo && byValInfo->stubInfo && !byValInfo->tookSlowPath && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadIdent) && !m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, BadCell)) {
    4210                     compiledAsGetById = true;
     4220                    compileAsGetById = true;
     4221                    compileAsPureGetById = !byValInfo->stubInfo->didSideEffects;
    42114222                    identifierNumber = m_graph.identifiers().ensure(byValInfo->cachedId.impl());
    42124223                    UniquedStringImpl* uid = m_graph.identifiers()[identifierNumber];
     
    42264237            }
    42274238
    4228             if (compiledAsGetById)
    4229                 handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, AccessType::Get, OPCODE_LENGTH(op_get_by_val));
    4230             else {
     4239            if (compileAsGetById) {
     4240                AccessType type = compileAsPureGetById ? AccessType::PureGet : AccessType::Get;
     4241                handleGetById(currentInstruction[1].u.operand, prediction, base, identifierNumber, getByIdStatus, type, OPCODE_LENGTH(op_get_by_val));
     4242            } else {
    42314243                ArrayMode arrayMode = getArrayMode(currentInstruction[4].u.arrayProfile, Array::Read);
    42324244                Node* getByVal = addToGraph(GetByVal, OpInfo(arrayMode.asWord()), OpInfo(prediction), base, property);
     
    43644376                m_inlineStackTop->m_stubInfos, m_dfgStubInfos,
    43654377                currentCodeOrigin(), uid);
    4366             AccessType type = op_try_get_by_id == opcodeID ? AccessType::GetPure : AccessType::Get;
     4378            AccessType type;
     4379            if (opcodeID == op_try_get_by_id)
     4380                type = AccessType::TryGet;
     4381            else {
     4382                ConcurrentJITLocker locker(m_inlineStackTop->m_profiledBlock->m_lock);
     4383                unsigned bytecodeIndex = currentCodeOrigin().bytecodeIndex;
     4384                StructureStubInfo* info = m_inlineStackTop->m_stubInfos.get(CodeOrigin(bytecodeIndex));
     4385                if (info && info->everConsidered && !info->didSideEffects)
     4386                    type = AccessType::PureGet;
     4387                else
     4388                    type = AccessType::Get;
     4389            }
    43674390
    43684391            unsigned opcodeLength = opcodeID == op_try_get_by_id ? OPCODE_LENGTH(op_try_get_by_id) : OPCODE_LENGTH(op_get_by_id);
  • trunk/Source/JavaScriptCore/dfg/DFGClobberize.h

    r208077 r208117  
    496496        return;
    497497       
     498    case PureGetById: {
     499        // We model what is allowed inside a getOwnPropertySlot(VMInquiry) here.
     500        // Some getOwnPropertySlot implementations will lazily inject properties, which
     501        // may change the object's structure.
     502
     503        read(JSCell_structureID);
     504        read(JSCell_typeInfoFlags);
     505        read(JSCell_typeInfoType);
     506        read(JSCell_indexingType);
     507        read(JSObject_butterfly);
     508        read(MiscFields);
     509
     510        AbstractHeap propertyNameHeap(NamedProperties, node->identifierNumber());
     511        read(propertyNameHeap);
     512
     513        write(JSCell_structureID);
     514        write(JSCell_typeInfoFlags);
     515
     516        write(Watchpoint_fire);
     517        write(MiscFields);
     518
     519        // This can happen if lazily adding fields to an object happens in getOwnPropertySlot
     520        // and we need to allocate out of line storage.
     521        write(JSObject_butterfly);
     522
     523        def(HeapLocation(NamedPropertyLoc, propertyNameHeap, node->child1()), LazyNode(node));
     524        return;
     525    }
     526
    498527    case GetById:
    499528    case GetByIdFlush:
  • trunk/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp

    r206846 r208117  
    449449            }
    450450       
     451            case PureGetById:
    451452            case GetById:
    452453            case GetByIdFlush: {
     
    459460                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
    460461                alreadyHandled = true; // Don't allow the default constant folder to do things to this.
     462
     463                if (!Options::useAccessInlining())
     464                    break;
    461465
    462466                if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered()
     
    514518                m_interpreter.execute(indexInBlock); // Push CFA over this node after we get the state before.
    515519                alreadyHandled = true; // Don't allow the default constant folder to do things to this.
     520
     521                if (!Options::useAccessInlining())
     522                    break;
    516523
    517524                if (baseValue.m_structure.isTop() || baseValue.m_structure.isClobbered())
  • trunk/Source/JavaScriptCore/dfg/DFGDoesGC.cpp

    r208077 r208117  
    265265        return false;
    266266
     267    case PureGetById: // We are modeling getOwnPropertySlot here, which may GC because it is allowed to allocate things.
    267268    case CreateActivation:
    268269    case CreateDirectArguments:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r208077 r208117  
    11681168        }
    11691169
     1170        case PureGetById:
    11701171        case GetById:
    11711172        case GetByIdFlush: {
  • trunk/Source/JavaScriptCore/dfg/DFGNode.h

    r208078 r208117  
    533533    void convertToGetByOffset(StorageAccessData& data, Edge storage, Edge base)
    534534    {
    535         ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == MultiGetByOffset);
     535        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById || m_op == MultiGetByOffset);
    536536        m_opInfo = &data;
    537537        children.setChild1(storage);
     
    543543    void convertToMultiGetByOffset(MultiGetByOffsetData* data)
    544544    {
    545         ASSERT(m_op == GetById || m_op == GetByIdFlush);
     545        ASSERT(m_op == GetById || m_op == GetByIdFlush || m_op == PureGetById);
    546546        m_opInfo = data;
    547547        child1().setUseKind(CellUse);
     
    919919        case TryGetById:
    920920        case GetById:
     921        case PureGetById:
    921922        case GetByIdFlush:
    922923        case GetByIdWithThis:
     
    14291430        case ArithTrunc:
    14301431        case GetDirectPname:
     1432        case PureGetById:
    14311433        case GetById:
    14321434        case GetByIdFlush:
  • trunk/Source/JavaScriptCore/dfg/DFGNodeType.h

    r208077 r208117  
    186186    macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs) \
    187187    macro(TryGetById, NodeResultJS) \
     188    macro(PureGetById, NodeResultJS | NodeMustGenerate) \
    188189    macro(GetById, NodeResultJS | NodeMustGenerate) \
    189190    macro(GetByIdFlush, NodeResultJS | NodeMustGenerate) \
  • trunk/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp

    r208077 r208117  
    683683        case StringReplace:
    684684        case StringReplaceRegExp:
     685        case PureGetById:
    685686        case GetById:
    686687        case GetByIdFlush:
  • trunk/Source/JavaScriptCore/dfg/DFGSafeToExecute.h

    r208077 r208117  
    200200    case DeleteById:
    201201    case DeleteByVal:
     202    case PureGetById:
    202203    case GetById:
    203204    case GetByIdWithThis:
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp

    r208077 r208117  
    10041004        base.use();
    10051005
    1006         cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::GetPure);
     1006        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::TryGet);
    10071007
    10081008        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
     
    10211021        JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
    10221022
    1023         cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::GetPure);
     1023        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::TryGet);
    10241024
    10251025        jsValueResult(resultRegs, node, DataFormatJS, UseChildrenCalledExplicitly);
     
    10311031        break;
    10321032    }
     1033}
     1034
     1035void SpeculativeJIT::compilePureGetById(Node* node)
     1036{
     1037    ASSERT(node->op() == PureGetById);
     1038
     1039    switch (node->child1().useKind()) {
     1040    case CellUse: {
     1041        SpeculateCellOperand base(this, node->child1());
     1042        JSValueRegsTemporary result(this, Reuse, base);
     1043
     1044        JSValueRegs baseRegs = JSValueRegs::payloadOnly(base.gpr());
     1045        JSValueRegs resultRegs = result.regs();
     1046
     1047        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), JITCompiler::Jump(), NeedToSpill, AccessType::PureGet);
     1048
     1049        jsValueResult(resultRegs, node);
     1050        break;
     1051    }
     1052    case UntypedUse: {
     1053        JSValueOperand base(this, node->child1());
     1054        JSValueRegsTemporary result(this, Reuse, base);
     1055
     1056        JSValueRegs baseRegs = base.jsValueRegs();
     1057        JSValueRegs resultRegs = result.regs();
     1058   
     1059        JITCompiler::Jump notCell = m_jit.branchIfNotCell(baseRegs);
     1060   
     1061        cachedGetById(node->origin.semantic, baseRegs, resultRegs, node->identifierNumber(), notCell, NeedToSpill, AccessType::PureGet);
     1062   
     1063        jsValueResult(resultRegs, node);
     1064        break;
     1065    }
     1066    default:
     1067        RELEASE_ASSERT_NOT_REACHED();
     1068    }
    10331069}
    10341070
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h

    r208077 r208117  
    722722    void compileDeleteByVal(Node*);
    723723    void compileTryGetById(Node*);
     724    void compilePureGetById(Node*);
    724725    void compileIn(Node*);
    725726   
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp

    r208077 r208117  
    211211    if (type == AccessType::Get)
    212212        getByIdFunction = operationGetByIdOptimize;
     213    else if (type == AccessType::PureGet)
     214        getByIdFunction = operationPureGetByIdOptimize;
    213215    else
    214216        getByIdFunction = operationTryGetByIdOptimize;
     
    42704272    }
    42714273
     4274    case PureGetById: {
     4275        compilePureGetById(node);
     4276        break;
     4277    }
     4278
    42724279    case GetByIdWithThis: {
    42734280        JSValueOperand base(this, node->child1());
  • trunk/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp

    r208077 r208117  
    180180    slowCases.append(gen.slowPathJump());
    181181   
     182    auto slowPathFunction = type == AccessType::Get ? operationGetByIdOptimize :
     183        type == AccessType::PureGet ? operationPureGetByIdOptimize : operationTryGetByIdOptimize;
     184
    182185    auto slowPath = slowPathCall(
    183         slowCases, this, type == AccessType::Get ? operationGetByIdOptimize : operationTryGetByIdOptimize,
     186        slowCases, this, slowPathFunction,
    184187        spillMode, ExceptionCheckRequirement::CheckNeeded,
    185188        resultGPR, gen.stubInfo(), baseGPR, identifierUID(identifierNumber));
     
    42364239    }
    42374240
     4241    case PureGetById: {
     4242        compilePureGetById(node);
     4243        break;
     4244    }
     4245
    42384246    case GetByIdFlush: {
    42394247        if (!node->prediction()) {
  • trunk/Source/JavaScriptCore/ftl/FTLCapabilities.cpp

    r208077 r208117  
    177177    case TryGetById:
    178178    case GetById:
     179    case PureGetById:
    179180    case GetByIdFlush:
    180181    case GetByIdWithThis:
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r208077 r208117  
    624624            break;
    625625        case TryGetById:
    626             compileGetById(AccessType::GetPure);
     626            compileGetById(AccessType::TryGet);
     627            break;
     628        case PureGetById:
     629            compileGetById(AccessType::PureGet);
    627630            break;
    628631        case GetById:
     
    27892792    void compileGetById(AccessType type)
    27902793    {
    2791         ASSERT(type == AccessType::Get || type == AccessType::GetPure);
     2794        ASSERT(type == AccessType::Get || type == AccessType::TryGet || type == AccessType::PureGet);
    27922795        switch (m_node->child1().useKind()) {
    27932796        case CellUse: {
     
    28162819            if (type == AccessType::Get)
    28172820                getByIdFunction = operationGetByIdGeneric;
     2821            else if (type == AccessType::PureGet)
     2822                getByIdFunction = operationPureGetByIdGeneric;
    28182823            else
    28192824                getByIdFunction = operationTryGetByIdGeneric;
     
    88398844                        if (type == AccessType::Get)
    88408845                            optimizationFunction = operationGetByIdOptimize;
     8846                        else if (type == AccessType::PureGet)
     8847                            optimizationFunction = operationPureGetByIdOptimize;
    88418848                        else
    88428849                            optimizationFunction = operationTryGetByIdOptimize;
  • trunk/Source/JavaScriptCore/jit/JITOperations.cpp

    r208052 r208117  
    7171namespace JSC {
    7272
     73ALWAYS_INLINE static EncodedJSValue pureGetByIdCommon(VM& vm, ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid, const std::function<void (const PropertySlot&, const Identifier&)>& function = [] (const PropertySlot&, const Identifier&) { })
     74{
     75    Identifier ident = Identifier::fromUid(&vm, uid);
     76    JSValue baseValue = JSValue::decode(base);
     77
     78    ASSERT(JITCode::isOptimizingJIT(exec->codeBlock()->jitType()));
     79
     80    PropertySlot slot(baseValue, PropertySlot::InternalMethodType::VMInquiry);
     81    return JSValue::encode(baseValue.getPropertySlot(exec, ident, slot, [&] (bool, PropertySlot&) -> JSValue {
     82        bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
     83        if (UNLIKELY(willDoSideEffects)) {
     84            {
     85                CodeOrigin codeOrigin = exec->codeOrigin();
     86                CodeBlock* currentBaseline = baselineCodeBlockForOriginAndBaselineCodeBlock(codeOrigin, exec->codeBlock()->alternative());
     87                CodeOrigin originBytecodeIndex = CodeOrigin(codeOrigin.bytecodeIndex); // Since we're searching in the baseline, we just care about bytecode index.
     88                ConcurrentJITLocker locker(currentBaseline->m_lock);
     89                if (StructureStubInfo* stub = currentBaseline->findStubInfo(originBytecodeIndex))
     90                    stub->didSideEffects = true;
     91            }
     92
     93            exec->codeBlock()->jettison(Profiler::JettisonDueToPureGetByIdEffects);
     94            return baseValue.get(exec, uid);
     95        }
     96
     97        function(slot, ident);
     98        return slot.isValue() ? slot.getValue(exec, ident) : jsUndefined();
     99    }));
     100}
     101
    73102extern "C" {
    74103
     
    166195}
    167196
     197EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
     198{
     199    VM* vm = &exec->vm();
     200    NativeCallFrameTracer tracer(vm, exec);
     201
     202    return pureGetByIdCommon(*vm, exec, base, uid);
     203}
     204
     205EncodedJSValue JIT_OPERATION operationPureGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
     206{
     207    VM* vm = &exec->vm();
     208    NativeCallFrameTracer tracer(vm, exec);
     209
     210    stubInfo->tookSlowPath = true;
     211
     212    return pureGetByIdCommon(*vm, exec, base, uid);
     213}
     214
     215EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
     216{
     217    VM* vm = &exec->vm();
     218    NativeCallFrameTracer tracer(vm, exec);
     219
     220    return pureGetByIdCommon(*vm, exec, base, uid,
     221        [&] (const PropertySlot& slot, const Identifier& ident) {
     222            ASSERT((slot.isValue() || slot.isUnset()) && !slot.isTaintedByOpaqueObject());
     223            JSValue baseValue = JSValue::decode(base);
     224            if (stubInfo->considerCaching(baseValue.structureOrNull()))
     225                repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Pure);
     226        });
     227}
     228
    168229EncodedJSValue JIT_OPERATION operationTryGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
    169230{
     
    180241}
    181242
    182 
    183243EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
    184244{
     
    208268
    209269    if (stubInfo->considerCaching(baseValue.structureOrNull()) && !slot.isTaintedByOpaqueObject() && (slot.isCacheableValue() || slot.isCacheableGetter() || slot.isUnset()))
    210         repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Pure);
     270        repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Try);
    211271
    212272    return JSValue::encode(slot.getPureResult());
     
    227287   
    228288    LOG_IC((ICEvent::OperationGetById, baseValue.classInfoOrNull(), ident));
    229     return JSValue::encode(baseValue.get(exec, ident, slot));
     289    JSValue result = baseValue.get(exec, ident, slot);
     290    bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
     291    stubInfo->didSideEffects |= willDoSideEffects;
     292    return JSValue::encode(result);
    230293}
    231294
     
    256319
    257320    return JSValue::encode(baseValue.getPropertySlot(exec, ident, [&] (bool found, PropertySlot& slot) -> JSValue {
     321        bool willDoSideEffects = !(slot.isValue() || slot.isUnset()) || slot.isTaintedByOpaqueObject();
     322        stubInfo->didSideEffects |= willDoSideEffects;
     323
    258324        if (stubInfo->considerCaching(baseValue.structureOrNull()))
    259325            repatchGetByID(exec, baseValue, ident, slot, *stubInfo, GetByIDKind::Normal);
  • trunk/Source/JavaScriptCore/jit/JITOperations.h

    r208052 r208117  
    331331EncodedJSValue JIT_OPERATION operationTryGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
    332332EncodedJSValue JIT_OPERATION operationTryGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
     333EncodedJSValue JIT_OPERATION operationPureGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
     334EncodedJSValue JIT_OPERATION operationPureGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
     335EncodedJSValue JIT_OPERATION operationPureGetByIdOptimize(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
    333336EncodedJSValue JIT_OPERATION operationGetById(ExecState*, StructureStubInfo*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
    334337EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState*, EncodedJSValue, UniquedStringImpl*) WTF_INTERNAL;
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess.cpp

    r206778 r208117  
    580580    JITGetByIdGenerator gen(
    581581        m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(m_bytecodeOffset), RegisterSet::stubUnavailableRegisters(),
    582         ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType::GetPure);
     582        ident->impl(), JSValueRegs(regT0), JSValueRegs(regT0), AccessType::TryGet);
    583583    gen.generateFastPath(*this);
    584584    addSlowCase(gen.slowPathJump());
  • trunk/Source/JavaScriptCore/jit/JITPropertyAccess32_64.cpp

    r206555 r208117  
    595595    JITGetByIdGenerator gen(
    596596        m_codeBlock, CodeOrigin(m_bytecodeOffset), CallSiteIndex(currentInstruction), RegisterSet::stubUnavailableRegisters(),
    597         ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType::GetPure);
     597        ident->impl(), JSValueRegs::payloadOnly(regT0), JSValueRegs(regT1, regT0), AccessType::TryGet);
    598598    gen.generateFastPath(*this);
    599599    addSlowCase(gen.slowPathJump());
  • trunk/Source/JavaScriptCore/jit/Repatch.cpp

    r207475 r208117  
    135135inline J_JITOperation_ESsiJI appropriateOptimizingGetByIdFunction(GetByIDKind kind)
    136136{
    137     if (kind == GetByIDKind::Normal)
     137    switch (kind) {
     138    case GetByIDKind::Normal:
    138139        return operationGetByIdOptimize;
    139     return operationTryGetByIdOptimize;
     140    case GetByIDKind::Try:
     141        return operationTryGetByIdOptimize;
     142    case GetByIDKind::Pure:
     143        return operationPureGetByIdOptimize;
     144    default:
     145        break;
     146    }
     147    ASSERT_NOT_REACHED();
     148    return operationGetByIdOptimize;
    140149}
    141150
    142151inline J_JITOperation_ESsiJI appropriateGenericGetByIdFunction(GetByIDKind kind)
    143152{
    144     if (kind == GetByIDKind::Normal)
     153    switch (kind) {
     154    case GetByIDKind::Normal:
    145155        return operationGetById;
    146     return operationTryGetById;
     156    case GetByIDKind::Try:
     157        return operationTryGetById;
     158    case GetByIDKind::Pure:
     159        return operationPureGetById;
     160    default:
     161        break;
     162    }
     163    ASSERT_NOT_REACHED();
     164    return operationGetById;
    147165}
    148166
     
    267285
    268286        if (kind == GetByIDKind::Pure) {
     287            AccessCase::AccessType type;
     288            if (slot.isCacheableValue())
     289                type = AccessCase::Load;
     290            else if (slot.isUnset())
     291                type = AccessCase::Miss;
     292            else
     293                RELEASE_ASSERT_NOT_REACHED();
     294
     295            newCase = AccessCase::tryGet(vm, codeBlock, type, offset, structure, conditionSet, loadTargetFromProxy, slot.watchpointSet());
     296        } else if (kind == GetByIDKind::Try) {
    269297            AccessCase::AccessType type;
    270298            if (slot.isCacheableValue())
  • trunk/Source/JavaScriptCore/jit/Repatch.h

    r207475 r208117  
    3737enum class GetByIDKind {
    3838    Normal,
     39    Try,
    3940    Pure
    4041};
  • trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.cpp

    r201239 r208117  
    5757        out.print("OSRExit");
    5858        return;
     59    case JettisonDueToPureGetByIdEffects:
     60        out.print("PureGetByIdEffects");
     61        return;
    5962    case JettisonDueToProfiledWatchpoint:
    6063        out.print("ProfiledWatchpoint");
  • trunk/Source/JavaScriptCore/profiler/ProfilerJettisonReason.h

    r206525 r208117  
    3636    JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail,
    3737    JettisonDueToOSRExit,
     38    JettisonDueToPureGetByIdEffects,
    3839    JettisonDueToProfiledWatchpoint,
    3940    JettisonDueToUnprofiledWatchpoint,
Note: See TracChangeset for help on using the changeset viewer.