Skip to content

Commit 1164ea7

Browse files
alexmarkovCommit Queue
authored andcommitted
[vm,dyn_modules] Support collecting source positions for a script declared in bytecode
TEST=pkg/vm_service/ Change-Id: If9111373f4ddf08bded2a23ab4bb130f1f6ad4a4 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 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436680 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 592e5c1 commit 1164ea7

File tree

6 files changed

+195
-66
lines changed

6 files changed

+195
-66
lines changed

runtime/vm/bytecode_reader.cc

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2563,6 +2563,113 @@ void BytecodeReader::ReadParameterCovariance(
25632563
is_generic_covariant_impl);
25642564
}
25652565

2566+
static void CollectTokenPosition(TokenPosition token_pos,
2567+
GrowableArray<intptr_t>* token_positions) {
2568+
if (!token_pos.IsReal()) {
2569+
return;
2570+
}
2571+
const intptr_t token_pos_value = token_pos.Serialize();
2572+
if (!token_positions->is_empty() &&
2573+
token_positions->Last() == token_pos_value) {
2574+
return;
2575+
}
2576+
token_positions->Add(token_pos_value);
2577+
}
2578+
2579+
static void CollectBytecodeFunctionTokenPositions(
2580+
Zone* zone,
2581+
const Function& function,
2582+
GrowableArray<intptr_t>* token_positions) {
2583+
ASSERT(function.is_declared_in_bytecode());
2584+
CollectTokenPosition(function.token_pos(), token_positions);
2585+
CollectTokenPosition(function.end_token_pos(), token_positions);
2586+
if (!function.HasBytecode()) {
2587+
return;
2588+
}
2589+
Bytecode& bytecode = Bytecode::Handle(zone, function.GetBytecode());
2590+
ASSERT(!bytecode.IsNull());
2591+
if (bytecode.HasSourcePositions()) {
2592+
BytecodeSourcePositionsIterator iter(zone, bytecode);
2593+
while (iter.MoveNext()) {
2594+
CollectTokenPosition(iter.TokenPos(), token_positions);
2595+
}
2596+
if (!function.IsNonImplicitClosureFunction()) {
2597+
// Find closure functions in the object pool.
2598+
const ObjectPool& pool = ObjectPool::Handle(zone, bytecode.object_pool());
2599+
Object& object = Object::Handle(zone);
2600+
for (intptr_t i = 0; i < pool.Length(); i++) {
2601+
ObjectPool::EntryType entry_type = pool.TypeAt(i);
2602+
if (entry_type != ObjectPool::EntryType::kTaggedObject) {
2603+
continue;
2604+
}
2605+
object = pool.ObjectAt(i);
2606+
if (object.IsFunction()) {
2607+
const auto& closure = Function::Cast(object);
2608+
if (closure.IsNonImplicitClosureFunction()) {
2609+
CollectBytecodeFunctionTokenPositions(zone, closure,
2610+
token_positions);
2611+
}
2612+
}
2613+
}
2614+
}
2615+
}
2616+
}
2617+
2618+
void BytecodeReader::CollectScriptTokenPositionsFromBytecode(
2619+
const Script& interesting_script,
2620+
GrowableArray<intptr_t>* token_positions) {
2621+
Thread* thread = Thread::Current();
2622+
Zone* zone = thread->zone();
2623+
2624+
const GrowableObjectArray& libs = GrowableObjectArray::Handle(
2625+
zone, thread->isolate_group()->object_store()->libraries());
2626+
auto& lib = Library::Handle(zone);
2627+
auto& cls = Class::Handle(zone);
2628+
auto& array = Array::Handle(zone);
2629+
auto& function = Function::Handle(zone);
2630+
auto& field = Field::Handle(zone);
2631+
2632+
for (intptr_t i = 0, n = libs.Length(); i < n; ++i) {
2633+
lib ^= libs.At(i);
2634+
cls = lib.toplevel_class();
2635+
if (!cls.is_declared_in_bytecode()) {
2636+
continue;
2637+
}
2638+
ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
2639+
while (it.HasNext()) {
2640+
cls = it.GetNextClass();
2641+
ASSERT(cls.is_declared_in_bytecode());
2642+
if (cls.script() == interesting_script.ptr()) {
2643+
CollectTokenPosition(cls.token_pos(), token_positions);
2644+
CollectTokenPosition(cls.end_token_pos(), token_positions);
2645+
}
2646+
array = cls.fields();
2647+
for (intptr_t i = 0, n = array.Length(); i < n; ++i) {
2648+
field ^= array.At(i);
2649+
if (field.Script() != interesting_script.ptr()) {
2650+
continue;
2651+
}
2652+
CollectTokenPosition(field.token_pos(), token_positions);
2653+
CollectTokenPosition(field.end_token_pos(), token_positions);
2654+
if ((field.is_static() || field.is_late()) &&
2655+
field.has_nontrivial_initializer()) {
2656+
function = field.EnsureInitializerFunction();
2657+
CollectBytecodeFunctionTokenPositions(zone, function,
2658+
token_positions);
2659+
}
2660+
}
2661+
array = cls.current_functions();
2662+
for (intptr_t i = 0, n = array.Length(); i < n; ++i) {
2663+
function ^= array.At(i);
2664+
if (function.script() != interesting_script.ptr()) {
2665+
continue;
2666+
}
2667+
CollectBytecodeFunctionTokenPositions(zone, function, token_positions);
2668+
}
2669+
}
2670+
}
2671+
}
2672+
25662673
} // namespace bytecode
25672674
} // namespace dart
25682675

