Ignore:
Timestamp:
Jul 7, 2020, 5:32:35 PM (5 years ago)
Author:
[email protected]
Message:

Bytecode UseDef should be aware of checkpoints
https://bugs.webkit.org/show_bug.cgi?id=213566

Reviewed by Saam Barati.

JSTests:

  • stress/def-then-use-in-single-bytecode-with-checkpoints-for-of.js: Added.

(foo):

Source/JavaScriptCore:

Previously, we tried to solve teaching DFG about uses and defs of
locals across checkpoints by asking what locals were def'd at some
checkpoint. However, this was subtly wrong because we couldn't
report any uses at subsequent checkpoints so DFG thought the
local was dead immediately after its birth.

This patch reverts that change and instead teaches BytecodeUseDef
about checkpoints. Right now, BytecodeUseDef only knows about
locals at checkpoints but in the future we may teach it about tmps
at well.

Since the vectors containing our liveness bitmaps were already
sparse (they are indexed by the bytecode offset) we can reuse the
gaps to hold our checkpoint liveness information. To make sure we
don't overlap between the next bytecode and a checkpoint for the
current bytecode there is now a static assert that the length of
the bytecode is greater than the number of checkpoints. This
assumption is already true for existing bytecodes with checkpoints (and
likely to be true for future ones anyway).

Many of the BytecodeLivenessPropegation functions have been
renamed to reflect that they operate over the full instruction,
including checkpoints, rather than just the BytecodeIndex passed.

Lastly, this patch makes a speculative fix to forAllKilledOperands where we
wouldn't report that all tmps die at the end of each bytecode. I can't think
of a case where this would break things but it's probably good hygiene.

  • bytecode/BytecodeGeneratorification.cpp:

(JSC::GeneratorLivenessAnalysis::run):

  • bytecode/BytecodeIndex.h:

(JSC::BytecodeIndex::BytecodeIndex):
(JSC::BytecodeIndex::checkpoint const):
(JSC::BytecodeIndex::withCheckpoint const):
(JSC::BytecodeIndex::pack):

  • bytecode/BytecodeLivenessAnalysis.cpp:

(JSC::BytecodeLivenessAnalysis::computeFullLiveness):
(JSC::BytecodeLivenessAnalysis::dumpResults):
(JSC::tmpLivenessForCheckpoint):
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeIndex): Deleted.
(JSC::livenessForCheckpoint): Deleted.

  • bytecode/BytecodeLivenessAnalysis.h:

(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtInstruction):

  • bytecode/BytecodeLivenessAnalysisInlines.h:

(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexDef):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUse):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndexUseInExceptionHandler):
(JSC::BytecodeLivenessPropagation::stepOverBytecodeIndex):
(JSC::BytecodeLivenessPropagation::stepOverInstruction):
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForInstruction):
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForBlock):
(JSC::BytecodeLivenessPropagation::getLivenessInfoAtInstruction):
(JSC::BytecodeLivenessPropagation::stepOverInstructionDef): Deleted.
(JSC::BytecodeLivenessPropagation::stepOverInstructionUse): Deleted.
(JSC::BytecodeLivenessPropagation::stepOverInstructionUseInExceptionHandler): Deleted.
(JSC::BytecodeLivenessPropagation::computeLocalLivenessForBytecodeIndex): Deleted.
(JSC::BytecodeLivenessPropagation::getLivenessInfoAtBytecodeIndex): Deleted.

  • bytecode/BytecodeUseDef.cpp:

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

  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeIndex):
(JSC::computeDefsForBytecodeIndex):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::ensureCatchLivenessIsComputedForBytecodeIndexSlow):
(JSC::CodeBlock::validate):

  • bytecode/FullBytecodeLiveness.h:

(JSC::FullBytecodeLiveness::getLiveness const):
(JSC::FullBytecodeLiveness::toIndex):

  • bytecode/Instruction.h:

(JSC::BaseInstruction::numberOfCheckpoints const):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::ForInContext::finalize):

  • dfg/DFGForAllKills.h:

(JSC::DFG::forAllKilledOperands):

  • dfg/DFGGraph.cpp:

(JSC::DFG::Graph::isLiveInBytecode):

  • dfg/DFGGraph.h:
  • dfg/DFGMovHintRemovalPhase.cpp:
  • dfg/DFGPlan.cpp:

