21using interpreter::BytecodeOperands;
22using interpreter::Bytecodes;
25using interpreter::Register;
28 int register_count,
Zone* zone)
34 if (
r.is_parameter()) {
42 if (
r.is_parameter()) {
43 for (uint32_t
i = 0;
i <
count;
i++) {
48 for (uint32_t
i = 0;
i <
count;
i++) {
73 int final_target_offset)
74 : suspend_id_(suspend_id),
75 target_offset_(target_offset),
76 final_target_offset_(final_target_offset) {}
90template <Bytecode
bytecode, OperandType operand_type,
size_t i>
91void UpdateInLivenessForOutOperand(
94 if constexpr (operand_type == OperandType::kRegOut ||
95 operand_type == OperandType::kRegInOut) {
97 if (!
r.is_parameter()) {
100 }
else if constexpr (operand_type == OperandType::kRegOutList) {
103 if (!
r.is_parameter()) {
104 for (uint32_t j = 0; j < reg_count; ++j) {
105 DCHECK(!Register(
r.index() + j).is_parameter());
109 }
else if constexpr (operand_type == OperandType::kRegOutPair) {
111 if (!
r.is_parameter()) {
116 }
else if constexpr (operand_type == OperandType::kRegOutTriple) {
118 if (!
r.is_parameter()) {
130template <Bytecode
bytecode, OperandType operand_type,
size_t i>
131void UpdateInLivenessForInOperand(
132 BytecodeLivenessState* in_liveness,
133 const interpreter::BytecodeArrayIterator& iterator) {
134 if constexpr (operand_type == OperandType::kReg ||
135 operand_type == OperandType::kRegInOut) {
137 if (!
r.is_parameter()) {
138 in_liveness->MarkRegisterLive(
r.index());
140 }
else if constexpr (operand_type == OperandType::kRegPair) {
142 if (!
r.is_parameter()) {
144 in_liveness->MarkRegisterLive(
r.index());
145 in_liveness->MarkRegisterLive(
r.index() + 1);
147 }
else if constexpr (operand_type == OperandType::kRegList) {
149 uint32_t reg_count = iterator.GetRegisterCountOperand(
i + 1);
150 if (!
r.is_parameter()) {
151 for (uint32_t j = 0; j < reg_count; ++j) {
152 DCHECK(!interpreter::Register(
r.index() + j).is_parameter());
153 in_liveness->MarkRegisterLive(
r.index() + j);
162 OperandType... operand_types,
size_t... operand_index>
163void UpdateInLiveness(BytecodeLivenessState* in_liveness,
164 const interpreter::BytecodeArrayIterator& iterator,
165 std::index_sequence<operand_index...>) {
167 if constexpr (bytecode == Bytecode::kSuspendGenerator) {
169 in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index());
172 in_liveness->MarkAccumulatorLive();
174 }
else if constexpr (bytecode == Bytecode::kResumeGenerator) {
176 in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index());
182 in_liveness->MarkAccumulatorDead();
185 !in_liveness->AccumulatorIsLive());
186 (UpdateInLivenessForOutOperand<bytecode, operand_types, operand_index>(
187 in_liveness, iterator),
191 implicit_register_use)) {
196 in_liveness->MarkAccumulatorLive();
198 (UpdateInLivenessForInOperand<bytecode, operand_types, operand_index>(
199 in_liveness, iterator),
205void UpdateInLiveness(BytecodeLivenessState* in_liveness,
206 const interpreter::BytecodeArrayIterator& iterator) {
207 UpdateInLiveness<
bytecode, implicit_register_use, operand_types...>(
208 in_liveness, iterator,
209 std::make_index_sequence<
sizeof...(operand_types)>());
213void UpdateInLiveness(
Bytecode bytecode, BytecodeLivenessState* in_liveness,
214 const interpreter::BytecodeArrayIterator& iterator) {
216#define BYTECODE_UPDATE_IN_LIVENESS(Name, ...) \
217 case Bytecode::k##Name: \
218 return UpdateInLiveness<Bytecode::k##Name, __VA_ARGS__>(in_liveness, \
220 BYTECODE_LIST(BYTECODE_UPDATE_IN_LIVENESS, BYTECODE_UPDATE_IN_LIVENESS)
221#undef BYTECODE_UPDATE_IN_LIVENESS
226template <
bool IsFirstUpdate = false>
227void EnsureOutLivenessIsNotAlias(
228 BytecodeLiveness& liveness,
229 BytecodeLivenessState* next_bytecode_in_liveness,
Zone* zone) {
230 if (!IsFirstUpdate) {
233 DCHECK_NE(liveness.out, next_bytecode_in_liveness);
236 if (liveness.out == next_bytecode_in_liveness) {
240 zone->New<BytecodeLivenessState>(*next_bytecode_in_liveness, zone);
244template <
bool IsFirstUpdate, Bytecode
bytecode>
245void UpdateOutLiveness(BytecodeLiveness& liveness,
246 BytecodeLivenessState* next_bytecode_in_liveness,
247 const interpreter::BytecodeArrayIterator& iterator,
248 DirectHandle<BytecodeArray> bytecode_array,
249 const BytecodeLivenessMap& liveness_map,
Zone* zone) {
252 if (!IsFirstUpdate && liveness.out == next_bytecode_in_liveness)
return;
255 if (bytecode == Bytecode::kSuspendGenerator ||
256 bytecode == Bytecode::kResumeGenerator) {
259 liveness.out = next_bytecode_in_liveness;
261 liveness.out->Union(*next_bytecode_in_liveness);
269 if (bytecode == Bytecode::kSwitchOnGeneratorState) {
274 int generator_reg_index = iterator.GetRegisterOperand(0).index();
275 DCHECK(!next_bytecode_in_liveness->RegisterIsLive(generator_reg_index));
277 zone->New<BytecodeLivenessState>(*next_bytecode_in_liveness, zone);
278 liveness.out->MarkRegisterLive(generator_reg_index);
280 liveness.out->Union(*next_bytecode_in_liveness);
287 if (next_bytecode_in_liveness !=
nullptr &&
296 liveness.out = next_bytecode_in_liveness;
298 liveness.out->Union(*next_bytecode_in_liveness);
300 }
else if (IsFirstUpdate) {
304 liveness.out = zone->New<BytecodeLivenessState>(
305 bytecode_array->register_count(), zone);
313 int target_offset = iterator.GetJumpTargetOffset();
314 EnsureOutLivenessIsNotAlias<IsFirstUpdate>(liveness,
315 next_bytecode_in_liveness, zone);
316 liveness.out->Union(*liveness_map.GetInLiveness(target_offset));
318 EnsureOutLivenessIsNotAlias<IsFirstUpdate>(liveness,
319 next_bytecode_in_liveness, zone);
320 for (interpreter::JumpTableTargetOffset entry :
321 iterator.GetJumpTableTargetOffsets()) {
322 liveness.out->Union(*liveness_map.GetInLiveness(entry.target_offset));
329 HandlerTable table(*bytecode_array);
331 table.LookupHandlerIndexForRange(iterator.current_offset());
334 EnsureOutLivenessIsNotAlias<IsFirstUpdate>(
335 liveness, next_bytecode_in_liveness, zone);
336 bool was_accumulator_live = liveness.out->AccumulatorIsLive();
338 *liveness_map.GetInLiveness(table.GetRangeHandler(handler_index)));
339 liveness.out->MarkRegisterLive(table.GetRangeData(handler_index));
340 if (!was_accumulator_live) {
345 liveness.out->MarkAccumulatorDead();
356template <
bool IsFirstUpdate = false>
357void UpdateOutLiveness(
Bytecode bytecode, BytecodeLiveness& liveness,
358 BytecodeLivenessState* next_bytecode_in_liveness,
359 const interpreter::BytecodeArrayIterator& iterator,
360 DirectHandle<BytecodeArray> bytecode_array,
361 const BytecodeLivenessMap& liveness_map,
Zone* zone) {
363#define BYTECODE_UPDATE_OUT_LIVENESS(Name, ...) \
364 case Bytecode::k##Name: \
365 return UpdateOutLiveness<IsFirstUpdate, Bytecode::k##Name>( \
366 liveness, next_bytecode_in_liveness, iterator, bytecode_array, \
369#undef BYTECODE_UPDATE_OUT_LIVENESS
376void UpdateLiveness(BytecodeLiveness& liveness,
377 BytecodeLivenessState** next_bytecode_in_liveness,
378 const interpreter::BytecodeArrayIterator& iterator,
379 DirectHandle<BytecodeArray> bytecode_array,
380 const BytecodeLivenessMap& liveness_map,
Zone* zone) {
381 UpdateOutLiveness<IsFirstUpdate, bytecode>(
382 liveness, *next_bytecode_in_liveness, iterator, bytecode_array,
388 liveness.in = zone->New<BytecodeLivenessState>(*liveness.out, zone);
393 liveness.in->CopyFrom(*liveness.out);
395 UpdateInLiveness<
bytecode, implicit_register_use, operand_types...>(
396 liveness.in, iterator);
398 *next_bytecode_in_liveness = liveness.in;
401template <
bool IsFirstUpdate = false>
402void UpdateLiveness(
Bytecode bytecode, BytecodeLiveness& liveness,
403 BytecodeLivenessState** next_bytecode_in_liveness,
404 const interpreter::BytecodeArrayIterator& iterator,
405 DirectHandle<BytecodeArray> bytecode_array,
406 const BytecodeLivenessMap& liveness_map,
Zone* zone) {
408#define BYTECODE_UPDATE_LIVENESS(Name, ...) \
409 case Bytecode::k##Name: \
410 return UpdateLiveness<IsFirstUpdate, Bytecode::k##Name, __VA_ARGS__>( \
411 liveness, next_bytecode_in_liveness, iterator, bytecode_array, \
414#undef BYTECODE_UPDATE_LIVENESS
418void UpdateAssignments(
Bytecode bytecode, BytecodeLoopAssignments* assignments,
419 const interpreter::BytecodeArrayIterator& iterator) {
423 for (
int i = 0;
i < num_operands; ++
i) {
424 switch (operand_types[
i]) {
425 case OperandType::kRegInOut:
426 case OperandType::kRegOut: {
427 assignments->Add(iterator.GetRegisterOperand(
i));
430 case OperandType::kRegOutList: {
431 interpreter::Register
r = iterator.GetRegisterOperand(
i++);
432 uint32_t reg_count = iterator.GetRegisterCountOperand(
i);
433 assignments->AddList(
r, reg_count);
436 case OperandType::kRegOutPair: {
437 assignments->AddList(iterator.GetRegisterOperand(
i), 2);
440 case OperandType::kRegOutTriple: {
441 assignments->AddList(iterator.GetRegisterOperand(
i), 3);
473 template <Bytecode BC>
484 int parent_offset =
loop_stack_.top().header_offset;
488 {loop_header,
LoopInfo(parent_offset, loop_header, loop_end,
492 LoopInfo* loop_info = &it.first->second;
501 bool ResumeJumpTargetsAreValid();
502 bool ResumeJumpTargetLeavesResolveSuspendIds(
505 std::map<int, int>* unresolved_suspend_ids);
507 bool LivenessIsValid();
530 Bytecode::kSuspendGenerator>(
int current_offset,
532 int suspend_id = iterator_.GetUnsignedImmediateOperand(3);
533 int resume_offset = current_offset + iterator_.current_bytecode_size();
534 current_loop_info->AddResumeTarget(
540 Bytecode::kResumeGenerator>(
int current_offset,
542 current_loop_info->mark_resumable();
563 if (bytecode == Bytecode::kJumpLoop) {
570 if (current_offset == osr_loop_end_offset_) {
572 }
else if (current_offset < osr_loop_end_offset_) {
589 (bytecode != Bytecode::kJumpLoop ||
603#define CASE(BC, ...) \
604 case Bytecode::k##BC: \
605 AnalyzeBCInLoop<Bytecode::k##BC>(current_offset, current_loop_info); \
662 }
else if (bytecode == Bytecode::kSuspendGenerator) {
675 UpdateLiveness<true>(bytecode, liveness, &next_bytecode_in_liveness,
683 DCHECK(ResumeJumpTargetsAreValid());
729 next_bytecode_in_liveness = end_liveness.
in;
737 UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness,
iterator_,
748 if (
v8_flags.trace_environment_liveness) {
753 DCHECK(LivenessIsValid());
773 if (loop_end_to_header->second <=
offset) {
774 return loop_end_to_header->second;
795 auto loop_end_to_header =
end_to_header_.upper_bound(header_offset + 1);
796 DCHECK_EQ(loop_end_to_header->second, header_offset);
797 return loop_end_to_header->first;
827 std::ostream& os)
const {
834 res_.GetInLivenessFor(current_offset);
836 res_.GetOutLivenessFor(current_offset);
839 << current_offset <<
": ";
840 iterator.
PrintTo(os) << std::endl;
847bool BytecodeAnalysis::BytecodeAnalysisImpl::ResumeJumpTargetsAreValid() {
852 for (iterator.GoToStart(); iterator.IsValid(); ++iterator) {
853 if (iterator.current_bytecode() == Bytecode::kSwitchOnGeneratorState) {
860 if (!iterator.IsValid()) {
862 if (!res_.resume_jump_targets().empty()) {
864 "Found %zu top-level resume targets but no resume switch\n",
865 res_.resume_jump_targets().size());
869 for (
const std::pair<const int, LoopInfo>& loop_info :
870 res_.header_to_info_) {
871 if (!loop_info.second.resume_jump_targets().empty()) {
873 "Found %zu resume targets at loop at offset %d, but no resume "
875 loop_info.second.resume_jump_targets().size(), loop_info.first);
889 std::map<int, int> unresolved_suspend_ids;
890 for (interpreter::JumpTableTargetOffset
offset :
891 iterator.GetJumpTableTargetOffsets()) {
892 int suspend_id =
offset.case_value;
893 int resume_offset =
offset.target_offset;
895 unresolved_suspend_ids[suspend_id] = resume_offset;
899 if (!ResumeJumpTargetLeavesResolveSuspendIds(-1, res_.resume_jump_targets(),
900 &unresolved_suspend_ids)) {
904 for (
const std::pair<const int, LoopInfo>& loop_info : res_.header_to_info_) {
905 if (!ResumeJumpTargetLeavesResolveSuspendIds(
906 loop_info.first, loop_info.second.resume_jump_targets(),
907 &unresolved_suspend_ids)) {
913 if (!unresolved_suspend_ids.empty()) {
915 "Found suspend ids that are not resolved by a final leaf resume "
918 for (
const std::pair<const int, int>& target : unresolved_suspend_ids) {
919 PrintF(stderr,
" %d -> %d\n", target.first, target.second);
927bool BytecodeAnalysis::BytecodeAnalysisImpl::
928 ResumeJumpTargetLeavesResolveSuspendIds(
931 std::map<int, int>* unresolved_suspend_ids) {
934 std::map<int, int>::iterator it =
935 unresolved_suspend_ids->find(target.suspend_id());
936 if (it == unresolved_suspend_ids->end()) {
939 "No unresolved suspend found for resume target with suspend id %d\n",
940 target.suspend_id());
944 int expected_target = it->second;
946 if (target.is_leaf()) {
948 if (target.target_offset() != expected_target) {
951 "Expected leaf resume target for id %d to have target offset %d, "
953 target.suspend_id(), expected_target, target.target_offset());
957 interpreter::BytecodeArrayIterator iterator(bytecode_array_,
958 target.target_offset());
959 if (iterator.current_bytecode() != Bytecode::kResumeGenerator) {
961 "Expected resume target for id %d, offset %d, to be "
962 "ResumeGenerator, but found %s\n",
963 target.suspend_id(), target.target_offset(),
971 unresolved_suspend_ids->erase(it);
974 if (!res_.IsLoopHeader(target.target_offset())) {
976 "Expected non-leaf resume target for id %d to have a loop "
977 "header at target offset %d\n",
978 target.suspend_id(), target.target_offset());
981 LoopInfo loop_info = res_.GetLoopInfoFor(target.target_offset());
982 if (loop_info.parent_offset() != parent_offset) {
984 "Expected non-leaf resume target for id %d to have a direct "
985 "inner loop at target offset %d\n",
986 target.suspend_id(), target.target_offset());
997bool BytecodeAnalysis::BytecodeAnalysisImpl::LivenessIsValid() {
998 interpreter::BytecodeArrayRandomIterator iterator(bytecode_array_, zone());
1000 BytecodeLivenessState previous_liveness(bytecode_array_->register_count(),
1003 int invalid_offset = -1;
1004 int which_invalid = -1;
1005 BytecodeLivenessState invalid_liveness(bytecode_array_->register_count(),
1008 BytecodeLivenessState* next_bytecode_in_liveness =
nullptr;
1011 for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
1012 Bytecode bytecode = iterator.current_bytecode();
1014 int current_offset = iterator.current_offset();
1018 previous_liveness.CopyFrom(*liveness.out);
1020 UpdateOutLiveness(bytecode, liveness, next_bytecode_in_liveness, iterator,
1023 if (bytecode == Bytecode::kJumpLoop) {
1024 int target_offset = iterator.GetJumpTargetOffset();
1025 liveness.out->Union(*
liveness_map().GetInLiveness(target_offset));
1028 if (!liveness.out->Equals(previous_liveness)) {
1029 invalid_liveness.CopyFrom(*liveness.out);
1031 liveness.out->CopyFrom(previous_liveness);
1032 invalid_offset = current_offset;
1037 previous_liveness.CopyFrom(*liveness.in);
1039 liveness.in->CopyFrom(*liveness.out);
1040 UpdateInLiveness(bytecode, liveness.in, iterator);
1042 if (!liveness.in->Equals(previous_liveness)) {
1043 invalid_liveness.CopyFrom(*liveness.in);
1045 liveness.in->CopyFrom(previous_liveness);
1046 invalid_offset = current_offset;
1051 next_bytecode_in_liveness = liveness.in;
1056 for (iterator.GoToStart(); iterator.IsValid() && invalid_offset == -1;
1058 Bytecode bytecode = iterator.current_bytecode();
1059 int current_offset = iterator.current_offset();
1060 int loop_header = res_.GetLoopOffsetFor(current_offset);
1063 if (loop_header == -1)
continue;
1068 int jump_target = iterator.GetJumpTargetOffset();
1072 res_.GetLoopOffsetFor(jump_target) == loop_header) {
1077 if (
liveness_map().GetLiveness(jump_target).in->AccumulatorIsLive()) {
1078 invalid_offset = jump_target;
1084 if (invalid_offset != -1) {
1085 OFStream of(stderr);
1086 of <<
"Invalid liveness:" << std::endl;
1090 int loop_indent = 0;
1092 interpreter::BytecodeArrayIterator forward_iterator(bytecode_array_);
1093 for (; !forward_iterator.done(); forward_iterator.Advance()) {
1094 int current_offset = forward_iterator.current_offset();
1095 const BytecodeLivenessState* in_liveness =
1096 res_.GetInLivenessFor(current_offset);
1097 const BytecodeLivenessState* out_liveness =
1098 res_.GetOutLivenessFor(current_offset);
1100 std::string in_liveness_str =
ToString(*in_liveness);
1101 std::string out_liveness_str =
ToString(*out_liveness);
1103 of << in_liveness_str <<
" | " << out_liveness_str <<
" : "
1104 << current_offset <<
" : ";
1108 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) {
1111 for (
int i = 0;
i < loop_indent; ++
i) {
1114 if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) {
1116 }
else if (res_.IsLoopHeader(current_offset)) {
1120 forward_iterator.PrintTo(of);
1122 of <<
" (@" << forward_iterator.GetJumpTargetOffset() <<
")";
1126 if (current_offset == invalid_offset) {
1128 char in_underline = which_invalid == 0 ?
'^' :
' ';
1129 char out_underline = which_invalid == 0 ?
' ' :
'^';
1130 of << std::string(in_liveness_str.size(), in_underline) <<
" "
1131 << std::string(out_liveness_str.size(), out_underline);
1134 of <<
" : " << current_offset <<
" : ";
1135 for (
int i = 0;
i < loop_indent; ++
i) {
1142 if (which_invalid == 0) {
1143 of <<
ToString(invalid_liveness) <<
" "
1144 << std::string(out_liveness_str.size(),
' ');
1146 of << std::string(in_liveness_str.size(),
' ') <<
" "
1151 of <<
" : " << current_offset <<
" : ";
1152 for (
int i = 0;
i < loop_indent; ++
i) {
1161 return invalid_offset == -1;
1167 bool analyze_liveness)
interpreter::Bytecode bytecode
#define BYTECODE_UPDATE_OUT_LIVENESS(Name,...)
#define BYTECODE_UPDATE_LIVENESS(Name,...)
#define BYTECODE_LIST(V, V_TSA)
bool Contains(int i) const
void Union(const BitVector &other)
constexpr bool IsNone() const
constexpr int ToInt() const
static const int kNoHandlerFound
void push_back(const T &value)
void AnalyzeBCInLoop(int current_offset, LoopInfo *current_loop_info)
interpreter::BytecodeArrayRandomIterator iterator_
void PushLoop(int loop_header, int loop_end)
Handle< BytecodeArray > const bytecode_array_
ZoneVector< int > loop_end_index_queue_
bool analyze_liveness() const
BytecodeAnalysisImpl(BytecodeAnalysis &res, Handle< BytecodeArray > bytecode_array, Zone *zone)
DirectHandle< BytecodeArray > bytecode_array() const
ZoneStack< LoopStackEntry > loop_stack_
std::ostream & PrintLivenessTo(std::ostream &os) const
BytecodeLivenessMap & liveness_map()
BytecodeOffset const osr_bailout_id_
const BytecodeLivenessState * GetInLivenessFor(int offset) const
const ZoneVector< ResumeJumpTarget > & resume_jump_targets() const
ZoneMap< int, LoopInfo > header_to_info_
const BytecodeLivenessState * GetOutLivenessFor(int offset) const
std::optional< BytecodeLivenessMap > liveness_map_
bool const analyze_liveness_
const LoopInfo & GetLoopInfoFor(int header_offset) const
BytecodeLivenessMap & liveness_map()
BytecodeOffset osr_bailout_id() const
const LoopInfo * TryGetLoopInfoFor(int header_offset) const
int GetLoopOffsetFor(int offset) const
BytecodeAnalysis(Handle< BytecodeArray > bytecode_array, Zone *zone, BytecodeOffset osr_bailout_id, bool analyze_liveness)
bool IsLoopHeader(int offset) const
int GetLoopEndOffsetForInnermost(int header_offset) const
ZoneMap< int, int > end_to_header_
ZoneVector< ResumeJumpTarget > resume_jump_targets_
BytecodeLiveness & InsertNewLiveness(int offset)
BytecodeLivenessState * GetInLiveness(int offset)
BytecodeLivenessState * GetOutLiveness(int offset)
BytecodeLiveness & GetLiveness(int offset)
void CopyFrom(const BytecodeLivenessState &other)
bool UnionIsChanged(const BytecodeLivenessState &other)
void MarkRegisterDead(int index)
bool ContainsParameter(int index) const
void Union(const BytecodeLoopAssignments &other)
int const parameter_count_
int parameter_count() const
BytecodeLoopAssignments(int parameter_count, int register_count, Zone *zone)
void Add(interpreter::Register r)
bool ContainsLocal(int index) const
BitVector *const bit_vector_
void AddList(interpreter::Register r, uint32_t count)
ResumeJumpTarget(int suspend_id, int target_offset, int final_target_offset)
static ResumeJumpTarget Leaf(int suspend_id, int target_offset)
static ResumeJumpTarget AtLoopHeader(int loop_header_offset, const ResumeJumpTarget &next)
int target_offset() const
Bytecode current_bytecode() const
Register GetRegisterOperand(int operand_index) const
int GetJumpTargetOffset() const
std::ostream & PrintTo(std::ostream &os) const
uint32_t GetUnsignedImmediateOperand(int operand_index) const
int current_bytecode_size() const
int current_offset() const
uint32_t GetRegisterCountOperand(int operand_index) const
void GoToIndex(int index)
int current_index() const
static constexpr bool WritesImplicitRegister(ImplicitRegisterUse implicit_register_use)
static constexpr bool ReadsAccumulator(ImplicitRegisterUse implicit_register_use)
static constexpr bool ClobbersAccumulator(ImplicitRegisterUse implicit_register_use)
static constexpr bool WritesAccumulator(ImplicitRegisterUse implicit_register_use)
static constexpr bool UnconditionallyThrows(Bytecode bytecode)
static constexpr bool Returns(Bytecode bytecode)
static const OperandType * GetOperandTypes(Bytecode bytecode)
static constexpr bool IsWithoutExternalSideEffects(Bytecode bytecode)
static constexpr bool IsForwardJump(Bytecode bytecode)
static constexpr bool IsSwitch(Bytecode bytecode)
static bool IsRegisterOutputOperandType(OperandType operand_type)
static bool ReadsAccumulator(Bytecode bytecode)
static bool WritesImplicitRegister(Bytecode bytecode)
static bool IsRegisterInputOperandType(OperandType operand_type)
static int NumberOfOperands(Bytecode bytecode)
static constexpr bool IsJump(Bytecode bytecode)
static const char * ToString(Bytecode bytecode)
static constexpr bool IsUnconditionalJump(Bytecode bytecode)
static constexpr Register FromShortStar(Bytecode bytecode)
constexpr bool is_parameter() const
std::string ToString(const BytecodeLivenessState &liveness)
void PrintF(const char *format,...)
V8_EXPORT_PRIVATE FlagValues v8_flags
#define DCHECK_LE(v1, v2)
#define DCHECK_NOT_NULL(val)
#define DCHECK_IMPLIES(v1, v2)
#define DCHECK_NE(v1, v2)
#define DCHECK_GE(v1, v2)
#define DCHECK(condition)
#define DCHECK_LT(v1, v2)
#define DCHECK_EQ(v1, v2)
BytecodeLivenessState * in
BytecodeLivenessState * out
void AddResumeTarget(const ResumeJumpTarget &target)
const ZoneVector< ResumeJumpTarget > & resume_jump_targets() const
BytecodeLoopAssignments & assignments()