runtime/vm/bytecode_reader.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,12 @@ class BytecodeReader : public AllStatic {
469469
static void ReadParameterCovariance(const Function& function,
470470
BitVector* is_covariant,
471471
BitVector* is_generic_covariant_impl);
472+
473+
// Fills [token_positions] array with all token positions for the given
474+
// script. Resulting array may have duplicates.
475+
static void CollectScriptTokenPositionsFromBytecode(
476+
const Script& interesting_script,
477+
GrowableArray<intptr_t>* token_positions);
472478
};
473479

474480
class BytecodeSourcePositionsIterator : ValueObject {

runtime/vm/kernel.cc

Lines changed: 14 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -81,42 +81,6 @@ void KernelTokenPositionCollector::RecordTokenPosition(TokenPosition position) {
8181
}
8282
}
8383

84-
static int LowestFirst(const intptr_t* a, const intptr_t* b) {
85-
return *a - *b;
86-
}
87-
88-
/**
89-
* If index exists as sublist in list, sort the sublist from lowest to highest,
90-
* then copy it, as Smis and without duplicates,
91-
* to a new Array in Heap::kOld which is returned.
92-
* Note that the source list is both sorted and de-duplicated as well, but will
93-
* possibly contain duplicate and unsorted data at the end.
94-
* Otherwise (when sublist doesn't exist in list) return new empty array.
95-
*/
96-
static ArrayPtr AsSortedDuplicateFreeArray(GrowableArray<intptr_t>* source) {
97-
intptr_t size = source->length();
98-
if (size == 0) {
99-
return Object::empty_array().ptr();
100-
}
101-
102-
source->Sort(LowestFirst);
103-
104-
intptr_t last = 0;
105-
for (intptr_t current = 1; current < size; ++current) {
106-
if (source->At(last) != source->At(current)) {
107-
(*source)[++last] = source->At(current);
108-
}
109-
}
110-
Array& array_object = Array::Handle();
111-
array_object = Array::New(last + 1, Heap::kOld);
112-
Smi& smi_value = Smi::Handle();
113-
for (intptr_t i = 0; i <= last; ++i) {
114-
smi_value = Smi::New(source->At(i));
115-
array_object.SetAt(i, smi_value);
116-
}
117-
return array_object.ptr();
118-
}
119-
12084
static void CollectKernelLibraryTokenPositions(
12185
const TypedDataView& kernel_data,
12286
const Script& script,
@@ -137,20 +101,18 @@ static void CollectKernelLibraryTokenPositions(
137101
token_position_collector.CollectTokenPositions(kernel_offset);
138102
}
139103

140-
} // namespace kernel
141-
142-
void Script::CollectTokenPositionsFor() const {
104+
void CollectScriptTokenPositionsFromKernel(
105+
const Script& interesting_script,
106+
GrowableArray<intptr_t>* token_positions) {
143107
Thread* thread = Thread::Current();
144108
Zone* zone = thread->zone();
145109

146110
const auto& kernel_info =
147-
KernelProgramInfo::Handle(zone, kernel_program_info());
111+
KernelProgramInfo::Handle(zone, interesting_script.kernel_program_info());
148112

149-
kernel::TranslationHelper helper(thread);
113+
TranslationHelper helper(thread);
150114
helper.InitFromKernelProgramInfo(kernel_info);
151115

152-
GrowableArray<intptr_t> token_positions(10);
153-
154116
auto isolate_group = thread->isolate_group();
155117
const GrowableObjectArray& libs = GrowableObjectArray::Handle(
156118
zone, isolate_group->object_store()->libraries());
@@ -159,8 +121,6 @@ void Script::CollectTokenPositionsFor() const {
159121
Script& entry_script = Script::Handle(zone);
160122
auto& data = TypedDataView::Handle(zone);
161123

162-
auto& interesting_script = *this;
163-
164124
auto& temp_array = Array::Handle(zone);
165125
auto& temp_field = Field::Handle(zone);
166126
auto& temp_function = Function::Handle(zone);
@@ -174,8 +134,8 @@ void Script::CollectTokenPositionsFor() const {
174134
if (entry.IsClass()) {
175135
const Class& klass = Class::Cast(entry);
176136
if (klass.script() == interesting_script.ptr()) {
177-
token_positions.Add(klass.token_pos().Serialize());
178-
token_positions.Add(klass.end_token_pos().Serialize());
137+
token_positions->Add(klass.token_pos().Serialize());
138+
token_positions->Add(klass.end_token_pos().Serialize());
179139
}
180140
if (klass.is_finalized()) {
181141
temp_array = klass.fields();
@@ -193,7 +153,7 @@ void Script::CollectTokenPositionsFor() const {
193153
CollectKernelLibraryTokenPositions(data, interesting_script,
194154
temp_field.kernel_offset(),
195155
temp_field.KernelLibraryOffset(),
196-
zone, &helper, &token_positions);
156+
zone, &helper, token_positions);
197157
}
198158
temp_array = klass.current_functions();
199159
for (intptr_t i = 0; i < temp_array.Length(); ++i) {
@@ -206,7 +166,7 @@ void Script::CollectTokenPositionsFor() const {
206166
CollectKernelLibraryTokenPositions(
207167
data, interesting_script, temp_function.kernel_offset(),
208168
temp_function.KernelLibraryOffset(), zone, &helper,
209-
&token_positions);
169+
token_positions);
210170
}
211171
} else {
212172
// Class isn't finalized yet: read the data attached to it.
@@ -223,7 +183,7 @@ void Script::CollectTokenPositionsFor() const {
223183
}
224184
CollectKernelLibraryTokenPositions(
225185
data, interesting_script, class_offset, library_kernel_offset,
226-
zone, &helper, &token_positions);
186+
zone, &helper, token_positions);
227187
}
228188
} else if (entry.IsFunction()) {
229189
temp_function ^= entry.ptr();
@@ -235,7 +195,7 @@ void Script::CollectTokenPositionsFor() const {
235195
CollectKernelLibraryTokenPositions(data, interesting_script,
236196
temp_function.kernel_offset(),
237197
temp_function.KernelLibraryOffset(),
238-
zone, &helper, &token_positions);
198+
zone, &helper, token_positions);
239199
} else if (entry.IsField()) {
240200
const Field& field = Field::Cast(entry);
241201
if (field.kernel_offset() <= 0) {
@@ -249,17 +209,14 @@ void Script::CollectTokenPositionsFor() const {
249209
data = field.KernelLibrary();
250210
CollectKernelLibraryTokenPositions(
251211
data, interesting_script, field.kernel_offset(),
252-
field.KernelLibraryOffset(), zone, &helper, &token_positions);
212+
field.KernelLibraryOffset(), zone, &helper, token_positions);
253213
}
254214
}
255215
}
256-
257-
Script& script = Script::Handle(zone, interesting_script.ptr());
258-
Array& array_object = Array::Handle(zone);
259-
array_object = kernel::AsSortedDuplicateFreeArray(&token_positions);
260-
script.set_debug_positions(array_object);
261216
}
262217

