Files
sdk/runtime/vm/bytecode_reader.h
T
Tess Strickland df693c20b0 [vm,dyn_modules] Add flags to bytecode source positions.
There are two possible flags for each source position currently:
a flag that marks the source position as synthetic and a flag that
marks the source position as within a yield point.

Synthetic source positions in bytecode are treated the same as synthetic
source positions in compiled code. That is, they encode the source
position in the text that caused them to be synthesized, but denote that
the covered instructions are internal and not to be used for debugger
pause points or for call site/branch coverage information.

Adding these flags allow us to mark appropriate parts of the async
machinery as synthetic, and also allow us to mark all the bytecode
involved in yield points as having the same token position.

The latter fixes tests where the code would step over a previous
expression, thus being paused at the start of the await bytecode,
and would record the fp and token position there as the ones to
ignore. However, since a new source position wasn't emitted until the
direct call to the await method, the recorded token position would
be the token position prior to the await call, and so the change
in token position at the await call would trigger an early pause.

TEST=pkg/vm_service/test/async_single_step_exception_test
     pkg/vm_service/test/async_single_step_into_test
     pkg/vm_service/test/async_single_step_out_test
     pkg/vm_service/test/async_star_single_step_into_test
     pkg/vm_service/test/async_step_out_test
     pkg/vm_service/test/positive_token_pos_test
     pkg/vm_service/test/step_into_async_no_await_test

Cq-Include-Trybots: luci.dart.try:vm-dyn-linux-debug-x64-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-mac-debug-arm64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-product-x64-try
Change-Id: Ic7642a74fb76227a473f461f360e84dd3d5a45a1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/453322
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2025-10-09 09:15:42 -07:00

722 lines
24 KiB
C++

// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_VM_BYTECODE_READER_H_
#define RUNTIME_VM_BYTECODE_READER_H_
#include "vm/globals.h"
#if defined(DART_DYNAMIC_MODULES)
#include "vm/bit_vector.h"
#include "vm/constants_kbc.h"
#include "vm/hash_table.h"
#include "vm/object.h"
namespace dart {
namespace bytecode {
class BytecodeComponentData;
class BytecodeLoader {
public:
BytecodeLoader(Thread* thread, const TypedDataBase& binary);
~BytecodeLoader();
FunctionPtr LoadBytecode(bool load_code = true);
void LoadPendingCode();
TypedDataBasePtr binary() const { return binary_.ptr(); }
ArrayPtr bytecode_component_array() const {
return bytecode_component_array_.ptr();
}
void AddPendingObject(const Object& obj, intptr_t offset) {
SetOffset(obj, offset);
pending_objects_.Add(obj);
}
void SetOffset(const Object& obj, intptr_t offset);
intptr_t GetOffset(const Object& obj) const;
bool HasOffset(const Object& obj) const;
void FindModifiedLibraries(BitVector* modified_libs,
intptr_t* p_num_libraries,
intptr_t* p_num_classes,
intptr_t* p_num_procedures);
void SetExpressionEvaluationLibrary(const Library& lib) {
ASSERT(expression_evaluation_library_ == nullptr);
expression_evaluation_library_ =
&Library::ZoneHandle(thread_->zone(), lib.ptr());
}
LibraryPtr GetExpressionEvaluationLibrary() const {
ASSERT(expression_evaluation_library_ != nullptr);
return expression_evaluation_library_->ptr();
}
void SetExpressionEvaluationRealClass(const Class& cls) {
ASSERT(expression_evaluation_real_classs_ == nullptr);
expression_evaluation_real_classs_ =
&Class::ZoneHandle(thread_->zone(), cls.ptr());
}
ClassPtr GetExpressionEvaluationRealClass() const {
ASSERT(expression_evaluation_real_classs_ != nullptr);
return expression_evaluation_real_classs_->ptr();
}
void SetExpressionEvaluationFunction(const Function& func) {
ASSERT(expression_evaluation_function_ == nullptr);
expression_evaluation_function_ =
&Function::ZoneHandle(thread_->zone(), func.ptr());
}
FunctionPtr GetExpressionEvaluationFunction() const {
ASSERT(expression_evaluation_function_ != nullptr);
return expression_evaluation_function_->ptr();
}
private:
Thread* thread_;
const TypedDataBase& binary_;
Array& bytecode_component_array_;
const GrowableObjectArray& pending_objects_;
Array& bytecode_offsets_map_;
Library* expression_evaluation_library_ = nullptr;
Class* expression_evaluation_real_classs_ = nullptr;
Function* expression_evaluation_function_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(BytecodeLoader);
};
class Reader : public ValueObject {
public:
explicit Reader(const TypedDataBase& typed_data) : typed_data_(&typed_data) {
Init();
}
uint32_t ReadUInt32At(intptr_t offset) const {
ASSERT((size_ >= 4) && (offset >= 0) && (offset <= size_ - 4));
uint32_t value =
LoadUnaligned(reinterpret_cast<const uint32_t*>(raw_buffer_ + offset));
// All supported platforms are little-endian, so there is no need to
// convert from little-endian to host.
return value;
}
uint32_t ReadUInt32() {
uint32_t value = ReadUInt32At(offset_);
offset_ += 4;
return value;
}
uint32_t ReadUInt() {
ASSERT((size_ >= 1) && (offset_ >= 0) && (offset_ <= size_ - 1));
const uint8_t* buffer = raw_buffer_;
uword byte0 = buffer[offset_];
if ((byte0 & 0x80) == 0) {
// 0...
offset_++;
return byte0;
} else if ((byte0 & 0xc0) == 0x80) {
// 10...
ASSERT((size_ >= 2) && (offset_ >= 0) && (offset_ <= size_ - 2));
uint32_t value =
((byte0 & ~static_cast<uword>(0x80)) << 8) | (buffer[offset_ + 1]);
offset_ += 2;
return value;
} else {
// 11...
ASSERT((size_ >= 4) && (offset_ >= 0) && (offset_ <= size_ - 4));
uint32_t value = ((byte0 & ~static_cast<uword>(0xc0)) << 24) |
(buffer[offset_ + 1] << 16) |
(buffer[offset_ + 2] << 8) | (buffer[offset_ + 3] << 0);
offset_ += 4;
return value;
}
}
intptr_t ReadSLEB128() {
ReadStream stream(raw_buffer_, size_, offset_);
const intptr_t result = stream.ReadSLEB128();
offset_ = stream.Position();
return result;
}
int64_t ReadSLEB128AsInt64() {
ReadStream stream(raw_buffer_, size_, offset_);
const int64_t result = stream.ReadSLEB128<int64_t>();
offset_ = stream.Position();
return result;
}
/**
* Read and return a TokenPosition from this reader.
*/
TokenPosition ReadPosition() {
// Position is saved as unsigned,
// but actually ranges from -1 and up (thus the -1)
intptr_t value = ReadUInt() - 1;
TokenPosition result = TokenPosition::Deserialize(value);
return result;
}
intptr_t ReadListLength() { return ReadUInt(); }
uint8_t ReadByte() { return raw_buffer_[offset_++]; }
uint8_t PeekByte() { return raw_buffer_[offset_]; }
void ReadBytes(uint8_t* buffer, uint8_t size) {
for (int i = 0; i < size; i++) {
buffer[i] = ReadByte();
}
}
const TypedDataBase* typed_data() { return typed_data_; }
intptr_t offset() const { return offset_; }
void set_offset(intptr_t offset) {
ASSERT(offset <= size_);
offset_ = offset;
}
intptr_t size() const { return size_; }
TypedDataViewPtr ViewFromTo(intptr_t start, intptr_t end) {
return typed_data_->ViewFromTo(start, end, Heap::kOld);
}
const uint8_t* BufferAt(intptr_t offset) {
ASSERT((offset >= 0) && (offset < size_));
return &raw_buffer_[offset];
}
private:
friend class AlternativeReadingScope;
void Init() {
ASSERT(typed_data_->IsExternalOrExternalView());
raw_buffer_ = reinterpret_cast<uint8_t*>(typed_data_->DataAddr(0));
size_ = typed_data_->LengthInBytes();
offset_ = 0;
}
// A external typed data or a view on an external typed data.
const TypedDataBase* typed_data_ = nullptr;
// The raw data size/length of [typed_data_].
const uint8_t* raw_buffer_ = nullptr;
intptr_t size_ = 0;
intptr_t offset_ = 0;
};
// A helper class that saves the current reader position, goes to another reader
// position, and upon destruction, resets to the original reader position.
class AlternativeReadingScope {
public:
AlternativeReadingScope(Reader* reader, intptr_t new_position)
: reader_(reader), saved_offset_(reader_->offset_) {
reader_->offset_ = new_position;
}
~AlternativeReadingScope() { reader_->offset_ = saved_offset_; }
private:
Reader* const reader_;
const intptr_t saved_offset_;
DISALLOW_COPY_AND_ASSIGN(AlternativeReadingScope);
};
// Helper class for reading bytecode.
class BytecodeReaderHelper : public ValueObject {
public:
explicit BytecodeReaderHelper(Thread* thread,
const TypedDataBase& typed_data);
explicit BytecodeReaderHelper(Thread* thread,
BytecodeComponentData* bytecode_component);
Reader& reader() { return reader_; }
void ReadCode(const Function& function, intptr_t code_offset);
void ReadCoveredConstConstructors(const Script& script, intptr_t offset);
void ReadMembers(const Class& cls, bool discard_fields);
void ReadFieldDeclarations(const Class& cls, bool discard_fields);
void ReadFunctionDeclarations(const Class& cls);
void ReadClassDeclaration(const Class& cls);
void ReadLibraryDeclaration(const Library& library, bool register_classes);
void ReadLibraryDeclarations(intptr_t num_libraries,
const GrowableObjectArray& pending_objects,
bool load_code);
void ReadPendingCode(const GrowableObjectArray& pending_objects);
void FindModifiedLibraries(BitVector* modified_libs, intptr_t num_libraries);
LibraryPtr ReadMain();
ArrayPtr ReadBytecodeComponent();
void ResetObjects();
// Fills in [is_covariant] and [is_generic_covariant_impl] vectors
// according to covariance attributes of [function] parameters.
//
// [function] should be declared in bytecode.
// [is_covariant] and [is_generic_covariant_impl] should contain bitvectors
// of function.NumParameters() length.
void ReadParameterCovariance(const Function& function,
intptr_t code_offset,
BitVector* is_covariant,
BitVector* is_generic_covariant_impl);
// Read bytecode PackedObject.
ObjectPtr ReadObject();
private:
// These constants should match corresponding constants in class ObjectHandle
// (pkg/dart2bytecode/lib/object_table.dart).
static const int kReferenceBit = 1 << 0;
static const int kIndexShift = 1;
static const int kKindShift = 1;
static const int kKindMask = 0x0f;
static const int kFlagBit0 = 1 << 5;
static const int kFlagBit1 = 1 << 6;
static const int kFlagBit2 = 1 << 7;
static const int kFlagBit3 = 1 << 8;
static const int kFlagBit4 = 1 << 9;
static const int kFlagBit5 = 1 << 10;
static const int kTagMask = (kFlagBit0 | kFlagBit1 | kFlagBit2 | kFlagBit3);
static const int kFlagIsNullable = kFlagBit4;
static const int kFlagsMask = (kTagMask | kFlagBit4 | kFlagBit5);
// Code flags, must be in sync with Code constants in
// pkg/dart2bytecode/lib/declarations.dart.
struct Code {
static const int kHasExceptionsTableFlag = 1 << 0;
static const int kHasSourcePositionsFlag = 1 << 1;
static const int kHasNullableFieldsFlag = 1 << 2;
static const int kHasClosuresFlag = 1 << 3;
static const int kHasParameterFlagsFlag = 1 << 4;
static const int kHasForwardingStubTargetFlag = 1 << 5;
static const int kHasDefaultFunctionTypeArgsFlag = 1 << 6;
static const int kHasLocalVariablesFlag = 1 << 7;
};
// Closure code flags, must be in sync with ClosureCode constants in
// pkg/dart2bytecode/lib/declarations.dart.
struct ClosureCode {
static const int kHasExceptionsTableFlag = 1 << 0;
static const int kHasSourcePositionsFlag = 1 << 1;
static const int kHasLocalVariablesFlag = 1 << 2;
};
// Parameter flags, must be in sync with ParameterFlags constants in
// pkg/dart2bytecode/lib/object_table.dart.
struct Parameter {
// Parameter flags in FunctionDeclaration, ClosureDeclaration and
// FunctionType.
static const int kIsRequiredFlag = 1 << 0;
// Parameter flags in Code.
static const int kIsCovariantFlag = 1 << 0;
static const int kIsCovariantByClassFlag = 1 << 1;
};
class FunctionTypeScope : public ValueObject {
public:
explicit FunctionTypeScope(BytecodeReaderHelper* bytecode_reader,
const FunctionType& type)
: bytecode_reader_(bytecode_reader) {
bytecode_reader_->enclosing_function_types_.Add(&type);
}
~FunctionTypeScope() {
bytecode_reader_->enclosing_function_types_.RemoveLast();
}
private:
BytecodeReaderHelper* const bytecode_reader_;
};
class FunctionScope : public ValueObject {
public:
FunctionScope(BytecodeReaderHelper* bytecode_reader,
const Function& function,
const String& name,
const Class& cls)
: bytecode_reader_(bytecode_reader) {
ASSERT(bytecode_reader_->scoped_function_.IsNull());
ASSERT(bytecode_reader_->scoped_function_name_.IsNull());
ASSERT(bytecode_reader_->scoped_function_class_.IsNull());
ASSERT(name.IsSymbol());
bytecode_reader_->scoped_function_ = function.ptr();
bytecode_reader_->scoped_function_name_ = name.ptr();
bytecode_reader_->scoped_function_class_ = cls.ptr();
}
~FunctionScope() {
bytecode_reader_->scoped_function_ = Function::null();
bytecode_reader_->scoped_function_name_ = String::null();
bytecode_reader_->scoped_function_class_ = Class::null();
}
private:
BytecodeReaderHelper* bytecode_reader_;
};
void ReadClosureDeclaration(const Function& function, intptr_t closureIndex);
FunctionTypePtr ReadFunctionSignature(const FunctionType& signature,
const Function& closure_function,
bool has_optional_positional_params,
bool has_optional_named_params,
bool has_type_params,
bool has_positional_param_names,
bool has_parameter_flags);
void ReadTypeParametersDeclaration(
const Class& parameterized_class,
const FunctionType& parameterized_signature);
// Read portion of constant pool corresponding to one function/closure.
// Start with [start_index], and stop when reaching EndClosureFunctionScope.
// Return index of the last read constant pool entry.
intptr_t ReadConstantPool(const Function& function,
const ObjectPool& pool,
intptr_t start_index);
BytecodePtr ReadBytecode(const ObjectPool& pool);
void ReadExceptionsTable(const Function& function,
const Bytecode& bytecode,
bool has_exceptions_table);
void ReadSourcePositions(const Bytecode& bytecode, bool has_source_positions);
void ReadLocalVariables(const Bytecode& bytecode, bool has_local_variables);
StringPtr ConstructorName(const Class& cls, const String& name);
ObjectPtr ReadObjectContents(uint32_t header);
ObjectPtr ReadConstObject(intptr_t tag);
ObjectPtr ReadType(intptr_t tag, Nullability nullability);
StringPtr ReadString(bool is_canonical = true);
TypedDataPtr ReadLineStartsData(intptr_t line_starts_offset);
ScriptPtr ReadSourceFile(const String& uri, intptr_t offset);
TypeArgumentsPtr ReadTypeArguments();
void ReadAnnotations(const Class& cls,
const Object& declaration,
bool has_pragma);
void SetupFieldAccessorFunction(const Class& klass,
const Function& function,
const AbstractType& field_type);
PatchClassPtr GetPatchClass(const Class& cls, const Script& script);
InstancePtr Canonicalize(const Instance& instance);
// Similar to cls.EnsureClassDeclaration, but may be more efficient if
// class is from the current kernel binary.
void LoadReferencedClass(const Class& cls);
Reader reader_;
Thread* const thread_;
Zone* const zone_;
BytecodeComponentData* bytecode_component_;
Array* closures_ = nullptr;
PatchClass* patch_class_ = nullptr;
Array* functions_ = nullptr;
intptr_t function_index_ = 0;
GrowableArray<const FunctionType*> enclosing_function_types_;
Function& scoped_function_;
String& scoped_function_name_;
Class& scoped_function_class_;
DISALLOW_COPY_AND_ASSIGN(BytecodeReaderHelper);
};
class BytecodeComponentData : ValueObject {
public:
enum {
kTypedData,
kVersion,
kStringsHeaderOffset,
kStringsContentsOffset,
kObjectOffsetsOffset,
kNumObjects,
kObjectsContentsOffset,
kMainOffset,
kNumLibraries,
kLibraryIndexOffset,
kLibrariesOffset,
kNumClasses,
kClassesOffset,
kMembersOffset,
kNumCodes,
kCodesOffset,
kSourcePositionsOffset,
kSourceFilesOffset,
kLineStartsOffset,
kLocalVariablesOffset,
kAnnotationsOffset,
kNumFields
};
explicit BytecodeComponentData(const Array& data) : data_(data) {}
TypedDataBasePtr GetTypedData() const;
intptr_t GetVersion() const;
intptr_t GetStringsHeaderOffset() const;
intptr_t GetStringsContentsOffset() const;
intptr_t GetObjectOffsetsOffset() const;
intptr_t GetNumObjects() const;
intptr_t GetObjectsContentsOffset() const;
intptr_t GetMainOffset() const;
intptr_t GetNumLibraries() const;
intptr_t GetLibraryIndexOffset() const;
intptr_t GetLibrariesOffset() const;
intptr_t GetNumClasses() const;
intptr_t GetClassesOffset() const;
intptr_t GetMembersOffset() const;
intptr_t GetNumCodes() const;
intptr_t GetCodesOffset() const;
intptr_t GetSourcePositionsOffset() const;
intptr_t GetSourceFilesOffset() const;
intptr_t GetLineStartsOffset() const;
intptr_t GetLocalVariablesOffset() const;
intptr_t GetAnnotationsOffset() const;
void SetObject(intptr_t index, const Object& obj) const;
ObjectPtr GetObject(intptr_t index) const;
bool IsNull() const { return data_.IsNull(); }
static ArrayPtr New(Zone* zone,
const TypedDataBase& typed_data,
intptr_t version,
intptr_t num_objects,
intptr_t strings_header_offset,
intptr_t strings_contents_offset,
intptr_t object_offsets_offset,
intptr_t objects_contents_offset,
intptr_t main_offset,
intptr_t num_libraries,
intptr_t library_index_offset,
intptr_t libraries_offset,
intptr_t num_classes,
intptr_t classes_offset,
intptr_t members_offset,
intptr_t num_codes,
intptr_t codes_offset,
intptr_t source_positions_offset,
intptr_t source_files_offset,
intptr_t line_starts_offset,
intptr_t local_variables_offset,
intptr_t annotations_offset,
Heap::Space space);
private:
const Array& data_;
};
class BytecodeReader : public AllStatic {
public:
// Read declaration of the given class.
static void LoadClassDeclaration(const Class& cls);
// Read members of the given class.
static void FinishClassLoading(const Class& cls);
static void ReadParameterCovariance(const Function& function,
BitVector* is_covariant,
BitVector* is_generic_covariant_impl);
// Fills [token_positions] array with all token positions for the given
// script. Resulting array may have duplicates.
static void CollectScriptTokenPositionsFromBytecode(
const Script& interesting_script,
GrowableArray<intptr_t>* token_positions);
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
// Compute local variable descriptors for [function] with [bytecode].
static LocalVarDescriptorsPtr ComputeLocalVarDescriptors(
Zone* zone,
const Function& function,
const Bytecode& bytecode);
#endif
};
class BytecodeSourcePositionsIterator : ValueObject {
// These constants should match corresponding constants in class
// SourcePositions (pkg/dart2bytecode/lib/source_positions.dart).
static const intptr_t kNoSourcePosition = -1;
static const intptr_t kSyntheticFlag = 1 << 0;
static const intptr_t kYieldPointFlag = 1 << 1;
static const intptr_t kNumFlags = 2;
static const intptr_t kFlagMask = (1 << kNumFlags) - 1;
public:
BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
: reader_(TypedDataBase::Handle(zone, bytecode.binary())) {
ASSERT(bytecode.HasSourcePositions());
reader_.set_offset(bytecode.source_positions_binary_offset());
pairs_remaining_ = reader_.ReadUInt();
}
bool MoveNext() {
if (pairs_remaining_ == 0) {
return false;
}
ASSERT(pairs_remaining_ > 0);
--pairs_remaining_;
cur_bci_ += reader_.ReadUInt();
cur_encoded_ += reader_.ReadSLEB128();
if (cur_encoded_ >= 0 || cur_encoded_ == kNoSourcePosition) {
cur_position_ = cur_encoded_;
flags_ = 0;
} else {
const intptr_t value = -cur_encoded_ - 1;
cur_position_ = value >> kNumFlags;
flags_ = value & kFlagMask;
}
return true;
}
uword PcOffset() const { return cur_bci_; }
TokenPosition TokenPos() const {
return ((flags_ & kSyntheticFlag) != 0)
? TokenPosition::Synthetic(cur_position_)
: cur_position_ == kNoSourcePosition
? TokenPosition::kNoSource
: TokenPosition::Deserialize(cur_position_);
}
bool IsYieldPoint() const { return (flags_ & kYieldPointFlag) != 0; }
private:
Reader reader_;
intptr_t pairs_remaining_ = 0;
intptr_t cur_bci_ = 0;
intptr_t cur_encoded_ = 0;
intptr_t cur_position_ = 0;
intptr_t flags_ = 0;
};
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
class BytecodeLocalVariablesIterator : ValueObject {
public:
// These constants should match corresponding constants in
// pkg/dart2bytecode/lib/local_variable_table.dart.
enum {
kInvalid,
kScope,
kVariableDeclaration,
kContextVariable,
};
static const char* kKindNames[];
static const intptr_t kKindMask = 0xF;
static const intptr_t kIsCapturedFlag = 1 << 4;
BytecodeLocalVariablesIterator(Zone* zone, const Bytecode& bytecode)
: reader_(TypedDataBase::Handle(zone, bytecode.binary())),
object_pool_(ObjectPool::Handle(zone, bytecode.object_pool())) {
if (bytecode.HasLocalVariablesInfo()) {
reader_.set_offset(bytecode.local_variables_binary_offset());
entries_remaining_ = reader_.ReadUInt();
}
}
bool MoveNext() {
if (entries_remaining_ <= 0) {
// Finished looking at the last entry, now we're done.
entries_remaining_ = -1;
return false;
}
--entries_remaining_;
cur_kind_and_flags_ = reader_.ReadByte();
cur_start_pc_ += reader_.ReadSLEB128();
switch (Kind()) {
case kScope:
cur_end_pc_ = cur_start_pc_ + reader_.ReadUInt();
cur_index_ = reader_.ReadSLEB128();
cur_token_pos_ = reader_.ReadPosition();
cur_end_token_pos_ = reader_.ReadPosition();
break;
case kVariableDeclaration:
cur_index_ = reader_.ReadSLEB128();
cur_name_ = reader_.ReadUInt();
cur_type_ = reader_.ReadUInt();
cur_declaration_token_pos_ = reader_.ReadPosition();
cur_token_pos_ = reader_.ReadPosition();
break;
case kContextVariable:
cur_index_ = reader_.ReadSLEB128();
break;
}
return true;
}
// Returns true after iterator moved past the last entry and
// MoveNext() returned false.
bool IsDone() const { return entries_remaining_ < 0; }
intptr_t Kind() const { return cur_kind_and_flags_ & kKindMask; }
const char* KindName() const { return kKindNames[Kind()]; }
bool IsScope() const { return Kind() == kScope; }
bool IsVariableDeclaration() const { return Kind() == kVariableDeclaration; }
bool IsContextVariable() const { return Kind() == kContextVariable; }
intptr_t StartPC() const { return cur_start_pc_; }
intptr_t EndPC() const {
ASSERT(IsScope() || IsVariableDeclaration());
return cur_end_pc_;
}
intptr_t ContextLevel() const {
ASSERT(IsScope());
return cur_index_;
}
TokenPosition StartTokenPos() const {
ASSERT(IsScope() || IsVariableDeclaration());
return cur_token_pos_;
}
TokenPosition EndTokenPos() const {
ASSERT(IsScope() || IsVariableDeclaration());
return cur_end_token_pos_;
}
intptr_t Index() const {
ASSERT(IsVariableDeclaration() || IsContextVariable());
return cur_index_;
}
StringPtr Name() const {
ASSERT(IsVariableDeclaration());
return String::RawCast(object_pool_.ObjectAt(cur_name_));
}
AbstractTypePtr Type() const {
ASSERT(IsVariableDeclaration());
return AbstractType::RawCast(object_pool_.ObjectAt(cur_type_));
}
TokenPosition DeclarationTokenPos() const {
ASSERT(IsVariableDeclaration());
return cur_declaration_token_pos_;
}
bool IsCaptured() const {
ASSERT(IsVariableDeclaration());
return (cur_kind_and_flags_ & kIsCapturedFlag) != 0;
}
private:
Reader reader_;
const ObjectPool& object_pool_;
intptr_t entries_remaining_ = 0;
intptr_t cur_kind_and_flags_ = 0;
intptr_t cur_start_pc_ = 0;
intptr_t cur_end_pc_ = 0;
intptr_t cur_index_ = -1;
intptr_t cur_name_ = -1;
intptr_t cur_type_ = -1;
TokenPosition cur_token_pos_ = TokenPosition::kNoSource;
TokenPosition cur_declaration_token_pos_ = TokenPosition::kNoSource;
TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
};
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
} // namespace bytecode
} // namespace dart
#endif // defined(DART_DYNAMIC_MODULES)
#endif // RUNTIME_VM_BYTECODE_READER_H_