static bool should_snapshot()

in Jit/hir/builder.cpp [377:450]


static bool should_snapshot(
    const BytecodeInstruction& bci,
    bool is_in_async_for_header_block) {
  switch (bci.opcode()) {
    // These instructions conditionally alter the operand stack based on which
    // branch is taken, thus we cannot safely take a snapshot in the same basic
    // block. They're also control instructions, so snapshotting in the same
    // basic block doesn't make sense anyway.
    case FOR_ITER:
    case JUMP_IF_FALSE_OR_POP:
    case JUMP_IF_NONZERO_OR_POP:
    case JUMP_IF_TRUE_OR_POP:
    case JUMP_IF_ZERO_OR_POP:
    // These are all control instructions. Taking a snapshot after them in the
    // same basic block doesn't make sense, as control immediately transfers
    // to another basic block.
    case BEGIN_FINALLY:
    case CALL_FINALLY:
    case END_FINALLY:
    case JUMP_ABSOLUTE:
    case JUMP_FORWARD:
    case POP_JUMP_IF_FALSE:
    case POP_JUMP_IF_TRUE:
    case POP_JUMP_IF_ZERO:
    case POP_JUMP_IF_NONZERO:
    case RETURN_PRIMITIVE:
    case RETURN_VALUE:
    case RAISE_VARARGS:
    // These instructions only modify frame state and are always safe to
    // replay. We don't snapshot these in order to limit the amount of
    // unnecessary metadata in the lowered IR.
    case CHECK_ARGS:
    case CONVERT_PRIMITIVE:
    case DUP_TOP:
    case DUP_TOP_TWO:
    case EXTENDED_ARG:
    case INT_LOAD_CONST_OLD:
    case LOAD_CLOSURE:
    case LOAD_CONST:
    case LOAD_FAST:
    case LOAD_LOCAL:
    case NOP:
    case POP_FINALLY:
    case POP_TOP:
    case PRIMITIVE_BOX:
    case PRIMITIVE_LOAD_CONST:
    case PRIMITIVE_UNARY_OP:
    case PRIMITIVE_UNBOX:
    case REFINE_TYPE:
    case ROT_FOUR:
    case ROT_THREE:
    case ROT_TWO:
    case STORE_FAST:
    case STORE_LOCAL: {
      return false;
    }
    // The `is` and `is not` comparison operators are implemented using pointer
    // equality. They are always safe to replay.
    case COMPARE_OP: {
      auto op = static_cast<CompareOp>(bci.oparg());
      return (op != CompareOp::kIs) && (op != CompareOp::kIsNot);
    }
    // In an async-for header block YIELD_FROM controls whether we end the loop
    case YIELD_FROM: {
      return !is_in_async_for_header_block;
    }
    // Take a snapshot after translating all other bytecode instructions. This
    // may generate unnecessary deoptimization metadata but will always be
    // correct.
    default: {
      return true;
    }
  }
}