| File: | out/../deps/v8/src/compiler/bytecode-analysis.cc |
| Warning: | line 266, column 9 Forming reference to null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | // Copyright 2016 the V8 project authors. All rights reserved. | |||
| 2 | // Use of this source code is governed by a BSD-style license that can be | |||
| 3 | // found in the LICENSE file. | |||
| 4 | ||||
| 5 | #include "src/compiler/bytecode-analysis.h" | |||
| 6 | ||||
| 7 | #include <utility> | |||
| 8 | ||||
| 9 | #include "src/compiler/bytecode-liveness-map.h" | |||
| 10 | #include "src/interpreter/bytecode-array-iterator.h" | |||
| 11 | #include "src/interpreter/bytecode-array-random-iterator.h" | |||
| 12 | #include "src/objects/objects-inl.h" | |||
| 13 | #include "src/utils/ostreams.h" | |||
| 14 | ||||
| 15 | namespace v8 { | |||
| 16 | namespace internal { | |||
| 17 | namespace compiler { | |||
| 18 | ||||
| 19 | using interpreter::Bytecode; | |||
| 20 | using interpreter::BytecodeOperands; | |||
| 21 | using interpreter::Bytecodes; | |||
| 22 | using interpreter::ImplicitRegisterUse; | |||
| 23 | using interpreter::OperandType; | |||
| 24 | using interpreter::Register; | |||
| 25 | ||||
| 26 | BytecodeLoopAssignments::BytecodeLoopAssignments(int parameter_count, | |||
| 27 | int register_count, Zone* zone) | |||
| 28 | : parameter_count_(parameter_count), | |||
| 29 | bit_vector_( | |||
| 30 | zone->New<BitVector>(parameter_count + register_count, zone)) {} | |||
| 31 | ||||
| 32 | void BytecodeLoopAssignments::Add(interpreter::Register r) { | |||
| 33 | if (r.is_parameter()) { | |||
| 34 | bit_vector_->Add(r.ToParameterIndex()); | |||
| 35 | } else { | |||
| 36 | bit_vector_->Add(parameter_count_ + r.index()); | |||
| 37 | } | |||
| 38 | } | |||
| 39 | ||||
| 40 | void BytecodeLoopAssignments::AddList(interpreter::Register r, uint32_t count) { | |||
| 41 | if (r.is_parameter()) { | |||
| 42 | for (uint32_t i = 0; i < count; i++) { | |||
| 43 | DCHECK(interpreter::Register(r.index() + i).is_parameter())((void) 0); | |||
| 44 | bit_vector_->Add(r.ToParameterIndex() + i); | |||
| 45 | } | |||
| 46 | } else { | |||
| 47 | for (uint32_t i = 0; i < count; i++) { | |||
| 48 | DCHECK(!interpreter::Register(r.index() + i).is_parameter())((void) 0); | |||
| 49 | bit_vector_->Add(parameter_count_ + r.index() + i); | |||
| 50 | } | |||
| 51 | } | |||
| 52 | } | |||
| 53 | ||||
| 54 | ||||
| 55 | void BytecodeLoopAssignments::Union(const BytecodeLoopAssignments& other) { | |||
| 56 | bit_vector_->Union(*other.bit_vector_); | |||
| 57 | } | |||
| 58 | ||||
| 59 | bool BytecodeLoopAssignments::ContainsParameter(int index) const { | |||
| 60 | DCHECK_GE(index, 0)((void) 0); | |||
| 61 | DCHECK_LT(index, parameter_count())((void) 0); | |||
| 62 | return bit_vector_->Contains(index); | |||
| 63 | } | |||
| 64 | ||||
| 65 | bool BytecodeLoopAssignments::ContainsLocal(int index) const { | |||
| 66 | DCHECK_GE(index, 0)((void) 0); | |||
| 67 | DCHECK_LT(index, local_count())((void) 0); | |||
| 68 | return bit_vector_->Contains(parameter_count_ + index); | |||
| 69 | } | |||
| 70 | ||||
| 71 | ResumeJumpTarget::ResumeJumpTarget(int suspend_id, int target_offset, | |||
| 72 | int final_target_offset) | |||
| 73 | : suspend_id_(suspend_id), | |||
| 74 | target_offset_(target_offset), | |||
| 75 | final_target_offset_(final_target_offset) {} | |||
| 76 | ||||
| 77 | ResumeJumpTarget ResumeJumpTarget::Leaf(int suspend_id, int target_offset) { | |||
| 78 | return ResumeJumpTarget(suspend_id, target_offset, target_offset); | |||
| 79 | } | |||
| 80 | ||||
| 81 | ResumeJumpTarget ResumeJumpTarget::AtLoopHeader(int loop_header_offset, | |||
| 82 | const ResumeJumpTarget& next) { | |||
| 83 | return ResumeJumpTarget(next.suspend_id(), loop_header_offset, | |||
| 84 | next.target_offset()); | |||
| 85 | } | |||
| 86 | ||||
| 87 | BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array, | |||
| 88 | Zone* zone, BytecodeOffset osr_bailout_id, | |||
| 89 | bool analyze_liveness) | |||
| 90 | : bytecode_array_(bytecode_array), | |||
| 91 | zone_(zone), | |||
| 92 | osr_bailout_id_(osr_bailout_id), | |||
| 93 | analyze_liveness_(analyze_liveness), | |||
| 94 | loop_stack_(zone), | |||
| 95 | loop_end_index_queue_(zone), | |||
| 96 | resume_jump_targets_(zone), | |||
| 97 | end_to_header_(zone), | |||
| 98 | header_to_info_(zone), | |||
| 99 | osr_entry_point_(-1) { | |||
| 100 | Analyze(); | |||
| 101 | } | |||
| 102 | ||||
| 103 | namespace { | |||
| 104 | ||||
| 105 | template <Bytecode bytecode, OperandType operand_type, size_t i> | |||
| 106 | void UpdateInLivenessForOutOperand( | |||
| 107 | BytecodeLivenessState* in_liveness, | |||
| 108 | const interpreter::BytecodeArrayIterator& iterator) { | |||
| 109 | switch (operand_type) { | |||
| 110 | case OperandType::kRegOut: { | |||
| 111 | Register r = iterator.GetRegisterOperand(i); | |||
| 112 | if (!r.is_parameter()) { | |||
| 113 | in_liveness->MarkRegisterDead(r.index()); | |||
| 114 | } | |||
| 115 | break; | |||
| 116 | } | |||
| 117 | case OperandType::kRegOutList: { | |||
| 118 | Register r = iterator.GetRegisterOperand(i); | |||
| 119 | uint32_t reg_count = iterator.GetRegisterCountOperand(i + 1); | |||
| 120 | if (!r.is_parameter()) { | |||
| 121 | for (uint32_t j = 0; j < reg_count; ++j) { | |||
| 122 | DCHECK(!Register(r.index() + j).is_parameter())((void) 0); | |||
| 123 | in_liveness->MarkRegisterDead(r.index() + j); | |||
| 124 | } | |||
| 125 | } | |||
| 126 | break; | |||
| 127 | } | |||
| 128 | case OperandType::kRegOutPair: { | |||
| 129 | Register r = iterator.GetRegisterOperand(i); | |||
| 130 | if (!r.is_parameter()) { | |||
| 131 | DCHECK(!Register(r.index() + 1).is_parameter())((void) 0); | |||
| 132 | in_liveness->MarkRegisterDead(r.index()); | |||
| 133 | in_liveness->MarkRegisterDead(r.index() + 1); | |||
| 134 | } | |||
| 135 | break; | |||
| 136 | } | |||
| 137 | case OperandType::kRegOutTriple: { | |||
| 138 | Register r = iterator.GetRegisterOperand(i); | |||
| 139 | if (!r.is_parameter()) { | |||
| 140 | DCHECK(!Register(r.index() + 1).is_parameter())((void) 0); | |||
| 141 | DCHECK(!Register(r.index() + 2).is_parameter())((void) 0); | |||
| 142 | in_liveness->MarkRegisterDead(r.index()); | |||
| 143 | in_liveness->MarkRegisterDead(r.index() + 1); | |||
| 144 | in_liveness->MarkRegisterDead(r.index() + 2); | |||
| 145 | } | |||
| 146 | break; | |||
| 147 | } | |||
| 148 | default: | |||
| 149 | DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_type))((void) 0); | |||
| 150 | break; | |||
| 151 | } | |||
| 152 | } | |||
| 153 | ||||
| 154 | template <Bytecode bytecode, OperandType operand_type, size_t i> | |||
| 155 | void UpdateInLivenessForInOperand( | |||
| 156 | BytecodeLivenessState* in_liveness, | |||
| 157 | const interpreter::BytecodeArrayIterator& iterator) { | |||
| 158 | switch (operand_type) { | |||
| 159 | case OperandType::kReg: { | |||
| 160 | Register r = iterator.GetRegisterOperand(i); | |||
| 161 | if (!r.is_parameter()) { | |||
| 162 | in_liveness->MarkRegisterLive(r.index()); | |||
| 163 | } | |||
| 164 | break; | |||
| 165 | } | |||
| 166 | case OperandType::kRegPair: { | |||
| 167 | Register r = iterator.GetRegisterOperand(i); | |||
| 168 | if (!r.is_parameter()) { | |||
| 169 | DCHECK(!Register(r.index() + 1).is_parameter())((void) 0); | |||
| 170 | in_liveness->MarkRegisterLive(r.index()); | |||
| 171 | in_liveness->MarkRegisterLive(r.index() + 1); | |||
| 172 | } | |||
| 173 | break; | |||
| 174 | } | |||
| 175 | case OperandType::kRegList: { | |||
| 176 | Register r = iterator.GetRegisterOperand(i); | |||
| 177 | uint32_t reg_count = iterator.GetRegisterCountOperand(i + 1); | |||
| 178 | if (!r.is_parameter()) { | |||
| 179 | for (uint32_t j = 0; j < reg_count; ++j) { | |||
| 180 | DCHECK(!interpreter::Register(r.index() + j).is_parameter())((void) 0); | |||
| 181 | in_liveness->MarkRegisterLive(r.index() + j); | |||
| 182 | } | |||
| 183 | } | |||
| 184 | break; | |||
| 185 | } | |||
| 186 | default: | |||
| 187 | DCHECK(!Bytecodes::IsRegisterInputOperandType(operand_type))((void) 0); | |||
| 188 | break; | |||
| 189 | } | |||
| 190 | } | |||
| 191 | ||||
| 192 | template <Bytecode bytecode, ImplicitRegisterUse implicit_register_use, | |||
| 193 | OperandType... operand_types, size_t... operand_index> | |||
| 194 | void UpdateInLiveness(BytecodeLivenessState* in_liveness, | |||
| 195 | const interpreter::BytecodeArrayIterator& iterator, | |||
| 196 | std::index_sequence<operand_index...>) { | |||
| 197 | // Special case Suspend and Resume to just pass through liveness. | |||
| 198 | if (bytecode == Bytecode::kSuspendGenerator) { | |||
| 199 | // The generator object has to be live. | |||
| 200 | in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index()); | |||
| 201 | // Suspend additionally reads and returns the accumulator | |||
| 202 | DCHECK(Bytecodes::ReadsAccumulator(bytecode))((void) 0); | |||
| 203 | in_liveness->MarkAccumulatorLive(); | |||
| 204 | return; | |||
| 205 | } | |||
| 206 | if (bytecode == Bytecode::kResumeGenerator) { | |||
| 207 | // The generator object has to be live. | |||
| 208 | in_liveness->MarkRegisterLive(iterator.GetRegisterOperand(0).index()); | |||
| 209 | return; | |||
| 210 | } | |||
| 211 | ||||
| 212 | if (BytecodeOperands::WritesAccumulator(implicit_register_use)) { | |||
| 213 | in_liveness->MarkAccumulatorDead(); | |||
| 214 | } | |||
| 215 | (UpdateInLivenessForOutOperand<bytecode, operand_types, operand_index>( | |||
| 216 | in_liveness, iterator), | |||
| 217 | ...); | |||
| 218 | ||||
| 219 | if (Bytecodes::WritesImplicitRegister(bytecode)) { | |||
| 220 | in_liveness->MarkRegisterDead(Register::FromShortStar(bytecode).index()); | |||
| 221 | } | |||
| 222 | ||||
| 223 | if (BytecodeOperands::ReadsAccumulator(implicit_register_use)) { | |||
| 224 | in_liveness->MarkAccumulatorLive(); | |||
| 225 | } | |||
| 226 | (UpdateInLivenessForInOperand<bytecode, operand_types, operand_index>( | |||
| 227 | in_liveness, iterator), | |||
| 228 | ...); | |||
| 229 | } | |||
| 230 | ||||
| 231 | template <Bytecode bytecode, ImplicitRegisterUse implicit_register_use, | |||
| 232 | OperandType... operand_types> | |||
| 233 | void UpdateInLiveness(BytecodeLivenessState* in_liveness, | |||
| 234 | const interpreter::BytecodeArrayIterator& iterator) { | |||
| 235 | UpdateInLiveness<bytecode, implicit_register_use, operand_types...>( | |||
| 236 | in_liveness, iterator, | |||
| 237 | std::make_index_sequence<sizeof...(operand_types)>()); | |||
| 238 | } | |||
| 239 | ||||
| 240 | void UpdateInLiveness(Bytecode bytecode, BytecodeLivenessState* in_liveness, | |||
| 241 | const interpreter::BytecodeArrayIterator& iterator) { | |||
| 242 | switch (bytecode) { | |||
| 243 | #define BYTECODE_UPDATE_IN_LIVENESS(Name, ...) \ | |||
| 244 | case Bytecode::k##Name: \ | |||
| 245 | return UpdateInLiveness<Bytecode::k##Name, __VA_ARGS__>(in_liveness, \ | |||
| 246 | iterator); | |||
| 247 | BYTECODE_LIST(BYTECODE_UPDATE_IN_LIVENESS)BYTECODE_UPDATE_IN_LIVENESS(Wide, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_IN_LIVENESS(ExtraWide, ImplicitRegisterUse:: kNone) BYTECODE_UPDATE_IN_LIVENESS(DebugBreakWide, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(DebugBreakExtraWide , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (DebugBreak0, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (DebugBreak1, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg) BYTECODE_UPDATE_IN_LIVENESS(DebugBreak2, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kReg ) BYTECODE_UPDATE_IN_LIVENESS(DebugBreak3, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kReg , OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS(DebugBreak4, ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kReg, OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS (DebugBreak5, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRuntimeId, OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS (DebugBreak6, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRuntimeId, OperandType::kReg, OperandType::kReg, OperandType ::kReg) BYTECODE_UPDATE_IN_LIVENESS(Ldar, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS (LdaZero, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (LdaSmi, ImplicitRegisterUse::kWriteAccumulator, OperandType:: kImm) BYTECODE_UPDATE_IN_LIVENESS(LdaUndefined, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LdaNull, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LdaTheHole, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LdaTrue, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LdaFalse, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LdaConstant, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (LdaContextSlot, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (LdaImmutableContextSlot, ImplicitRegisterUse::kWriteAccumulator , OperandType::kReg, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (LdaCurrentContextSlot, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(LdaImmutableCurrentContextSlot , ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (Star, ImplicitRegisterUse::kReadAccumulator, OperandType::kRegOut ) BYTECODE_UPDATE_IN_LIVENESS(Mov, ImplicitRegisterUse::kNone , OperandType::kReg, OperandType::kRegOut) BYTECODE_UPDATE_IN_LIVENESS (PushContext, ImplicitRegisterUse::kReadAccumulator, OperandType ::kRegOut) BYTECODE_UPDATE_IN_LIVENESS(PopContext, ImplicitRegisterUse ::kNone, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS(TestReferenceEqual , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_IN_LIVENESS(TestUndetectable, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(TestNull , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (TestUndefined, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (TestTypeOf, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kFlag8) BYTECODE_UPDATE_IN_LIVENESS(LdaGlobal, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (LdaGlobalInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (StaGlobal, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(StaContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS(StaCurrentContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (LdaLookupSlot, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(LdaLookupContextSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(LdaLookupGlobalSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(LdaLookupSlotInsideTypeof , ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (LdaLookupContextSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (LdaLookupGlobalSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (StaLookupSlot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_IN_LIVENESS(GetNamedProperty , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(GetNamedPropertyFromSuper , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (GetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (LdaModuleVariable, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kImm, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS(StaModuleVariable , ImplicitRegisterUse::kReadAccumulator, OperandType::kImm, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(SetNamedProperty, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(DefineNamedOwnProperty , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (SetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (DefineKeyedOwnProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (StaInArrayLiteral, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (DefineKeyedOwnPropertyInLiteral, ImplicitRegisterUse::kReadAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CollectTypeProfile, ImplicitRegisterUse ::kReadAccumulator, OperandType::kImm) BYTECODE_UPDATE_IN_LIVENESS (Add, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(Sub, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(Mul, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (Div, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(Mod, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(Exp, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (BitwiseOr, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(BitwiseXor , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(BitwiseAnd, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(ShiftLeft, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ShiftRight, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ShiftRightLogical , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(AddSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(SubSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (MulSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(DivSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ModSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(ExpSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (BitwiseOrSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(BitwiseXorSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(BitwiseAndSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ShiftLeftSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ShiftRightSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ShiftRightLogicalSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(Inc, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (Dec, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(Negate, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (BitwiseNot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ToBooleanLogicalNot, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(LogicalNot , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (TypeOf, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (DeletePropertyStrict, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS(DeletePropertySloppy , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_IN_LIVENESS(GetSuperConstructor, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_IN_LIVENESS (CallAnyReceiver, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CallProperty, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kRegList , OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CallProperty0, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CallProperty1, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(CallProperty2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CallUndefinedReceiver, ImplicitRegisterUse::kWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CallUndefinedReceiver0 , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CallUndefinedReceiver1, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CallUndefinedReceiver2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CallWithSpread , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kRegList, OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CallRuntime, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kRuntimeId, OperandType::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_IN_LIVENESS (CallRuntimeForPair, ImplicitRegisterUse::kNone, OperandType:: kRuntimeId, OperandType::kRegList, OperandType::kRegCount, OperandType ::kRegOutPair) BYTECODE_UPDATE_IN_LIVENESS(CallJSRuntime, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kNativeContextIndex, OperandType ::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_IN_LIVENESS (InvokeIntrinsic, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIntrinsicId, OperandType::kRegList, OperandType::kRegCount ) BYTECODE_UPDATE_IN_LIVENESS(Construct, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kReg, OperandType::kRegList , OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ConstructWithSpread, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(TestEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestEqualStrict, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestLessThan, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestGreaterThan, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestLessThanOrEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestGreaterThanOrEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestInstanceOf, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(TestIn, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ToName, ImplicitRegisterUse::kReadAccumulator, OperandType:: kRegOut) BYTECODE_UPDATE_IN_LIVENESS(ToNumber, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ToNumeric, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(ToObject, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_IN_LIVENESS (ToString, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (CreateRegExpLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_IN_LIVENESS (CreateArrayLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_IN_LIVENESS (CreateArrayFromIterable, ImplicitRegisterUse::kReadWriteAccumulator ) BYTECODE_UPDATE_IN_LIVENESS(CreateEmptyArrayLiteral, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CreateObjectLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_IN_LIVENESS (CreateEmptyObjectLiteral, ImplicitRegisterUse::kWriteAccumulator ) BYTECODE_UPDATE_IN_LIVENESS(CloneObject, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(GetTemplateObject, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CreateClosure, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_IN_LIVENESS (CreateBlockContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CreateCatchContext, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (CreateFunctionContext, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (CreateEvalContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS(CreateWithContext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(CreateMappedArguments, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(CreateUnmappedArguments , ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS (CreateRestParameter, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(JumpLoop, ImplicitRegisterUse::kNone , OperandType::kUImm, OperandType::kImm) BYTECODE_UPDATE_IN_LIVENESS (Jump, ImplicitRegisterUse::kNone, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpConstant, ImplicitRegisterUse::kNone, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfNullConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (JumpIfNotNullConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfUndefinedConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (JumpIfNotUndefinedConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfUndefinedOrNullConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (JumpIfTrueConstant, ImplicitRegisterUse::kReadAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfFalseConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (JumpIfJSReceiverConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfToBooleanTrueConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (JumpIfToBooleanFalseConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(JumpIfToBooleanTrue , ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpIfToBooleanFalse, ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS(JumpIfTrue, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpIfFalse, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(JumpIfNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpIfNotNull, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(JumpIfUndefined, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpIfNotUndefined, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(JumpIfUndefinedOrNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (JumpIfJSReceiver, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_IN_LIVENESS(SwitchOnSmiNoFeedback, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx, OperandType::kUImm, OperandType ::kImm) BYTECODE_UPDATE_IN_LIVENESS(ForInEnumerate, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS (ForInPrepare, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRegOutTriple, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ForInContinue, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg) BYTECODE_UPDATE_IN_LIVENESS(ForInNext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kReg, OperandType::kRegPair, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ForInStep, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg) BYTECODE_UPDATE_IN_LIVENESS(SetPendingMessage, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_IN_LIVENESS(Throw, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_IN_LIVENESS(ReThrow, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_IN_LIVENESS(Return, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_IN_LIVENESS(ThrowReferenceErrorIfHole , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (ThrowSuperNotCalledIfHole, ImplicitRegisterUse::kReadAccumulator ) BYTECODE_UPDATE_IN_LIVENESS(ThrowSuperAlreadyCalledIfNotHole , ImplicitRegisterUse::kReadAccumulator) BYTECODE_UPDATE_IN_LIVENESS (ThrowIfNotSuperConstructor, ImplicitRegisterUse::kNone, OperandType ::kReg) BYTECODE_UPDATE_IN_LIVENESS(SwitchOnGeneratorState, ImplicitRegisterUse ::kNone, OperandType::kReg, OperandType::kIdx, OperandType::kUImm ) BYTECODE_UPDATE_IN_LIVENESS(SuspendGenerator, ImplicitRegisterUse ::kReadAccumulator, OperandType::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType::kUImm) BYTECODE_UPDATE_IN_LIVENESS (ResumeGenerator, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kRegOutList, OperandType::kRegCount) BYTECODE_UPDATE_IN_LIVENESS (GetIterator, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS (Debugger, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_IN_LIVENESS (IncBlockCounter, ImplicitRegisterUse::kNone, OperandType::kIdx ) BYTECODE_UPDATE_IN_LIVENESS(Abort, ImplicitRegisterUse::kNone , OperandType::kIdx) BYTECODE_UPDATE_IN_LIVENESS(Star15, ImplicitRegisterUse ::kReadAccumulatorWriteShortStar) BYTECODE_UPDATE_IN_LIVENESS (Star14, ImplicitRegisterUse::kReadAccumulatorWriteShortStar) BYTECODE_UPDATE_IN_LIVENESS(Star13, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star12, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star11, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star10, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star9, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star8, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star7, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star6, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star5, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star4, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star3, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star2, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star1, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Star0, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_IN_LIVENESS(Illegal, ImplicitRegisterUse::kNone ) | |||
| 248 | #undef BYTECODE_UPDATE_IN_LIVENESS | |||
| 249 | } | |||
| 250 | } | |||
| 251 | ||||
| 252 | template <bool IsFirstUpdate = false> | |||
| 253 | void EnsureOutLivenessIsNotAlias( | |||
| 254 | BytecodeLiveness& liveness, | |||
| 255 | BytecodeLivenessState* next_bytecode_in_liveness, Zone* zone) { | |||
| 256 | if (!IsFirstUpdate) { | |||
| 257 | // We should have copied the next bytecode's in liveness already in the | |||
| 258 | // first pass, so on subsequent passes this should already not be an alias. | |||
| 259 | DCHECK_NE(liveness.out, next_bytecode_in_liveness)((void) 0); | |||
| 260 | return; | |||
| 261 | } | |||
| 262 | if (liveness.out == next_bytecode_in_liveness) { | |||
| 263 | // If the out-liveness is aliasing the next bytecode's in-liveness, | |||
| 264 | // reallocate it and copy the data to the newly allocated state. | |||
| 265 | liveness.out = | |||
| 266 | zone->New<BytecodeLivenessState>(*next_bytecode_in_liveness, zone); | |||
| ||||
| 267 | } | |||
| 268 | } | |||
| 269 | ||||
| 270 | template <bool IsFirstUpdate, Bytecode bytecode> | |||
| 271 | void UpdateOutLiveness(BytecodeLiveness& liveness, | |||
| 272 | BytecodeLivenessState* next_bytecode_in_liveness, | |||
| 273 | const interpreter::BytecodeArrayIterator& iterator, | |||
| 274 | Handle<BytecodeArray> bytecode_array, | |||
| 275 | const BytecodeLivenessMap& liveness_map, Zone* zone) { | |||
| 276 | // On subsequent updates, only update out-liveness manually if it isn't | |||
| 277 | // already aliasing the next bytecode's in-liveness. | |||
| 278 | if (!IsFirstUpdate && liveness.out == next_bytecode_in_liveness) return; | |||
| 279 | ||||
| 280 | // Special case Suspend and Resume to just pass through liveness. | |||
| 281 | if (bytecode == Bytecode::kSuspendGenerator || | |||
| 282 | bytecode == Bytecode::kResumeGenerator) { | |||
| 283 | DCHECK_NOT_NULL(next_bytecode_in_liveness)((void) 0); | |||
| 284 | if (IsFirstUpdate) { | |||
| 285 | liveness.out = next_bytecode_in_liveness; | |||
| 286 | } else { | |||
| 287 | liveness.out->Union(*next_bytecode_in_liveness); | |||
| 288 | } | |||
| 289 | return; | |||
| 290 | } | |||
| 291 | ||||
| 292 | // Update from next bytecode (unless there isn't one or this is an | |||
| 293 | // unconditional jump). | |||
| 294 | if (next_bytecode_in_liveness != nullptr && | |||
| 295 | !Bytecodes::IsUnconditionalJump(bytecode) && | |||
| 296 | !Bytecodes::Returns(bytecode) && | |||
| 297 | !Bytecodes::UnconditionallyThrows(bytecode)) { | |||
| 298 | if (IsFirstUpdate) { | |||
| 299 | // On first update, we can assume that this out-liveness is the same as | |||
| 300 | // the next liveness, and can directly alias it -- we'll allocate a new | |||
| 301 | // one using EnsureOutLivenessIsNotAlias if it needs to be mutated. | |||
| 302 | DCHECK_NULL(liveness.out)((void) 0); | |||
| 303 | liveness.out = next_bytecode_in_liveness; | |||
| 304 | } else { | |||
| 305 | liveness.out->Union(*next_bytecode_in_liveness); | |||
| 306 | } | |||
| 307 | } else if (IsFirstUpdate) { | |||
| 308 | // Otherwise, on the first allocation we need to make sure that there is an | |||
| 309 | // allocated out liveness. | |||
| 310 | DCHECK_NULL(liveness.out)((void) 0); | |||
| 311 | liveness.out = zone->New<BytecodeLivenessState>( | |||
| 312 | bytecode_array->register_count(), zone); | |||
| 313 | } | |||
| 314 | ||||
| 315 | DCHECK_NOT_NULL(liveness.out)((void) 0); | |||
| 316 | ||||
| 317 | // Update from jump target (if any). Skip loops, we update these manually in | |||
| 318 | // the liveness iterations. | |||
| 319 | if (Bytecodes::IsForwardJump(bytecode)) { | |||
| 320 | int target_offset = iterator.GetJumpTargetOffset(); | |||
| 321 | EnsureOutLivenessIsNotAlias<IsFirstUpdate>(liveness, | |||
| 322 | next_bytecode_in_liveness, zone); | |||
| 323 | liveness.out->Union(*liveness_map.GetInLiveness(target_offset)); | |||
| 324 | } else if (Bytecodes::IsSwitch(bytecode)) { | |||
| 325 | EnsureOutLivenessIsNotAlias<IsFirstUpdate>(liveness, | |||
| 326 | next_bytecode_in_liveness, zone); | |||
| 327 | for (interpreter::JumpTableTargetOffset entry : | |||
| 328 | iterator.GetJumpTableTargetOffsets()) { | |||
| 329 | liveness.out->Union(*liveness_map.GetInLiveness(entry.target_offset)); | |||
| 330 | } | |||
| 331 | } | |||
| 332 | ||||
| 333 | // Update from exception handler (if any). | |||
| 334 | if (!interpreter::Bytecodes::IsWithoutExternalSideEffects(bytecode)) { | |||
| 335 | int handler_context; | |||
| 336 | // TODO(leszeks): We should look up this range only once per entry. | |||
| 337 | HandlerTable table(*bytecode_array); | |||
| 338 | int handler_offset = | |||
| 339 | table.LookupRange(iterator.current_offset(), &handler_context, nullptr); | |||
| 340 | ||||
| 341 | if (handler_offset != -1) { | |||
| 342 | EnsureOutLivenessIsNotAlias<IsFirstUpdate>( | |||
| 343 | liveness, next_bytecode_in_liveness, zone); | |||
| 344 | bool was_accumulator_live = liveness.out->AccumulatorIsLive(); | |||
| 345 | liveness.out->Union(*liveness_map.GetInLiveness(handler_offset)); | |||
| 346 | liveness.out->MarkRegisterLive(handler_context); | |||
| 347 | if (!was_accumulator_live) { | |||
| 348 | // The accumulator is reset to the exception on entry into a handler, | |||
| 349 | // and so shouldn't be considered live coming out of this bytecode just | |||
| 350 | // because it's live coming into the handler. So, kill the accumulator | |||
| 351 | // if the handler is the only thing that made it live. | |||
| 352 | liveness.out->MarkAccumulatorDead(); | |||
| 353 | ||||
| 354 | // TODO(leszeks): Ideally the accumulator wouldn't be considered live at | |||
| 355 | // the start of the handler, but looking up if the current bytecode is | |||
| 356 | // the start of a handler is not free, so we should only do it if we | |||
| 357 | // decide it's necessary. | |||
| 358 | } | |||
| 359 | } | |||
| 360 | } | |||
| 361 | } | |||
| 362 | ||||
| 363 | template <bool IsFirstUpdate = false> | |||
| 364 | void UpdateOutLiveness(Bytecode bytecode, BytecodeLiveness& liveness, | |||
| 365 | BytecodeLivenessState* next_bytecode_in_liveness, | |||
| 366 | const interpreter::BytecodeArrayIterator& iterator, | |||
| 367 | Handle<BytecodeArray> bytecode_array, | |||
| 368 | const BytecodeLivenessMap& liveness_map, Zone* zone) { | |||
| 369 | switch (bytecode) { | |||
| 370 | #define BYTECODE_UPDATE_OUT_LIVENESS(Name, ...) \ | |||
| 371 | case Bytecode::k##Name: \ | |||
| 372 | return UpdateOutLiveness<IsFirstUpdate, Bytecode::k##Name>( \ | |||
| 373 | liveness, next_bytecode_in_liveness, iterator, bytecode_array, \ | |||
| 374 | liveness_map, zone); | |||
| 375 | BYTECODE_LIST(BYTECODE_UPDATE_OUT_LIVENESS)BYTECODE_UPDATE_OUT_LIVENESS(Wide, ImplicitRegisterUse::kNone ) BYTECODE_UPDATE_OUT_LIVENESS(ExtraWide, ImplicitRegisterUse ::kNone) BYTECODE_UPDATE_OUT_LIVENESS(DebugBreakWide, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(DebugBreakExtraWide , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (DebugBreak0, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (DebugBreak1, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg) BYTECODE_UPDATE_OUT_LIVENESS(DebugBreak2, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kReg ) BYTECODE_UPDATE_OUT_LIVENESS(DebugBreak3, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kReg , OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS(DebugBreak4 , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kReg, OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS (DebugBreak5, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRuntimeId, OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS (DebugBreak6, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRuntimeId, OperandType::kReg, OperandType::kReg, OperandType ::kReg) BYTECODE_UPDATE_OUT_LIVENESS(Ldar, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS (LdaZero, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (LdaSmi, ImplicitRegisterUse::kWriteAccumulator, OperandType:: kImm) BYTECODE_UPDATE_OUT_LIVENESS(LdaUndefined, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(LdaNull, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(LdaTheHole, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (LdaTrue, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (LdaFalse, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (LdaConstant, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(LdaContextSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(LdaImmutableContextSlot , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(LdaCurrentContextSlot , ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (LdaImmutableCurrentContextSlot, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Star, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_OUT_LIVENESS (Mov, ImplicitRegisterUse::kNone, OperandType::kReg, OperandType ::kRegOut) BYTECODE_UPDATE_OUT_LIVENESS(PushContext, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_OUT_LIVENESS (PopContext, ImplicitRegisterUse::kNone, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS (TestReferenceEqual, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS(TestUndetectable , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (TestNull, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (TestUndefined, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (TestTypeOf, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS(LdaGlobal, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (LdaGlobalInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (StaGlobal, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(StaContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(StaCurrentContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (LdaLookupSlot, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(LdaLookupContextSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(LdaLookupGlobalSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(LdaLookupSlotInsideTypeof , ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (LdaLookupContextSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (LdaLookupGlobalSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (StaLookupSlot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS(GetNamedProperty , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(GetNamedPropertyFromSuper , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (GetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (LdaModuleVariable, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kImm, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(StaModuleVariable , ImplicitRegisterUse::kReadAccumulator, OperandType::kImm, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(SetNamedProperty, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(DefineNamedOwnProperty , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (SetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (DefineKeyedOwnProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (StaInArrayLiteral, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (DefineKeyedOwnPropertyInLiteral, ImplicitRegisterUse::kReadAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CollectTypeProfile, ImplicitRegisterUse ::kReadAccumulator, OperandType::kImm) BYTECODE_UPDATE_OUT_LIVENESS (Add, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Sub, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(Mul, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (Div, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Mod, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(Exp, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (BitwiseOr, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(BitwiseXor , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(BitwiseAnd, ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ShiftLeft, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(ShiftRight, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(ShiftRightLogical, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(AddSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (SubSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(MulSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(DivSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(ModSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ExpSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(BitwiseOrSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(BitwiseXorSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(BitwiseAndSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ShiftLeftSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ShiftRightSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ShiftRightLogicalSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Inc, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (Dec, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Negate, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (BitwiseNot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ToBooleanLogicalNot, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(LogicalNot , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (TypeOf, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (DeletePropertyStrict, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS(DeletePropertySloppy , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_OUT_LIVENESS(GetSuperConstructor, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_OUT_LIVENESS (CallAnyReceiver, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CallProperty, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kRegList , OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CallProperty0, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CallProperty1, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(CallProperty2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CallUndefinedReceiver, ImplicitRegisterUse::kWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CallUndefinedReceiver0 , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CallUndefinedReceiver1, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CallUndefinedReceiver2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CallWithSpread , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kRegList, OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CallRuntime, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kRuntimeId, OperandType::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_OUT_LIVENESS (CallRuntimeForPair, ImplicitRegisterUse::kNone, OperandType:: kRuntimeId, OperandType::kRegList, OperandType::kRegCount, OperandType ::kRegOutPair) BYTECODE_UPDATE_OUT_LIVENESS(CallJSRuntime, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kNativeContextIndex, OperandType ::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_OUT_LIVENESS (InvokeIntrinsic, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIntrinsicId, OperandType::kRegList, OperandType::kRegCount ) BYTECODE_UPDATE_OUT_LIVENESS(Construct, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kRegList , OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ConstructWithSpread, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(TestEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestEqualStrict, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestLessThan, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestGreaterThan, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestLessThanOrEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestGreaterThanOrEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestInstanceOf, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(TestIn, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ToName, ImplicitRegisterUse::kReadAccumulator, OperandType:: kRegOut) BYTECODE_UPDATE_OUT_LIVENESS(ToNumber, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ToNumeric, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(ToObject, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_OUT_LIVENESS (ToString, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (CreateRegExpLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS (CreateArrayLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS (CreateArrayFromIterable, ImplicitRegisterUse::kReadWriteAccumulator ) BYTECODE_UPDATE_OUT_LIVENESS(CreateEmptyArrayLiteral, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CreateObjectLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS (CreateEmptyObjectLiteral, ImplicitRegisterUse::kWriteAccumulator ) BYTECODE_UPDATE_OUT_LIVENESS(CloneObject, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(GetTemplateObject, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CreateClosure, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_OUT_LIVENESS (CreateBlockContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CreateCatchContext, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (CreateFunctionContext, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (CreateEvalContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(CreateWithContext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(CreateMappedArguments, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(CreateUnmappedArguments , ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (CreateRestParameter, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(JumpLoop, ImplicitRegisterUse:: kNone, OperandType::kUImm, OperandType::kImm) BYTECODE_UPDATE_OUT_LIVENESS (Jump, ImplicitRegisterUse::kNone, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpConstant, ImplicitRegisterUse::kNone, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfNullConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfNotNullConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfUndefinedConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfNotUndefinedConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfUndefinedOrNullConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfTrueConstant, ImplicitRegisterUse::kReadAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfFalseConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfJSReceiverConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfToBooleanTrueConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfToBooleanFalseConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfToBooleanTrue , ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfToBooleanFalse, ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfTrue, ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfFalse, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfNotNull, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfUndefined, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfNotUndefined, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(JumpIfUndefinedOrNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (JumpIfJSReceiver, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_OUT_LIVENESS(SwitchOnSmiNoFeedback, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx, OperandType::kUImm, OperandType ::kImm) BYTECODE_UPDATE_OUT_LIVENESS(ForInEnumerate, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS (ForInPrepare, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRegOutTriple, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ForInContinue, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg) BYTECODE_UPDATE_OUT_LIVENESS(ForInNext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kReg, OperandType::kRegPair, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ForInStep, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg) BYTECODE_UPDATE_OUT_LIVENESS(SetPendingMessage, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(Throw, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(ReThrow, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(Return, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_OUT_LIVENESS(ThrowReferenceErrorIfHole , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (ThrowSuperNotCalledIfHole, ImplicitRegisterUse::kReadAccumulator ) BYTECODE_UPDATE_OUT_LIVENESS(ThrowSuperAlreadyCalledIfNotHole , ImplicitRegisterUse::kReadAccumulator) BYTECODE_UPDATE_OUT_LIVENESS (ThrowIfNotSuperConstructor, ImplicitRegisterUse::kNone, OperandType ::kReg) BYTECODE_UPDATE_OUT_LIVENESS(SwitchOnGeneratorState, ImplicitRegisterUse ::kNone, OperandType::kReg, OperandType::kIdx, OperandType::kUImm ) BYTECODE_UPDATE_OUT_LIVENESS(SuspendGenerator, ImplicitRegisterUse ::kReadAccumulator, OperandType::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType::kUImm) BYTECODE_UPDATE_OUT_LIVENESS (ResumeGenerator, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kRegOutList, OperandType::kRegCount) BYTECODE_UPDATE_OUT_LIVENESS (GetIterator, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS (Debugger, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_OUT_LIVENESS (IncBlockCounter, ImplicitRegisterUse::kNone, OperandType::kIdx ) BYTECODE_UPDATE_OUT_LIVENESS(Abort, ImplicitRegisterUse::kNone , OperandType::kIdx) BYTECODE_UPDATE_OUT_LIVENESS(Star15, ImplicitRegisterUse ::kReadAccumulatorWriteShortStar) BYTECODE_UPDATE_OUT_LIVENESS (Star14, ImplicitRegisterUse::kReadAccumulatorWriteShortStar) BYTECODE_UPDATE_OUT_LIVENESS(Star13, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star12, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star11, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star10, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star9, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star8, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star7, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star6, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star5, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star4, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star3, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star2, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star1, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Star0, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_OUT_LIVENESS(Illegal, ImplicitRegisterUse:: kNone) | |||
| 376 | #undef BYTECODE_UPDATE_OUT_LIVENESS | |||
| 377 | } | |||
| 378 | } | |||
| 379 | ||||
| 380 | template <bool IsFirstUpdate, Bytecode bytecode, | |||
| 381 | ImplicitRegisterUse implicit_register_use, | |||
| 382 | OperandType... operand_types> | |||
| 383 | void UpdateLiveness(BytecodeLiveness& liveness, | |||
| 384 | BytecodeLivenessState** next_bytecode_in_liveness, | |||
| 385 | const interpreter::BytecodeArrayIterator& iterator, | |||
| 386 | Handle<BytecodeArray> bytecode_array, | |||
| 387 | const BytecodeLivenessMap& liveness_map, Zone* zone) { | |||
| 388 | UpdateOutLiveness<IsFirstUpdate, bytecode>( | |||
| 389 | liveness, *next_bytecode_in_liveness, iterator, bytecode_array, | |||
| ||||
| 390 | liveness_map, zone); | |||
| 391 | if (IsFirstUpdate) { | |||
| 392 | // On the first update, allocate the in-liveness as a copy of the | |||
| 393 | // out-liveness. | |||
| 394 | DCHECK_NULL(liveness.in)((void) 0); | |||
| 395 | liveness.in = zone->New<BytecodeLivenessState>(*liveness.out, zone); | |||
| 396 | } else { | |||
| 397 | // On subsequent updates, copy liveness from the out vector. | |||
| 398 | // TODO(leszeks): If this copy doesn't change liveness, we could | |||
| 399 | // opportunistically terminate early. | |||
| 400 | liveness.in->CopyFrom(*liveness.out); | |||
| 401 | } | |||
| 402 | UpdateInLiveness<bytecode, implicit_register_use, operand_types...>( | |||
| 403 | liveness.in, iterator); | |||
| 404 | ||||
| 405 | *next_bytecode_in_liveness = liveness.in; | |||
| 406 | } | |||
| 407 | ||||
| 408 | template <bool IsFirstUpdate = false> | |||
| 409 | void UpdateLiveness(Bytecode bytecode, BytecodeLiveness& liveness, | |||
| 410 | BytecodeLivenessState** next_bytecode_in_liveness, | |||
| 411 | const interpreter::BytecodeArrayIterator& iterator, | |||
| 412 | Handle<BytecodeArray> bytecode_array, | |||
| 413 | const BytecodeLivenessMap& liveness_map, Zone* zone) { | |||
| 414 | switch (bytecode) { | |||
| 415 | #define BYTECODE_UPDATE_LIVENESS(Name, ...) \ | |||
| 416 | case Bytecode::k##Name: \ | |||
| 417 | return UpdateLiveness<IsFirstUpdate, Bytecode::k##Name, __VA_ARGS__>( \ | |||
| 418 | liveness, next_bytecode_in_liveness, iterator, bytecode_array, \ | |||
| 419 | liveness_map, zone); | |||
| 420 | BYTECODE_LIST(BYTECODE_UPDATE_LIVENESS)BYTECODE_UPDATE_LIVENESS(Wide, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_LIVENESS (ExtraWide, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_LIVENESS (DebugBreakWide, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS (DebugBreakExtraWide, ImplicitRegisterUse::kReadWriteAccumulator ) BYTECODE_UPDATE_LIVENESS(DebugBreak0, ImplicitRegisterUse:: kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS(DebugBreak1, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_LIVENESS (DebugBreak2, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kReg) BYTECODE_UPDATE_LIVENESS(DebugBreak3 , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_LIVENESS (DebugBreak4, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kReg, OperandType::kReg ) BYTECODE_UPDATE_LIVENESS(DebugBreak5, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kRuntimeId, OperandType:: kReg, OperandType::kReg) BYTECODE_UPDATE_LIVENESS(DebugBreak6 , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kRuntimeId , OperandType::kReg, OperandType::kReg, OperandType::kReg) BYTECODE_UPDATE_LIVENESS (Ldar, ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_LIVENESS(LdaZero, ImplicitRegisterUse::kWriteAccumulator ) BYTECODE_UPDATE_LIVENESS(LdaSmi, ImplicitRegisterUse::kWriteAccumulator , OperandType::kImm) BYTECODE_UPDATE_LIVENESS(LdaUndefined, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LdaNull, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LdaTheHole, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LdaTrue, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LdaFalse, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LdaConstant, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (LdaContextSlot, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (LdaImmutableContextSlot, ImplicitRegisterUse::kWriteAccumulator , OperandType::kReg, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (LdaCurrentContextSlot, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(LdaImmutableCurrentContextSlot , ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (Star, ImplicitRegisterUse::kReadAccumulator, OperandType::kRegOut ) BYTECODE_UPDATE_LIVENESS(Mov, ImplicitRegisterUse::kNone, OperandType ::kReg, OperandType::kRegOut) BYTECODE_UPDATE_LIVENESS(PushContext , ImplicitRegisterUse::kReadAccumulator, OperandType::kRegOut ) BYTECODE_UPDATE_LIVENESS(PopContext, ImplicitRegisterUse::kNone , OperandType::kReg) BYTECODE_UPDATE_LIVENESS(TestReferenceEqual , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_LIVENESS(TestUndetectable, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS(TestNull, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS(TestUndefined , ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS (TestTypeOf, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kFlag8) BYTECODE_UPDATE_LIVENESS(LdaGlobal, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (LdaGlobalInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (StaGlobal, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(StaContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS(StaCurrentContextSlot , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (LdaLookupSlot, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(LdaLookupContextSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(LdaLookupGlobalSlot, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(LdaLookupSlotInsideTypeof, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (LdaLookupContextSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (LdaLookupGlobalSlotInsideTypeof, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (StaLookupSlot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_LIVENESS(GetNamedProperty , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(GetNamedPropertyFromSuper , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (GetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (LdaModuleVariable, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kImm, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS(StaModuleVariable , ImplicitRegisterUse::kReadAccumulator, OperandType::kImm, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(SetNamedProperty, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(DefineNamedOwnProperty , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (SetKeyedProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (DefineKeyedOwnProperty, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (StaInArrayLiteral, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (DefineKeyedOwnPropertyInLiteral, ImplicitRegisterUse::kReadAccumulator , OperandType::kReg, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CollectTypeProfile, ImplicitRegisterUse ::kReadAccumulator, OperandType::kImm) BYTECODE_UPDATE_LIVENESS (Add, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(Sub, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(Mul, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (Div, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(Mod, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(Exp, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (BitwiseOr, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(BitwiseXor , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(BitwiseAnd, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(ShiftLeft, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ShiftRight, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(ShiftRightLogical , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(AddSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(SubSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (MulSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(DivSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(ModSmi, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ExpSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(BitwiseOrSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(BitwiseXorSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(BitwiseAndSmi, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(ShiftLeftSmi, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ShiftRightSmi, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kImm, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(ShiftRightLogicalSmi , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kImm , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(Inc, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (Dec, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(Negate, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (BitwiseNot, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(ToBooleanLogicalNot, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS(LogicalNot, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS (TypeOf, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS (DeletePropertyStrict, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg) BYTECODE_UPDATE_LIVENESS(DeletePropertySloppy , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg ) BYTECODE_UPDATE_LIVENESS(GetSuperConstructor, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_LIVENESS (CallAnyReceiver, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CallProperty, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kRegList , OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CallProperty0, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CallProperty1, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(CallProperty2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CallUndefinedReceiver, ImplicitRegisterUse::kWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(CallUndefinedReceiver0 , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CallUndefinedReceiver1, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CallUndefinedReceiver2, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kReg, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(CallWithSpread , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kRegList, OperandType::kRegCount, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CallRuntime, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kRuntimeId, OperandType::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_LIVENESS (CallRuntimeForPair, ImplicitRegisterUse::kNone, OperandType:: kRuntimeId, OperandType::kRegList, OperandType::kRegCount, OperandType ::kRegOutPair) BYTECODE_UPDATE_LIVENESS(CallJSRuntime, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kNativeContextIndex, OperandType ::kRegList, OperandType::kRegCount) BYTECODE_UPDATE_LIVENESS( InvokeIntrinsic, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIntrinsicId, OperandType::kRegList, OperandType::kRegCount ) BYTECODE_UPDATE_LIVENESS(Construct, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kRegList, OperandType::kRegCount , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(ConstructWithSpread , ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg , OperandType::kRegList, OperandType::kRegCount, OperandType:: kIdx) BYTECODE_UPDATE_LIVENESS(TestEqual, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(TestEqualStrict, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(TestLessThan, ImplicitRegisterUse:: kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (TestGreaterThan, ImplicitRegisterUse::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (TestLessThanOrEqual, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (TestGreaterThanOrEqual, ImplicitRegisterUse::kReadWriteAccumulator , OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (TestInstanceOf, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(TestIn, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kReg, OperandType::kIdx ) BYTECODE_UPDATE_LIVENESS(ToName, ImplicitRegisterUse::kReadAccumulator , OperandType::kRegOut) BYTECODE_UPDATE_LIVENESS(ToNumber, ImplicitRegisterUse ::kReadWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ToNumeric, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(ToObject, ImplicitRegisterUse ::kReadAccumulator, OperandType::kRegOut) BYTECODE_UPDATE_LIVENESS (ToString, ImplicitRegisterUse::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS (CreateRegExpLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_LIVENESS (CreateArrayLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_LIVENESS (CreateArrayFromIterable, ImplicitRegisterUse::kReadWriteAccumulator ) BYTECODE_UPDATE_LIVENESS(CreateEmptyArrayLiteral, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CreateObjectLiteral, ImplicitRegisterUse::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_LIVENESS (CreateEmptyObjectLiteral, ImplicitRegisterUse::kWriteAccumulator ) BYTECODE_UPDATE_LIVENESS(CloneObject, ImplicitRegisterUse:: kWriteAccumulator, OperandType::kReg, OperandType::kFlag8, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(GetTemplateObject, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CreateClosure, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kIdx, OperandType::kFlag8) BYTECODE_UPDATE_LIVENESS (CreateBlockContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CreateCatchContext, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (CreateFunctionContext, ImplicitRegisterUse::kWriteAccumulator , OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (CreateEvalContext, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS(CreateWithContext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(CreateMappedArguments, ImplicitRegisterUse ::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(CreateUnmappedArguments , ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS (CreateRestParameter, ImplicitRegisterUse::kWriteAccumulator) BYTECODE_UPDATE_LIVENESS(JumpLoop, ImplicitRegisterUse::kNone , OperandType::kUImm, OperandType::kImm) BYTECODE_UPDATE_LIVENESS (Jump, ImplicitRegisterUse::kNone, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpConstant, ImplicitRegisterUse::kNone, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfNullConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (JumpIfNotNullConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfUndefinedConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (JumpIfNotUndefinedConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfUndefinedOrNullConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (JumpIfTrueConstant, ImplicitRegisterUse::kReadAccumulator, OperandType ::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfFalseConstant, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (JumpIfJSReceiverConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfToBooleanTrueConstant , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (JumpIfToBooleanFalseConstant, ImplicitRegisterUse::kReadAccumulator , OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(JumpIfToBooleanTrue , ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpIfToBooleanFalse, ImplicitRegisterUse::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS(JumpIfTrue, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpIfFalse, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(JumpIfNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpIfNotNull, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(JumpIfUndefined, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpIfNotUndefined, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(JumpIfUndefinedOrNull, ImplicitRegisterUse ::kReadAccumulator, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (JumpIfJSReceiver, ImplicitRegisterUse::kReadAccumulator, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(SwitchOnSmiNoFeedback, ImplicitRegisterUse ::kReadAccumulator, OperandType::kIdx, OperandType::kUImm, OperandType ::kImm) BYTECODE_UPDATE_LIVENESS(ForInEnumerate, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg) BYTECODE_UPDATE_LIVENESS (ForInPrepare, ImplicitRegisterUse::kReadWriteAccumulator, OperandType ::kRegOutTriple, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS( ForInContinue, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg, OperandType::kReg) BYTECODE_UPDATE_LIVENESS(ForInNext , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kReg, OperandType::kRegPair, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ForInStep, ImplicitRegisterUse::kWriteAccumulator, OperandType ::kReg) BYTECODE_UPDATE_LIVENESS(SetPendingMessage, ImplicitRegisterUse ::kReadWriteAccumulator) BYTECODE_UPDATE_LIVENESS(Throw, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_LIVENESS(ReThrow, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_LIVENESS(Return, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_LIVENESS(ThrowReferenceErrorIfHole , ImplicitRegisterUse::kReadAccumulator, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (ThrowSuperNotCalledIfHole, ImplicitRegisterUse::kReadAccumulator ) BYTECODE_UPDATE_LIVENESS(ThrowSuperAlreadyCalledIfNotHole, ImplicitRegisterUse ::kReadAccumulator) BYTECODE_UPDATE_LIVENESS(ThrowIfNotSuperConstructor , ImplicitRegisterUse::kNone, OperandType::kReg) BYTECODE_UPDATE_LIVENESS (SwitchOnGeneratorState, ImplicitRegisterUse::kNone, OperandType ::kReg, OperandType::kIdx, OperandType::kUImm) BYTECODE_UPDATE_LIVENESS (SuspendGenerator, ImplicitRegisterUse::kReadAccumulator, OperandType ::kReg, OperandType::kRegList, OperandType::kRegCount, OperandType ::kUImm) BYTECODE_UPDATE_LIVENESS(ResumeGenerator, ImplicitRegisterUse ::kWriteAccumulator, OperandType::kReg, OperandType::kRegOutList , OperandType::kRegCount) BYTECODE_UPDATE_LIVENESS(GetIterator , ImplicitRegisterUse::kWriteAccumulator, OperandType::kReg, OperandType ::kIdx, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS(Debugger, ImplicitRegisterUse::kNone) BYTECODE_UPDATE_LIVENESS(IncBlockCounter , ImplicitRegisterUse::kNone, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (Abort, ImplicitRegisterUse::kNone, OperandType::kIdx) BYTECODE_UPDATE_LIVENESS (Star15, ImplicitRegisterUse::kReadAccumulatorWriteShortStar) BYTECODE_UPDATE_LIVENESS(Star14, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star13, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star12, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star11, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star10, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star9, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star8, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star7, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star6, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star5, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star4, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star3, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star2, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star1, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Star0, ImplicitRegisterUse::kReadAccumulatorWriteShortStar ) BYTECODE_UPDATE_LIVENESS(Illegal, ImplicitRegisterUse::kNone ) | |||
| 421 | #undef BYTECODE_UPDATE_LIVENESS | |||
| 422 | } | |||
| 423 | } | |||
| 424 | ||||
| 425 | void UpdateAssignments(Bytecode bytecode, BytecodeLoopAssignments* assignments, | |||
| 426 | const interpreter::BytecodeArrayIterator& iterator) { | |||
| 427 | int num_operands = Bytecodes::NumberOfOperands(bytecode); | |||
| 428 | const OperandType* operand_types = Bytecodes::GetOperandTypes(bytecode); | |||
| 429 | ||||
| 430 | for (int i = 0; i < num_operands; ++i) { | |||
| 431 | switch (operand_types[i]) { | |||
| 432 | case OperandType::kRegOut: { | |||
| 433 | assignments->Add(iterator.GetRegisterOperand(i)); | |||
| 434 | break; | |||
| 435 | } | |||
| 436 | case OperandType::kRegOutList: { | |||
| 437 | interpreter::Register r = iterator.GetRegisterOperand(i++); | |||
| 438 | uint32_t reg_count = iterator.GetRegisterCountOperand(i); | |||
| 439 | assignments->AddList(r, reg_count); | |||
| 440 | break; | |||
| 441 | } | |||
| 442 | case OperandType::kRegOutPair: { | |||
| 443 | assignments->AddList(iterator.GetRegisterOperand(i), 2); | |||
| 444 | break; | |||
| 445 | } | |||
| 446 | case OperandType::kRegOutTriple: { | |||
| 447 | assignments->AddList(iterator.GetRegisterOperand(i), 3); | |||
| 448 | break; | |||
| 449 | } | |||
| 450 | default: | |||
| 451 | DCHECK(!Bytecodes::IsRegisterOutputOperandType(operand_types[i]))((void) 0); | |||
| 452 | break; | |||
| 453 | } | |||
| 454 | } | |||
| 455 | ||||
| 456 | if (Bytecodes::WritesImplicitRegister(bytecode)) { | |||
| 457 | assignments->Add(interpreter::Register::FromShortStar(bytecode)); | |||
| 458 | } | |||
| 459 | } | |||
| 460 | ||||
| 461 | } // namespace | |||
| 462 | ||||
| 463 | void BytecodeAnalysis::Analyze() { | |||
| 464 | loop_stack_.push({-1, nullptr}); | |||
| 465 | ||||
| 466 | BytecodeLivenessState* next_bytecode_in_liveness = nullptr; | |||
| 467 | int generator_switch_index = -1; | |||
| 468 | int osr_loop_end_offset = osr_bailout_id_.ToInt(); | |||
| 469 | DCHECK_EQ(osr_loop_end_offset < 0, osr_bailout_id_.IsNone())((void) 0); | |||
| 470 | ||||
| 471 | interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); | |||
| 472 | ||||
| 473 | bytecode_count_ = iterator.size(); | |||
| 474 | if (analyze_liveness_) { | |||
| 475 | liveness_map_.emplace(bytecode_array()->length(), zone()); | |||
| 476 | } | |||
| 477 | ||||
| 478 | for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { | |||
| 479 | Bytecode bytecode = iterator.current_bytecode(); | |||
| 480 | int current_offset = iterator.current_offset(); | |||
| 481 | ||||
| 482 | if (bytecode == Bytecode::kSwitchOnGeneratorState) { | |||
| 483 | DCHECK_EQ(generator_switch_index, -1)((void) 0); | |||
| 484 | generator_switch_index = iterator.current_index(); | |||
| 485 | } else if (bytecode == Bytecode::kJumpLoop) { | |||
| 486 | // Every byte up to and including the last byte within the backwards jump | |||
| 487 | // instruction is considered part of the loop, set loop end accordingly. | |||
| 488 | int loop_end = current_offset + iterator.current_bytecode_size(); | |||
| 489 | int loop_header = iterator.GetJumpTargetOffset(); | |||
| 490 | PushLoop(loop_header, loop_end); | |||
| 491 | ||||
| 492 | if (current_offset == osr_loop_end_offset) { | |||
| 493 | osr_entry_point_ = loop_header; | |||
| 494 | } else if (current_offset < osr_loop_end_offset) { | |||
| 495 | // Assert that we've found the osr_entry_point if we've gone past the | |||
| 496 | // osr_loop_end_offset. Note, we are iterating the bytecode in reverse, | |||
| 497 | // so the less-than in the above condition is correct. | |||
| 498 | DCHECK_LE(0, osr_entry_point_)((void) 0); | |||
| 499 | } | |||
| 500 | ||||
| 501 | // Save the index so that we can do another pass later. | |||
| 502 | if (analyze_liveness_) { | |||
| 503 | loop_end_index_queue_.push_back(iterator.current_index()); | |||
| 504 | } | |||
| 505 | } | |||
| 506 | ||||
| 507 | // We have to pop from loop_stack_ if: | |||
| 508 | // 1) We entered the body of the loop | |||
| 509 | // 2) If we have a JumpLoop that jumps to itself (i.e an empty loop) | |||
| 510 | bool pop_current_loop = loop_stack_.size() > 1 && | |||
| 511 | (bytecode != Bytecode::kJumpLoop || | |||
| 512 | iterator.GetJumpTargetOffset() == current_offset); | |||
| 513 | ||||
| 514 | if (pop_current_loop) { | |||
| 515 | LoopStackEntry& current_loop = loop_stack_.top(); | |||
| 516 | LoopInfo* current_loop_info = current_loop.loop_info; | |||
| 517 | ||||
| 518 | // TODO(leszeks): Ideally, we'd only set values that were assigned in | |||
| 519 | // the loop *and* are live when the loop exits. However, this requires | |||
| 520 | // tracking the out-liveness of *all* loop exits, which is not | |||
| 521 | // information we currently have. | |||
| 522 | UpdateAssignments(bytecode, ¤t_loop_info->assignments(), iterator); | |||
| 523 | ||||
| 524 | // Update suspend counts for this loop. | |||
| 525 | if (bytecode == Bytecode::kSuspendGenerator) { | |||
| 526 | int suspend_id = iterator.GetUnsignedImmediateOperand(3); | |||
| 527 | int resume_offset = current_offset + iterator.current_bytecode_size(); | |||
| 528 | current_loop_info->AddResumeTarget( | |||
| 529 | ResumeJumpTarget::Leaf(suspend_id, resume_offset)); | |||
| 530 | } | |||
| 531 | ||||
| 532 | // If we've reached the header of the loop, pop it off the stack. | |||
| 533 | if (current_offset == current_loop.header_offset) { | |||
| 534 | loop_stack_.pop(); | |||
| 535 | if (loop_stack_.size() > 1) { | |||
| 536 | // If there is still an outer loop, propagate inner loop assignments. | |||
| 537 | LoopInfo* parent_loop_info = loop_stack_.top().loop_info; | |||
| 538 | ||||
| 539 | parent_loop_info->assignments().Union( | |||
| 540 | current_loop_info->assignments()); | |||
| 541 | ||||
| 542 | // Also, propagate resume targets. Instead of jumping to the target | |||
| 543 | // itself, the outer loop will jump to this loop header for any | |||
| 544 | // targets that are inside the current loop, so that this loop stays | |||
| 545 | // reducible. Hence, a nested loop of the form: | |||
| 546 | // | |||
| 547 | // switch (#1 -> suspend1, #2 -> suspend2) | |||
| 548 | // loop { | |||
| 549 | // suspend1: suspend #1 | |||
| 550 | // loop { | |||
| 551 | // suspend2: suspend #2 | |||
| 552 | // } | |||
| 553 | // } | |||
| 554 | // | |||
| 555 | // becomes: | |||
| 556 | // | |||
| 557 | // switch (#1 -> loop1, #2 -> loop1) | |||
| 558 | // loop1: loop { | |||
| 559 | // switch (#1 -> suspend1, #2 -> loop2) | |||
| 560 | // suspend1: suspend #1 | |||
| 561 | // loop2: loop { | |||
| 562 | // switch (#2 -> suspend2) | |||
| 563 | // suspend2: suspend #2 | |||
| 564 | // } | |||
| 565 | // } | |||
| 566 | for (const auto& target : current_loop_info->resume_jump_targets()) { | |||
| 567 | parent_loop_info->AddResumeTarget( | |||
| 568 | ResumeJumpTarget::AtLoopHeader(current_offset, target)); | |||
| 569 | } | |||
| 570 | ||||
| 571 | } else { | |||
| 572 | // Otherwise, just propagate inner loop suspends to top-level. | |||
| 573 | for (const auto& target : current_loop_info->resume_jump_targets()) { | |||
| 574 | resume_jump_targets_.push_back( | |||
| 575 | ResumeJumpTarget::AtLoopHeader(current_offset, target)); | |||
| 576 | } | |||
| 577 | } | |||
| 578 | } | |||
| 579 | } else if (bytecode == Bytecode::kSuspendGenerator) { | |||
| 580 | // If we're not in a loop, we still need to look for suspends. | |||
| 581 | // TODO(leszeks): It would be nice to de-duplicate this with the in-loop | |||
| 582 | // case | |||
| 583 | int suspend_id = iterator.GetUnsignedImmediateOperand(3); | |||
| 584 | int resume_offset = current_offset + iterator.current_bytecode_size(); | |||
| 585 | resume_jump_targets_.push_back( | |||
| 586 | ResumeJumpTarget::Leaf(suspend_id, resume_offset)); | |||
| 587 | } | |||
| 588 | ||||
| 589 | if (analyze_liveness_) { | |||
| 590 | BytecodeLiveness& liveness = | |||
| 591 | liveness_map().InsertNewLiveness(current_offset); | |||
| 592 | UpdateLiveness<true>(bytecode, liveness, &next_bytecode_in_liveness, | |||
| 593 | iterator, bytecode_array(), liveness_map(), zone()); | |||
| 594 | } | |||
| 595 | } | |||
| 596 | ||||
| 597 | DCHECK_EQ(loop_stack_.size(), 1u)((void) 0); | |||
| 598 | DCHECK_EQ(loop_stack_.top().header_offset, -1)((void) 0); | |||
| 599 | ||||
| 600 | DCHECK(ResumeJumpTargetsAreValid())((void) 0); | |||
| 601 | ||||
| 602 | if (!analyze_liveness_) return; | |||
| 603 | ||||
| 604 | // At this point, every bytecode has a valid in and out liveness, except for | |||
| 605 | // propagating liveness across back edges (i.e. JumpLoop). Subsequent liveness | |||
| 606 | // analysis iterations can only add additional liveness bits that are pulled | |||
| 607 | // across these back edges. | |||
| 608 | // | |||
| 609 | // Furthermore, a loop header's in-liveness can only change based on any | |||
| 610 | // bytecodes *after* the loop end -- it cannot change as a result of the | |||
| 611 | // JumpLoop liveness being updated, as the only liveness bits than can be | |||
| 612 | // added to the loop body are those of the loop header. | |||
| 613 | // | |||
| 614 | // So, if we know that the liveness of bytecodes after a loop header won't | |||
| 615 | // change (e.g. because there are no loops in them, or we have already ensured | |||
| 616 | // those loops are valid), we can safely update the loop end and pass over the | |||
| 617 | // loop body, and then never have to pass over that loop end again, because we | |||
| 618 | // have shown that its target, the loop header, can't change from the entries | |||
| 619 | // after the loop, and can't change from any loop body pass. | |||
| 620 | // | |||
| 621 | // This means that in a pass, we can iterate backwards over the bytecode | |||
| 622 | // array, process any loops that we encounter, and on subsequent passes we can | |||
| 623 | // skip processing those loops (though we still have to process inner loops). | |||
| 624 | // | |||
| 625 | // Equivalently, we can queue up loop ends from back to front, and pass over | |||
| 626 | // the loops in that order, as this preserves both the bottom-to-top and | |||
| 627 | // outer-to-inner requirements. | |||
| 628 | ||||
| 629 | for (int loop_end_index : loop_end_index_queue_) { | |||
| 630 | iterator.GoToIndex(loop_end_index); | |||
| 631 | ||||
| 632 | DCHECK_EQ(iterator.current_bytecode(), Bytecode::kJumpLoop)((void) 0); | |||
| 633 | ||||
| 634 | int header_offset = iterator.GetJumpTargetOffset(); | |||
| 635 | int end_offset = iterator.current_offset(); | |||
| 636 | ||||
| 637 | BytecodeLiveness& header_liveness = | |||
| 638 | liveness_map().GetLiveness(header_offset); | |||
| 639 | BytecodeLiveness& end_liveness = liveness_map().GetLiveness(end_offset); | |||
| 640 | ||||
| 641 | if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) { | |||
| 642 | // Only update the loop body if the loop end liveness changed. | |||
| 643 | continue; | |||
| 644 | } | |||
| 645 | end_liveness.in->CopyFrom(*end_liveness.out); | |||
| 646 | next_bytecode_in_liveness = end_liveness.in; | |||
| 647 | ||||
| 648 | // Advance into the loop body. | |||
| 649 | --iterator; | |||
| 650 | for (; iterator.current_offset() > header_offset; --iterator) { | |||
| 651 | Bytecode bytecode = iterator.current_bytecode(); | |||
| 652 | int current_offset = iterator.current_offset(); | |||
| 653 | BytecodeLiveness& liveness = liveness_map().GetLiveness(current_offset); | |||
| 654 | UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator, | |||
| 655 | bytecode_array(), liveness_map(), zone()); | |||
| 656 | } | |||
| 657 | // Now we are at the loop header. Since the in-liveness of the header | |||
| 658 | // can't change, we need only to update the out-liveness. | |||
| 659 | UpdateOutLiveness(iterator.current_bytecode(), header_liveness, | |||
| 660 | next_bytecode_in_liveness, iterator, bytecode_array(), | |||
| 661 | liveness_map(), zone()); | |||
| 662 | } | |||
| 663 | ||||
| 664 | // Process the generator switch statement separately, once the loops are done. | |||
| 665 | // This has to be a separate pass because the generator switch can jump into | |||
| 666 | // the middle of loops (and is the only kind of jump that can jump across a | |||
| 667 | // loop header). | |||
| 668 | if (generator_switch_index != -1) { | |||
| 669 | iterator.GoToIndex(generator_switch_index); | |||
| 670 | DCHECK_EQ(iterator.current_bytecode(), Bytecode::kSwitchOnGeneratorState)((void) 0); | |||
| 671 | ||||
| 672 | int current_offset = iterator.current_offset(); | |||
| 673 | BytecodeLiveness& switch_liveness = | |||
| 674 | liveness_map().GetLiveness(current_offset); | |||
| 675 | ||||
| 676 | bool any_changed = false; | |||
| 677 | for (interpreter::JumpTableTargetOffset entry : | |||
| 678 | iterator.GetJumpTableTargetOffsets()) { | |||
| 679 | if (switch_liveness.out->UnionIsChanged( | |||
| 680 | *liveness_map().GetInLiveness(entry.target_offset))) { | |||
| 681 | any_changed = true; | |||
| 682 | } | |||
| 683 | } | |||
| 684 | ||||
| 685 | // If the switch liveness changed, we have to propagate it up the remaining | |||
| 686 | // bytecodes before it. | |||
| 687 | if (any_changed) { | |||
| 688 | switch_liveness.in->CopyFrom(*switch_liveness.out); | |||
| 689 | UpdateInLiveness(Bytecode::kSwitchOnGeneratorState, switch_liveness.in, | |||
| 690 | iterator); | |||
| 691 | next_bytecode_in_liveness = switch_liveness.in; | |||
| 692 | for (--iterator; iterator.IsValid(); --iterator) { | |||
| 693 | Bytecode bytecode = iterator.current_bytecode(); | |||
| 694 | BytecodeLiveness& liveness = | |||
| 695 | liveness_map().GetLiveness(iterator.current_offset()); | |||
| 696 | ||||
| 697 | // There shouldn't be any more loops. | |||
| 698 | DCHECK_NE(bytecode, Bytecode::kJumpLoop)((void) 0); | |||
| 699 | ||||
| 700 | UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator, | |||
| 701 | bytecode_array(), liveness_map(), zone()); | |||
| 702 | } | |||
| 703 | } | |||
| 704 | } | |||
| 705 | ||||
| 706 | DCHECK(analyze_liveness_)((void) 0); | |||
| 707 | if (FLAG_trace_environment_liveness) { | |||
| 708 | StdoutStream of; | |||
| 709 | PrintLivenessTo(of); | |||
| 710 | } | |||
| 711 | ||||
| 712 | DCHECK(LivenessIsValid())((void) 0); | |||
| 713 | } | |||
| 714 | ||||
| 715 | void BytecodeAnalysis::PushLoop(int loop_header, int loop_end) { | |||
| 716 | DCHECK_LT(loop_header, loop_end)((void) 0); | |||
| 717 | DCHECK_LT(loop_stack_.top().header_offset, loop_header)((void) 0); | |||
| 718 | DCHECK_EQ(end_to_header_.find(loop_end), end_to_header_.end())((void) 0); | |||
| 719 | DCHECK_EQ(header_to_info_.find(loop_header), header_to_info_.end())((void) 0); | |||
| 720 | ||||
| 721 | int parent_offset = loop_stack_.top().header_offset; | |||
| 722 | ||||
| 723 | end_to_header_.insert({loop_end, loop_header}); | |||
| 724 | auto it = header_to_info_.insert( | |||
| 725 | {loop_header, LoopInfo(parent_offset, bytecode_array_->parameter_count(), | |||
| 726 | bytecode_array_->register_count(), zone_)}); | |||
| 727 | // Get the loop info pointer from the output of insert. | |||
| 728 | LoopInfo* loop_info = &it.first->second; | |||
| 729 | ||||
| 730 | loop_stack_.push({loop_header, loop_info}); | |||
| 731 | } | |||
| 732 | ||||
| 733 | bool BytecodeAnalysis::IsLoopHeader(int offset) const { | |||
| 734 | return header_to_info_.find(offset) != header_to_info_.end(); | |||
| 735 | } | |||
| 736 | ||||
| 737 | int BytecodeAnalysis::GetLoopOffsetFor(int offset) const { | |||
| 738 | auto loop_end_to_header = end_to_header_.upper_bound(offset); | |||
| 739 | // If there is no next end => offset is not in a loop. | |||
| 740 | if (loop_end_to_header == end_to_header_.end()) { | |||
| 741 | return -1; | |||
| 742 | } | |||
| 743 | // If the header precedes the offset, this is the loop | |||
| 744 | // | |||
| 745 | // .> header <--loop_end_to_header | |||
| 746 | // | | |||
| 747 | // | <--offset | |||
| 748 | // | | |||
| 749 | // `- end | |||
| 750 | if (loop_end_to_header->second <= offset) { | |||
| 751 | return loop_end_to_header->second; | |||
| 752 | } | |||
| 753 | // Otherwise there is a (potentially nested) loop after this offset. | |||
| 754 | // | |||
| 755 | // <--offset | |||
| 756 | // | |||
| 757 | // .> header | |||
| 758 | // | | |||
| 759 | // | .> header <--loop_end_to_header | |||
| 760 | // | | | |||
| 761 | // | `- end | |||
| 762 | // | | |||
| 763 | // `- end | |||
| 764 | // We just return the parent of the next loop (might be -1). | |||
| 765 | DCHECK(header_to_info_.upper_bound(offset) != header_to_info_.end())((void) 0); | |||
| 766 | ||||
| 767 | return header_to_info_.upper_bound(offset)->second.parent_offset(); | |||
| 768 | } | |||
| 769 | ||||
| 770 | const LoopInfo& BytecodeAnalysis::GetLoopInfoFor(int header_offset) const { | |||
| 771 | DCHECK(IsLoopHeader(header_offset))((void) 0); | |||
| 772 | ||||
| 773 | return header_to_info_.find(header_offset)->second; | |||
| 774 | } | |||
| 775 | ||||
| 776 | const LoopInfo* BytecodeAnalysis::TryGetLoopInfoFor(int header_offset) const { | |||
| 777 | auto it = header_to_info_.find(header_offset); | |||
| 778 | if (it == header_to_info_.end()) return nullptr; | |||
| 779 | return &it->second; | |||
| 780 | } | |||
| 781 | ||||
| 782 | const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor( | |||
| 783 | int offset) const { | |||
| 784 | if (!analyze_liveness_) return nullptr; | |||
| 785 | ||||
| 786 | return liveness_map().GetInLiveness(offset); | |||
| 787 | } | |||
| 788 | ||||
| 789 | const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor( | |||
| 790 | int offset) const { | |||
| 791 | if (!analyze_liveness_) return nullptr; | |||
| 792 | ||||
| 793 | return liveness_map().GetOutLiveness(offset); | |||
| 794 | } | |||
| 795 | ||||
| 796 | std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const { | |||
| 797 | interpreter::BytecodeArrayIterator iterator(bytecode_array()); | |||
| 798 | ||||
| 799 | for (; !iterator.done(); iterator.Advance()) { | |||
| 800 | int current_offset = iterator.current_offset(); | |||
| 801 | ||||
| 802 | const BytecodeLivenessState* in_liveness = GetInLivenessFor(current_offset); | |||
| 803 | const BytecodeLivenessState* out_liveness = | |||
| 804 | GetOutLivenessFor(current_offset); | |||
| 805 | ||||
| 806 | os << ToString(*in_liveness) << " -> " << ToString(*out_liveness) << " | " | |||
| 807 | << current_offset << ": "; | |||
| 808 | iterator.PrintTo(os) << std::endl; | |||
| 809 | } | |||
| 810 | ||||
| 811 | return os; | |||
| 812 | } | |||
| 813 | ||||
| 814 | #if DEBUG | |||
| 815 | bool BytecodeAnalysis::ResumeJumpTargetsAreValid() { | |||
| 816 | bool valid = true; | |||
| 817 | ||||
| 818 | // Find the generator switch. | |||
| 819 | interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); | |||
| 820 | for (iterator.GoToStart(); iterator.IsValid(); ++iterator) { | |||
| 821 | if (iterator.current_bytecode() == Bytecode::kSwitchOnGeneratorState) { | |||
| 822 | break; | |||
| 823 | } | |||
| 824 | } | |||
| 825 | ||||
| 826 | // If the iterator is invalid, we've reached the end without finding the | |||
| 827 | // generator switch. So, ensure there are no jump targets and exit. | |||
| 828 | if (!iterator.IsValid()) { | |||
| 829 | // Check top-level. | |||
| 830 | if (!resume_jump_targets().empty()) { | |||
| 831 | PrintF(stderrstderr, | |||
| 832 | "Found %zu top-level resume targets but no resume switch\n", | |||
| 833 | resume_jump_targets().size()); | |||
| 834 | valid = false; | |||
| 835 | } | |||
| 836 | // Check loops. | |||
| 837 | for (const std::pair<const int, LoopInfo>& loop_info : header_to_info_) { | |||
| 838 | if (!loop_info.second.resume_jump_targets().empty()) { | |||
| 839 | PrintF(stderrstderr, | |||
| 840 | "Found %zu resume targets at loop at offset %d, but no resume " | |||
| 841 | "switch\n", | |||
| 842 | loop_info.second.resume_jump_targets().size(), loop_info.first); | |||
| 843 | valid = false; | |||
| 844 | } | |||
| 845 | } | |||
| 846 | ||||
| 847 | return valid; | |||
| 848 | } | |||
| 849 | ||||
| 850 | // Otherwise, we've found the resume switch. Check that the top level jumps | |||
| 851 | // only to leaves and loop headers, then check that each loop header handles | |||
| 852 | // all the unresolved jumps, also jumping only to leaves and inner loop | |||
| 853 | // headers. | |||
| 854 | ||||
| 855 | // First collect all required suspend ids. | |||
| 856 | std::map<int, int> unresolved_suspend_ids; | |||
| 857 | for (interpreter::JumpTableTargetOffset offset : | |||
| 858 | iterator.GetJumpTableTargetOffsets()) { | |||
| 859 | int suspend_id = offset.case_value; | |||
| 860 | int resume_offset = offset.target_offset; | |||
| 861 | ||||
| 862 | unresolved_suspend_ids[suspend_id] = resume_offset; | |||
| 863 | } | |||
| 864 | ||||
| 865 | // Check top-level. | |||
| 866 | if (!ResumeJumpTargetLeavesResolveSuspendIds(-1, resume_jump_targets(), | |||
| 867 | &unresolved_suspend_ids)) { | |||
| 868 | valid = false; | |||
| 869 | } | |||
| 870 | // Check loops. | |||
| 871 | for (const std::pair<const int, LoopInfo>& loop_info : header_to_info_) { | |||
| 872 | if (!ResumeJumpTargetLeavesResolveSuspendIds( | |||
| 873 | loop_info.first, loop_info.second.resume_jump_targets(), | |||
| 874 | &unresolved_suspend_ids)) { | |||
| 875 | valid = false; | |||
| 876 | } | |||
| 877 | } | |||
| 878 | ||||
| 879 | // Check that everything is resolved. | |||
| 880 | if (!unresolved_suspend_ids.empty()) { | |||
| 881 | PrintF(stderrstderr, | |||
| 882 | "Found suspend ids that are not resolved by a final leaf resume " | |||
| 883 | "jump:\n"); | |||
| 884 | ||||
| 885 | for (const std::pair<const int, int>& target : unresolved_suspend_ids) { | |||
| 886 | PrintF(stderrstderr, " %d -> %d\n", target.first, target.second); | |||
| 887 | } | |||
| 888 | valid = false; | |||
| 889 | } | |||
| 890 | ||||
| 891 | return valid; | |||
| 892 | } | |||
| 893 | ||||
| 894 | bool BytecodeAnalysis::ResumeJumpTargetLeavesResolveSuspendIds( | |||
| 895 | int parent_offset, const ZoneVector<ResumeJumpTarget>& resume_jump_targets, | |||
| 896 | std::map<int, int>* unresolved_suspend_ids) { | |||
| 897 | bool valid = true; | |||
| 898 | for (const ResumeJumpTarget& target : resume_jump_targets) { | |||
| 899 | std::map<int, int>::iterator it = | |||
| 900 | unresolved_suspend_ids->find(target.suspend_id()); | |||
| 901 | if (it == unresolved_suspend_ids->end()) { | |||
| 902 | PrintF( | |||
| 903 | stderrstderr, | |||
| 904 | "No unresolved suspend found for resume target with suspend id %d\n", | |||
| 905 | target.suspend_id()); | |||
| 906 | valid = false; | |||
| 907 | continue; | |||
| 908 | } | |||
| 909 | int expected_target = it->second; | |||
| 910 | ||||
| 911 | if (target.is_leaf()) { | |||
| 912 | // Leaves should have the expected target as their target. | |||
| 913 | if (target.target_offset() != expected_target) { | |||
| 914 | PrintF( | |||
| 915 | stderrstderr, | |||
| 916 | "Expected leaf resume target for id %d to have target offset %d, " | |||
| 917 | "but had %d\n", | |||
| 918 | target.suspend_id(), expected_target, target.target_offset()); | |||
| 919 | valid = false; | |||
| 920 | } else { | |||
| 921 | // Make sure we're resuming to a Resume bytecode | |||
| 922 | interpreter::BytecodeArrayIterator iterator(bytecode_array(), | |||
| 923 | target.target_offset()); | |||
| 924 | if (iterator.current_bytecode() != Bytecode::kResumeGenerator) { | |||
| 925 | PrintF(stderrstderr, | |||
| 926 | "Expected resume target for id %d, offset %d, to be " | |||
| 927 | "ResumeGenerator, but found %s\n", | |||
| 928 | target.suspend_id(), target.target_offset(), | |||
| 929 | Bytecodes::ToString(iterator.current_bytecode())); | |||
| 930 | ||||
| 931 | valid = false; | |||
| 932 | } | |||
| 933 | } | |||
| 934 | // We've resolved this suspend id, so erase it to make sure we don't | |||
| 935 | // resolve it twice. | |||
| 936 | unresolved_suspend_ids->erase(it); | |||
| 937 | } else { | |||
| 938 | // Non-leaves should have a direct inner loop header as their target. | |||
| 939 | if (!IsLoopHeader(target.target_offset())) { | |||
| 940 | PrintF(stderrstderr, | |||
| 941 | "Expected non-leaf resume target for id %d to have a loop " | |||
| 942 | "header at target offset %d\n", | |||
| 943 | target.suspend_id(), target.target_offset()); | |||
| 944 | valid = false; | |||
| 945 | } else { | |||
| 946 | LoopInfo loop_info = GetLoopInfoFor(target.target_offset()); | |||
| 947 | if (loop_info.parent_offset() != parent_offset) { | |||
| 948 | PrintF(stderrstderr, | |||
| 949 | "Expected non-leaf resume target for id %d to have a direct " | |||
| 950 | "inner loop at target offset %d\n", | |||
| 951 | target.suspend_id(), target.target_offset()); | |||
| 952 | valid = false; | |||
| 953 | } | |||
| 954 | // If the target loop is a valid inner loop, we'll check its validity | |||
| 955 | // when we analyze its resume targets. | |||
| 956 | } | |||
| 957 | } | |||
| 958 | } | |||
| 959 | return valid; | |||
| 960 | } | |||
| 961 | ||||
| 962 | bool BytecodeAnalysis::LivenessIsValid() { | |||
| 963 | interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone()); | |||
| 964 | ||||
| 965 | BytecodeLivenessState previous_liveness(bytecode_array()->register_count(), | |||
| 966 | zone()); | |||
| 967 | ||||
| 968 | int invalid_offset = -1; | |||
| 969 | int which_invalid = -1; | |||
| 970 | BytecodeLivenessState invalid_liveness(bytecode_array()->register_count(), | |||
| 971 | zone()); | |||
| 972 | ||||
| 973 | BytecodeLivenessState* next_bytecode_in_liveness = nullptr; | |||
| 974 | ||||
| 975 | // Ensure that there are no liveness changes if we iterate one more time. | |||
| 976 | for (iterator.GoToEnd(); iterator.IsValid(); --iterator) { | |||
| 977 | Bytecode bytecode = iterator.current_bytecode(); | |||
| 978 | ||||
| 979 | int current_offset = iterator.current_offset(); | |||
| 980 | ||||
| 981 | BytecodeLiveness& liveness = liveness_map().GetLiveness(current_offset); | |||
| 982 | ||||
| 983 | previous_liveness.CopyFrom(*liveness.out); | |||
| 984 | ||||
| 985 | UpdateOutLiveness(bytecode, liveness, next_bytecode_in_liveness, iterator, | |||
| 986 | bytecode_array(), liveness_map(), zone()); | |||
| 987 | // UpdateOutLiveness skips kJumpLoop, so we update it manually. | |||
| 988 | if (bytecode == Bytecode::kJumpLoop) { | |||
| 989 | int target_offset = iterator.GetJumpTargetOffset(); | |||
| 990 | liveness.out->Union(*liveness_map().GetInLiveness(target_offset)); | |||
| 991 | } | |||
| 992 | ||||
| 993 | if (!liveness.out->Equals(previous_liveness)) { | |||
| 994 | invalid_liveness.CopyFrom(*liveness.out); | |||
| 995 | // Reset the invalid liveness. | |||
| 996 | liveness.out->CopyFrom(previous_liveness); | |||
| 997 | invalid_offset = current_offset; | |||
| 998 | which_invalid = 1; | |||
| 999 | break; | |||
| 1000 | } | |||
| 1001 | ||||
| 1002 | previous_liveness.CopyFrom(*liveness.in); | |||
| 1003 | ||||
| 1004 | liveness.in->CopyFrom(*liveness.out); | |||
| 1005 | UpdateInLiveness(bytecode, liveness.in, iterator); | |||
| 1006 | ||||
| 1007 | if (!liveness.in->Equals(previous_liveness)) { | |||
| 1008 | invalid_liveness.CopyFrom(*liveness.in); | |||
| 1009 | // Reset the invalid liveness. | |||
| 1010 | liveness.in->CopyFrom(previous_liveness); | |||
| 1011 | invalid_offset = current_offset; | |||
| 1012 | which_invalid = 0; | |||
| 1013 | break; | |||
| 1014 | } | |||
| 1015 | ||||
| 1016 | next_bytecode_in_liveness = liveness.in; | |||
| 1017 | } | |||
| 1018 | ||||
| 1019 | // Ensure that the accumulator is not live when jumping out of a loop, or on | |||
| 1020 | // the back-edge of a loop. | |||
| 1021 | for (iterator.GoToStart(); iterator.IsValid() && invalid_offset == -1; | |||
| 1022 | ++iterator) { | |||
| 1023 | Bytecode bytecode = iterator.current_bytecode(); | |||
| 1024 | int current_offset = iterator.current_offset(); | |||
| 1025 | int loop_header = GetLoopOffsetFor(current_offset); | |||
| 1026 | ||||
| 1027 | // We only care if we're inside a loop. | |||
| 1028 | if (loop_header == -1) continue; | |||
| 1029 | ||||
| 1030 | // We only care about jumps. | |||
| 1031 | if (!Bytecodes::IsJump(bytecode)) continue; | |||
| 1032 | ||||
| 1033 | int jump_target = iterator.GetJumpTargetOffset(); | |||
| 1034 | ||||
| 1035 | // If this is a forward jump to somewhere else in the same loop, ignore it. | |||
| 1036 | if (Bytecodes::IsForwardJump(bytecode) && | |||
| 1037 | GetLoopOffsetFor(jump_target) == loop_header) { | |||
| 1038 | continue; | |||
| 1039 | } | |||
| 1040 | ||||
| 1041 | // The accumulator must be dead at the start of the target of the jump. | |||
| 1042 | if (liveness_map().GetLiveness(jump_target).in->AccumulatorIsLive()) { | |||
| 1043 | invalid_offset = jump_target; | |||
| 1044 | which_invalid = 0; | |||
| 1045 | break; | |||
| 1046 | } | |||
| 1047 | } | |||
| 1048 | ||||
| 1049 | if (invalid_offset != -1) { | |||
| 1050 | OFStream of(stderrstderr); | |||
| 1051 | of << "Invalid liveness:" << std::endl; | |||
| 1052 | ||||
| 1053 | // Dump the bytecode, annotated with the liveness and marking loops. | |||
| 1054 | ||||
| 1055 | int loop_indent = 0; | |||
| 1056 | ||||
| 1057 | interpreter::BytecodeArrayIterator forward_iterator(bytecode_array()); | |||
| 1058 | for (; !forward_iterator.done(); forward_iterator.Advance()) { | |||
| 1059 | int current_offset = forward_iterator.current_offset(); | |||
| 1060 | const BytecodeLivenessState* in_liveness = | |||
| 1061 | GetInLivenessFor(current_offset); | |||
| 1062 | const BytecodeLivenessState* out_liveness = | |||
| 1063 | GetOutLivenessFor(current_offset); | |||
| 1064 | ||||
| 1065 | std::string in_liveness_str = ToString(*in_liveness); | |||
| 1066 | std::string out_liveness_str = ToString(*out_liveness); | |||
| 1067 | ||||
| 1068 | of << in_liveness_str << " | " << out_liveness_str << " : " | |||
| 1069 | << current_offset << " : "; | |||
| 1070 | ||||
| 1071 | // Draw loop back edges by indentin everything between loop headers and | |||
| 1072 | // jump loop instructions. | |||
| 1073 | if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { | |||
| 1074 | loop_indent--; | |||
| 1075 | } | |||
| 1076 | for (int i = 0; i < loop_indent; ++i) { | |||
| 1077 | of << "| "; | |||
| 1078 | } | |||
| 1079 | if (forward_iterator.current_bytecode() == Bytecode::kJumpLoop) { | |||
| 1080 | of << "`-"; | |||
| 1081 | } else if (IsLoopHeader(current_offset)) { | |||
| 1082 | of << ".>"; | |||
| 1083 | loop_indent++; | |||
| 1084 | } | |||
| 1085 | forward_iterator.PrintTo(of); | |||
| 1086 | if (Bytecodes::IsJump(forward_iterator.current_bytecode())) { | |||
| 1087 | of << " (@" << forward_iterator.GetJumpTargetOffset() << ")"; | |||
| 1088 | } | |||
| 1089 | of << std::endl; | |||
| 1090 | ||||
| 1091 | if (current_offset == invalid_offset) { | |||
| 1092 | // Underline the invalid liveness. | |||
| 1093 | char in_underline = which_invalid == 0 ? '^' : ' '; | |||
| 1094 | char out_underline = which_invalid == 0 ? ' ' : '^'; | |||
| 1095 | of << std::string(in_liveness_str.size(), in_underline) << " " | |||
| 1096 | << std::string(out_liveness_str.size(), out_underline); | |||
| 1097 | ||||
| 1098 | // Make sure to draw the loop indentation marks on this additional line. | |||
| 1099 | of << " : " << current_offset << " : "; | |||
| 1100 | for (int i = 0; i < loop_indent; ++i) { | |||
| 1101 | of << "| "; | |||
| 1102 | } | |||
| 1103 | ||||
| 1104 | of << std::endl; | |||
| 1105 | ||||
| 1106 | // Print the invalid liveness. | |||
| 1107 | if (which_invalid == 0) { | |||
| 1108 | of << ToString(invalid_liveness) << " " | |||
| 1109 | << std::string(out_liveness_str.size(), ' '); | |||
| 1110 | } else { | |||
| 1111 | of << std::string(in_liveness_str.size(), ' ') << " " | |||
| 1112 | << ToString(invalid_liveness); | |||
| 1113 | } | |||
| 1114 | ||||
| 1115 | // Make sure to draw the loop indentation marks on this additional line. | |||
| 1116 | of << " : " << current_offset << " : "; | |||
| 1117 | for (int i = 0; i < loop_indent; ++i) { | |||
| 1118 | of << "| "; | |||
| 1119 | } | |||
| 1120 | ||||
| 1121 | of << std::endl; | |||
| 1122 | } | |||
| 1123 | } | |||
| 1124 | } | |||
| 1125 | ||||
| 1126 | return invalid_offset == -1; | |||
| 1127 | } | |||
| 1128 | #endif | |||
| 1129 | ||||
| 1130 | } // namespace compiler | |||
| 1131 | } // namespace internal | |||
| 1132 | } // namespace v8 |