Ignore:
Timestamp:
May 22, 2020, 3:31:13 PM (5 years ago)
Author:
[email protected]
Message:

in_by_val inside structure property for-in loop should use an opcode like has_structure_property but for "in"
https://bugs.webkit.org/show_bug.cgi?id=212239

Reviewed by Tadeu Zagallo.

JSTests:

  • microbenchmarks/in-by-val-inside-for-in-loop.js: Added.

(assert):
(count):

  • stress/in-by-val-inside-for-in-loop.js: Added.

(assert):
(test1.count):
(test1):
(test2.count):
(test2):
(test3.count):
(test3):
(test4.count):
(test4):
(test5.count):
(test5):
(test6.count):
(test6):
(test7.count):
(test7):
(test8.count):
(test8):

Source/JavaScriptCore:

There is code inside Speedometer 2 that is like:

`
for (let p in o) {

if (p in o2)

...

}
`

Where o and o2 frequently share the same structure. Elm does this when it's
diffing two objects. We already optimize o2[p] (get_by_val) in the above loop
for structure properties. This patch adds that same optimization for in_by_val.
Because we already emit a "structure" loop for for-in, where we iterate structure
properties, the fast path for the above, where o and o2 have the same
structure is simply a structure check followed by return true.

This patch introduces the new opcode: op_in_structure_property. Its fast path is identical
to op_has_structure_property. Its slow path, however, behaves like "in", which
uses the HasProperty internal method, unlike op_has_structure_property,
which uses the GetOwnProperty internal method. This behavior difference is
observable using Proxy.

This a 5% perf improvement in the Elm subtest in Speedometer 2.

  • bytecode/BytecodeList.rb:
  • bytecode/BytecodeUseDef.cpp:

(JSC::computeUsesForBytecodeIndexImpl):
(JSC::computeDefsForBytecodeIndexImpl):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitInByVal):
(JSC::rewriteOp):
(JSC::StructureForInContext::finalize):

  • bytecompiler/BytecodeGenerator.h:

(JSC::StructureForInContext::addInInst):

  • dfg/DFGAbstractInterpreterInlines.h:

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

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCapabilities.cpp:

(JSC::DFG::capabilityLevel):

  • dfg/DFGClobberize.h:

(JSC::DFG::clobberize):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

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

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

(JSC::DFG::safeToExecute):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileInStructureProperty):

  • 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::compileHasStructurePropertyImpl):
(JSC::FTL::DFG::LowerDFGToB3::compileHasStructureProperty):
(JSC::FTL::DFG::LowerDFGToB3::compileInStructureProperty):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_in_structure_property):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_in_structure_property):

  • llint/LLIntOffsetsExtractor.cpp:
  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • runtime/JSObject.cpp:

(JSC::JSObject::hasPropertyGeneric const):

  • runtime/JSPropertyNameEnumerator.h:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ftl/FTLLowerDFGToB3.cpp

    r261755 r262083  
    14781478            compileHasStructureProperty();
    14791479            break;
     1480        case InStructureProperty:
     1481            compileInStructureProperty();
     1482            break;
    14801483        case GetDirectPname:
    14811484            compileGetDirectPname();
     
    1224212245    }
    1224312246
    12244     void compileHasStructureProperty()
     12247    template <typename SlowPathCall>
     12248    void compileHasStructurePropertyImpl(LValue base, SlowPathCall slowPathCall)
    1224512249    {
    1224612250        JSGlobalObject* globalObject = m_graph.globalObjectFor(m_node->origin.semantic);
    12247         LValue base = lowJSValue(m_node->child1());
    1224812251        LValue property = lowString(m_node->child2());
    1224912252        LValue enumerator = lowCell(m_node->child3());
    1225012253
     12254        LBasicBlock isCellCase = m_out.newBlock();
    1225112255        LBasicBlock correctStructure = m_out.newBlock();
    12252         LBasicBlock wrongStructure = m_out.newBlock();
     12256        LBasicBlock slowPath = m_out.newBlock();
    1225312257        LBasicBlock continuation = m_out.newBlock();
     12258
     12259        m_out.branch(isCell(base, provenType(m_node->child1())),
     12260            usually(isCellCase), rarely(slowPath));
     12261
     12262        LBasicBlock lastNext = m_out.appendTo(isCellCase, correctStructure);
    1225412263
    1225512264        m_out.branch(m_out.notEqual(
    1225612265            m_out.load32(base, m_heaps.JSCell_structureID),
    1225712266            m_out.load32(enumerator, m_heaps.JSPropertyNameEnumerator_cachedStructureID)),
    12258             rarely(wrongStructure), usually(correctStructure));
    12259 
    12260         LBasicBlock lastNext = m_out.appendTo(correctStructure, wrongStructure);
     12267            rarely(slowPath), usually(correctStructure));
     12268
     12269        m_out.appendTo(correctStructure, slowPath);
    1226112270        ValueFromBlock correctStructureResult = m_out.anchor(m_out.booleanTrue);
    1226212271        m_out.jump(continuation);
    1226312272
    12264         m_out.appendTo(wrongStructure, continuation);
    12265         ValueFromBlock wrongStructureResult = m_out.anchor(
     12273        m_out.appendTo(slowPath, continuation);
     12274        ValueFromBlock slowPathResult = m_out.anchor(
    1226612275            m_out.equal(
    1226712276                m_out.constInt64(JSValue::encode(jsBoolean(true))),
    12268                 vmCall(Int64, operationHasGenericProperty, weakPointer(globalObject), base, property)));
     12277                vmCall(Int64, slowPathCall, weakPointer(globalObject), base, property)));
    1226912278        m_out.jump(continuation);
    1227012279
    1227112280        m_out.appendTo(continuation, lastNext);
    12272         setBoolean(m_out.phi(Int32, correctStructureResult, wrongStructureResult));
     12281        setBoolean(m_out.phi(Int32, correctStructureResult, slowPathResult));
     12282    }
     12283
     12284    void compileHasStructureProperty()
     12285    {
     12286        compileHasStructurePropertyImpl(lowJSValue(m_node->child1()), operationHasGenericProperty);
     12287    }
     12288
     12289    void compileInStructureProperty()
     12290    {
     12291        compileHasStructurePropertyImpl(lowCell(m_node->child1()), operationInStructureProperty);
    1227312292    }
    1227412293
Note: See TracChangeset for help on using the changeset viewer.