1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#if !defined(DART_PRECOMPILED_RUNTIME)
6
7#include "vm/kernel.h"
8
9#include "vm/bit_vector.h"
10#include "vm/compiler/frontend/constant_reader.h"
11#include "vm/compiler/frontend/kernel_translation_helper.h"
12#include "vm/compiler/jit/compiler.h"
13#include "vm/longjump.h"
14#include "vm/object_store.h"
15#include "vm/parser.h" // For Parser::kParameter* constants.
16#include "vm/stack_frame.h"
17
18
19namespace dart {
20namespace kernel {
21
22KernelLineStartsReader::KernelLineStartsReader(
23 const dart::TypedData& line_starts_data,
24 dart::Zone* zone)
25 : line_starts_data_(line_starts_data) {
26 TypedDataElementType type = line_starts_data_.ElementType();
27 if (type == kUint16ArrayElement) {
28 helper_ = new KernelUint16LineStartsHelper();
29 } else if (type == kUint32ArrayElement) {
30 helper_ = new KernelUint32LineStartsHelper();
31 } else {
32 UNREACHABLE();
33 }
34}
35
36uint32_t KernelLineStartsReader::MaxPosition() const {
37 const intptr_t line_count = line_starts_data_.Length();
38 if (line_count == 0) {
39 return 0;
40 }
41 return helper_->At(data: line_starts_data_, index: line_count - 1);
42}
43
44bool KernelLineStartsReader::LocationForPosition(intptr_t position,
45 intptr_t* line,
46 intptr_t* col) const {
47 const intptr_t line_count = line_starts_data_.Length();
48 if (position < 0 || static_cast<uint32_t>(position) > MaxPosition() ||
49 line_count == 0) {
50 return false;
51 }
52
53 intptr_t lo = 0;
54 intptr_t hi = line_count;
55 while (hi > lo + 1) {
56 const intptr_t mid = lo + (hi - lo) / 2;
57 const intptr_t mid_position = helper_->At(data: line_starts_data_, index: mid);
58 if (mid_position > position) {
59 hi = mid;
60 } else {
61 lo = mid;
62 }
63 }
64 *line = lo + 1;
65 if (col != nullptr) {
66 *col = position - helper_->At(data: line_starts_data_, index: lo) + 1;
67 }
68
69 return true;
70}
71
72bool KernelLineStartsReader::TokenRangeAtLine(
73 intptr_t line_number,
74 TokenPosition* first_token_index,
75 TokenPosition* last_token_index) const {
76 const intptr_t line_count = line_starts_data_.Length();
77 if (line_number <= 0 || line_number > line_count) {
78 return false;
79 }
80 *first_token_index = dart::TokenPosition::Deserialize(
81 value: helper_->At(data: line_starts_data_, index: line_number - 1));
82 if (line_number == line_count) {
83 *last_token_index = *first_token_index;
84 } else {
85 *last_token_index = dart::TokenPosition::Deserialize(
86 value: helper_->At(data: line_starts_data_, index: line_number) - 1);
87 }
88 return true;
89}
90
91uint32_t KernelLineStartsReader::KernelUint16LineStartsHelper::At(
92 const dart::TypedData& data,
93 intptr_t index) const {
94 return data.GetUint16(byte_offset: index << 1);
95}
96
97uint32_t KernelLineStartsReader::KernelUint32LineStartsHelper::At(
98 const dart::TypedData& data,
99 intptr_t index) const {
100 return data.GetUint32(byte_offset: index << 2);
101}
102
103class KernelTokenPositionCollector : public KernelReaderHelper {
104 public:
105 KernelTokenPositionCollector(
106 Zone* zone,
107 TranslationHelper* translation_helper,
108 const Script& script,
109 const TypedDataView& data,
110 intptr_t data_program_offset,
111 intptr_t initial_script_index,
112 intptr_t record_for_script_id,
113 GrowableArray<intptr_t>* record_token_positions_into)
114 : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
115 current_script_id_(initial_script_index),
116 record_for_script_id_(record_for_script_id),
117 record_token_positions_into_(record_token_positions_into) {}
118
119 void CollectTokenPositions(intptr_t kernel_offset);
120
121 void RecordTokenPosition(TokenPosition position) override;
122
123 void set_current_script_id(intptr_t id) override { current_script_id_ = id; }
124
125 private:
126 intptr_t current_script_id_;
127 intptr_t record_for_script_id_;
128 GrowableArray<intptr_t>* record_token_positions_into_;
129
130 DISALLOW_COPY_AND_ASSIGN(KernelTokenPositionCollector);
131};
132
133void KernelTokenPositionCollector::CollectTokenPositions(
134 intptr_t kernel_offset) {
135 SetOffset(kernel_offset);
136
137 const Tag tag = PeekTag();
138 if (tag == kProcedure) {
139 ProcedureHelper procedure_helper(this);
140 procedure_helper.ReadUntilExcluding(field: ProcedureHelper::kEnd);
141 } else if (tag == kConstructor) {
142 ConstructorHelper constructor_helper(this);
143 constructor_helper.ReadUntilExcluding(field: ConstructorHelper::kEnd);
144 } else if (tag == kFunctionNode) {
145 FunctionNodeHelper function_node_helper(this);
146 function_node_helper.ReadUntilExcluding(field: FunctionNodeHelper::kEnd);
147 } else if (tag == kField) {
148 FieldHelper field_helper(this);
149 field_helper.ReadUntilExcluding(field: FieldHelper::kEnd);
150 } else if (tag == kClass) {
151 ClassHelper class_helper(this);
152 class_helper.ReadUntilExcluding(field: ClassHelper::kEnd);
153 } else {
154 ReportUnexpectedTag(variant: "a class or a member", tag);
155 UNREACHABLE();
156 }
157}
158
159void KernelTokenPositionCollector::RecordTokenPosition(TokenPosition position) {
160 if (record_for_script_id_ == current_script_id_ &&
161 record_token_positions_into_ != nullptr && position.IsReal()) {
162 record_token_positions_into_->Add(value: position.Serialize());
163 }
164}
165
166static int LowestFirst(const intptr_t* a, const intptr_t* b) {
167 return *a - *b;
168}
169
170/**
171 * If index exists as sublist in list, sort the sublist from lowest to highest,
172 * then copy it, as Smis and without duplicates,
173 * to a new Array in Heap::kOld which is returned.
174 * Note that the source list is both sorted and de-duplicated as well, but will
175 * possibly contain duplicate and unsorted data at the end.
176 * Otherwise (when sublist doesn't exist in list) return new empty array.
177 */
178static ArrayPtr AsSortedDuplicateFreeArray(GrowableArray<intptr_t>* source) {
179 intptr_t size = source->length();
180 if (size == 0) {
181 return Object::empty_array().ptr();
182 }
183
184 source->Sort(compare: LowestFirst);
185
186 intptr_t last = 0;
187 for (intptr_t current = 1; current < size; ++current) {
188 if (source->At(index: last) != source->At(index: current)) {
189 (*source)[++last] = source->At(index: current);
190 }
191 }
192 Array& array_object = Array::Handle();
193 array_object = Array::New(len: last + 1, space: Heap::kOld);
194 Smi& smi_value = Smi::Handle();
195 for (intptr_t i = 0; i <= last; ++i) {
196 smi_value = Smi::New(value: source->At(index: i));
197 array_object.SetAt(index: i, value: smi_value);
198 }
199 return array_object.ptr();
200}
201
202static void CollectKernelLibraryTokenPositions(
203 const TypedDataView& kernel_data,
204 const Script& script,
205 intptr_t kernel_offset,
206 intptr_t data_kernel_offset,
207 Zone* zone,
208 TranslationHelper* helper,
209 GrowableArray<intptr_t>* token_positions) {
210 if (kernel_data.IsNull()) {
211 return;
212 }
213
214 KernelTokenPositionCollector token_position_collector(
215 zone, helper, script, kernel_data, data_kernel_offset,
216 script.kernel_script_index(), script.kernel_script_index(),
217 token_positions);
218
219 token_position_collector.CollectTokenPositions(kernel_offset);
220}
221
222} // namespace kernel
223
224void Script::CollectTokenPositionsFor() const {
225 Thread* thread = Thread::Current();
226 Zone* zone = thread->zone();
227
228 const auto& kernel_info =
229 KernelProgramInfo::Handle(zone, ptr: kernel_program_info());
230
231 kernel::TranslationHelper helper(thread);
232 helper.InitFromKernelProgramInfo(info: kernel_info);
233
234 GrowableArray<intptr_t> token_positions(10);
235
236 auto isolate_group = thread->isolate_group();
237 const GrowableObjectArray& libs = GrowableObjectArray::Handle(
238 zone, ptr: isolate_group->object_store()->libraries());
239 Library& lib = Library::Handle(zone);
240 Object& entry = Object::Handle(zone);
241 Script& entry_script = Script::Handle(zone);
242 auto& data = TypedDataView::Handle(zone);
243
244 auto& interesting_script = *this;
245
246 auto& temp_array = Array::Handle(zone);
247 auto& temp_field = Field::Handle(zone);
248 auto& temp_function = Function::Handle(zone);
249 for (intptr_t i = 0; i < libs.Length(); i++) {
250 lib ^= libs.At(index: i);
251 lib.EnsureTopLevelClassIsFinalized();
252 DictionaryIterator it(lib);
253 while (it.HasNext()) {
254 entry = it.GetNext();
255 data = TypedDataView::null();
256 if (entry.IsClass()) {
257 const Class& klass = Class::Cast(obj: entry);
258 if (klass.script() == interesting_script.ptr()) {
259 token_positions.Add(value: klass.token_pos().Serialize());
260 token_positions.Add(value: klass.end_token_pos().Serialize());
261 }
262 if (klass.is_finalized()) {
263 temp_array = klass.fields();
264 for (intptr_t i = 0; i < temp_array.Length(); ++i) {
265 temp_field ^= temp_array.At(index: i);
266 if (temp_field.kernel_offset() <= 0) {
267 // Skip artificially injected fields.
268 continue;
269 }
270 entry_script = temp_field.Script();
271 if (entry_script.ptr() != interesting_script.ptr()) {
272 continue;
273 }
274 data = temp_field.KernelLibrary();
275 CollectKernelLibraryTokenPositions(kernel_data: data, script: interesting_script,
276 kernel_offset: temp_field.kernel_offset(),
277 data_kernel_offset: temp_field.KernelLibraryOffset(),
278 zone, helper: &helper, token_positions: &token_positions);
279 }
280 temp_array = klass.current_functions();
281 for (intptr_t i = 0; i < temp_array.Length(); ++i) {
282 temp_function ^= temp_array.At(index: i);
283 entry_script = temp_function.script();
284 if (entry_script.ptr() != interesting_script.ptr()) {
285 continue;
286 }
287 data = temp_function.KernelLibrary();
288 CollectKernelLibraryTokenPositions(
289 kernel_data: data, script: interesting_script, kernel_offset: temp_function.kernel_offset(),
290 data_kernel_offset: temp_function.KernelLibraryOffset(), zone, helper: &helper,
291 token_positions: &token_positions);
292 }
293 } else {
294 // Class isn't finalized yet: read the data attached to it.
295 ASSERT(klass.kernel_offset() > 0);
296 data = lib.KernelLibrary();
297 ASSERT(!data.IsNull());
298 const intptr_t library_kernel_offset = lib.KernelLibraryOffset();
299 ASSERT(library_kernel_offset > 0);
300 const intptr_t class_offset = klass.kernel_offset();
301
302 entry_script = klass.script();
303 if (entry_script.ptr() != interesting_script.ptr()) {
304 continue;
305 }
306 CollectKernelLibraryTokenPositions(
307 kernel_data: data, script: interesting_script, kernel_offset: class_offset, data_kernel_offset: library_kernel_offset,
308 zone, helper: &helper, token_positions: &token_positions);
309 }
310 } else if (entry.IsFunction()) {
311 temp_function ^= entry.ptr();
312 entry_script = temp_function.script();
313 if (entry_script.ptr() != interesting_script.ptr()) {
314 continue;
315 }
316 data = temp_function.KernelLibrary();
317 CollectKernelLibraryTokenPositions(kernel_data: data, script: interesting_script,
318 kernel_offset: temp_function.kernel_offset(),
319 data_kernel_offset: temp_function.KernelLibraryOffset(),
320 zone, helper: &helper, token_positions: &token_positions);
321 } else if (entry.IsField()) {
322 const Field& field = Field::Cast(obj: entry);
323 if (field.kernel_offset() <= 0) {
324 // Skip artificially injected fields.
325 continue;
326 }
327 entry_script = field.Script();
328 if (entry_script.ptr() != interesting_script.ptr()) {
329 continue;
330 }
331 data = field.KernelLibrary();
332 CollectKernelLibraryTokenPositions(
333 kernel_data: data, script: interesting_script, kernel_offset: field.kernel_offset(),
334 data_kernel_offset: field.KernelLibraryOffset(), zone, helper: &helper, token_positions: &token_positions);
335 }
336 }
337 }
338
339 Script& script = Script::Handle(zone, ptr: interesting_script.ptr());
340 Array& array_object = Array::Handle(zone);
341 array_object = kernel::AsSortedDuplicateFreeArray(source: &token_positions);
342 script.set_debug_positions(array_object);
343}
344
345#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
346ArrayPtr Script::CollectConstConstructorCoverageFrom() const {
347 Thread* thread = Thread::Current();
348 Zone* zone = thread->zone();
349 kernel::TranslationHelper helper(thread);
350
351 const auto& interesting_script = *this;
352
353 const auto& kernel_info =
354 KernelProgramInfo::Handle(zone, ptr: kernel_program_info());
355 helper.InitFromKernelProgramInfo(info: kernel_info);
356
357 const auto& data =
358 TypedDataView::Handle(zone, ptr: interesting_script.constant_coverage());
359
360 kernel::KernelReaderHelper kernel_reader(zone, &helper, data, 0);
361
362 // Read "constant coverage constructors".
363 const intptr_t constant_coverage_constructors =
364 kernel_reader.ReadListLength();
365 const Array& constructors =
366 Array::Handle(ptr: Array::New(len: constant_coverage_constructors));
367 for (intptr_t i = 0; i < constant_coverage_constructors; ++i) {
368 kernel::NameIndex kernel_name = kernel_reader.ReadCanonicalNameReference();
369 Class& klass = Class::ZoneHandle(
370 zone,
371 ptr: helper.LookupClassByKernelClass(klass: helper.EnclosingName(name: kernel_name)));
372 const Function& target = Function::ZoneHandle(
373 zone, ptr: helper.LookupConstructorByKernelConstructor(owner: klass, constructor: kernel_name));
374 constructors.SetAt(index: i, value: target);
375 }
376 return constructors.ptr();
377}
378#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
379
380namespace kernel {
381
382ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field) {
383 ASSERT(field.is_static() && field.is_const());
384
385 LongJumpScope jump;
386 if (setjmp(*jump.Set()) == 0) {
387 Thread* thread = Thread::Current();
388 Zone* zone = thread->zone();
389 TranslationHelper helper(thread);
390 auto& kernel_program_info =
391 KernelProgramInfo::Handle(zone, ptr: field.KernelProgramInfo());
392 helper.InitFromKernelProgramInfo(info: kernel_program_info);
393
394 const Class& owner_class = Class::Handle(zone, ptr: field.Owner());
395 ActiveClass active_class;
396 ActiveClassScope active_class_scope(&active_class, &owner_class);
397
398 KernelReaderHelper kernel_reader(
399 zone, &helper, TypedDataView::Handle(zone, ptr: field.KernelLibrary()),
400 field.KernelLibraryOffset());
401 kernel_reader.SetOffset(field.kernel_offset());
402 ConstantReader constant_reader(&kernel_reader, &active_class);
403
404 FieldHelper field_helper(&kernel_reader);
405 field_helper.ReadUntilExcluding(field: FieldHelper::kInitializer);
406 ASSERT(field_helper.IsConst());
407
408 return constant_reader.ReadConstantInitializer();
409 } else {
410 return Thread::Current()->StealStickyError();
411 }
412}
413
414class MetadataEvaluator : public KernelReaderHelper {
415 public:
416 MetadataEvaluator(Zone* zone,
417 TranslationHelper* translation_helper,
418 const TypedDataView& data,
419 intptr_t data_program_offset,
420 ActiveClass* active_class)
421 : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
422 constant_reader_(this, active_class) {}
423
424 ObjectPtr EvaluateMetadata(intptr_t kernel_offset,
425 bool is_annotations_offset) {
426 SetOffset(kernel_offset);
427
428 // Library and LibraryDependency objects do not have a tag in kernel binary.
429 // Synthetic metadata fields corresponding to these objects keep kernel
430 // offset of annotations list instead of annotated object.
431 if (!is_annotations_offset) {
432 const Tag tag = PeekTag();
433
434 if (tag == kClass) {
435 ClassHelper class_helper(this);
436 class_helper.ReadUntilExcluding(field: ClassHelper::kAnnotations);
437 } else if (tag == kProcedure) {
438 ProcedureHelper procedure_helper(this);
439 procedure_helper.ReadUntilExcluding(field: ProcedureHelper::kAnnotations);
440 } else if (tag == kField) {
441 FieldHelper field_helper(this);
442 field_helper.ReadUntilExcluding(field: FieldHelper::kAnnotations);
443 } else if (tag == kConstructor) {
444 ConstructorHelper constructor_helper(this);
445 constructor_helper.ReadUntilExcluding(field: ConstructorHelper::kAnnotations);
446 } else if (tag == kFunctionDeclaration) {
447 ReadTag();
448 ReadPosition(); // fileOffset
449 VariableDeclarationHelper variable_declaration_helper(this);
450 variable_declaration_helper.ReadUntilExcluding(
451 field: VariableDeclarationHelper::kAnnotations);
452 } else {
453 FATAL("No support for metadata on this type of kernel node: %" Pd32
454 "\n",
455 tag);
456 }
457 }
458
459 return constant_reader_.ReadAnnotations();
460 }
461
462 private:
463 ConstantReader constant_reader_;
464
465 DISALLOW_COPY_AND_ASSIGN(MetadataEvaluator);
466};
467
468ObjectPtr EvaluateMetadata(const Library& library,
469 intptr_t kernel_offset,
470 bool is_annotations_offset) {
471 LongJumpScope jump;
472 if (setjmp(*jump.Set()) == 0) {
473 Thread* thread = Thread::Current();
474 Zone* zone = thread->zone();
475 TranslationHelper helper(thread);
476 const auto& kernel_info =
477 KernelProgramInfo::Handle(zone, ptr: library.kernel_program_info());
478 helper.InitFromKernelProgramInfo(info: kernel_info);
479
480 const Class& owner_class = Class::Handle(zone, ptr: library.toplevel_class());
481 ActiveClass active_class;
482 ActiveClassScope active_class_scope(&active_class, &owner_class);
483
484 MetadataEvaluator metadata_evaluator(
485 zone, &helper, TypedDataView::Handle(zone, ptr: library.KernelLibrary()),
486 library.KernelLibraryOffset(), &active_class);
487
488 return metadata_evaluator.EvaluateMetadata(kernel_offset,
489 is_annotations_offset);
490
491 } else {
492 return Thread::Current()->StealStickyError();
493 }
494}
495
496class ParameterDescriptorBuilder : public KernelReaderHelper {
497 public:
498 ParameterDescriptorBuilder(TranslationHelper* translation_helper,
499 Zone* zone,
500 const TypedDataView& data,
501 intptr_t data_program_offset,
502 ActiveClass* active_class)
503 : KernelReaderHelper(zone, translation_helper, data, data_program_offset),
504 constant_reader_(this, active_class) {}
505
506 ObjectPtr BuildParameterDescriptor(const Function& function);
507
508 private:
509 ConstantReader constant_reader_;
510
511 DISALLOW_COPY_AND_ASSIGN(ParameterDescriptorBuilder);
512};
513
514ObjectPtr ParameterDescriptorBuilder::BuildParameterDescriptor(
515 const Function& function) {
516 SetOffset(function.kernel_offset());
517 ReadUntilFunctionNode();
518 FunctionNodeHelper function_node_helper(this);
519 function_node_helper.ReadUntilExcluding(
520 field: FunctionNodeHelper::kPositionalParameters);
521 intptr_t param_count = function_node_helper.total_parameter_count_;
522 intptr_t positional_count = ReadListLength(); // read list length.
523 intptr_t named_parameter_count = param_count - positional_count;
524
525 const Array& param_descriptor = Array::Handle(
526 ptr: Array::New(len: param_count * Parser::kParameterEntrySize, space: Heap::kOld));
527 for (intptr_t i = 0; i < param_count; ++i) {
528 const intptr_t entry_start = i * Parser::kParameterEntrySize;
529
530 if (i == positional_count) {
531 intptr_t named_parameter_count_check =
532 ReadListLength(); // read list length.
533 ASSERT(named_parameter_count_check == named_parameter_count);
534 }
535
536 // Read ith variable declaration.
537 intptr_t param_kernel_offset = reader_.offset();
538 VariableDeclarationHelper helper(this);
539 helper.ReadUntilExcluding(field: VariableDeclarationHelper::kInitializer);
540 param_descriptor.SetAt(index: entry_start + Parser::kParameterIsFinalOffset,
541 value: helper.IsFinal() ? Bool::True() : Bool::False());
542
543 Tag tag = ReadTag(); // read (first part of) initializer.
544 if ((tag == kSomething) && !function.is_abstract()) {
545 // This will read the initializer.
546 Instance& constant = Instance::ZoneHandle(
547 zone: zone_, ptr: constant_reader_.ReadConstantExpression());
548 param_descriptor.SetAt(index: entry_start + Parser::kParameterDefaultValueOffset,
549 value: constant);
550 } else {
551 if (tag == kSomething) {
552 SkipExpression(); // Skip initializer.
553 }
554 param_descriptor.SetAt(index: entry_start + Parser::kParameterDefaultValueOffset,
555 value: Object::null_instance());
556 }
557
558 if (FLAG_enable_mirrors && (helper.annotation_count_ > 0)) {
559 AlternativeReadingScope alt(&reader_, param_kernel_offset);
560 VariableDeclarationHelper helper(this);
561 helper.ReadUntilExcluding(field: VariableDeclarationHelper::kAnnotations);
562 Object& metadata =
563 Object::ZoneHandle(zone: zone_, ptr: constant_reader_.ReadAnnotations());
564 param_descriptor.SetAt(index: entry_start + Parser::kParameterMetadataOffset,
565 value: metadata);
566 } else {
567 param_descriptor.SetAt(index: entry_start + Parser::kParameterMetadataOffset,
568 value: Object::null_instance());
569 }
570 }
571 return param_descriptor.ptr();
572}
573
574ObjectPtr BuildParameterDescriptor(const Function& function) {
575 LongJumpScope jump;
576 if (setjmp(*jump.Set()) == 0) {
577 Thread* thread = Thread::Current();
578 Zone* zone = thread->zone();
579
580 const auto& kernel_info =
581 KernelProgramInfo::Handle(zone, ptr: function.KernelProgramInfo());
582
583 TranslationHelper helper(thread);
584 helper.InitFromKernelProgramInfo(info: kernel_info);
585
586 const Class& owner_class = Class::Handle(zone, ptr: function.Owner());
587 ActiveClass active_class;
588 ActiveClassScope active_class_scope(&active_class, &owner_class);
589
590 ParameterDescriptorBuilder builder(
591 &helper, zone, TypedDataView::Handle(zone, ptr: function.KernelLibrary()),
592 function.KernelLibraryOffset(), &active_class);
593
594 return builder.BuildParameterDescriptor(function);
595 } else {
596 return Thread::Current()->StealStickyError();
597 }
598}
599
600void ReadParameterCovariance(const Function& function,
601 BitVector* is_covariant,
602 BitVector* is_generic_covariant_impl) {
603 Thread* thread = Thread::Current();
604 Zone* zone = thread->zone();
605
606 const intptr_t num_params = function.NumParameters();
607 ASSERT(is_covariant->length() == num_params);
608 ASSERT(is_generic_covariant_impl->length() == num_params);
609
610 const auto& kernel_info =
611 KernelProgramInfo::Handle(zone, ptr: function.KernelProgramInfo());
612
613 TranslationHelper translation_helper(thread);
614 translation_helper.InitFromKernelProgramInfo(info: kernel_info);
615
616 KernelReaderHelper reader_helper(
617 zone, &translation_helper,
618 TypedDataView::Handle(zone, ptr: function.KernelLibrary()),
619 function.KernelLibraryOffset());
620
621 reader_helper.SetOffset(function.kernel_offset());
622 reader_helper.ReadUntilFunctionNode();
623
624 FunctionNodeHelper function_node_helper(&reader_helper);
625 function_node_helper.ReadUntilExcluding(
626 field: FunctionNodeHelper::kPositionalParameters);
627
628 // Positional.
629 const intptr_t num_positional_params = reader_helper.ReadListLength();
630 intptr_t param_index = function.NumImplicitParameters();
631 for (intptr_t i = 0; i < num_positional_params; ++i, ++param_index) {
632 VariableDeclarationHelper helper(&reader_helper);
633 helper.ReadUntilExcluding(field: VariableDeclarationHelper::kEnd);
634
635 if (helper.IsCovariant()) {
636 is_covariant->Add(i: param_index);
637 }
638 if (helper.IsGenericCovariantImpl()) {
639 is_generic_covariant_impl->Add(i: param_index);
640 }
641 }
642
643 // Named.
644 const intptr_t num_named_params = reader_helper.ReadListLength();
645 for (intptr_t i = 0; i < num_named_params; ++i, ++param_index) {
646 VariableDeclarationHelper helper(&reader_helper);
647 helper.ReadUntilExcluding(field: VariableDeclarationHelper::kEnd);
648
649 if (helper.IsCovariant()) {
650 is_covariant->Add(i: param_index);
651 }
652 if (helper.IsGenericCovariantImpl()) {
653 is_generic_covariant_impl->Add(i: param_index);
654 }
655 }
656}
657
658bool NeedsDynamicInvocationForwarder(const Function& function) {
659 Zone* zone = Thread::Current()->zone();
660
661 // Right now closures do not need a dyn:* forwarder.
662 // See https://github.com/dart-lang/sdk/issues/40813
663 if (function.IsClosureFunction()) return false;
664
665 // Method extractors have no parameters to check and return value is a closure
666 // and therefore not an unboxed primitive type.
667 if (function.IsMethodExtractor()) {
668 return false;
669 }
670
671 // Record field getters have no parameters to check and 'dynamic' return type.
672 if (function.IsRecordFieldGetter()) {
673 return false;
674 }
675
676 // Invoke field dispatchers are dynamically generated, will invoke a getter to
677 // obtain the field value and then invoke ".call()" on the result.
678 // Those dynamically generated dispathers don't have proper kernel metadata
679 // associated with them - we can therefore not query if there are dynamic
680 // calls to them or not and are therefore conservative.
681 if (function.IsInvokeFieldDispatcher()) {
682 return true;
683 }
684
685 // The dyn:* forwarders perform unboxing of parameters before calling the
686 // actual target (which accepts unboxed parameters) and boxes return values
687 // of the return value.
688 if (function.HasUnboxedParameters() || function.HasUnboxedReturnValue()) {
689 return true;
690 }
691
692 // There are no parameters to type check for getters and if the return value
693 // is boxed, then the dyn:* forwarder is not needed.
694 if (function.IsImplicitGetterFunction()) {
695 return false;
696 }
697
698 // Covariant parameters (both explicitly covariant and generic-covariant-impl)
699 // are checked in the body of a function and therefore don't need checks in a
700 // dynamic invocation forwarder. So dynamic invocation forwarder is only
701 // needed if there are non-covariant parameters of non-top type.
702 if (function.IsImplicitSetterFunction()) {
703 const auto& field = Field::Handle(zone, ptr: function.accessor_field());
704 return !(field.is_covariant() || field.is_generic_covariant_impl());
705 }
706
707 const auto& type_params =
708 TypeParameters::Handle(zone, ptr: function.type_parameters());
709 if (!type_params.IsNull()) {
710 auto& bound = AbstractType::Handle(zone);
711 for (intptr_t i = 0, n = type_params.Length(); i < n; ++i) {
712 bound = type_params.BoundAt(index: i);
713 if (!bound.IsTopTypeForSubtyping() &&
714 !type_params.IsGenericCovariantImplAt(index: i)) {
715 return true;
716 }
717 }
718 }
719
720 const intptr_t num_params = function.NumParameters();
721 BitVector is_covariant(zone, num_params);
722 BitVector is_generic_covariant_impl(zone, num_params);
723 ReadParameterCovariance(function, is_covariant: &is_covariant, is_generic_covariant_impl: &is_generic_covariant_impl);
724
725 auto& type = AbstractType::Handle(zone);
726 for (intptr_t i = function.NumImplicitParameters(); i < num_params; ++i) {
727 type = function.ParameterTypeAt(index: i);
728 if (!type.IsTopTypeForSubtyping() &&
729 !is_generic_covariant_impl.Contains(i) && !is_covariant.Contains(i)) {
730 return true;
731 }
732 }
733
734 return false;
735}
736
737static ProcedureAttributesMetadata ProcedureAttributesOf(
738 Zone* zone,
739 const KernelProgramInfo& kernel_program_info,
740 const TypedDataView& kernel_data,
741 intptr_t kernel_data_program_offset,
742 intptr_t kernel_offset) {
743 TranslationHelper translation_helper(Thread::Current());
744 translation_helper.InitFromKernelProgramInfo(info: kernel_program_info);
745 KernelReaderHelper reader_helper(zone, &translation_helper, kernel_data,
746 kernel_data_program_offset);
747 ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper(
748 &reader_helper);
749 ProcedureAttributesMetadata attrs =
750 procedure_attributes_metadata_helper.GetProcedureAttributes(
751 node_offset: kernel_offset);
752 return attrs;
753}
754
755ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
756 Zone* zone) {
757 const auto& kernel_program_info =
758 KernelProgramInfo::Handle(zone, ptr: function.KernelProgramInfo());
759 return ProcedureAttributesOf(
760 zone, kernel_program_info,
761 kernel_data: TypedDataView::Handle(zone, ptr: function.KernelLibrary()),
762 kernel_data_program_offset: function.KernelLibraryOffset(), kernel_offset: function.kernel_offset());
763}
764
765ProcedureAttributesMetadata ProcedureAttributesOf(const Field& field,
766 Zone* zone) {
767 const auto& kernel_program_info =
768 KernelProgramInfo::Handle(zone, ptr: field.KernelProgramInfo());
769 return ProcedureAttributesOf(
770 zone, kernel_program_info,
771 kernel_data: TypedDataView::Handle(zone, ptr: field.KernelLibrary()),
772 kernel_data_program_offset: field.KernelLibraryOffset(), kernel_offset: field.kernel_offset());
773}
774
775static UnboxingInfoMetadata* UnboxingInfoMetadataOf(
776 Zone* zone,
777 const KernelProgramInfo& kernel_program_info,
778 const TypedDataView& kernel_data,
779 intptr_t kernel_data_program_offset,
780 intptr_t kernel_offset) {
781 TranslationHelper translation_helper(Thread::Current());
782 translation_helper.InitFromKernelProgramInfo(info: kernel_program_info);
783 KernelReaderHelper reader_helper(zone, &translation_helper, kernel_data,
784 kernel_data_program_offset);
785 UnboxingInfoMetadataHelper unboxing_info_metadata_helper(&reader_helper);
786 return unboxing_info_metadata_helper.GetUnboxingInfoMetadata(node_offset: kernel_offset);
787}
788
789UnboxingInfoMetadata* UnboxingInfoMetadataOf(const Function& function,
790 Zone* zone) {
791 const auto& kernel_program_info =
792 KernelProgramInfo::Handle(zone, ptr: function.KernelProgramInfo());
793 return UnboxingInfoMetadataOf(
794 zone, kernel_program_info,
795 kernel_data: TypedDataView::Handle(zone, ptr: function.KernelLibrary()),
796 kernel_data_program_offset: function.KernelLibraryOffset(), kernel_offset: function.kernel_offset());
797}
798
799TableSelectorMetadata* TableSelectorMetadataForProgram(
800 const KernelProgramInfo& info,
801 Zone* zone) {
802 TranslationHelper translation_helper(Thread::Current());
803 translation_helper.InitFromKernelProgramInfo(info);
804 const auto& data = TypedDataView::Handle(zone, ptr: info.metadata_payloads());
805 KernelReaderHelper reader_helper(zone, &translation_helper, data, 0);
806 TableSelectorMetadataHelper table_selector_metadata_helper(&reader_helper);
807 return table_selector_metadata_helper.GetTableSelectorMetadata(zone);
808}
809
810} // namespace kernel
811} // namespace dart
812
813#endif // !defined(DART_PRECOMPILED_RUNTIME)
814

source code of flutter_engine/third_party/dart/runtime/vm/kernel.cc