1 // Copyright 2015 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/interpreter/bytecode-array-iterator.h"
6 
7 #include "src/interpreter/bytecode-decoder.h"
8 #include "src/interpreter/interpreter-intrinsics.h"
9 #include "src/objects/code-inl.h"
10 #include "src/objects/feedback-vector.h"
11 #include "src/objects/objects-inl.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace interpreter {
16 
BytecodeArrayIterator(Handle<BytecodeArray> bytecode_array,int initial_offset)17 BytecodeArrayIterator::BytecodeArrayIterator(
18     Handle<BytecodeArray> bytecode_array, int initial_offset)
19     : bytecode_array_(bytecode_array),
20       start_(reinterpret_cast<uint8_t*>(
21           bytecode_array_->GetFirstBytecodeAddress())),
22       end_(start_ + bytecode_array_->length()),
23       cursor_(start_ + initial_offset),
24       operand_scale_(OperandScale::kSingle),
25       prefix_size_(0),
26       local_heap_(LocalHeap::Current()
27                       ? LocalHeap::Current()
28                       : Isolate::Current()->main_thread_local_heap()) {
29   local_heap_->AddGCEpilogueCallback(UpdatePointersCallback, this);
30   UpdateOperandScale();
31 }
32 
~BytecodeArrayIterator()33 BytecodeArrayIterator::~BytecodeArrayIterator() {
34   local_heap_->RemoveGCEpilogueCallback(UpdatePointersCallback, this);
35 }
36 
SetOffset(int offset)37 void BytecodeArrayIterator::SetOffset(int offset) {
38   if (offset < 0) return;
39   cursor_ = reinterpret_cast<uint8_t*>(
40       bytecode_array()->GetFirstBytecodeAddress() + offset);
41   UpdateOperandScale();
42 }
43 
ApplyDebugBreak()44 void BytecodeArrayIterator::ApplyDebugBreak() {
45   // Get the raw bytecode from the bytecode array. This may give us a
46   // scaling prefix, which we can patch with the matching debug-break
47   // variant.
48   uint8_t* cursor = cursor_ - prefix_size_;
49   interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(*cursor);
50   if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return;
51   interpreter::Bytecode debugbreak =
52       interpreter::Bytecodes::GetDebugBreak(bytecode);
53   *cursor = interpreter::Bytecodes::ToByte(debugbreak);
54 }
55 
current_bytecode_size() const56 int BytecodeArrayIterator::current_bytecode_size() const {
57   return prefix_size_ + current_bytecode_size_without_prefix();
58 }
59 
current_bytecode_size_without_prefix() const60 int BytecodeArrayIterator::current_bytecode_size_without_prefix() const {
61   return Bytecodes::Size(current_bytecode(), current_operand_scale());
62 }
63 
GetUnsignedOperand(int operand_index,OperandType operand_type) const64 uint32_t BytecodeArrayIterator::GetUnsignedOperand(
65     int operand_index, OperandType operand_type) const {
66   DCHECK_GE(operand_index, 0);
67   DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
68   DCHECK_EQ(operand_type,
69             Bytecodes::GetOperandType(current_bytecode(), operand_index));
70   DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
71   Address operand_start =
72       reinterpret_cast<Address>(cursor_) +
73       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
74                                   current_operand_scale());
75   return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type,
76                                                 current_operand_scale());
77 }
78 
GetSignedOperand(int operand_index,OperandType operand_type) const79 int32_t BytecodeArrayIterator::GetSignedOperand(
80     int operand_index, OperandType operand_type) const {
81   DCHECK_GE(operand_index, 0);
82   DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
83   DCHECK_EQ(operand_type,
84             Bytecodes::GetOperandType(current_bytecode(), operand_index));
85   DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
86   Address operand_start =
87       reinterpret_cast<Address>(cursor_) +
88       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
89                                   current_operand_scale());
90   return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type,
91                                               current_operand_scale());
92 }
93 
GetFlagOperand(int operand_index) const94 uint32_t BytecodeArrayIterator::GetFlagOperand(int operand_index) const {
95   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
96             OperandType::kFlag8);
97   return GetUnsignedOperand(operand_index, OperandType::kFlag8);
98 }
99 
GetUnsignedImmediateOperand(int operand_index) const100 uint32_t BytecodeArrayIterator::GetUnsignedImmediateOperand(
101     int operand_index) const {
102   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
103             OperandType::kUImm);
104   return GetUnsignedOperand(operand_index, OperandType::kUImm);
105 }
106 
GetImmediateOperand(int operand_index) const107 int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
108   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
109             OperandType::kImm);
110   return GetSignedOperand(operand_index, OperandType::kImm);
111 }
112 
GetRegisterCountOperand(int operand_index) const113 uint32_t BytecodeArrayIterator::GetRegisterCountOperand(
114     int operand_index) const {
115   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
116             OperandType::kRegCount);
117   return GetUnsignedOperand(operand_index, OperandType::kRegCount);
118 }
119 
GetIndexOperand(int operand_index) const120 uint32_t BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
121   OperandType operand_type =
122       Bytecodes::GetOperandType(current_bytecode(), operand_index);
123   DCHECK_EQ(operand_type, OperandType::kIdx);
124   return GetUnsignedOperand(operand_index, operand_type);
125 }
126 
GetSlotOperand(int operand_index) const127 FeedbackSlot BytecodeArrayIterator::GetSlotOperand(int operand_index) const {
128   int index = GetIndexOperand(operand_index);
129   return FeedbackVector::ToSlot(index);
130 }
131 
GetReceiver() const132 Register BytecodeArrayIterator::GetReceiver() const {
133   return Register::FromParameterIndex(0, bytecode_array()->parameter_count());
134 }
135 
GetParameter(int parameter_index) const136 Register BytecodeArrayIterator::GetParameter(int parameter_index) const {
137   DCHECK_GE(parameter_index, 0);
138   // The parameter indices are shifted by 1 (receiver is the
139   // first entry).
140   return Register::FromParameterIndex(parameter_index + 1,
141                                       bytecode_array()->parameter_count());
142 }
143 
GetRegisterOperand(int operand_index) const144 Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
145   OperandType operand_type =
146       Bytecodes::GetOperandType(current_bytecode(), operand_index);
147   Address operand_start =
148       reinterpret_cast<Address>(cursor_) +
149       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
150                                   current_operand_scale());
151   return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type,
152                                                 current_operand_scale());
153 }
154 
GetRegisterPairOperand(int operand_index) const155 std::pair<Register, Register> BytecodeArrayIterator::GetRegisterPairOperand(
156     int operand_index) const {
157   Register first = GetRegisterOperand(operand_index);
158   Register second(first.index() + 1);
159   return std::make_pair(first, second);
160 }
161 
GetRegisterListOperand(int operand_index) const162 RegisterList BytecodeArrayIterator::GetRegisterListOperand(
163     int operand_index) const {
164   Register first = GetRegisterOperand(operand_index);
165   uint32_t count = GetRegisterCountOperand(operand_index + 1);
166   return RegisterList(first.index(), count);
167 }
168 
GetRegisterOperandRange(int operand_index) const169 int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
170   DCHECK_LE(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
171   const OperandType* operand_types =
172       Bytecodes::GetOperandTypes(current_bytecode());
173   OperandType operand_type = operand_types[operand_index];
174   DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
175   if (operand_type == OperandType::kRegList ||
176       operand_type == OperandType::kRegOutList) {
177     return GetRegisterCountOperand(operand_index + 1);
178   } else {
179     return Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type);
180   }
181 }
182 
GetRuntimeIdOperand(int operand_index) const183 Runtime::FunctionId BytecodeArrayIterator::GetRuntimeIdOperand(
184     int operand_index) const {
185   OperandType operand_type =
186       Bytecodes::GetOperandType(current_bytecode(), operand_index);
187   DCHECK_EQ(operand_type, OperandType::kRuntimeId);
188   uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
189   return static_cast<Runtime::FunctionId>(raw_id);
190 }
191 
GetNativeContextIndexOperand(int operand_index) const192 uint32_t BytecodeArrayIterator::GetNativeContextIndexOperand(
193     int operand_index) const {
194   OperandType operand_type =
195       Bytecodes::GetOperandType(current_bytecode(), operand_index);
196   DCHECK_EQ(operand_type, OperandType::kNativeContextIndex);
197   return GetUnsignedOperand(operand_index, operand_type);
198 }
199 
GetIntrinsicIdOperand(int operand_index) const200 Runtime::FunctionId BytecodeArrayIterator::GetIntrinsicIdOperand(
201     int operand_index) const {
202   OperandType operand_type =
203       Bytecodes::GetOperandType(current_bytecode(), operand_index);
204   DCHECK_EQ(operand_type, OperandType::kIntrinsicId);
205   uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
206   return IntrinsicsHelper::ToRuntimeId(
207       static_cast<IntrinsicsHelper::IntrinsicId>(raw_id));
208 }
209 
210 template <typename IsolateT>
GetConstantAtIndex(int index,IsolateT * isolate) const211 Handle<Object> BytecodeArrayIterator::GetConstantAtIndex(
212     int index, IsolateT* isolate) const {
213   return handle(bytecode_array()->constant_pool().get(index), isolate);
214 }
215 
IsConstantAtIndexSmi(int index) const216 bool BytecodeArrayIterator::IsConstantAtIndexSmi(int index) const {
217   return bytecode_array()->constant_pool().get(index).IsSmi();
218 }
219 
GetConstantAtIndexAsSmi(int index) const220 Smi BytecodeArrayIterator::GetConstantAtIndexAsSmi(int index) const {
221   return Smi::cast(bytecode_array()->constant_pool().get(index));
222 }
223 
224 template <typename IsolateT>
GetConstantForIndexOperand(int operand_index,IsolateT * isolate) const225 Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
226     int operand_index, IsolateT* isolate) const {
227   return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
228 }
229 
230 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
231     Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
232         int operand_index, Isolate* isolate) const;
233 template Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
234     int operand_index, LocalIsolate* isolate) const;
235 
GetRelativeJumpTargetOffset() const236 int BytecodeArrayIterator::GetRelativeJumpTargetOffset() const {
237   Bytecode bytecode = current_bytecode();
238   if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
239     int relative_offset = GetUnsignedImmediateOperand(0);
240     if (bytecode == Bytecode::kJumpLoop) {
241       relative_offset = -relative_offset;
242     }
243     return relative_offset;
244   } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
245     Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0));
246     return smi.value();
247   } else {
248     UNREACHABLE();
249   }
250 }
251 
GetJumpTargetOffset() const252 int BytecodeArrayIterator::GetJumpTargetOffset() const {
253   return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
254 }
255 
GetJumpTableTargetOffsets() const256 JumpTableTargetOffsets BytecodeArrayIterator::GetJumpTableTargetOffsets()
257     const {
258   uint32_t table_start, table_size;
259   int32_t case_value_base;
260   if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) {
261     table_start = GetIndexOperand(1);
262     table_size = GetUnsignedImmediateOperand(2);
263     case_value_base = 0;
264   } else {
265     DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
266     table_start = GetIndexOperand(0);
267     table_size = GetUnsignedImmediateOperand(1);
268     case_value_base = GetImmediateOperand(2);
269   }
270   return JumpTableTargetOffsets(this, table_start, table_size, case_value_base);
271 }
272 
GetAbsoluteOffset(int relative_offset) const273 int BytecodeArrayIterator::GetAbsoluteOffset(int relative_offset) const {
274   return current_offset() + relative_offset + prefix_size_;
275 }
276 
PrintTo(std::ostream & os) const277 std::ostream& BytecodeArrayIterator::PrintTo(std::ostream& os) const {
278   return BytecodeDecoder::Decode(os, cursor_ - prefix_size_,
279                                  bytecode_array()->parameter_count());
280 }
281 
UpdatePointers()282 void BytecodeArrayIterator::UpdatePointers() {
283   DisallowGarbageCollection no_gc;
284   uint8_t* start =
285       reinterpret_cast<uint8_t*>(bytecode_array_->GetFirstBytecodeAddress());
286   if (start != start_) {
287     start_ = start;
288     uint8_t* end = start + bytecode_array_->length();
289     size_t distance_to_end = end_ - cursor_;
290     cursor_ = end - distance_to_end;
291     end_ = end;
292   }
293 }
294 
JumpTableTargetOffsets(const BytecodeArrayIterator * iterator,int table_start,int table_size,int case_value_base)295 JumpTableTargetOffsets::JumpTableTargetOffsets(
296     const BytecodeArrayIterator* iterator, int table_start, int table_size,
297     int case_value_base)
298     : iterator_(iterator),
299       table_start_(table_start),
300       table_size_(table_size),
301       case_value_base_(case_value_base) {}
302 
begin() const303 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::begin() const {
304   return iterator(case_value_base_, table_start_, table_start_ + table_size_,
305                   iterator_);
306 }
end() const307 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::end() const {
308   return iterator(case_value_base_ + table_size_, table_start_ + table_size_,
309                   table_start_ + table_size_, iterator_);
310 }
size() const311 int JumpTableTargetOffsets::size() const {
312   int ret = 0;
313   // TODO(leszeks): Is there a more efficient way of doing this than iterating?
314   for (JumpTableTargetOffset entry : *this) {
315     USE(entry);
316     ret++;
317   }
318   return ret;
319 }
320 
iterator(int case_value,int table_offset,int table_end,const BytecodeArrayIterator * iterator)321 JumpTableTargetOffsets::iterator::iterator(
322     int case_value, int table_offset, int table_end,
323     const BytecodeArrayIterator* iterator)
324     : iterator_(iterator),
325       current_(Smi::zero()),
326       index_(case_value),
327       table_offset_(table_offset),
328       table_end_(table_end) {
329   UpdateAndAdvanceToValid();
330 }
331 
operator *()332 JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() {
333   DCHECK_LT(table_offset_, table_end_);
334   return {index_, iterator_->GetAbsoluteOffset(Smi::ToInt(current_))};
335 }
336 
337 JumpTableTargetOffsets::iterator&
operator ++()338 JumpTableTargetOffsets::iterator::operator++() {
339   DCHECK_LT(table_offset_, table_end_);
340   ++table_offset_;
341   ++index_;
342   UpdateAndAdvanceToValid();
343   return *this;
344 }
345 
operator !=(const JumpTableTargetOffsets::iterator & other)346 bool JumpTableTargetOffsets::iterator::operator!=(
347     const JumpTableTargetOffsets::iterator& other) {
348   DCHECK_EQ(iterator_, other.iterator_);
349   DCHECK_EQ(table_end_, other.table_end_);
350   DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_);
351   return index_ != other.index_;
352 }
353 
UpdateAndAdvanceToValid()354 void JumpTableTargetOffsets::iterator::UpdateAndAdvanceToValid() {
355   while (table_offset_ < table_end_ &&
356          !iterator_->IsConstantAtIndexSmi(table_offset_)) {
357     ++table_offset_;
358     ++index_;
359   }
360 
361   // Make sure we haven't reached the end of the table with a hole in current.
362   if (table_offset_ < table_end_) {
363     DCHECK(iterator_->IsConstantAtIndexSmi(table_offset_));
364     current_ = iterator_->GetConstantAtIndexAsSmi(table_offset_);
365   }
366 }
367 
368 }  // namespace interpreter
369 }  // namespace internal
370 }  // namespace v8
371