Changeset 128219 in webkit


Ignore:
Timestamp:
Sep 11, 2012 1:00:31 PM (12 years ago)
Author:
fpizlo@apple.com
Message:

LLInt should optimize and profile array length accesses
https://bugs.webkit.org/show_bug.cgi?id=96417

Reviewed by Oliver Hunt.

This fixes the following hole in our array profiling strategy, where the array
is large (more than 1000 elements):

for (var i = 0; i < array.length; ++i) ...

The peeled use of array.length (in the array prologue) will execute only once
before DFG optimization kicks in from the loop's OSR point. Since it executed
only once, it executed in the LLInt. And prior to this patch, the LLInt did
not profile array.length accesses - so the DFG will assume, based on the lack
of profiling, that the access is in fact not an access to the JSArray length
property. That could then impede our ability to hoist the array structure
check, and may make us pessimistic in other ways as well, since the generic
GetById used for the array length access will be viewed as a side-effecting
operation.

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::printGetByIdCacheStatus):
(JSC::CodeBlock::finalizeUnconditionally):

  • bytecode/GetByIdStatus.cpp:

(JSC::GetByIdStatus::computeFromLLInt):

  • dfg/DFGByteCodeParser.cpp:

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

  • dfg/DFGCapabilities.h:

(JSC::DFG::canCompileOpcode):

  • dfg/DFGFixupPhase.cpp:

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

  • jit/JIT.cpp:

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

  • llint/LLIntSlowPaths.cpp:

(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
Location:
trunk/Source/JavaScriptCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r128191 r128219  
     12012-09-11  Filip Pizlo  <fpizlo@apple.com>
     2
     3        LLInt should optimize and profile array length accesses
     4        https://bugs.webkit.org/show_bug.cgi?id=96417
     5
     6        Reviewed by Oliver Hunt.
     7
     8        This fixes the following hole in our array profiling strategy, where the array
     9        is large (more than 1000 elements):
     10       
     11        for (var i = 0; i < array.length; ++i) ...
     12       
     13        The peeled use of array.length (in the array prologue) will execute only once
     14        before DFG optimization kicks in from the loop's OSR point. Since it executed
     15        only once, it executed in the LLInt. And prior to this patch, the LLInt did
     16        not profile array.length accesses - so the DFG will assume, based on the lack
     17        of profiling, that the access is in fact not an access to the JSArray length
     18        property. That could then impede our ability to hoist the array structure
     19        check, and may make us pessimistic in other ways as well, since the generic
     20        GetById used for the array length access will be viewed as a side-effecting
     21        operation.
     22
     23        * bytecode/CodeBlock.cpp:
     24        (JSC::CodeBlock::printGetByIdCacheStatus):
     25        (JSC::CodeBlock::finalizeUnconditionally):
     26        * bytecode/GetByIdStatus.cpp:
     27        (JSC::GetByIdStatus::computeFromLLInt):
     28        * dfg/DFGByteCodeParser.cpp:
     29        (JSC::DFG::ByteCodeParser::parseBlock):
     30        * dfg/DFGCapabilities.h:
     31        (JSC::DFG::canCompileOpcode):
     32        * dfg/DFGFixupPhase.cpp:
     33        (JSC::DFG::FixupPhase::fixupNode):
     34        * jit/JIT.cpp:
     35        (JSC::JIT::privateCompileMainPass):
     36        (JSC::JIT::privateCompileSlowCases):
     37        * llint/LLIntSlowPaths.cpp:
     38        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
     39        * llint/LowLevelInterpreter.asm:
     40        * llint/LowLevelInterpreter32_64.asm:
     41        * llint/LowLevelInterpreter64.asm:
     42
    1432012-09-11  Raphael Kubo da Costa  <rakuco@webkit.org>
    244
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r128096 r128219  
    292292   
    293293#if ENABLE(LLINT)
    294     Structure* structure = instruction[4].u.structure.get();
    295     dataLog(" llint(");
    296     dumpStructure("struct", exec, structure, ident);
    297     dataLog(")");
     294    if (exec->interpreter()->getOpcodeID(instruction[0].u.opcode) == op_get_array_length)
     295        dataLog(" llint(array_length)");
     296    else {
     297        Structure* structure = instruction[4].u.structure.get();
     298        dataLog(" llint(");
     299        dumpStructure("struct", exec, structure, ident);
     300        dataLog(")");
     301    }
    298302#endif
    299303
     
    20822086                curInstruction[0].u.opcode = interpreter->getOpcode(op_put_by_id);
    20832087                break;
     2088            case op_get_array_length:
     2089                break;
    20842090            default:
    20852091                ASSERT_NOT_REACHED();
  • trunk/Source/JavaScriptCore/bytecode/GetByIdStatus.cpp

    r127333 r128219  
    4444    if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_method_check))
    4545        instruction++;
     46   
     47    if (instruction[0].u.opcode == LLInt::getOpcode(llint_op_get_array_length))
     48        return GetByIdStatus(NoInformation, false);
    4649
    4750    Structure* structure = instruction[4].u.structure.get();
  • trunk/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp

    r128111 r128219  
    22772277        }
    22782278        case op_get_by_id:
    2279         case op_get_by_id_out_of_line: {
     2279        case op_get_by_id_out_of_line:
     2280        case op_get_array_length: {
    22802281            SpeculatedType prediction = getPrediction();
    22812282           
  • trunk/Source/JavaScriptCore/dfg/DFGCapabilities.h

    r121925 r128219  
    121121    case op_get_by_id:
    122122    case op_get_by_id_out_of_line:
     123    case op_get_array_length:
    123124    case op_put_by_id:
    124125    case op_put_by_id_out_of_line:
  • trunk/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp

    r126715 r128219  
    9393                    fromObserved(arrayProfile->observedArrayModes(), false),
    9494                    m_graph[node.child1()].prediction(),
    95                     m_graph[m_compileIndex].prediction());                   
     95                    m_graph[m_compileIndex].prediction());
    9696                if (modeSupportsLength(arrayMode) && arrayProfile->hasDefiniteStructure()) {
    9797                    m_graph.ref(nodePtr->child1());
  • trunk/Source/JavaScriptCore/jit/JIT.cpp

    r127393 r128219  
    257257        DEFINE_OP(op_eq_null)
    258258        case op_get_by_id_out_of_line:
     259        case op_get_array_length:
    259260        DEFINE_OP(op_get_by_id)
    260261        DEFINE_OP(op_get_arguments_length)
     
    359360        DEFINE_OP(op_to_primitive)
    360361
    361         case op_get_array_length:
    362362        case op_get_by_id_chain:
    363363        case op_get_by_id_generic:
     
    447447        DEFINE_SLOWCASE_OP(op_eq)
    448448        case op_get_by_id_out_of_line:
     449        case op_get_array_length:
    449450        DEFINE_SLOWCASE_OP(op_get_by_id)
    450451        DEFINE_SLOWCASE_OP(op_get_arguments_length)
  • trunk/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp

    r128096 r128219  
    859859    LLINT_CHECK_EXCEPTION();
    860860    LLINT_OP(1) = result;
    861 
     861   
    862862    if (!LLINT_ALWAYS_ACCESS_SLOW
    863863        && baseValue.isCell()
     
    881881            }
    882882        }
     883    }
     884
     885    if (!LLINT_ALWAYS_ACCESS_SLOW
     886        && isJSArray(baseValue)
     887        && ident == exec->propertyNames().length) {
     888        pc[0].u.opcode = LLInt::getOpcode(llint_op_get_array_length);
     889#if ENABLE(VALUE_PROFILER)
     890        ArrayProfile* arrayProfile = codeBlock->getOrAddArrayProfile(pc - codeBlock->instructions().begin());
     891        arrayProfile->observeStructure(baseValue.asCell()->structure());
     892        pc[4].u.arrayProfile = arrayProfile;
     893#endif
    883894    }
    884895
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter.asm

    r128146 r128219  
    846846end
    847847
    848 _llint_op_get_array_length:
    849     notSupported()
    850 
    851848_llint_op_get_by_id_chain:
    852849    notSupported()
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm

    r128146 r128219  
    11671167_llint_op_get_by_id_out_of_line:
    11681168    getById(withOutOfLineStorage)
     1169
     1170
     1171_llint_op_get_array_length:
     1172    traceExecution()
     1173    loadi 8[PC], t0
     1174    loadp 16[PC], t1
     1175    loadConstantOrVariablePayload(t0, CellTag, t3, .opGetArrayLengthSlot)
     1176    loadp JSCell::m_structure[t3], t2
     1177    if VALUE_PROFILER
     1178        storep t2, ArrayProfile::m_lastSeenStructure[t1]
     1179    end
     1180    loadp CodeBlock[cfr], t1
     1181    loadp CodeBlock::m_globalData[t1], t1
     1182    loadp JSGlobalData::jsArrayClassInfo[t1], t1
     1183    bpneq Structure::m_classInfo[t2], t1, .opGetArrayLengthSlow
     1184    loadi 4[PC], t1
     1185    loadp 32[PC], t2
     1186    loadp JSArray::m_storage[t3], t0
     1187    loadi ArrayStorage::m_length[t0], t0
     1188    bilt t0, 0, .opGetArrayLengthSlow
     1189    valueProfile(Int32Tag, t0, t2)
     1190    storep t0, PayloadOffset[cfr, t1, 8]
     1191    storep Int32Tag, TagOffset[cfr, t1, 8]
     1192    dispatch(9)
     1193
     1194.opGetArrayLengthSlow:
     1195    callSlowPath(_llint_slow_path_get_by_id)
     1196    dispatch(9)
    11691197
    11701198
  • trunk/Source/JavaScriptCore/llint/LowLevelInterpreter64.asm

    r128146 r128219  
    10141014_llint_op_get_by_id_out_of_line:
    10151015    getById(withOutOfLineStorage)
     1016
     1017
     1018_llint_op_get_array_length:
     1019    traceExecution()
     1020    loadis 16[PB, PC, 8], t0
     1021    loadp 32[PB, PC, 8], t1
     1022    loadConstantOrVariableCell(t0, t3, .opGetArrayLengthSlow)
     1023    loadp JSCell::m_structure[t3], t2
     1024    if VALUE_PROFILER
     1025        storep t2, ArrayProfile::m_lastSeenStructure[t1]
     1026    end
     1027    loadp CodeBlock[cfr], t1
     1028    loadp CodeBlock::m_globalData[t1], t1
     1029    loadp JSGlobalData::jsArrayClassInfo[t1], t1
     1030    bpneq Structure::m_classInfo[t2], t1, .opGetArrayLengthSlow
     1031    loadis 8[PB, PC, 8], t1
     1032    loadp 64[PB, PC, 8], t2
     1033    loadp JSArray::m_storage[t3], t0
     1034    loadi ArrayStorage::m_length[t0], t0
     1035    bilt t0, 0, .opGetArrayLengthSlow
     1036    orp tagTypeNumber, t0
     1037    valueProfile(t0, t2)
     1038    storep t0, [cfr, t1, 8]
     1039    dispatch(9)
     1040
     1041.opGetArrayLengthSlow:
     1042    callSlowPath(_llint_slow_path_get_by_id)
     1043    dispatch(9)
    10161044
    10171045
Note: See TracChangeset for help on using the changeset viewer.