[vm/bytecode] Support source positions when executing bytecode
This includes both interpreted and compiled bytecode.
Change-Id: I6309ec4f0687f68caf6260cc57dacf94f027177d
Reviewed-on: https://dart-review.googlesource.com/c/84481
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 2917008..56c49bb 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -337,6 +337,26 @@
return bit << n;
}
+ // Decode integer in SLEB128 format from |data| and update |byte_index|.
+ static intptr_t DecodeSLEB128(const uint8_t* data,
+ const intptr_t data_length,
+ intptr_t* byte_index) {
+ ASSERT(*byte_index < data_length);
+ uword shift = 0;
+ intptr_t value = 0;
+ uint8_t part = 0;
+ do {
+ part = data[(*byte_index)++];
+ value |= static_cast<intptr_t>(part & 0x7f) << shift;
+ shift += 7;
+ } while ((part & 0x80) != 0);
+
+ if ((shift < (sizeof(value) * 8)) && ((part & 0x40) != 0)) {
+ value |= static_cast<intptr_t>(kUwordMax << shift);
+ }
+ return value;
+ }
+
static char* StrError(int err, char* buffer, size_t bufsize);
// Not all platforms support strndup.
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 68fc310..1cd8950 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1756,6 +1756,7 @@
for (RawObject** p = from; p <= to; p++) {
s->WriteRef(*p);
}
+ s->Write<int32_t>(bytecode->ptr()->source_positions_binary_offset_);
}
}
@@ -1791,6 +1792,7 @@
for (RawObject** p = from; p <= to; p++) {
*p = d->ReadRef();
}
+ bytecode->ptr()->source_positions_binary_offset_ = d->Read<int32_t>();
}
}
};
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 5692014..ecf4f80 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -5,6 +5,7 @@
#include "vm/compiler/frontend/bytecode_flow_graph_builder.h"
#include "vm/compiler/backend/il_printer.h"
+#include "vm/compiler/frontend/bytecode_reader.h"
#include "vm/compiler/frontend/prologue_builder.h"
#include "vm/compiler/jit/compiler.h"
#include "vm/object_store.h"
@@ -1473,6 +1474,9 @@
CollectControlFlow(descriptors, handlers, graph_entry);
+ kernel::BytecodeSourcePositionsIterator source_pos_iter(Z, bytecode);
+ bool update_position = source_pos_iter.MoveNext();
+
code_ = Fragment(normal_entry);
for (pc_ = 0; pc_ < bytecode_length_; ++pc_) {
@@ -1495,6 +1499,12 @@
ASSERT(!code_.is_closed());
}
+ while (update_position &&
+ pc_ >= source_pos_iter.BytecodeInstructionIndex()) {
+ position_ = source_pos_iter.TokenPos();
+ update_position = source_pos_iter.MoveNext();
+ }
+
BuildInstruction(KernelBytecode::DecodeOpcode(bytecode_instr_));
if (code_.is_closed()) {
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index d2fdfee..b5f2acc 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -103,6 +103,8 @@
const Bytecode& bytecode =
Bytecode::Handle(helper_->zone_, ReadBytecode(pool));
function.AttachBytecode(bytecode);
+ ASSERT(bytecode.GetBinary(helper_->zone_) ==
+ helper_->reader_.typed_data()->raw());
ReadExceptionsTable(bytecode, has_exceptions_table);
@@ -148,8 +150,9 @@
// Read closure bytecode and attach to closure function.
closure_bytecode = ReadBytecode(pool);
closure.AttachBytecode(closure_bytecode);
+ ASSERT(bytecode.GetBinary(helper_->zone_) ==
+ helper_->reader_.typed_data()->raw());
- // Read closure exceptions table.
ReadExceptionsTable(closure_bytecode, has_exceptions_table);
ReadSourcePositions(closure_bytecode, has_source_positions);
@@ -736,8 +739,9 @@
return;
}
- // TODO(alexmarkov): store offset of source positions into Bytecode object.
- helper_->SkipBytes(helper_->reader_.ReadUInt());
+ intptr_t length = helper_->reader_.ReadUInt();
+ bytecode.set_source_positions_binary_offset(helper_->reader_.offset());
+ helper_->SkipBytes(length);
}
RawTypedData* BytecodeMetadataHelper::NativeEntry(const Function& function,
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 8dbc003..079316c 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -6,6 +6,7 @@
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
#include "vm/compiler/frontend/kernel_translation_helper.h"
+#include "vm/constants_kbc.h"
#include "vm/object.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
@@ -52,6 +53,46 @@
const Function& function);
};
+class BytecodeSourcePositionsIterator : ValueObject {
+ public:
+ BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
+ : reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))),
+ pairs_remaining_(0),
+ cur_bci_(0),
+ cur_token_pos_(TokenPosition::kNoSource.value()) {
+ if (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_token_pos_ += reader_.ReadSLEB128();
+ return true;
+ }
+
+ intptr_t BytecodeInstructionIndex() const { return cur_bci_; }
+
+ uword PcOffset() const {
+ return KernelBytecode::BytecodePcToOffset(BytecodeInstructionIndex(),
+ /* is_return_address = */ true);
+ }
+
+ TokenPosition TokenPos() const { return TokenPosition(cur_token_pos_); }
+
+ private:
+ Reader reader_;
+ intptr_t pairs_remaining_;
+ intptr_t cur_bci_;
+ intptr_t cur_token_pos_;
+};
+
} // namespace kernel
} // namespace dart
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index cad0c46..3b7d847 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -238,6 +238,11 @@
}
}
+ intptr_t ReadSLEB128() {
+ const uint8_t* buffer = this->buffer();
+ return Utils::DecodeSLEB128(buffer, size_, &offset_);
+ }
+
/**
* Read and return a TokenPosition from this reader.
*/
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index a82b1f4..4d20ed2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -12722,26 +12722,6 @@
}
}
-// Decode integer in SLEB128 format from |data| and update |byte_index|.
-static intptr_t DecodeSLEB128(const uint8_t* data,
- const intptr_t data_length,
- intptr_t* byte_index) {
- ASSERT(*byte_index < data_length);
- uword shift = 0;
- intptr_t value = 0;
- uint8_t part = 0;
- do {
- part = data[(*byte_index)++];
- value |= static_cast<intptr_t>(part & 0x7f) << shift;
- shift += 7;
- } while ((part & 0x80) != 0);
-
- if ((shift < (sizeof(value) * 8)) && ((part & 0x40) != 0)) {
- value |= static_cast<intptr_t>(kUwordMax << shift);
- }
- return value;
-}
-
// Encode integer in SLEB128 format.
void PcDescriptors::EncodeInteger(GrowableArray<uint8_t>* data,
intptr_t value) {
@@ -12752,7 +12732,7 @@
intptr_t PcDescriptors::DecodeInteger(intptr_t* byte_index) const {
NoSafepointScope no_safepoint;
const uint8_t* data = raw_ptr()->data();
- return DecodeSLEB128(data, Length(), byte_index);
+ return Utils::DecodeSLEB128(data, Length(), byte_index);
}
RawObjectPool* ObjectPool::New(intptr_t len) {
@@ -15361,11 +15341,43 @@
result.set_pc_descriptors(Object::empty_descriptors());
result.set_instructions(instructions);
result.set_object_pool(object_pool);
+ result.set_source_positions_binary_offset(0);
}
return result.raw();
}
#endif
+RawExternalTypedData* Bytecode::GetBinary(Zone* zone) const {
+ const Function& func = Function::Handle(zone, function());
+ const Script& script = Script::Handle(zone, func.script());
+ const KernelProgramInfo& info =
+ KernelProgramInfo::Handle(zone, script.kernel_program_info());
+ return info.metadata_payloads();
+}
+
+TokenPosition Bytecode::GetTokenIndexOfPC(uword pc) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+ UNREACHABLE();
+#else
+ if (!HasSourcePositions()) {
+ return TokenPosition::kNoSource;
+ }
+ uword pc_offset = pc - PayloadStart();
+ // PC could equal to bytecode size if the last instruction is Throw.
+ ASSERT(pc_offset <= static_cast<uword>(Size()));
+ kernel::BytecodeSourcePositionsIterator iter(Thread::Current()->zone(),
+ *this);
+ TokenPosition token_pos = TokenPosition::kNoSource;
+ while (iter.MoveNext()) {
+ if (pc_offset < iter.PcOffset()) {
+ break;
+ }
+ token_pos = iter.TokenPos();
+ }
+ return token_pos;
+#endif
+}
+
const char* Bytecode::ToCString() const {
return Thread::Current()->zone()->PrintToString("Bytecode(%s)",
QualifiedName());
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 6f5a157..5ac93eb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -5341,9 +5341,18 @@
const ObjectPool& object_pool);
#endif
- TokenPosition GetTokenIndexOfPC(uword pc) const {
- // TODO(alexmarkov): implement.
- return TokenPosition::kNoSource;
+ RawExternalTypedData* GetBinary(Zone* zone) const;
+
+ TokenPosition GetTokenIndexOfPC(uword pc) const;
+
+ intptr_t source_positions_binary_offset() const {
+ return raw_ptr()->source_positions_binary_offset_;
+ }
+ void set_source_positions_binary_offset(intptr_t value) const {
+ StoreNonPointer(&raw_ptr()->source_positions_binary_offset_, value);
+ }
+ bool HasSourcePositions() const {
+ return (source_positions_binary_offset() != 0);
}
const char* Name() const;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ce9a94a..3b4717d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1488,6 +1488,8 @@
RawPcDescriptors* pc_descriptors_;
VISIT_TO(RawObject*, pc_descriptors_);
+ intptr_t source_positions_binary_offset_;
+
friend class Function;
friend class StackFrame;
};
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 59ed934..a43e7d6 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -456,8 +456,11 @@
TokenPosition StackFrame::GetTokenPos() const {
if (is_interpreted()) {
- // TODO(alexmarkov): Support source information in bytecode.
- return TokenPosition::kNoSource;
+ const Bytecode& bytecode = Bytecode::Handle(LookupDartBytecode());
+ if (bytecode.IsNull()) {
+ return TokenPosition::kNoSource; // Stub frames do not have token_pos.
+ }
+ return bytecode.GetTokenIndexOfPC(pc());
}
const Code& code = Code::Handle(LookupDartCode());
if (code.IsNull()) {
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 26ee8bd..abdaa8a 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -347,11 +347,9 @@
const_dynamic_type_literal_test/02: Pass
map_literal3_test/01: Pass
map_literal3_test/02: Pass
-vm/bool_check_stack_traces_test/01: RuntimeError # No support for line numbers in stacktraces
-vm/bool_check_stack_traces_test/none: RuntimeError # No support for line numbers in stacktraces
-vm/causal_async_exception_stack2_test: RuntimeError # No support for line numbers in stacktraces
-vm/causal_async_exception_stack_test: RuntimeError # No support for line numbers in stacktraces
-vm/regress_28325_test: RuntimeError # No support for line numbers in stacktraces
+vm/bool_check_stack_traces_test/02: Pass
+vm/causal_async_exception_stack2_test: RuntimeError # Please triage
+vm/causal_async_exception_stack_test: RuntimeError # Please triage
[ $compiler != dartkb && $compiler != dartkp && $fasta ]
vm/symbols_test/01: MissingCompileTimeError
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 32b0de8..8fe7756 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -1108,6 +1108,7 @@
if (_configuration.useKernelBytecode) {
args.add('--gen-bytecode');
args.add('--drop-ast');
+ args.add('--emit-bytecode-source-positions');
}
return Command.vmKernelCompilation(dillFile, true, bootstrapDependencies(),