218+
} // namespace kernel
219+
263220
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
264221
ArrayPtr Script::CollectConstConstructorCoverageFrom() const {
265222
Thread* thread = Thread::Current();

runtime/vm/kernel.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ TableSelectorMetadata* TableSelectorMetadataForProgram(
155155
const KernelProgramInfo& info,
156156
Zone* zone);
157157

158+
// Fills [token_positions] array with all token positions for the given script.
159+
// Resulting array may have duplicates.
160+
void CollectScriptTokenPositionsFromKernel(
161+
const Script& interesting_script,
162+
GrowableArray<intptr_t>* token_positions);
163+
158164
} // namespace kernel
159165
} // namespace dart
160166

runtime/vm/object.cc

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13805,6 +13805,7 @@ GrowableObjectArrayPtr Script::GenerateLineNumberArray() const {
1380513805
const TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
1380613806
intptr_t line_count = line_starts_data.Length();
1380713807
const Array& debug_positions_array = Array::Handle(debug_positions());
13808+
ASSERT(!debug_positions_array.IsNull());
1380813809
intptr_t token_count = debug_positions_array.Length();
1380913810
int token_index = 0;
1381013811

@@ -13886,12 +13887,61 @@ void Script::set_line_starts(const TypedData& value) const {
1388613887
untag()->set_line_starts(value.ptr());
1388713888
}
1388813889

13890+
#if !defined(DART_PRECOMPILED_RUNTIME)
13891+
13892+
static int LowestFirst(const intptr_t* a, const intptr_t* b) {
13893+
return *a - *b;
13894+
}
13895+
13896+
static ArrayPtr SortAndDeduplicate(GrowableArray<intptr_t>* source) {
13897+
intptr_t size = source->length();
13898+
if (size == 0) {
13899+
return Object::empty_array().ptr();
13900+
}
13901+
13902+
source->Sort(LowestFirst);
13903+
13904+
intptr_t last = 0;
13905+
for (intptr_t current = 1; current < size; ++current) {
13906+
if (source->At(last) != source->At(current)) {
13907+
(*source)[++last] = source->At(current);
13908+
}
13909+
}
13910+
Array& array_object = Array::Handle();
13911+
array_object = Array::New(last + 1, Heap::kOld);
13912+
Smi& smi_value = Smi::Handle();
13913+
for (intptr_t i = 0; i <= last; ++i) {
13914+
smi_value = Smi::New(source->At(i));
13915+
array_object.SetAt(i, smi_value);
13916+
}
13917+
return array_object.ptr();
13918+
}
13919+
13920+
void Script::CollectDebugTokenPositions() const {
13921+
GrowableArray<intptr_t> token_positions(10);
13922+
if (kernel_program_info() != Object::null()) {
13923+
kernel::CollectScriptTokenPositionsFromKernel(*this, &token_positions);
13924+
} else {
13925+
#if defined(DART_DYNAMIC_MODULES)
13926+
bytecode::BytecodeReader::CollectScriptTokenPositionsFromBytecode(
13927+
*this, &token_positions);
13928+
#else
13929+
UNREACHABLE();
13930+
#endif
13931+
}
13932+
const auto& debug_positions =
13933+
Array::Handle(SortAndDeduplicate(&token_positions));
13934+
set_debug_positions(debug_positions);
13935+
}
13936+
13937+
#endif // !defined(DART_PRECOMPILED_RUNTIME)
13938+
1388913939
ArrayPtr Script::debug_positions() const {
1389013940
#if !defined(DART_PRECOMPILED_RUNTIME)
1389113941
Array& debug_positions_array = Array::Handle(untag()->debug_positions());
1389213942
if (debug_positions_array.IsNull()) {
1389313943
// This is created lazily. Now we need it.
13894-
CollectTokenPositionsFor();
13944+
CollectDebugTokenPositions();
1389513945
}
1389613946
#endif // !defined(DART_PRECOMPILED_RUNTIME)
1389713947
return untag()->debug_positions();
@@ -13966,7 +14016,7 @@ bool Script::GetTokenLocation(const TokenPosition& token_pos,
1396614016
if (line_starts_data.IsNull()) return false;
1396714017
LineStartsReader line_starts_reader(line_starts_data);
1396814018
return line_starts_reader.LocationForPosition(token_pos.Pos(), line, column);
13969-
#endif // defined(DART_PRECOMPILED_RUNTIME)
14019+
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
1397014020
}
1397114021

1397214022
intptr_t Script::GetTokenLength(const TokenPosition& token_pos) const {
@@ -13994,14 +14044,15 @@ bool Script::TokenRangeAtLine(intptr_t line_number,
1399414044
TokenPosition* first_token_index,
1399514045
TokenPosition* last_token_index) const {
1399614046
ASSERT(first_token_index != nullptr && last_token_index != nullptr);
13997-
#if defined(DART_PRECOMPILED_RUNTIME)
14047+
#if defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
1399814048
// Scripts in the AOT snapshot do not have a line starts array.
1399914049
return false;
1400014050
#else
1400114051
// Line numbers are 1-indexed.
1400214052
if (line_number <= 0) return false;
1400314053
Zone* zone = Thread::Current()->zone();
1400414054
const TypedData& line_starts_data = TypedData::Handle(zone, line_starts());
14055+
if (line_starts_data.IsNull()) return false;
1400514056
LineStartsReader line_starts_reader(line_starts_data);
1400614057
if (!line_starts_reader.TokenRangeAtLine(line_number, first_token_index,
1400714058
last_token_index)) {
@@ -14012,6 +14063,7 @@ bool Script::TokenRangeAtLine(intptr_t line_number,
1401214063
if (!HasSource()) {
1401314064
Smi& value = Smi::Handle(zone);
1401414065
const Array& debug_positions_array = Array::Handle(zone, debug_positions());
14066+
ASSERT(!debug_positions_array.IsNull());
1401514067
value ^= debug_positions_array.At(debug_positions_array.Length() - 1);
1401614068
source_length = value.Value();
1401714069
} else {
@@ -14021,7 +14073,7 @@ bool Script::TokenRangeAtLine(intptr_t line_number,
1402114073
ASSERT(last_token_index->Serialize() <= source_length);
1402214074
#endif
1402314075
return true;
14024-
#endif // !defined(DART_PRECOMPILED_RUNTIME)
14076+
#endif // defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_DYNAMIC_MODULES)
1402514077
}
1402614078

1402714079
// Returns the index in the given source string for the given (1-based) absolute

0 commit comments

Comments
 (0)