(JSC::DFG::Plan::cleanMustHandleValuesIfNecessary):

  • generator/Opcode.rb:
  • generator/Section.rb:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.cpp

    r263035 r264049  
    3434#define USES_OR_DEFS(__opcode, ...) \
    3535    case __opcode::opcodeID: { \
     36        static_assert(__opcode::opcodeID >= NUMBER_OF_BYTECODE_WITH_CHECKPOINTS, "Don't use this macro for bytecodes that have checkpoints."); \
    3637        auto __bytecode = instruction->as<__opcode>(); \
    3738        WTF_LAZY_FOR_EACH_TERM(CALL_FUNCTOR, __VA_ARGS__) \
     
    4243#define DEFS USES_OR_DEFS
    4344
    44 void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
     45void computeUsesForBytecodeIndexImpl(VirtualRegister scopeRegister, const Instruction* instruction, Checkpoint checkpoint, const ScopedLambda<void(VirtualRegister)>& functor)
    4546{
    4647    OpcodeID opcodeID = instruction->opcodeID();
    4748
    48     auto handleNewArrayLike = [&](auto op) {
     49
     50    auto handleNewArrayLike = [&] (auto op) {
    4951        int base = op.m_argv.offset();
    5052        for (int i = 0; i < static_cast<int>(op.m_argc); i++)
     
    5254    };
    5355
    54     auto handleOpCallLike = [&](auto op) {
     56    auto handleOpCallLike = [&] (auto op) {
    5557        functor(op.m_callee);
    5658        int lastArg = -static_cast<int>(op.m_argv) + CallFrame::thisArgumentOffset();
     
    6062            functor(scopeRegister);
    6163        return;
     64    };
     65
     66    auto useAtEachCheckpoint = [&] (auto... virtualRegisters) {
     67        (functor(virtualRegisters), ...);
     68    };
     69
     70    auto useAtEachCheckpointStartingWith = [&] (Checkpoint firstUse, auto... virtualRegisters) {
     71        if (checkpoint >= firstUse)
     72            (functor(virtualRegisters), ...);
    6273    };
    6374
     
    251262    USES(OpHasOwnStructureProperty, base, property, enumerator)
    252263    USES(OpInStructureProperty, base, property, enumerator)
    253     USES(OpConstructVarargs, callee, thisValue, arguments)
    254     USES(OpCallVarargs, callee, thisValue, arguments)
    255     USES(OpTailCallVarargs, callee, thisValue, arguments)
     264
     265    case op_call_varargs: {
     266        auto bytecode = instruction->as<OpCallVarargs>();
     267        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
     268        return;
     269    }
     270    case op_tail_call_varargs: {
     271        auto bytecode = instruction->as<OpTailCallVarargs>();
     272        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
     273        return;
     274    }
     275    case op_construct_varargs: {
     276        auto bytecode = instruction->as<OpConstructVarargs>();
     277        useAtEachCheckpoint(bytecode.m_callee, bytecode.m_thisValue, bytecode.m_arguments);
     278        return;
     279    }
    256280
    257281    USES(OpGetDirectPname, base, property, index, enumerator)
     
    266290    USES(OpYield, generator, argument)
    267291
    268     USES(OpIteratorOpen, symbolIterator, iterable)
    269     USES(OpIteratorNext, iterator, next, iterable)
     292    case op_iterator_open: {
     293        auto bytecode = instruction->as<OpIteratorOpen>();
     294        useAtEachCheckpointStartingWith(OpIteratorOpen::symbolCall, bytecode.m_symbolIterator, bytecode.m_iterable);
     295        useAtEachCheckpointStartingWith(OpIteratorOpen::getNext, bytecode.m_iterator);
     296        return;
     297    }
     298
     299    case op_iterator_next: {
     300        auto bytecode = instruction->as<OpIteratorNext>();
     301        useAtEachCheckpoint(bytecode.m_iterator);
     302        useAtEachCheckpointStartingWith(OpIteratorNext::computeNext, bytecode.m_next, bytecode.m_iterable);
     303        return;
     304    }
    270305
    271306    case op_new_array_with_spread:
     
    303338}
    304339
    305 void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instruction, const Function<void(VirtualRegister)>& functor)
     340void computeDefsForBytecodeIndexImpl(unsigned numVars, const Instruction* instruction, Checkpoint checkpoint, const ScopedLambda<void(VirtualRegister)>& functor)
    306341{
     342
     343    auto defAt = [&] (Checkpoint target, VirtualRegister operand) {
     344        if (target == checkpoint)
     345            functor(operand);
     346    };
     347
    307348    switch (instruction->opcodeID()) {
    308349    case op_wide16:
     
    413454    DEFS(OpNewAsyncFunc, dst)
    414455    DEFS(OpNewAsyncFuncExp, dst)
    415     DEFS(OpCallVarargs, dst)
    416     DEFS(OpTailCallVarargs, dst)
     456    case op_call_varargs: {
     457        auto bytecode = instruction->as<OpCallVarargs>();
     458        defAt(OpCallVarargs::makeCall, bytecode.m_dst);
     459        return;
     460    }
     461    case op_tail_call_varargs: {
     462        auto bytecode = instruction->as<OpTailCallVarargs>();
     463        defAt(OpTailCallVarargs::makeCall, bytecode.m_dst);
     464        return;
     465    }
     466    case op_construct_varargs: {
     467        auto bytecode = instruction->as<OpConstructVarargs>();
     468        defAt(OpConstructVarargs::makeCall, bytecode.m_dst);
     469        return;
     470    }
     471
    417472    DEFS(OpTailCallForwardArguments, dst)
    418     DEFS(OpConstructVarargs, dst)
    419473    DEFS(OpGetFromScope, dst)
    420474    DEFS(OpCall, dst)
     
    502556    DEFS(OpCatch, exception, thrownValue)
    503557
    504     DEFS(OpIteratorOpen, iterator, next)
    505     DEFS(OpIteratorNext, done, value)
     558    case op_iterator_open: {
     559        auto bytecode = instruction->as<OpIteratorOpen>();
     560
     561        defAt(OpIteratorOpen::symbolCall, bytecode.m_iterator);
     562        defAt(OpIteratorOpen::getNext, bytecode.m_next);
     563        return;
     564    }
     565
     566    case op_iterator_next: {
     567        auto bytecode = instruction->as<OpIteratorNext>();
     568
     569        defAt(OpIteratorNext::getDone, bytecode.m_done);
     570        // We need to claim we set m_value here because we could early exit from the bytecode if we are done.
     571        defAt(OpIteratorNext::getDone, bytecode.m_value);
     572
     573        defAt(OpIteratorNext::getValue, bytecode.m_value);
     574        return;
     575    }
    506576
    507577    case op_enter: {
Note: See TracChangeset for help on using the changeset viewer.