/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/interpreter/bytecode-array-iterator.cc
488 строк
18 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2015 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/interpreter/bytecode-array-iterator.h" #include "src/codegen/bailout-reason.h" #include "src/interpreter/bytecode-decoder.h" #include "src/interpreter/interpreter-intrinsics.h" #include "src/objects/feedback-vector.h" #include "src/objects/objects-inl.h" namespace v8 { namespace internal { namespace interpreter { BytecodeArrayIterator::BytecodeArrayIterator( Handle<BytecodeArray> bytecode_array, int initial_offset) : bytecode_array_(bytecode_array), start_(reinterpret_cast<uint8_t*>( bytecode_array_->GetFirstBytecodeAddress())), end_(start_ + bytecode_array_->length()), cursor_(start_), operand_scale_(OperandScale::kSingle), prefix_size_(0), local_heap_(LocalHeap::Current() ? LocalHeap::Current() : Isolate::Current()->main_thread_local_heap()) { local_heap_->AddGCEpilogueCallback(UpdatePointersCallback, this); UpdateCurrentBytecode(); if (initial_offset != 0) { AdvanceTo(initial_offset); } } BytecodeArrayIterator::BytecodeArrayIterator( Handle<BytecodeArray> bytecode_array, int initial_offset, DisallowGarbageCollection& no_gc) : bytecode_array_(bytecode_array), start_(reinterpret_cast<uint8_t*>( bytecode_array_->GetFirstBytecodeAddress())), end_(start_ + bytecode_array_->length()), cursor_(start_), operand_scale_(OperandScale::kSingle), prefix_size_(0), local_heap_(nullptr) { // Don't add a GC callback, since we're in a no_gc scope. UpdateCurrentBytecode(); if (initial_offset != 0) { AdvanceTo(initial_offset); } } BytecodeArrayIterator::~BytecodeArrayIterator() { if (local_heap_) { local_heap_->RemoveGCEpilogueCallback(UpdatePointersCallback, this); } } void BytecodeArrayIterator::AdvanceTo(int offset) { DCHECK(base::IsInRange(cursor_ - prefix_size_, start_, start_ + offset)); DCHECK_LE(current_offset(), offset); while (current_offset() < offset) { Advance(); } // Make sure we're always at a valid offset. CHECK_EQ(current_offset(), offset); } void BytecodeArrayIterator::SetOffset(int offset) { DCHECK_GE(offset, 0); if (!base::IsInRange(cursor_ - prefix_size_, start_, start_ + offset)) { Reset(); } // Advance to the given offset instead of just setting cursor_. // This way, we can guarantee that the offset is always valid. AdvanceTo(offset); } void BytecodeArrayIterator::Reset() { cursor_ = start_; UpdateCurrentBytecode(); } // protected void BytecodeArrayIterator::SetOffsetUnchecked(int offset) { DCHECK_GE(offset, 0); cursor_ = start_ + offset; UpdateCurrentBytecode(); } // static bool BytecodeArrayIterator::IsValidOffset(Handle<BytecodeArray> bytecode_array, int offset) { for (BytecodeArrayIterator it(bytecode_array); !it.done(); it.Advance()) { if (it.current_offset() == offset) return true; if (it.current_offset() > offset) break; } return false; } // static bool BytecodeArrayIterator::IsValidOSREntryOffset( Handle<BytecodeArray> bytecode_array, int offset) { BytecodeArrayIterator it(bytecode_array, offset); return it.CurrentBytecodeIsValidOSREntry(); } bool BytecodeArrayIterator::CurrentBytecodeIsValidOSREntry() const { return current_bytecode() == interpreter::Bytecode::kJumpLoop; } void BytecodeArrayIterator::ApplyDebugBreak() { // Get the raw bytecode from the bytecode array. This may give us a // scaling prefix, which we can patch with the matching debug-break // variant. uint8_t* cursor = cursor_ - prefix_size_; interpreter::Bytecode bytecode = interpreter::Bytecodes::FromByte(*cursor); if (interpreter::Bytecodes::IsDebugBreak(bytecode)) return; interpreter::Bytecode debugbreak = interpreter::Bytecodes::GetDebugBreak(bytecode); *cursor = interpreter::Bytecodes::ToByte(debugbreak); } uint32_t BytecodeArrayIterator::GetUnsignedOperand( int operand_index, OperandType operand_type) const { DCHECK_GE(operand_index, 0); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_EQ(operand_type, Bytecodes::GetOperandType(current_bytecode(), operand_index)); DCHECK(Bytecodes::IsUnsignedOperandType(operand_type)); Address operand_start = reinterpret_cast<Address>(cursor_) + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, current_operand_scale()); return BytecodeDecoder::DecodeUnsignedOperand(operand_start, operand_type, current_operand_scale()); } int32_t BytecodeArrayIterator::GetSignedOperand( int operand_index, OperandType operand_type) const { DCHECK_GE(operand_index, 0); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_EQ(operand_type, Bytecodes::GetOperandType(current_bytecode(), operand_index)); DCHECK(!Bytecodes::IsUnsignedOperandType(operand_type)); Address operand_start = reinterpret_cast<Address>(cursor_) + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, current_operand_scale()); return BytecodeDecoder::DecodeSignedOperand(operand_start, operand_type, current_operand_scale()); } uint32_t BytecodeArrayIterator::GetFlag8Operand(int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kFlag8); return GetUnsignedOperand(operand_index, OperandType::kFlag8); } uint32_t BytecodeArrayIterator::GetFlag16Operand(int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kFlag16); return GetUnsignedOperand(operand_index, OperandType::kFlag16); } uint32_t BytecodeArrayIterator::GetUnsignedImmediateOperand( int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kUImm); return GetUnsignedOperand(operand_index, OperandType::kUImm); } int32_t BytecodeArrayIterator::GetImmediateOperand(int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kImm); return GetSignedOperand(operand_index, OperandType::kImm); } uint32_t BytecodeArrayIterator::GetRegisterCountOperand( int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kRegCount); return GetUnsignedOperand(operand_index, OperandType::kRegCount); } uint32_t BytecodeArrayIterator::GetConstantPoolIndexOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kConstantPoolIndex); return GetUnsignedOperand(operand_index, operand_type); } uint32_t BytecodeArrayIterator::GetFeedbackSlotOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kFeedbackSlot); return GetUnsignedOperand(operand_index, operand_type); } uint32_t BytecodeArrayIterator::GetContextSlotOperand(int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kContextSlot); return GetUnsignedOperand(operand_index, operand_type); } uint32_t BytecodeArrayIterator::GetCoverageSlotOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kCoverageSlot); return GetUnsignedOperand(operand_index, operand_type); } FeedbackSlot BytecodeArrayIterator::GetSlotOperand(int operand_index) const { int index = GetFeedbackSlotOperand(operand_index); return FeedbackVector::ToSlot(index); } Register BytecodeArrayIterator::GetParameter(int parameter_index) const { DCHECK_GE(parameter_index, 0); // The parameter indices are shifted by 1 (receiver is the // first entry). return Register::FromParameterIndex(parameter_index + 1); } Register BytecodeArrayIterator::GetRegisterOperand(int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); Address operand_start = reinterpret_cast<Address>(cursor_) + Bytecodes::GetOperandOffset(current_bytecode(), operand_index, current_operand_scale()); return BytecodeDecoder::DecodeRegisterOperand(operand_start, operand_type, current_operand_scale()); } Register BytecodeArrayIterator::GetStarTargetRegister() const { Bytecode bytecode = current_bytecode(); DCHECK(Bytecodes::IsAnyStar(bytecode)); if (Bytecodes::IsShortStar(bytecode)) { return Register::FromShortStar(bytecode); } else { DCHECK_EQ(bytecode, Bytecode::kStar); DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 1); DCHECK_EQ(Bytecodes::GetOperandTypes(bytecode)[0], OperandType::kRegOut); return GetRegisterOperand(0); } } std::pair<Register, Register> BytecodeArrayIterator::GetRegisterPairOperand( int operand_index) const { Register first = GetRegisterOperand(operand_index); Register second(first.index() + 1); return std::make_pair(first, second); } RegisterList BytecodeArrayIterator::GetRegisterListOperand( int operand_index) const { Register first = GetRegisterOperand(operand_index); uint32_t count = GetRegisterCountOperand(operand_index + 1); return RegisterList(first.index(), count); } int BytecodeArrayIterator::GetRegisterOperandRange(int operand_index) const { DCHECK_LE(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); const OperandType* operand_types = Bytecodes::GetOperandTypes(current_bytecode()); OperandType operand_type = operand_types[operand_index]; DCHECK(Bytecodes::IsRegisterOperandType(operand_type)); if (operand_type == OperandType::kRegList || operand_type == OperandType::kRegOutList) { return GetRegisterCountOperand(operand_index + 1); } else { return Bytecodes::GetNumberOfRegistersRepresentedBy(operand_type); } } Runtime::FunctionId BytecodeArrayIterator::GetRuntimeIdOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kRuntimeId); uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type); return static_cast<Runtime::FunctionId>(raw_id); } uint32_t BytecodeArrayIterator::GetNativeContextIndexOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kNativeContextIndex); return GetUnsignedOperand(operand_index, operand_type); } Runtime::FunctionId BytecodeArrayIterator::GetIntrinsicIdOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kIntrinsicId); uint32_t raw_id = GetUnsignedOperand(operand_index, operand_type); return IntrinsicsHelper::ToRuntimeId( static_cast<IntrinsicsHelper::IntrinsicId>(raw_id)); } AbortReason BytecodeArrayIterator::GetAbortReasonOperand( int operand_index) const { OperandType operand_type = Bytecodes::GetOperandType(current_bytecode(), operand_index); DCHECK_EQ(operand_type, OperandType::kAbortReason); return static_cast<AbortReason>( GetUnsignedOperand(operand_index, operand_type)); } Tagged<Object> BytecodeArrayIterator::GetConstantAtIndex(int index) const { Tagged<TrustedFixedArray> constant_pool = bytecode_array()->constant_pool(); CHECK_WITH_MSG(base::IsInHalfOpenRange(index, 0, constant_pool->length()), "Constant pool index out of bounds"); return constant_pool->get(index); } Handle<Object> BytecodeArrayIterator::GetConstantAtIndex( int index, Isolate* isolate) const { return handle(GetConstantAtIndex(index), isolate); } Handle<Object> BytecodeArrayIterator::GetConstantAtIndex( int index, LocalIsolate* isolate) const { return handle(GetConstantAtIndex(index), isolate); } Tagged<Smi> BytecodeArrayIterator::GetConstantAtIndexAsSmi(int index) const { Tagged<Object> object = GetConstantAtIndex(index); CHECK_WITH_MSG(IsSmi(object), "Constant pool entry is not a Smi"); return Cast<Smi>(object); } Handle<Object> BytecodeArrayIterator::GetConstantForOperand( int operand_index, Isolate* isolate) const { return GetConstantAtIndex(GetConstantPoolIndexOperand(operand_index), isolate); } Handle<Object> BytecodeArrayIterator::GetConstantForOperand( int operand_index, LocalIsolate* isolate) const { return GetConstantAtIndex(GetConstantPoolIndexOperand(operand_index), isolate); } int BytecodeArrayIterator::GetRelativeJumpTargetOffset() const { Bytecode bytecode = current_bytecode(); if (interpreter::Bytecodes::IsJumpImmediate(bytecode)) { int relative_offset = GetUnsignedImmediateOperand(0); if (bytecode == Bytecode::kJumpLoop) { relative_offset = -relative_offset; } return relative_offset; } else if (interpreter::Bytecodes::IsJumpConstant(bytecode)) { Tagged<Smi> smi = GetConstantAtIndexAsSmi(GetConstantPoolIndexOperand(0)); return smi.value(); } else { UNREACHABLE(); } } int BytecodeArrayIterator::GetJumpTargetOffset() const { return GetAbsoluteOffset(GetRelativeJumpTargetOffset()); } JumpTableTargetOffsets BytecodeArrayIterator::GetJumpTableTargetOffsets() const { uint32_t table_start, table_size; int32_t case_value_base; if (current_bytecode() == Bytecode::kSwitchOnGeneratorState) { table_start = GetConstantPoolIndexOperand(1); table_size = GetUnsignedImmediateOperand(2); case_value_base = 0; } else { DCHECK_EQ(current_bytecode(), Bytecode::kSwitchOnSmiNoFeedback); table_start = GetConstantPoolIndexOperand(0); table_size = GetUnsignedImmediateOperand(1); case_value_base = GetImmediateOperand(2); } return JumpTableTargetOffsets(this, table_start, table_size, case_value_base); } int BytecodeArrayIterator::GetAbsoluteOffset(int relative_offset) const { return current_offset() + relative_offset + prefix_size_; } std::ostream& BytecodeArrayIterator::PrintCurrentBytecodeTo( std::ostream& os) const { return BytecodeDecoder::Decode(os, cursor_ - prefix_size_, bytecode_array_->constant_pool()); } void BytecodeArrayIterator::UpdatePointers() { DisallowGarbageCollection no_gc; uint8_t* start = reinterpret_cast<uint8_t*>(bytecode_array_->GetFirstBytecodeAddress()); if (start != start_) { start_ = start; uint8_t* end = start + bytecode_array_->length(); if (cursor_ != nullptr) { size_t distance_to_end = end_ - cursor_; cursor_ = end - distance_to_end; } end_ = end; } } uint32_t BytecodeArrayIterator::GetEmbeddedFeedback(int operand_index) const { DCHECK_GE(operand_index, 0); DCHECK_LT(operand_index, Bytecodes::NumberOfOperands(current_bytecode())); DCHECK_EQ(OperandType::kEmbeddedFeedback, Bytecodes::GetOperandType(current_bytecode(), operand_index)); Address embedded_feedback_start = reinterpret_cast<Address>(cursor_) + current_operand_offset(operand_index); return BytecodeDecoder::RacyDecodeEmbeddedFeedback(embedded_feedback_start); } CompareOperationHint BytecodeArrayIterator::GetEmbeddedCompareOperationHint() { DCHECK(Bytecodes::IsCompareWithEmbeddedFeedback(current_bytecode())); uint32_t type_feedback = GetEmbeddedFeedback(1); return v8::internal::CompareOperationHintFromFeedback(type_feedback); } int BytecodeArrayIterator::GetEmbeddedFeedbackOffset(int operand_index) const { DCHECK_EQ(Bytecodes::GetOperandType(current_bytecode(), operand_index), OperandType::kEmbeddedFeedback); return BytecodeArray::kHeaderSize - kHeapObjectTag + current_offset() + prefix_size_ + current_operand_offset(operand_index); } JumpTableTargetOffsets::JumpTableTargetOffsets( const BytecodeArrayIterator* iterator, int table_start, int table_size, int case_value_base) : iterator_(iterator), table_start_(table_start), table_size_(table_size), case_value_base_(case_value_base) {} JumpTableTargetOffsets::iterator JumpTableTargetOffsets::begin() const { return iterator(case_value_base_, table_start_, table_start_ + table_size_, iterator_); } JumpTableTargetOffsets::iterator JumpTableTargetOffsets::end() const { return iterator(case_value_base_ + table_size_, table_start_ + table_size_, table_start_ + table_size_, iterator_); } int JumpTableTargetOffsets::size() const { return table_size_; } JumpTableTargetOffsets::iterator::iterator( int case_value, int table_offset, int table_end, const BytecodeArrayIterator* iterator) : iterator_(iterator), index_(case_value), table_offset_(table_offset), table_end_(table_end) {} JumpTableTargetOffset JumpTableTargetOffsets::iterator::operator*() { DCHECK_LT(table_offset_, table_end_); return {index_, iterator_->GetAbsoluteOffset(Smi::ToInt( iterator_->GetConstantAtIndexAsSmi(table_offset_)))}; } JumpTableTargetOffsets::iterator& JumpTableTargetOffsets::iterator::operator++() { DCHECK_LT(table_offset_, table_end_); ++table_offset_; ++index_; return *this; } bool JumpTableTargetOffsets::iterator::operator!=( const JumpTableTargetOffsets::iterator& other) { DCHECK_EQ(iterator_, other.iterator_); DCHECK_EQ(table_end_, other.table_end_); DCHECK_EQ(index_ - other.index_, table_offset_ - other.table_offset_); return index_ != other.index_; } } // namespace interpreter } // namespace internal } // namespace v8