• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetUnsignedOperand(int operand_index,OperandType operand_type) const56 uint32_t BytecodeArrayIterator::GetUnsignedOperand(
57     int operand_index, OperandType operand_type) const {
58   DCHECK_GE(operand_index, 0);
59   DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
60   DCHECK_EQ(operand_type,
61             Bytecodes::GetOperandType(current_bytecode(), operand_index));
62   DCHECK(Bytecodes::IsUnsignedOperandType(operand_type));
63   Address operand_start =
64       reinterpret_cast<Address>(cursor_) +
65       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
66                                   current_operand_scale());
67   return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type,
68                                                 current_operand_scale());
69 }
70 
GetSignedOperand(int operand_index,OperandType operand_type) const71 int32_t BytecodeArrayIterator::GetSignedOperand(
72     int operand_index, OperandType operand_type) const {
73   DCHECK_GE(operand_index, 0);
74   DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
75   DCHECK_EQ(operand_type,
76             Bytecodes::GetOperandType(current_bytecode(), operand_index));
77   DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type));
78   Address operand_start =
79       reinterpret_cast<Address>(cursor_) +
80       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
81                                   current_operand_scale());
82   return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type,
83                                               current_operand_scale());
84 }
85 
GetFlagOperand(int operand_index) const86 uint32_t BytecodeArrayIterator::GetFlagOperand(int operand_index) const {
87   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
88             OperandType::kFlag8);
89   return GetUnsignedOperand(operand_index, OperandType::kFlag8);
90 }
91 
GetUnsignedImmediateOperand(int operand_index) const92 uint32_t BytecodeArrayIterator::GetUnsignedImmediateOperand(
93     int operand_index) const {
94   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
95             OperandType::kUImm);
96   return GetUnsignedOperand(operand_index, OperandType::kUImm);
97 }
98 
GetImmediateOperand(int operand_index) const99 int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const {
100   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
101             OperandType::kImm);
102   return GetSignedOperand(operand_index, OperandType::kImm);
103 }
104 
GetRegisterCountOperand(int operand_index) const105 uint32_t BytecodeArrayIterator::GetRegisterCountOperand(
106     int operand_index) const {
107   DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index),
108             OperandType::kRegCount);
109   return GetUnsignedOperand(operand_index, OperandType::kRegCount);
110 }
111 
GetIndexOperand(int operand_index) const112 uint32_t BytecodeArrayIterator::GetIndexOperand(int operand_index) const {
113   OperandType operand_type =
114       Bytecodes::GetOperandType(current_bytecode(), operand_index);
115   DCHECK_EQ(operand_type, OperandType::kIdx);
116   return GetUnsignedOperand(operand_index, operand_type);
117 }
118 
GetSlotOperand(int operand_index) const119 FeedbackSlot BytecodeArrayIterator::GetSlotOperand(int operand_index) const {
120   int index = GetIndexOperand(operand_index);
121   return FeedbackVector::ToSlot(index);
122 }
123 
GetReceiver() const124 Register BytecodeArrayIterator::GetReceiver() const {
125   return Register::FromParameterIndex(0);
126 }
127 
GetParameter(int parameter_index) const128 Register BytecodeArrayIterator::GetParameter(int parameter_index) const {
129   DCHECK_GE(parameter_index, 0);
130   // The parameter indices are shifted by 1 (receiver is the
131   // first entry).
132   return Register::FromParameterIndex(parameter_index + 1);
133 }
134 
GetRegisterOperand(int operand_index) const135 Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const {
136   OperandType operand_type =
137       Bytecodes::GetOperandType(current_bytecode(), operand_index);
138   Address operand_start =
139       reinterpret_cast<Address>(cursor_) +
140       Bytecodes::GetOperandOffset(current_bytecode(), operand_index,
141                                   current_operand_scale());
142   return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type,
143                                                 current_operand_scale());
144 }
145 
GetRegisterPairOperand(int operand_index) const146 std::pair<Register, Register> BytecodeArrayIterator::GetRegisterPairOperand(
147     int operand_index) const {
148   Register first = GetRegisterOperand(operand_index);
149   Register second(first.index() + 1);
150   return std::make_pair(first, second);
151 }
152 
GetRegisterListOperand(int operand_index) const153 RegisterList BytecodeArrayIterator::GetRegisterListOperand(
154     int operand_index) const {
155   Register first = GetRegisterOperand(operand_index);
156   uint32_t count = GetRegisterCountOperand(operand_index + 1);
157   return RegisterList(first.index(), count);
158 }
159 
GetRegisterOperandRange(int operand_index) const160 int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const {
161   DCHECK_LE(operand_index, Bytecodes::NumberOfOperands(current_bytecode()));
162   const OperandType* operand_types =
163       Bytecodes::GetOperandTypes(current_bytecode());
164   OperandType operand_type = operand_types[operand_index];
165   DCHECK(Bytecodes::IsRegisterOperandType(operand_type));
166   if (operand_type == OperandType::kRegList ||
167       operand_type == OperandType::kRegOutList) {
168     return GetRegisterCountOperand(operand_index + 1);
169   } else {
170     return Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type);
171   }
172 }
173 
GetRuntimeIdOperand(int operand_index) const174 Runtime::FunctionId BytecodeArrayIterator::GetRuntimeIdOperand(
175     int operand_index) const {
176   OperandType operand_type =
177       Bytecodes::GetOperandType(current_bytecode(), operand_index);
178   DCHECK_EQ(operand_type, OperandType::kRuntimeId);
179   uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
180   return static_cast<Runtime::FunctionId>(raw_id);
181 }
182 
GetNativeContextIndexOperand(int operand_index) const183 uint32_t BytecodeArrayIterator::GetNativeContextIndexOperand(
184     int operand_index) const {
185   OperandType operand_type =
186       Bytecodes::GetOperandType(current_bytecode(), operand_index);
187   DCHECK_EQ(operand_type, OperandType::kNativeContextIndex);
188   return GetUnsignedOperand(operand_index, operand_type);
189 }
190 
GetIntrinsicIdOperand(int operand_index) const191 Runtime::FunctionId BytecodeArrayIterator::GetIntrinsicIdOperand(
192     int operand_index) const {
193   OperandType operand_type =
194       Bytecodes::GetOperandType(current_bytecode(), operand_index);
195   DCHECK_EQ(operand_type, OperandType::kIntrinsicId);
196   uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type);
197   return IntrinsicsHelper::ToRuntimeId(
198       static_cast<IntrinsicsHelper::IntrinsicId>(raw_id));
199 }
200 
201 template <typename IsolateT>
GetConstantAtIndex(int index,IsolateT * isolate) const202 Handle<Object> BytecodeArrayIterator::GetConstantAtIndex(
203     int index, IsolateT* isolate) const {
204   return handle(bytecode_array()->constant_pool().get(index), isolate);
205 }
206 
IsConstantAtIndexSmi(int index) const207 bool BytecodeArrayIterator::IsConstantAtIndexSmi(int index) const {
208   return bytecode_array()->constant_pool().get(index).IsSmi();
209 }
210 
GetConstantAtIndexAsSmi(int index) const211 Smi BytecodeArrayIterator::GetConstantAtIndexAsSmi(int index) const {
212   return Smi::cast(bytecode_array()->constant_pool().get(index));
213 }
214 
215 template <typename IsolateT>
GetConstantForIndexOperand(int operand_index,IsolateT * isolate) const216 Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
217     int operand_index, IsolateT* isolate) const {
218   return GetConstantAtIndex(GetIndexOperand(operand_index), isolate);
219 }
220 
221 template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
222     Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
223         int operand_index, Isolate* isolate) const;
224 template Handle<Object> BytecodeArrayIterator::GetConstantForIndexOperand(
225     int operand_index, LocalIsolate* isolate) const;
226 
GetRelativeJumpTargetOffset() const227 int BytecodeArrayIterator::GetRelativeJumpTargetOffset() const {
228   Bytecode bytecode = current_bytecode();
229   if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) {
230     int relative_offset = GetUnsignedImmediateOperand(0);
231     if (bytecode == Bytecode::kJumpLoop) {
232       relative_offset = -relative_offset;
233     }
234     return relative_offset;
235   } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) {
236     Smi smi = GetConstantAtIndexAsSmi(GetIndexOperand(0));
237     return smi.value();
238   } else {
239     UNREACHABLE();
240   }
241 }
242 
GetJumpTargetOffset() const243 int BytecodeArrayIterator::GetJumpTargetOffset() const {
244   return GetAbsoluteOffset(GetRelativeJumpTargetOffset());
245 }
246 
GetJumpTableTargetOffsets() const247 JumpTableTargetOffsets BytecodeArrayIterator::GetJumpTableTargetOffsets()
248     const {
249   uint32_t table_start, table_size;
250   int32_t case_value_base;
251   if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) {
252     table_start = GetIndexOperand(1);
253     table_size = GetUnsignedImmediateOperand(2);
254     case_value_base = 0;
255   } else {
256     DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback);
257     table_start = GetIndexOperand(0);
258     table_size = GetUnsignedImmediateOperand(1);
259     case_value_base = GetImmediateOperand(2);
260   }
261   return JumpTableTargetOffsets(this, table_start, table_size, case_value_base);
262 }
263 
GetAbsoluteOffset(int relative_offset) const264 int BytecodeArrayIterator::GetAbsoluteOffset(int relative_offset) const {
265   return current_offset() + relative_offset + prefix_size_;
266 }
267 
PrintTo(std::ostream & os) const268 std::ostream& BytecodeArrayIterator::PrintTo(std::ostream& os) const {
269   return BytecodeDecoder::Decode(os, cursor_ - prefix_size_);
270 }
271 
UpdatePointers()272 void BytecodeArrayIterator::UpdatePointers() {
273   DisallowGarbageCollection no_gc;
274   uint8_t* start =
275       reinterpret_cast<uint8_t*>(bytecode_array_->GetFirstBytecodeAddress());
276   if (start != start_) {
277     start_ = start;
278     uint8_t* end = start + bytecode_array_->length();
279     size_t distance_to_end = end_ - cursor_;
280     cursor_ = end - distance_to_end;
281     end_ = end;
282   }
283 }
284 
JumpTableTargetOffsets(const BytecodeArrayIterator * iterator,int table_start,int table_size,int case_value_base)285 JumpTableTargetOffsets::JumpTableTargetOffsets(
286     const BytecodeArrayIterator* iterator, int table_start, int table_size,
287     int case_value_base)
288     : iterator_(iterator),
289       table_start_(table_start),
290       table_size_(table_size),
291       case_value_base_(case_value_base) {}
292 
begin() const293 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::begin() const {
294   return iterator(case_value_base_, table_start_, table_start_ + table_size_,
295                   iterator_);
296 }
end() const297 JumpTableTargetOffsets::iterator JumpTableTargetOffsets::end() const {
298   return iterator(case_value_base_ + table_size_, table_start_ + table_size_,
299                   table_start_ + table_size_, iterator_);
300 }
size() const301 int JumpTableTargetOffsets::size() const {
302   int ret = 0;
303   // TODO(leszeks): Is there a more efficient way of doing this than iterating?
304   for (JumpTableTargetOffset entry : *this) {
305     USE(entry);
306     ret++;
307   }
308   return ret;
309 }
310 
iterator(int case_value,int table_offset,int table_end,const BytecodeArrayIterator * iterator)311 JumpTableTargetOffsets::iterator::iterator(
312     int case_value, int table_offset, int table_end,
313     const BytecodeArrayIterator* iterator)
314     : iterator_(iterator),
315       current_(Smi::zero()),
316       index_(case_value),
317       table_offset_(table_offset),
318       table_end_(table_end) {
319   UpdateAndAdvanceToValid();
320 }
321 
operator *()322 JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() {
323   DCHECK_LT(table_offset_, table_end_);
324   return {index_, iterator_->GetAbsoluteOffset(Smi::ToInt(current_))};
325 }
326 
327 JumpTableTargetOffsets::iterator&
operator ++()328 JumpTableTargetOffsets::iterator::operator++() {
329   DCHECK_LT(table_offset_, table_end_);
330   ++table_offset_;
331   ++index_;
332   UpdateAndAdvanceToValid();
333   return *this;
334 }
335 
operator !=(const JumpTableTargetOffsets::iterator & other)336 bool JumpTableTargetOffsets::iterator::operator!=(
337     const JumpTableTargetOffsets::iterator& other) {
338   DCHECK_EQ(iterator_, other.iterator_);
339   DCHECK_EQ(table_end_, other.table_end_);
340   DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_);
341   return index_ != other.index_;
342 }
343 
UpdateAndAdvanceToValid()344 void JumpTableTargetOffsets::iterator::UpdateAndAdvanceToValid() {
345   while (table_offset_ < table_end_ &&
346          !iterator_->IsConstantAtIndexSmi(table_offset_)) {
347     ++table_offset_;
348     ++index_;
349   }
350 
351   // Make sure we haven't reached the end of the table with a hole in current.
352   if (table_offset_ < table_end_) {
353     DCHECK(iterator_->IsConstantAtIndexSmi(table_offset_));
354     current_ = iterator_->GetConstantAtIndexAsSmi(table_offset_);
355   }
356 }
357 
358 }  // namespace interpreter
359 }  // namespace internal
360 }  // namespace v8
361