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 | #if !defined(DART_PRECOMPILED_RUNTIME) |
5 | |
6 | #include "vm/kernel_loader.h" |
7 | |
8 | #include <string.h> |
9 | |
10 | #include <memory> |
11 | |
12 | #include "vm/compiler/backend/flow_graph_compiler.h" |
13 | #include "vm/compiler/frontend/constant_reader.h" |
14 | #include "vm/compiler/frontend/kernel_translation_helper.h" |
15 | #include "vm/dart_api_impl.h" |
16 | #include "vm/flags.h" |
17 | #include "vm/heap/heap.h" |
18 | #include "vm/kernel_binary.h" |
19 | #include "vm/longjump.h" |
20 | #include "vm/object_store.h" |
21 | #include "vm/parser.h" |
22 | #include "vm/reusable_handles.h" |
23 | #include "vm/service_isolate.h" |
24 | #include "vm/symbols.h" |
25 | #include "vm/thread.h" |
26 | |
27 | namespace dart { |
28 | namespace kernel { |
29 | |
30 | #define Z (zone_) |
31 | #define I (isolate_) |
32 | #define T (type_translator_) |
33 | #define H (translation_helper_) |
34 | |
35 | static const char* const kVMServiceIOLibraryUri = "dart:vmservice_io" ; |
36 | |
37 | class SimpleExpressionConverter { |
38 | public: |
39 | SimpleExpressionConverter(TranslationHelper* translation_helper, |
40 | KernelReaderHelper* reader_helper) |
41 | : translation_helper_(*translation_helper), |
42 | zone_(translation_helper_.zone()), |
43 | simple_value_(NULL), |
44 | helper_(reader_helper) {} |
45 | |
46 | bool IsSimple(intptr_t kernel_offset) { |
47 | AlternativeReadingScope alt(&helper_->reader_, kernel_offset); |
48 | uint8_t payload = 0; |
49 | Tag tag = helper_->ReadTag(&payload); // read tag. |
50 | switch (tag) { |
51 | case kBigIntLiteral: { |
52 | const String& literal_str = |
53 | H.DartString(helper_->ReadStringReference(), |
54 | Heap::kOld); // read index into string table. |
55 | simple_value_ = &Integer::ZoneHandle(Z, Integer::New(literal_str)); |
56 | if (simple_value_->IsNull()) { |
57 | H.ReportError("Integer literal %s is out of range" , |
58 | literal_str.ToCString()); |
59 | UNREACHABLE(); |
60 | } |
61 | *simple_value_ = H.Canonicalize(*simple_value_); |
62 | return true; |
63 | } |
64 | case kStringLiteral: |
65 | simple_value_ = &H.DartSymbolPlain( |
66 | helper_->ReadStringReference()); // read index into string table. |
67 | return true; |
68 | case kSpecializedIntLiteral: |
69 | simple_value_ = |
70 | &Integer::ZoneHandle(Z, Integer::New(static_cast<int32_t>(payload) - |
71 | SpecializedIntLiteralBias, |
72 | Heap::kOld)); |
73 | *simple_value_ = H.Canonicalize(*simple_value_); |
74 | return true; |
75 | case kNegativeIntLiteral: |
76 | simple_value_ = &Integer::ZoneHandle( |
77 | Z, Integer::New(-static_cast<int64_t>(helper_->ReadUInt()), |
78 | Heap::kOld)); // read value. |
79 | *simple_value_ = H.Canonicalize(*simple_value_); |
80 | return true; |
81 | case kPositiveIntLiteral: |
82 | simple_value_ = &Integer::ZoneHandle( |
83 | Z, Integer::New(static_cast<int64_t>(helper_->ReadUInt()), |
84 | Heap::kOld)); // read value. |
85 | *simple_value_ = H.Canonicalize(*simple_value_); |
86 | return true; |
87 | case kDoubleLiteral: |
88 | simple_value_ = &Double::ZoneHandle( |
89 | Z, Double::New(helper_->ReadDouble(), Heap::kOld)); // read value. |
90 | *simple_value_ = H.Canonicalize(*simple_value_); |
91 | return true; |
92 | case kTrueLiteral: |
93 | simple_value_ = &Bool::Handle(Z, Bool::Get(true).raw()); |
94 | return true; |
95 | case kFalseLiteral: |
96 | simple_value_ = &Bool::Handle(Z, Bool::Get(false).raw()); |
97 | return true; |
98 | case kNullLiteral: |
99 | simple_value_ = &Instance::ZoneHandle(Z, Instance::null()); |
100 | return true; |
101 | default: |
102 | return false; |
103 | } |
104 | } |
105 | |
106 | const Instance& SimpleValue() { return *simple_value_; } |
107 | Zone* zone() const { return zone_; } |
108 | |
109 | private: |
110 | TranslationHelper& translation_helper_; |
111 | Zone* zone_; |
112 | Instance* simple_value_; |
113 | KernelReaderHelper* helper_; |
114 | |
115 | DISALLOW_COPY_AND_ASSIGN(SimpleExpressionConverter); |
116 | }; |
117 | |
118 | ArrayPtr KernelLoader::MakeFieldsArray() { |
119 | const intptr_t len = fields_.length(); |
120 | const Array& res = Array::Handle(zone_, Array::New(len, Heap::kOld)); |
121 | for (intptr_t i = 0; i < len; i++) { |
122 | res.SetAt(i, *fields_[i]); |
123 | } |
124 | return res.raw(); |
125 | } |
126 | |
127 | ArrayPtr KernelLoader::MakeFunctionsArray() { |
128 | const intptr_t len = functions_.length(); |
129 | const Array& res = Array::Handle(zone_, Array::New(len, Heap::kOld)); |
130 | for (intptr_t i = 0; i < len; i++) { |
131 | res.SetAt(i, *functions_[i]); |
132 | } |
133 | return res.raw(); |
134 | } |
135 | |
136 | LibraryPtr BuildingTranslationHelper::LookupLibraryByKernelLibrary( |
137 | NameIndex library) { |
138 | return loader_->LookupLibrary(library); |
139 | } |
140 | |
141 | ClassPtr BuildingTranslationHelper::LookupClassByKernelClass(NameIndex klass) { |
142 | #if defined(DEBUG) |
143 | LibraryLookupHandleScope library_lookup_handle_scope(library_lookup_handle_); |
144 | #endif // defined(DEBUG) |
145 | library_lookup_handle_ = loader_->LookupLibraryFromClass(klass); |
146 | return loader_->LookupClass(library_lookup_handle_, klass); |
147 | } |
148 | |
149 | LibraryIndex::LibraryIndex(const ExternalTypedData& kernel_data, |
150 | uint32_t binary_version) |
151 | : reader_(kernel_data), binary_version_(binary_version) { |
152 | intptr_t data_size = reader_.size(); |
153 | |
154 | procedure_count_ = reader_.ReadUInt32At(data_size - 4); |
155 | procedure_index_offset_ = data_size - 4 - (procedure_count_ + 1) * 4; |
156 | |
157 | class_count_ = reader_.ReadUInt32At(procedure_index_offset_ - 4); |
158 | class_index_offset_ = procedure_index_offset_ - 4 - (class_count_ + 1) * 4; |
159 | |
160 | source_references_offset_ = -1; |
161 | source_references_offset_ = reader_.ReadUInt32At(class_index_offset_ - 4); |
162 | } |
163 | |
164 | ClassIndex::ClassIndex(const uint8_t* buffer, |
165 | intptr_t buffer_size, |
166 | intptr_t class_offset, |
167 | intptr_t class_size) |
168 | : reader_(buffer, buffer_size) { |
169 | Init(class_offset, class_size); |
170 | } |
171 | |
172 | ClassIndex::ClassIndex(const ExternalTypedData& library_kernel_data, |
173 | intptr_t class_offset, |
174 | intptr_t class_size) |
175 | : reader_(library_kernel_data) { |
176 | Init(class_offset, class_size); |
177 | } |
178 | |
179 | void ClassIndex::Init(intptr_t class_offset, intptr_t class_size) { |
180 | procedure_count_ = reader_.ReadUInt32At(class_offset + class_size - 4); |
181 | procedure_index_offset_ = |
182 | class_offset + class_size - 4 - (procedure_count_ + 1) * 4; |
183 | } |
184 | |
185 | using UriToSourceTable = DirectChainedHashMap<UriToSourceTableTrait>; |
186 | |
187 | KernelLoader::KernelLoader(Program* program, |
188 | UriToSourceTable* uri_to_source_table) |
189 | : program_(program), |
190 | thread_(Thread::Current()), |
191 | zone_(thread_->zone()), |
192 | isolate_(thread_->isolate()), |
193 | patch_classes_(Array::ZoneHandle(zone_)), |
194 | active_class_(), |
195 | library_kernel_offset_(-1), // Set to the correct value in LoadLibrary |
196 | kernel_binary_version_(program->binary_version()), |
197 | correction_offset_(-1), // Set to the correct value in LoadLibrary |
198 | loading_native_wrappers_library_(false), |
199 | library_kernel_data_(ExternalTypedData::ZoneHandle(zone_)), |
200 | kernel_program_info_(KernelProgramInfo::ZoneHandle(zone_)), |
201 | translation_helper_(this, thread_, Heap::kOld), |
202 | helper_(zone_, |
203 | &translation_helper_, |
204 | program_->kernel_data(), |
205 | program_->kernel_data_size(), |
206 | 0), |
207 | constant_reader_(&helper_, &active_class_), |
208 | type_translator_(&helper_, |
209 | &constant_reader_, |
210 | &active_class_, |
211 | /* finalize= */ false), |
212 | inferred_type_metadata_helper_(&helper_, &constant_reader_), |
213 | bytecode_metadata_helper_(&helper_, &active_class_), |
214 | external_name_class_(Class::Handle(Z)), |
215 | external_name_field_(Field::Handle(Z)), |
216 | potential_natives_(GrowableObjectArray::Handle(Z)), |
217 | potential_pragma_functions_(GrowableObjectArray::Handle(Z)), |
218 | pragma_class_(Class::Handle(Z)), |
219 | name_index_handle_(Smi::Handle(Z)), |
220 | expression_evaluation_library_(Library::Handle(Z)) { |
221 | if (!program->is_single_program()) { |
222 | FATAL( |
223 | "Trying to load a concatenated dill file at a time where that is " |
224 | "not allowed" ); |
225 | } |
226 | InitializeFields(uri_to_source_table); |
227 | } |
228 | |
229 | void KernelLoader::ReadObfuscationProhibitions() { |
230 | ObfuscationProhibitionsMetadataHelper helper(&helper_); |
231 | helper.ReadProhibitions(); |
232 | } |
233 | |
234 | void KernelLoader::ReadLoadingUnits() { |
235 | LoadingUnitsMetadataHelper helper(&helper_); |
236 | helper.ReadLoadingUnits(); |
237 | } |
238 | |
239 | Object& KernelLoader::LoadEntireProgram(Program* program, |
240 | bool process_pending_classes) { |
241 | Thread* thread = Thread::Current(); |
242 | TIMELINE_DURATION(thread, Isolate, "LoadKernel" ); |
243 | |
244 | if (program->is_single_program()) { |
245 | KernelLoader loader(program, /*uri_to_source_table=*/nullptr); |
246 | return Object::Handle(loader.LoadProgram(process_pending_classes)); |
247 | } |
248 | |
249 | kernel::Reader reader(program->kernel_data(), program->kernel_data_size()); |
250 | GrowableArray<intptr_t> subprogram_file_starts; |
251 | index_programs(&reader, &subprogram_file_starts); |
252 | |
253 | Zone* zone = thread->zone(); |
254 | Library& library = Library::Handle(zone); |
255 | intptr_t subprogram_count = subprogram_file_starts.length() - 1; |
256 | |
257 | // First index all source tables. |
258 | UriToSourceTable uri_to_source_table; |
259 | UriToSourceTableEntry wrapper; |
260 | for (intptr_t i = subprogram_count - 1; i >= 0; --i) { |
261 | intptr_t subprogram_start = subprogram_file_starts.At(i); |
262 | intptr_t subprogram_end = subprogram_file_starts.At(i + 1); |
263 | Thread* thread_ = Thread::Current(); |
264 | Zone* zone_ = thread_->zone(); |
265 | TranslationHelper translation_helper(thread); |
266 | KernelReaderHelper helper_(zone_, &translation_helper, |
267 | program->kernel_data() + subprogram_start, |
268 | subprogram_end - subprogram_start, 0); |
269 | const intptr_t source_table_size = helper_.SourceTableSize(); |
270 | for (intptr_t index = 0; index < source_table_size; ++index) { |
271 | const String& uri_string = helper_.SourceTableUriFor(index); |
272 | wrapper.uri = &uri_string; |
273 | TypedData& line_starts = |
274 | TypedData::Handle(Z, helper_.GetLineStartsFor(index)); |
275 | if (line_starts.Length() == 0) continue; |
276 | const String& script_source = helper_.GetSourceFor(index); |
277 | wrapper.uri = &uri_string; |
278 | UriToSourceTableEntry* pair = uri_to_source_table.LookupValue(&wrapper); |
279 | if (pair != NULL) { |
280 | // At least two entries with content. Unless the content is the same |
281 | // that's not valid. |
282 | const bool src_differ = pair->sources->CompareTo(script_source) != 0; |
283 | const bool line_starts_differ = |
284 | !pair->line_starts->CanonicalizeEquals(line_starts); |
285 | if (src_differ || line_starts_differ) { |
286 | FATAL3( |
287 | "Invalid kernel binary: Contains at least two source entries " |
288 | "that do not agree. URI '%s', difference: %s. Subprogram count: " |
289 | "%" Pd "." , |
290 | uri_string.ToCString(), |
291 | src_differ && line_starts_differ |
292 | ? "src and line starts" |
293 | : (src_differ ? "src" : "line starts" ), |
294 | subprogram_count); |
295 | } |
296 | } else { |
297 | UriToSourceTableEntry* tmp = new UriToSourceTableEntry(); |
298 | tmp->uri = &uri_string; |
299 | tmp->sources = &script_source; |
300 | tmp->line_starts = &line_starts; |
301 | uri_to_source_table.Insert(tmp); |
302 | } |
303 | } |
304 | } |
305 | |
306 | // Create "fake programs" for each sub-program. |
307 | for (intptr_t i = subprogram_count - 1; i >= 0; --i) { |
308 | intptr_t subprogram_start = subprogram_file_starts.At(i); |
309 | intptr_t subprogram_end = subprogram_file_starts.At(i + 1); |
310 | reader.set_raw_buffer(program->kernel_data() + subprogram_start); |
311 | reader.set_size(subprogram_end - subprogram_start); |
312 | reader.set_offset(0); |
313 | const char* error = nullptr; |
314 | std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader, &error); |
315 | if (subprogram == nullptr) { |
316 | FATAL1("Failed to load kernel file: %s" , error); |
317 | } |
318 | ASSERT(subprogram->is_single_program()); |
319 | KernelLoader loader(subprogram.get(), &uri_to_source_table); |
320 | Object& load_result = Object::Handle(loader.LoadProgram(false)); |
321 | if (load_result.IsError()) return load_result; |
322 | |
323 | if (load_result.IsLibrary()) { |
324 | library ^= load_result.raw(); |
325 | } |
326 | } |
327 | |
328 | if (process_pending_classes && !ClassFinalizer::ProcessPendingClasses()) { |
329 | // Class finalization failed -> sticky error would be set. |
330 | return Error::Handle(thread->StealStickyError()); |
331 | } |
332 | |
333 | return library; |
334 | } |
335 | |
336 | void KernelLoader::index_programs( |
337 | kernel::Reader* reader, |
338 | GrowableArray<intptr_t>* subprogram_file_starts) { |
339 | // Dill files can be concatenated (e.g. cat a.dill b.dill > c.dill), so we |
340 | // need to first index the (possibly combined) file. |
341 | // First entry becomes last entry. |
342 | // Last entry is for ease of calculating size of last subprogram. |
343 | subprogram_file_starts->Add(reader->size()); |
344 | reader->set_offset(reader->size() - 4); |
345 | while (reader->offset() > 0) { |
346 | intptr_t size = reader->ReadUInt32(); |
347 | intptr_t start = reader->offset() - size; |
348 | if (start < 0) { |
349 | FATAL("Invalid kernel binary: Indicated size is invalid." ); |
350 | } |
351 | subprogram_file_starts->Add(start); |
352 | reader->set_offset(start - 4); |
353 | } |
354 | subprogram_file_starts->Reverse(); |
355 | } |
356 | |
357 | StringPtr KernelLoader::FindSourceForScript(const uint8_t* kernel_buffer, |
358 | intptr_t kernel_buffer_length, |
359 | const String& uri) { |
360 | Thread* thread = Thread::Current(); |
361 | Zone* zone = thread->zone(); |
362 | TranslationHelper translation_helper(thread); |
363 | KernelReaderHelper reader(zone, &translation_helper, kernel_buffer, |
364 | kernel_buffer_length, 0); |
365 | intptr_t source_table_size = reader.SourceTableSize(); |
366 | for (intptr_t i = 0; i < source_table_size; ++i) { |
367 | const String& source_uri = reader.SourceTableUriFor(i); |
368 | if (source_uri.EndsWith(uri)) { |
369 | return reader.GetSourceFor(i).raw(); |
370 | } |
371 | } |
372 | return String::null(); |
373 | } |
374 | |
375 | void KernelLoader::InitializeFields(UriToSourceTable* uri_to_source_table) { |
376 | const intptr_t source_table_size = helper_.SourceTableSize(); |
377 | const Array& scripts = |
378 | Array::Handle(Z, Array::New(source_table_size, Heap::kOld)); |
379 | |
380 | // Copy the Kernel string offsets out of the binary and into the VM's heap. |
381 | ASSERT(program_->string_table_offset() >= 0); |
382 | Reader reader(program_->kernel_data(), program_->kernel_data_size()); |
383 | reader.set_offset(program_->string_table_offset()); |
384 | intptr_t count = reader.ReadUInt() + 1; |
385 | TypedData& offsets = TypedData::Handle( |
386 | Z, TypedData::New(kTypedDataUint32ArrayCid, count, Heap::kOld)); |
387 | offsets.SetUint32(0, 0); |
388 | intptr_t end_offset = 0; |
389 | for (intptr_t i = 1; i < count; ++i) { |
390 | end_offset = reader.ReadUInt(); |
391 | offsets.SetUint32(i << 2, end_offset); |
392 | } |
393 | |
394 | // Create view of the string data. |
395 | const ExternalTypedData& data = ExternalTypedData::Handle( |
396 | Z, |
397 | reader.ExternalDataFromTo(reader.offset(), reader.offset() + end_offset)); |
398 | |
399 | // Create a view of the constants table. The trailing ComponentIndex is |
400 | // negligible in size. |
401 | const ExternalTypedData& constants_table = ExternalTypedData::Handle( |
402 | Z, reader.ExternalDataFromTo(program_->constant_table_offset(), |
403 | program_->kernel_data_size())); |
404 | |
405 | // Copy the canonical names into the VM's heap. Encode them as unsigned, so |
406 | // the parent indexes are adjusted when extracted. |
407 | reader.set_offset(program_->name_table_offset()); |
408 | count = reader.ReadUInt() * 2; |
409 | TypedData& names = TypedData::Handle( |
410 | Z, TypedData::New(kTypedDataUint32ArrayCid, count, Heap::kOld)); |
411 | for (intptr_t i = 0; i < count; ++i) { |
412 | names.SetUint32(i << 2, reader.ReadUInt()); |
413 | } |
414 | |
415 | // Create view of metadata payloads. |
416 | const ExternalTypedData& metadata_payloads = ExternalTypedData::Handle( |
417 | Z, reader.ExternalDataFromTo(program_->metadata_payloads_offset(), |
418 | program_->metadata_mappings_offset())); |
419 | ASSERT(Utils::IsAligned(metadata_payloads.DataAddr(0), kWordSize)); |
420 | |
421 | // Create view of metadata mappings. |
422 | const ExternalTypedData& metadata_mappings = ExternalTypedData::Handle( |
423 | Z, reader.ExternalDataFromTo(program_->metadata_mappings_offset(), |
424 | program_->string_table_offset())); |
425 | |
426 | #if defined(DEBUG) |
427 | MetadataHelper::VerifyMetadataMappings(metadata_mappings); |
428 | #endif |
429 | |
430 | const Array& libraries_cache = |
431 | Array::Handle(Z, HashTables::New<UnorderedHashMap<SmiTraits>>( |
432 | program_->library_count(), Heap::kOld)); |
433 | |
434 | const intptr_t kClassesPerLibraryGuess = 5; |
435 | const Array& classes_cache = Array::Handle( |
436 | Z, HashTables::New<UnorderedHashMap<SmiTraits>>( |
437 | kClassesPerLibraryGuess * program_->library_count(), Heap::kOld)); |
438 | |
439 | kernel_program_info_ = KernelProgramInfo::New( |
440 | offsets, data, names, metadata_payloads, metadata_mappings, |
441 | constants_table, scripts, libraries_cache, classes_cache, |
442 | program_->typed_data() == nullptr ? Object::null_object() |
443 | : *program_->typed_data(), |
444 | program_->binary_version()); |
445 | |
446 | H.InitFromKernelProgramInfo(kernel_program_info_); |
447 | |
448 | Script& script = Script::Handle(Z); |
449 | for (intptr_t index = 0; index < source_table_size; ++index) { |
450 | script = LoadScriptAt(index, uri_to_source_table); |
451 | scripts.SetAt(index, script); |
452 | } |
453 | |
454 | bytecode_metadata_helper_.ReadBytecodeComponent(); |
455 | } |
456 | |
457 | KernelLoader::KernelLoader(const Script& script, |
458 | const ExternalTypedData& kernel_data, |
459 | intptr_t data_program_offset, |
460 | uint32_t kernel_binary_version) |
461 | : program_(NULL), |
462 | thread_(Thread::Current()), |
463 | zone_(thread_->zone()), |
464 | isolate_(thread_->isolate()), |
465 | patch_classes_(Array::ZoneHandle(zone_)), |
466 | library_kernel_offset_(data_program_offset), |
467 | kernel_binary_version_(kernel_binary_version), |
468 | correction_offset_(0), |
469 | loading_native_wrappers_library_(false), |
470 | library_kernel_data_(ExternalTypedData::ZoneHandle(zone_)), |
471 | kernel_program_info_( |
472 | KernelProgramInfo::ZoneHandle(zone_, script.kernel_program_info())), |
473 | translation_helper_(this, thread_, Heap::kOld), |
474 | helper_(zone_, &translation_helper_, script, kernel_data, 0), |
475 | constant_reader_(&helper_, &active_class_), |
476 | type_translator_(&helper_, |
477 | &constant_reader_, |
478 | &active_class_, |
479 | /* finalize= */ false), |
480 | inferred_type_metadata_helper_(&helper_, &constant_reader_), |
481 | bytecode_metadata_helper_(&helper_, &active_class_), |
482 | external_name_class_(Class::Handle(Z)), |
483 | external_name_field_(Field::Handle(Z)), |
484 | potential_natives_(GrowableObjectArray::Handle(Z)), |
485 | potential_pragma_functions_(GrowableObjectArray::Handle(Z)), |
486 | pragma_class_(Class::Handle(Z)), |
487 | name_index_handle_(Smi::Handle(Z)), |
488 | expression_evaluation_library_(Library::Handle(Z)) { |
489 | ASSERT(T.active_class_ == &active_class_); |
490 | T.finalize_ = false; |
491 | library_kernel_data_ = kernel_data.raw(); |
492 | H.InitFromKernelProgramInfo(kernel_program_info_); |
493 | } |
494 | |
495 | void KernelLoader::EvaluateDelayedPragmas() { |
496 | potential_pragma_functions_ = |
497 | kernel_program_info_.potential_pragma_functions(); |
498 | if (potential_pragma_functions_.IsNull()) return; |
499 | |
500 | Thread* thread = Thread::Current(); |
501 | NoOOBMessageScope no_msg_scope(thread); |
502 | NoReloadScope no_reload_scope(thread->isolate(), thread); |
503 | |
504 | Function& function = Function::Handle(); |
505 | Library& library = Library::Handle(); |
506 | Class& klass = Class::Handle(); |
507 | for (int i = 0; i < potential_pragma_functions_.Length(); ++i) { |
508 | function ^= potential_pragma_functions_.At(i); |
509 | klass = function.Owner(); |
510 | library = klass.library(); |
511 | library.GetMetadata(function); |
512 | } |
513 | |
514 | potential_pragma_functions_ = GrowableObjectArray::null(); |
515 | kernel_program_info_.set_potential_pragma_functions( |
516 | GrowableObjectArray::Handle(Z)); |
517 | } |
518 | |
519 | void KernelLoader::AnnotateNativeProcedures() { |
520 | potential_natives_ = kernel_program_info_.potential_natives(); |
521 | const intptr_t length = |
522 | !potential_natives_.IsNull() ? potential_natives_.Length() : 0; |
523 | if (length == 0) return; |
524 | |
525 | // Prepare lazy constant reading. |
526 | ConstantReader constant_reader(&helper_, &active_class_); |
527 | |
528 | // Obtain `dart:_internal::ExternalName.name`. |
529 | EnsureExternalClassIsLookedUp(); |
530 | Instance& constant = Instance::Handle(Z); |
531 | String& native_name = String::Handle(Z); |
532 | |
533 | // Start scanning all candidates in [potential_natives] for the annotation |
534 | // constant. If the annotation is found, flag the [Function] as native and |
535 | // attach the native name to it. |
536 | Function& function = Function::Handle(Z); |
537 | for (intptr_t i = 0; i < length; ++i) { |
538 | function ^= potential_natives_.At(i); |
539 | helper_.SetOffset(function.KernelDataProgramOffset() + |
540 | function.kernel_offset()); |
541 | { |
542 | ProcedureHelper procedure_helper(&helper_); |
543 | procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations); |
544 | } |
545 | |
546 | const intptr_t annotation_count = helper_.ReadListLength(); |
547 | for (intptr_t j = 0; j < annotation_count; ++j) { |
548 | const intptr_t tag = helper_.PeekTag(); |
549 | if (tag == kConstantExpression) { |
550 | helper_.ReadByte(); // Skip the tag. |
551 | helper_.ReadPosition(); // Skip fileOffset. |
552 | helper_.SkipDartType(); // Skip type. |
553 | |
554 | // We have a candidate. Let's look if it's an instance of the |
555 | // ExternalName class. |
556 | const intptr_t constant_table_offset = helper_.ReadUInt(); |
557 | if (constant_reader.IsInstanceConstant(constant_table_offset, |
558 | external_name_class_)) { |
559 | constant = constant_reader.ReadConstant(constant_table_offset); |
560 | ASSERT(constant.clazz() == external_name_class_.raw()); |
561 | // We found the annotation, let's flag the function as native and |
562 | // set the native name! |
563 | native_name ^= constant.GetField(external_name_field_); |
564 | function.set_is_native(true); |
565 | function.set_native_name(native_name); |
566 | function.set_is_external(false); |
567 | break; |
568 | } |
569 | } else { |
570 | helper_.SkipExpression(); |
571 | } |
572 | } |
573 | } |
574 | |
575 | // Clear out the list of [Function] objects which might need their native |
576 | // name to be set after reading the constant table from the kernel blob. |
577 | potential_natives_ = GrowableObjectArray::null(); |
578 | kernel_program_info_.set_potential_natives(potential_natives_); |
579 | } |
580 | |
581 | StringPtr KernelLoader::DetectExternalNameCtor() { |
582 | helper_.ReadTag(); |
583 | helper_.ReadPosition(); |
584 | NameIndex annotation_class = H.EnclosingName( |
585 | helper_.ReadCanonicalNameReference()); // read target reference, |
586 | |
587 | if (!IsClassName(annotation_class, Symbols::DartInternal(), |
588 | Symbols::ExternalName())) { |
589 | helper_.SkipArguments(); |
590 | return String::null(); |
591 | } |
592 | |
593 | // Read arguments: |
594 | intptr_t total_arguments = helper_.ReadUInt(); // read argument count. |
595 | helper_.SkipListOfDartTypes(); // read list of types. |
596 | intptr_t positional_arguments = helper_.ReadListLength(); |
597 | ASSERT(total_arguments == 1 && positional_arguments == 1); |
598 | |
599 | Tag tag = helper_.ReadTag(); |
600 | ASSERT(tag == kStringLiteral); |
601 | String& result = H.DartSymbolPlain( |
602 | helper_.ReadStringReference()); // read index into string table. |
603 | |
604 | // List of named. |
605 | intptr_t list_length = helper_.ReadListLength(); // read list length. |
606 | ASSERT(list_length == 0); |
607 | |
608 | return result.raw(); |
609 | } |
610 | |
611 | bool KernelLoader::IsClassName(NameIndex name, |
612 | const String& library, |
613 | const String& klass) { |
614 | ASSERT(H.IsClass(name)); |
615 | StringIndex class_name_index = H.CanonicalNameString(name); |
616 | |
617 | if (!H.StringEquals(class_name_index, klass.ToCString())) { |
618 | return false; |
619 | } |
620 | ASSERT(H.IsLibrary(H.CanonicalNameParent(name))); |
621 | StringIndex library_name_index = |
622 | H.CanonicalNameString(H.CanonicalNameParent(name)); |
623 | return H.StringEquals(library_name_index, library.ToCString()); |
624 | } |
625 | |
626 | bool KernelLoader::DetectPragmaCtor() { |
627 | helper_.ReadTag(); |
628 | helper_.ReadPosition(); |
629 | NameIndex annotation_class = H.EnclosingName( |
630 | helper_.ReadCanonicalNameReference()); // read target reference |
631 | helper_.SkipArguments(); |
632 | return IsClassName(annotation_class, Symbols::DartCore(), Symbols::Pragma()); |
633 | } |
634 | |
635 | void KernelLoader::LoadNativeExtensionLibraries() { |
636 | const auto& potential_extension_libraries = |
637 | GrowableObjectArray::Handle(Z, H.GetPotentialExtensionLibraries()); |
638 | if (potential_extension_libraries.IsNull()) { |
639 | return; |
640 | } |
641 | |
642 | // Prepare lazy constant reading. |
643 | ConstantReader constant_reader(&helper_, &active_class_); |
644 | |
645 | // Obtain `dart:_internal::ExternalName.name`. |
646 | EnsureExternalClassIsLookedUp(); |
647 | |
648 | Instance& constant = Instance::Handle(Z); |
649 | String& uri_path = String::Handle(Z); |
650 | Library& library = Library::Handle(Z); |
651 | |
652 | const intptr_t length = potential_extension_libraries.Length(); |
653 | for (intptr_t i = 0; i < length; ++i) { |
654 | library ^= potential_extension_libraries.At(i); |
655 | |
656 | if (library.is_declared_in_bytecode()) { |
657 | const auto& imports = Array::Handle(Z, library.imports()); |
658 | auto& ns = Namespace::Handle(Z); |
659 | auto& importee = Library::Handle(Z); |
660 | for (intptr_t j = 0; j < imports.Length(); ++j) { |
661 | ns ^= imports.At(j); |
662 | if (ns.IsNull()) continue; |
663 | importee = ns.library(); |
664 | uri_path = importee.url(); |
665 | if (uri_path.StartsWith(Symbols::DartExtensionScheme())) { |
666 | LoadNativeExtension(library, uri_path); |
667 | } |
668 | } |
669 | } else { |
670 | helper_.SetOffset(library.kernel_offset()); |
671 | |
672 | LibraryHelper library_helper(&helper_, kernel_binary_version_); |
673 | library_helper.ReadUntilExcluding(LibraryHelper::kAnnotations); |
674 | |
675 | const intptr_t annotation_count = helper_.ReadListLength(); |
676 | for (intptr_t j = 0; j < annotation_count; ++j) { |
677 | uri_path = String::null(); |
678 | |
679 | const intptr_t tag = helper_.PeekTag(); |
680 | if (tag == kConstantExpression) { |
681 | helper_.ReadByte(); // Skip the tag. |
682 | helper_.ReadPosition(); // Skip fileOffset. |
683 | helper_.SkipDartType(); // Skip type. |
684 | |
685 | // We have a candidate. Let's look if it's an instance of the |
686 | // ExternalName class. |
687 | const intptr_t constant_table_offset = helper_.ReadUInt(); |
688 | if (constant_reader.IsInstanceConstant(constant_table_offset, |
689 | external_name_class_)) { |
690 | constant = constant_reader.ReadConstant(constant_table_offset); |
691 | ASSERT(constant.clazz() == external_name_class_.raw()); |
692 | uri_path ^= constant.GetField(external_name_field_); |
693 | } |
694 | } else if (tag == kConstructorInvocation || |
695 | tag == kConstConstructorInvocation) { |
696 | uri_path = DetectExternalNameCtor(); |
697 | } else { |
698 | helper_.SkipExpression(); |
699 | } |
700 | |
701 | if (uri_path.IsNull()) continue; |
702 | |
703 | LoadNativeExtension(library, uri_path); |
704 | |
705 | // Create a dummy library and add it as an import to the current |
706 | // library. This allows later to discover and reload this native |
707 | // extension, e.g. when running from an app-jit snapshot. |
708 | // See Loader::ReloadNativeExtensions(...) which relies on |
709 | // Dart_GetImportsOfScheme('dart-ext'). |
710 | const auto& native_library = Library::Handle(Library::New(uri_path)); |
711 | library.AddImport(Namespace::Handle(Namespace::New( |
712 | native_library, Array::null_array(), Array::null_array()))); |
713 | } |
714 | } |
715 | } |
716 | } |
717 | |
718 | void KernelLoader::LoadNativeExtension(const Library& library, |
719 | const String& uri_path) { |
720 | #if !defined(DART_PRECOMPILER) |
721 | if (!I->HasTagHandler()) { |
722 | H.ReportError("no library handler registered." ); |
723 | } |
724 | |
725 | I->BlockClassFinalization(); |
726 | const auto& result = Object::Handle( |
727 | Z, I->CallTagHandler(Dart_kImportExtensionTag, library, uri_path)); |
728 | I->UnblockClassFinalization(); |
729 | |
730 | if (result.IsError()) { |
731 | H.ReportError(Error::Cast(result), "library handler failed" ); |
732 | } |
733 | #endif |
734 | } |
735 | |
736 | ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) { |
737 | ASSERT(kernel_program_info_.constants() == Array::null()); |
738 | |
739 | if (!program_->is_single_program()) { |
740 | FATAL( |
741 | "Trying to load a concatenated dill file at a time where that is " |
742 | "not allowed" ); |
743 | } |
744 | |
745 | LongJumpScope jump; |
746 | if (setjmp(*jump.Set()) == 0) { |
747 | if (!bytecode_metadata_helper_.ReadLibraries()) { |
748 | // Note that `problemsAsJson` on Component is implicitly skipped. |
749 | const intptr_t length = program_->library_count(); |
750 | for (intptr_t i = 0; i < length; i++) { |
751 | LoadLibrary(i); |
752 | } |
753 | } |
754 | |
755 | // Finalize still pending classes if requested. |
756 | if (process_pending_classes) { |
757 | if (!ClassFinalizer::ProcessPendingClasses()) { |
758 | // Class finalization failed -> sticky error would be set. |
759 | return H.thread()->StealStickyError(); |
760 | } |
761 | } |
762 | |
763 | // Sets the constants array to an empty hash and leaves the constant |
764 | // table's raw bytes in place for lazy reading. We can fix up all |
765 | // "pending" processing now, and must ensure we don't create new |
766 | // ones from this point on. |
767 | ASSERT(kernel_program_info_.constants_table() != ExternalTypedData::null()); |
768 | const Array& array = |
769 | Array::Handle(Z, HashTables::New<KernelConstantsMap>(16, Heap::kOld)); |
770 | kernel_program_info_.set_constants(array); |
771 | H.SetConstants(array); // for caching |
772 | AnnotateNativeProcedures(); |
773 | LoadNativeExtensionLibraries(); |
774 | EvaluateDelayedPragmas(); |
775 | |
776 | NameIndex main = program_->main_method(); |
777 | if (main != -1) { |
778 | NameIndex main_library = H.EnclosingName(main); |
779 | return LookupLibrary(main_library); |
780 | } |
781 | |
782 | return bytecode_metadata_helper_.GetMainLibrary(); |
783 | } |
784 | |
785 | // Either class finalization failed or we caught a compile error. |
786 | // In both cases sticky error would be set. |
787 | return Thread::Current()->StealStickyError(); |
788 | } |
789 | |
790 | void KernelLoader::LoadLibrary(const Library& library) { |
791 | ASSERT(!library.Loaded()); |
792 | |
793 | bytecode_metadata_helper_.ReadLibrary(library); |
794 | if (library.Loaded()) { |
795 | return; |
796 | } |
797 | const auto& uri = String::Handle(Z, library.url()); |
798 | const intptr_t num_libraries = program_->library_count(); |
799 | for (intptr_t i = 0; i < num_libraries; ++i) { |
800 | const String& library_uri = LibraryUri(i); |
801 | if (library_uri.Equals(uri)) { |
802 | LoadLibrary(i); |
803 | return; |
804 | } |
805 | } |
806 | } |
807 | |
808 | ObjectPtr KernelLoader::LoadExpressionEvaluationFunction( |
809 | const String& library_url, |
810 | const String& klass) { |
811 | // Find the original context, i.e. library/class, in which the evaluation will |
812 | // happen. |
813 | const Library& real_library = |
814 | Library::Handle(Z, Library::LookupLibrary(thread_, library_url)); |
815 | ASSERT(!real_library.IsNull()); |
816 | const Class& real_class = Class::Handle( |
817 | Z, klass.IsNull() ? real_library.toplevel_class() |
818 | : real_library.LookupClassAllowPrivate(klass)); |
819 | ASSERT(!real_class.IsNull()); |
820 | |
821 | const intptr_t num_cids = I->class_table()->NumCids(); |
822 | const intptr_t num_libs = |
823 | GrowableObjectArray::Handle(I->object_store()->libraries()).Length(); |
824 | |
825 | // Load the "evaluate:source" expression evaluation library. |
826 | ASSERT(expression_evaluation_library_.IsNull()); |
827 | ASSERT(H.GetExpressionEvaluationFunction().IsNull()); |
828 | H.SetExpressionEvaluationRealClass(real_class); |
829 | const Object& result = Object::Handle(Z, LoadProgram(true)); |
830 | if (result.IsError()) { |
831 | return result.raw(); |
832 | } |
833 | const Function& function = H.GetExpressionEvaluationFunction(); |
834 | ASSERT(!function.IsNull()); |
835 | ASSERT(GrowableObjectArray::Handle(I->object_store()->libraries()).Length() == |
836 | num_libs); |
837 | ASSERT(I->class_table()->NumCids() == num_cids); |
838 | |
839 | // Make the expression evaluation function have the right script, |
840 | // kernel data and parent. |
841 | const auto& eval_script = Script::Handle(Z, function.script()); |
842 | auto& kernel_data = ExternalTypedData::Handle(Z); |
843 | intptr_t kernel_offset = -1; |
844 | if (!function.is_declared_in_bytecode()) { |
845 | ASSERT(!expression_evaluation_library_.IsNull()); |
846 | kernel_data = expression_evaluation_library_.kernel_data(); |
847 | kernel_offset = expression_evaluation_library_.kernel_offset(); |
848 | } |
849 | function.SetKernelDataAndScript(eval_script, kernel_data, kernel_offset); |
850 | |
851 | function.set_owner(real_class); |
852 | |
853 | return function.raw(); |
854 | } |
855 | |
856 | void KernelLoader::FindModifiedLibraries(Program* program, |
857 | Isolate* isolate, |
858 | BitVector* modified_libs, |
859 | bool force_reload, |
860 | bool* is_empty_program, |
861 | intptr_t* p_num_classes, |
862 | intptr_t* p_num_procedures) { |
863 | LongJumpScope jump; |
864 | Zone* zone = Thread::Current()->zone(); |
865 | if (setjmp(*jump.Set()) == 0) { |
866 | if (force_reload) { |
867 | // If a reload is being forced we mark all libraries as having |
868 | // been modified. |
869 | const GrowableObjectArray& libs = |
870 | GrowableObjectArray::Handle(isolate->object_store()->libraries()); |
871 | intptr_t num_libs = libs.Length(); |
872 | Library& lib = dart::Library::Handle(zone); |
873 | for (intptr_t i = 0; i < num_libs; i++) { |
874 | lib ^= libs.At(i); |
875 | if (!lib.is_dart_scheme()) { |
876 | modified_libs->Add(lib.index()); |
877 | } |
878 | } |
879 | return; |
880 | } |
881 | |
882 | if (p_num_classes != nullptr) { |
883 | *p_num_classes = 0; |
884 | } |
885 | if (p_num_procedures != nullptr) { |
886 | *p_num_procedures = 0; |
887 | } |
888 | |
889 | // Now go through all the libraries that are present in the incremental |
890 | // kernel files, these will constitute the modified libraries. |
891 | *is_empty_program = true; |
892 | if (program->is_single_program()) { |
893 | KernelLoader loader(program, /*uri_to_source_table=*/nullptr); |
894 | loader.walk_incremental_kernel(modified_libs, is_empty_program, |
895 | p_num_classes, p_num_procedures); |
896 | } |
897 | kernel::Reader reader(program->kernel_data(), program->kernel_data_size()); |
898 | GrowableArray<intptr_t> subprogram_file_starts; |
899 | index_programs(&reader, &subprogram_file_starts); |
900 | |
901 | // Create "fake programs" for each sub-program. |
902 | intptr_t subprogram_count = subprogram_file_starts.length() - 1; |
903 | for (intptr_t i = 0; i < subprogram_count; ++i) { |
904 | intptr_t subprogram_start = subprogram_file_starts.At(i); |
905 | intptr_t subprogram_end = subprogram_file_starts.At(i + 1); |
906 | reader.set_raw_buffer(program->kernel_data() + subprogram_start); |
907 | reader.set_size(subprogram_end - subprogram_start); |
908 | reader.set_offset(0); |
909 | const char* error = nullptr; |
910 | std::unique_ptr<Program> subprogram = Program::ReadFrom(&reader, &error); |
911 | if (subprogram == nullptr) { |
912 | FATAL1("Failed to load kernel file: %s" , error); |
913 | } |
914 | ASSERT(subprogram->is_single_program()); |
915 | KernelLoader loader(subprogram.get(), /*uri_to_source_table=*/nullptr); |
916 | loader.walk_incremental_kernel(modified_libs, is_empty_program, |
917 | p_num_classes, p_num_procedures); |
918 | } |
919 | } |
920 | } |
921 | |
922 | void KernelLoader::walk_incremental_kernel(BitVector* modified_libs, |
923 | bool* is_empty_program, |
924 | intptr_t* p_num_classes, |
925 | intptr_t* p_num_procedures) { |
926 | if (bytecode_metadata_helper_.FindModifiedLibrariesForHotReload( |
927 | modified_libs, is_empty_program, p_num_classes, p_num_procedures)) { |
928 | return; |
929 | } |
930 | intptr_t length = program_->library_count(); |
931 | *is_empty_program = *is_empty_program && (length == 0); |
932 | bool collect_library_stats = |
933 | p_num_classes != nullptr || p_num_procedures != nullptr; |
934 | intptr_t num_classes = 0; |
935 | intptr_t num_procedures = 0; |
936 | Library& lib = Library::Handle(Z); |
937 | for (intptr_t i = 0; i < length; i++) { |
938 | intptr_t kernel_offset = library_offset(i); |
939 | helper_.SetOffset(kernel_offset); |
940 | LibraryHelper library_helper(&helper_, kernel_binary_version_); |
941 | library_helper.ReadUntilIncluding(LibraryHelper::kCanonicalName); |
942 | lib = LookupLibraryOrNull(library_helper.canonical_name_); |
943 | if (!lib.IsNull() && !lib.is_dart_scheme()) { |
944 | // This is a library that already exists so mark it as being modified. |
945 | modified_libs->Add(lib.index()); |
946 | } |
947 | if (collect_library_stats) { |
948 | intptr_t library_end = library_offset(i + 1); |
949 | library_kernel_data_ = |
950 | helper_.reader_.ExternalDataFromTo(kernel_offset, library_end); |
951 | LibraryIndex library_index(library_kernel_data_, kernel_binary_version_); |
952 | num_classes += library_index.class_count(); |
953 | num_procedures += library_index.procedure_count(); |
954 | } |
955 | } |
956 | if (p_num_classes != nullptr) { |
957 | *p_num_classes += num_classes; |
958 | } |
959 | if (p_num_procedures != nullptr) { |
960 | *p_num_procedures += num_procedures; |
961 | } |
962 | } |
963 | |
964 | void KernelLoader::ReadInferredType(const Field& field, |
965 | intptr_t kernel_offset) { |
966 | const InferredTypeMetadata type = |
967 | inferred_type_metadata_helper_.GetInferredType(kernel_offset, |
968 | /*read_constant=*/false); |
969 | if (type.IsTrivial()) { |
970 | return; |
971 | } |
972 | field.set_guarded_cid(type.cid); |
973 | field.set_is_nullable(type.IsNullable()); |
974 | field.set_guarded_list_length(Field::kNoFixedLength); |
975 | if (FLAG_precompiled_mode) { |
976 | field.set_is_unboxing_candidate( |
977 | !field.is_late() && !field.is_static() && |
978 | ((field.guarded_cid() == kDoubleCid && |
979 | FlowGraphCompiler::SupportsUnboxedDoubles()) || |
980 | (field.guarded_cid() == kFloat32x4Cid && |
981 | FlowGraphCompiler::SupportsUnboxedSimd128()) || |
982 | (field.guarded_cid() == kFloat64x2Cid && |
983 | FlowGraphCompiler::SupportsUnboxedSimd128()) || |
984 | type.IsInt()) && |
985 | !field.is_nullable()); |
986 | field.set_is_non_nullable_integer(!field.is_nullable() && type.IsInt()); |
987 | } |
988 | } |
989 | |
990 | void KernelLoader::CheckForInitializer(const Field& field) { |
991 | if (helper_.PeekTag() == kSomething) { |
992 | field.set_has_initializer(true); |
993 | SimpleExpressionConverter converter(&H, &helper_); |
994 | const bool has_simple_initializer = |
995 | converter.IsSimple(helper_.ReaderOffset() + 1); |
996 | if (!has_simple_initializer || !converter.SimpleValue().IsNull()) { |
997 | field.set_has_nontrivial_initializer(true); |
998 | return; |
999 | } |
1000 | } |
1001 | field.set_has_initializer(false); |
1002 | field.set_has_nontrivial_initializer(false); |
1003 | } |
1004 | |
1005 | LibraryPtr KernelLoader::LoadLibrary(intptr_t index) { |
1006 | if (!program_->is_single_program()) { |
1007 | FATAL( |
1008 | "Trying to load a concatenated dill file at a time where that is " |
1009 | "not allowed" ); |
1010 | } |
1011 | |
1012 | // Read library index. |
1013 | library_kernel_offset_ = library_offset(index); |
1014 | correction_offset_ = library_kernel_offset_; |
1015 | intptr_t library_end = library_offset(index + 1); |
1016 | intptr_t library_size = library_end - library_kernel_offset_; |
1017 | |
1018 | // NOTE: Since |helper_| is used to load the overall kernel program, |
1019 | // it's reader's offset is an offset into the overall kernel program. |
1020 | // Hence, when setting the kernel offsets of field and functions, one |
1021 | // has to subtract the library's kernel offset from the reader's |
1022 | // offset. |
1023 | helper_.SetOffset(library_kernel_offset_); |
1024 | |
1025 | LibraryHelper library_helper(&helper_, kernel_binary_version_); |
1026 | library_helper.ReadUntilIncluding(LibraryHelper::kCanonicalName); |
1027 | if (!FLAG_precompiled_mode && !I->should_load_vmservice()) { |
1028 | StringIndex lib_name_index = |
1029 | H.CanonicalNameString(library_helper.canonical_name_); |
1030 | if (H.StringEquals(lib_name_index, kVMServiceIOLibraryUri)) { |
1031 | // We are not the service isolate and we are not generating an AOT |
1032 | // snapshot so we skip loading 'dart:vmservice_io'. |
1033 | skip_vmservice_library_ = library_helper.canonical_name_; |
1034 | ASSERT(H.IsLibrary(skip_vmservice_library_)); |
1035 | return Library::null(); |
1036 | } |
1037 | } |
1038 | |
1039 | Library& library = |
1040 | Library::Handle(Z, LookupLibrary(library_helper.canonical_name_)); |
1041 | |
1042 | // The Kernel library is external implies that it is already loaded. |
1043 | ASSERT(!library_helper.IsExternal() || library.Loaded()); |
1044 | if (library.Loaded()) return library.raw(); |
1045 | |
1046 | library.set_is_nnbd(library_helper.IsNonNullableByDefault()); |
1047 | const NNBDCompiledMode mode = |
1048 | library_helper.GetNonNullableByDefaultCompiledMode(); |
1049 | if (!I->null_safety() && mode == NNBDCompiledMode::kStrong) { |
1050 | H.ReportError( |
1051 | "Library '%s' was compiled with sound null safety (in strong mode) and " |
1052 | "it " |
1053 | "requires --sound-null-safety option at runtime" , |
1054 | String::Handle(library.url()).ToCString()); |
1055 | } |
1056 | if (I->null_safety() && (mode == NNBDCompiledMode::kWeak || |
1057 | mode == NNBDCompiledMode::kDisabled)) { |
1058 | H.ReportError( |
1059 | "Library '%s' was compiled without sound null safety (in weak mode) " |
1060 | "and it " |
1061 | "cannot be used with --sound-null-safety at runtime" , |
1062 | String::Handle(library.url()).ToCString()); |
1063 | } |
1064 | library.set_nnbd_compiled_mode(mode); |
1065 | |
1066 | library_kernel_data_ = helper_.reader_.ExternalDataFromTo( |
1067 | library_kernel_offset_, library_kernel_offset_ + library_size); |
1068 | library.set_kernel_data(library_kernel_data_); |
1069 | library.set_kernel_offset(library_kernel_offset_); |
1070 | |
1071 | LibraryIndex library_index(library_kernel_data_, kernel_binary_version_); |
1072 | intptr_t class_count = library_index.class_count(); |
1073 | |
1074 | library_helper.ReadUntilIncluding(LibraryHelper::kName); |
1075 | library.SetName(H.DartSymbolObfuscate(library_helper.name_index_)); |
1076 | |
1077 | // The bootstrapper will take care of creating the native wrapper classes, but |
1078 | // we will add the synthetic constructors to them here. |
1079 | if (library.name() == |
1080 | Symbols::Symbol(Symbols::kDartNativeWrappersLibNameId).raw()) { |
1081 | ASSERT(library.LoadInProgress()); |
1082 | loading_native_wrappers_library_ = true; |
1083 | } else { |
1084 | loading_native_wrappers_library_ = false; |
1085 | library.SetLoadInProgress(); |
1086 | } |
1087 | |
1088 | library_helper.ReadUntilIncluding(LibraryHelper::kSourceUriIndex); |
1089 | const Script& script = |
1090 | Script::Handle(Z, ScriptAt(library_helper.source_uri_index_)); |
1091 | |
1092 | library_helper.ReadUntilExcluding(LibraryHelper::kAnnotations); |
1093 | intptr_t annotations_kernel_offset = |
1094 | helper_.ReaderOffset() - correction_offset_; |
1095 | intptr_t annotation_count = helper_.ReadListLength(); // read list length. |
1096 | if (annotation_count > 0) { |
1097 | // This must wait until we can evaluate constants. |
1098 | // So put on the "pending" list. |
1099 | H.AddPotentialExtensionLibrary(library); |
1100 | } |
1101 | for (intptr_t i = 0; i < annotation_count; ++i) { |
1102 | helper_.SkipExpression(); // read ith annotation. |
1103 | } |
1104 | library_helper.SetJustRead(LibraryHelper::kAnnotations); |
1105 | |
1106 | // Setup toplevel class (which contains library fields/procedures). |
1107 | |
1108 | // We do not register expression evaluation classes with the VM: |
1109 | // The expression evaluation functions should be GC-able as soon as |
1110 | // they are not reachable anymore and we never look them up by name. |
1111 | const bool register_class = |
1112 | library.raw() != expression_evaluation_library_.raw(); |
1113 | |
1114 | Class& toplevel_class = |
1115 | Class::Handle(Z, Class::New(library, Symbols::TopLevel(), script, |
1116 | TokenPosition::kNoSource, register_class)); |
1117 | toplevel_class.set_is_abstract(); |
1118 | toplevel_class.set_is_declaration_loaded(); |
1119 | toplevel_class.set_is_type_finalized(); |
1120 | library.set_toplevel_class(toplevel_class); |
1121 | |
1122 | library_helper.ReadUntilExcluding(LibraryHelper::kDependencies); |
1123 | LoadLibraryImportsAndExports(&library, toplevel_class); |
1124 | library_helper.SetJustRead(LibraryHelper::kDependencies); |
1125 | |
1126 | // Everything up til the classes are skipped implicitly, and library_helper |
1127 | // is no longer used. |
1128 | |
1129 | const GrowableObjectArray& classes = |
1130 | GrowableObjectArray::Handle(Z, I->object_store()->pending_classes()); |
1131 | |
1132 | // Load all classes. |
1133 | intptr_t next_class_offset = library_index.ClassOffset(0); |
1134 | Class& klass = Class::Handle(Z); |
1135 | for (intptr_t i = 0; i < class_count; ++i) { |
1136 | helper_.SetOffset(next_class_offset); |
1137 | next_class_offset = library_index.ClassOffset(i + 1); |
1138 | LoadClass(library, toplevel_class, next_class_offset, &klass); |
1139 | if (register_class) { |
1140 | classes.Add(klass, Heap::kOld); |
1141 | } |
1142 | } |
1143 | |
1144 | if (loading_native_wrappers_library_ || !register_class) { |
1145 | FinishTopLevelClassLoading(toplevel_class, library, library_index); |
1146 | } |
1147 | |
1148 | if (FLAG_enable_mirrors && annotation_count > 0) { |
1149 | ASSERT(annotations_kernel_offset > 0); |
1150 | library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource, |
1151 | annotations_kernel_offset, 0); |
1152 | } |
1153 | |
1154 | if (register_class) { |
1155 | helper_.SetOffset(library_index.SourceReferencesOffset()); |
1156 | intptr_t count = helper_.ReadUInt(); |
1157 | const GrowableObjectArray& used_scripts = |
1158 | GrowableObjectArray::Handle(library.used_scripts()); |
1159 | Script& script = Script::Handle(Z); |
1160 | for (intptr_t i = 0; i < count; i++) { |
1161 | intptr_t uri_index = helper_.ReadUInt(); |
1162 | script = ScriptAt(uri_index); |
1163 | used_scripts.Add(script); |
1164 | } |
1165 | } |
1166 | if (!library.Loaded()) library.SetLoaded(); |
1167 | |
1168 | return library.raw(); |
1169 | } |
1170 | |
1171 | void KernelLoader::FinishTopLevelClassLoading( |
1172 | const Class& toplevel_class, |
1173 | const Library& library, |
1174 | const LibraryIndex& library_index) { |
1175 | if (toplevel_class.is_loaded()) { |
1176 | return; |
1177 | } |
1178 | TIMELINE_DURATION(Thread::Current(), Isolate, "FinishTopLevelClassLoading" ); |
1179 | |
1180 | ActiveClassScope active_class_scope(&active_class_, &toplevel_class); |
1181 | |
1182 | // Offsets within library index are whole program offsets and not |
1183 | // relative to the library. |
1184 | const intptr_t correction = correction_offset_ - library_kernel_offset_; |
1185 | helper_.SetOffset(library_index.ClassOffset(library_index.class_count()) + |
1186 | correction); |
1187 | |
1188 | if (kernel_binary_version_ >= 30) { |
1189 | const intptr_t extension_count = helper_.ReadListLength(); |
1190 | for (intptr_t i = 0; i < extension_count; ++i) { |
1191 | helper_.ReadTag(); // read tag. |
1192 | helper_.SkipCanonicalNameReference(); // skip canonical name. |
1193 | helper_.SkipStringReference(); // skip name. |
1194 | helper_.ReadUInt(); // read source uri index. |
1195 | helper_.ReadPosition(); // read file offset. |
1196 | helper_.SkipTypeParametersList(); // skip type parameter list. |
1197 | helper_.SkipDartType(); // skip on-type. |
1198 | |
1199 | const intptr_t extension_member_count = helper_.ReadListLength(); |
1200 | for (intptr_t j = 0; j < extension_member_count; ++j) { |
1201 | helper_.SkipName(); // skip name. |
1202 | helper_.ReadByte(); // read kind. |
1203 | helper_.ReadByte(); // read flags. |
1204 | helper_.SkipCanonicalNameReference(); // skip member reference |
1205 | } |
1206 | } |
1207 | } |
1208 | |
1209 | fields_.Clear(); |
1210 | functions_.Clear(); |
1211 | |
1212 | // Load toplevel fields. |
1213 | const intptr_t field_count = helper_.ReadListLength(); // read list length. |
1214 | for (intptr_t i = 0; i < field_count; ++i) { |
1215 | intptr_t field_offset = helper_.ReaderOffset() - correction_offset_; |
1216 | ActiveMemberScope active_member_scope(&active_class_, NULL); |
1217 | FieldHelper field_helper(&helper_); |
1218 | field_helper.ReadUntilExcluding(FieldHelper::kName); |
1219 | |
1220 | const String& name = helper_.ReadNameAsFieldName(); |
1221 | field_helper.SetJustRead(FieldHelper::kName); |
1222 | |
1223 | field_helper.ReadUntilExcluding(FieldHelper::kAnnotations); |
1224 | intptr_t annotation_count = helper_.ReadListLength(); |
1225 | bool has_pragma_annotation; |
1226 | { |
1227 | String& native_name_unused = String::Handle(); |
1228 | bool is_potential_native_unused; |
1229 | ReadVMAnnotations(library, annotation_count, &native_name_unused, |
1230 | &is_potential_native_unused, &has_pragma_annotation); |
1231 | } |
1232 | field_helper.SetJustRead(FieldHelper::kAnnotations); |
1233 | |
1234 | field_helper.ReadUntilExcluding(FieldHelper::kType); |
1235 | const Object& script_class = |
1236 | ClassForScriptAt(toplevel_class, field_helper.source_uri_index_); |
1237 | // In the VM all const fields are implicitly final whereas in Kernel they |
1238 | // are not final because they are not explicitly declared that way. |
1239 | const bool is_final = field_helper.IsConst() || field_helper.IsFinal(); |
1240 | // Only instance fields could be covariant. |
1241 | ASSERT(!field_helper.IsCovariant() && |
1242 | !field_helper.IsGenericCovariantImpl()); |
1243 | const bool is_late = field_helper.IsLate(); |
1244 | const bool is_extension_member = field_helper.IsExtensionMember(); |
1245 | const Field& field = Field::Handle( |
1246 | Z, Field::NewTopLevel(name, is_final, field_helper.IsConst(), is_late, |
1247 | script_class, field_helper.position_, |
1248 | field_helper.end_position_)); |
1249 | field.set_kernel_offset(field_offset); |
1250 | field.set_has_pragma(has_pragma_annotation); |
1251 | field.set_is_extension_member(is_extension_member); |
1252 | const AbstractType& type = T.BuildType(); // read type. |
1253 | field.SetFieldType(type); |
1254 | ReadInferredType(field, field_offset + library_kernel_offset_); |
1255 | CheckForInitializer(field); |
1256 | // In NNBD libraries, static fields with initializers are |
1257 | // implicitly late. |
1258 | if (field.has_initializer() && library.is_nnbd()) { |
1259 | field.set_is_late(true); |
1260 | } |
1261 | field_helper.SetJustRead(FieldHelper::kType); |
1262 | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); |
1263 | intptr_t field_initializer_offset = helper_.ReaderOffset(); |
1264 | field_helper.ReadUntilExcluding(FieldHelper::kEnd); |
1265 | { |
1266 | // GenerateFieldAccessors reads (some of) the initializer. |
1267 | AlternativeReadingScope alt(&helper_.reader_, field_initializer_offset); |
1268 | GenerateFieldAccessors(toplevel_class, field, &field_helper); |
1269 | } |
1270 | if ((FLAG_enable_mirrors || has_pragma_annotation) && |
1271 | annotation_count > 0) { |
1272 | library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset, |
1273 | 0); |
1274 | } |
1275 | fields_.Add(&field); |
1276 | } |
1277 | |
1278 | ASSERT(!toplevel_class.is_loaded()); |
1279 | |
1280 | // Load toplevel procedures. |
1281 | intptr_t next_procedure_offset = |
1282 | library_index.ProcedureOffset(0) + correction; |
1283 | const intptr_t procedure_count = library_index.procedure_count(); |
1284 | for (intptr_t i = 0; i < procedure_count; ++i) { |
1285 | helper_.SetOffset(next_procedure_offset); |
1286 | next_procedure_offset = library_index.ProcedureOffset(i + 1) + correction; |
1287 | LoadProcedure(library, toplevel_class, false, next_procedure_offset); |
1288 | // LoadProcedure calls Library::GetMetadata which invokes Dart code |
1289 | // which may recursively trigger class finalization and |
1290 | // FinishTopLevelClassLoading. |
1291 | // In such case, return immediately and avoid overwriting already finalized |
1292 | // functions with freshly loaded and not yet finalized. |
1293 | if (toplevel_class.is_loaded()) { |
1294 | return; |
1295 | } |
1296 | } |
1297 | |
1298 | toplevel_class.SetFields(Array::Handle(MakeFieldsArray())); |
1299 | toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray())); |
1300 | |
1301 | String& name = String::Handle(Z); |
1302 | for (intptr_t i = 0, n = fields_.length(); i < n; ++i) { |
1303 | const Field* field = fields_.At(i); |
1304 | name = field->name(); |
1305 | library.AddObject(*field, name); |
1306 | } |
1307 | for (intptr_t i = 0, n = functions_.length(); i < n; ++i) { |
1308 | const Function* function = functions_.At(i); |
1309 | name = function->name(); |
1310 | library.AddObject(*function, name); |
1311 | } |
1312 | |
1313 | ASSERT(!toplevel_class.is_loaded()); |
1314 | toplevel_class.set_is_loaded(true); |
1315 | } |
1316 | |
1317 | void KernelLoader::LoadLibraryImportsAndExports(Library* library, |
1318 | const Class& toplevel_class) { |
1319 | GrowableObjectArray& show_list = GrowableObjectArray::Handle(Z); |
1320 | GrowableObjectArray& hide_list = GrowableObjectArray::Handle(Z); |
1321 | Array& show_names = Array::Handle(Z); |
1322 | Array& hide_names = Array::Handle(Z); |
1323 | Namespace& ns = Namespace::Handle(Z); |
1324 | LibraryPrefix& library_prefix = LibraryPrefix::Handle(Z); |
1325 | |
1326 | const intptr_t deps_count = helper_.ReadListLength(); |
1327 | const Array& deps = Array::Handle(Array::New(deps_count)); |
1328 | for (intptr_t dep = 0; dep < deps_count; ++dep) { |
1329 | LibraryDependencyHelper dependency_helper(&helper_); |
1330 | |
1331 | dependency_helper.ReadUntilExcluding(LibraryDependencyHelper::kAnnotations); |
1332 | intptr_t annotations_kernel_offset = |
1333 | helper_.ReaderOffset() - correction_offset_; |
1334 | |
1335 | dependency_helper.ReadUntilExcluding(LibraryDependencyHelper::kCombinators); |
1336 | |
1337 | // Ignore the dependency if the target library is invalid. |
1338 | // The error will be caught during compilation. |
1339 | if (dependency_helper.target_library_canonical_name_ < 0) { |
1340 | const intptr_t combinator_count = helper_.ReadListLength(); |
1341 | for (intptr_t c = 0; c < combinator_count; ++c) { |
1342 | helper_.SkipLibraryCombinator(); |
1343 | } |
1344 | continue; |
1345 | } |
1346 | |
1347 | // Prepare show and hide lists. |
1348 | show_list = GrowableObjectArray::New(Heap::kOld); |
1349 | hide_list = GrowableObjectArray::New(Heap::kOld); |
1350 | const intptr_t combinator_count = helper_.ReadListLength(); |
1351 | for (intptr_t c = 0; c < combinator_count; ++c) { |
1352 | uint8_t flags = helper_.ReadFlags(); |
1353 | intptr_t name_count = helper_.ReadListLength(); |
1354 | for (intptr_t n = 0; n < name_count; ++n) { |
1355 | String& show_hide_name = |
1356 | H.DartSymbolObfuscate(helper_.ReadStringReference()); |
1357 | if ((flags & LibraryDependencyHelper::Show) != 0) { |
1358 | show_list.Add(show_hide_name, Heap::kOld); |
1359 | } else { |
1360 | hide_list.Add(show_hide_name, Heap::kOld); |
1361 | } |
1362 | } |
1363 | } |
1364 | |
1365 | if (show_list.Length() > 0) { |
1366 | show_names = Array::MakeFixedLength(show_list); |
1367 | } else { |
1368 | show_names = Array::null(); |
1369 | } |
1370 | |
1371 | if (hide_list.Length() > 0) { |
1372 | hide_names = Array::MakeFixedLength(hide_list); |
1373 | } else { |
1374 | hide_names = Array::null(); |
1375 | } |
1376 | |
1377 | Library& target_library = Library::Handle( |
1378 | Z, LookupLibrary(dependency_helper.target_library_canonical_name_)); |
1379 | if (!FLAG_enable_mirrors && |
1380 | target_library.url() == Symbols::DartMirrors().raw()) { |
1381 | H.ReportError( |
1382 | "import of dart:mirrors is not supported in the current Dart " |
1383 | "runtime" ); |
1384 | } |
1385 | if (!Api::IsFfiEnabled() && |
1386 | target_library.url() == Symbols::DartFfi().raw()) { |
1387 | H.ReportError( |
1388 | "import of dart:ffi is not supported in the current Dart runtime" ); |
1389 | } |
1390 | String& prefix = H.DartSymbolPlain(dependency_helper.name_index_); |
1391 | ns = Namespace::New(target_library, show_names, hide_names); |
1392 | if ((dependency_helper.flags_ & LibraryDependencyHelper::Export) != 0) { |
1393 | library->AddExport(ns); |
1394 | } else { |
1395 | if (prefix.IsNull() || prefix.Length() == 0) { |
1396 | library->AddImport(ns); |
1397 | } else { |
1398 | library_prefix = library->LookupLocalLibraryPrefix(prefix); |
1399 | if (!library_prefix.IsNull()) { |
1400 | library_prefix.AddImport(ns); |
1401 | } else { |
1402 | library_prefix = LibraryPrefix::New( |
1403 | prefix, ns, |
1404 | (dependency_helper.flags_ & LibraryDependencyHelper::Deferred) != |
1405 | 0, |
1406 | *library); |
1407 | library->AddObject(library_prefix, prefix); |
1408 | } |
1409 | } |
1410 | } |
1411 | |
1412 | if (FLAG_enable_mirrors && dependency_helper.annotation_count_ > 0) { |
1413 | ASSERT(annotations_kernel_offset > 0); |
1414 | ns.AddMetadata(toplevel_class, TokenPosition::kNoSource, |
1415 | annotations_kernel_offset); |
1416 | } |
1417 | |
1418 | if (prefix.IsNull()) { |
1419 | deps.SetAt(dep, ns); |
1420 | } else { |
1421 | deps.SetAt(dep, library_prefix); |
1422 | } |
1423 | } |
1424 | |
1425 | library->set_dependencies(deps); |
1426 | } |
1427 | |
1428 | void KernelLoader::LoadPreliminaryClass(ClassHelper* class_helper, |
1429 | intptr_t type_parameter_count) { |
1430 | const Class* klass = active_class_.klass; |
1431 | |
1432 | // Enable access to type_parameters(). |
1433 | klass->set_is_declaration_loaded(); |
1434 | |
1435 | // Note: This assumes that ClassHelper is exactly at the position where |
1436 | // the length of the type parameters have been read, and that the order in |
1437 | // the binary is as follows: [...], kTypeParameters, kSuperClass, kMixinType, |
1438 | // kImplementedClasses, [...]. |
1439 | |
1440 | // Set type parameters. |
1441 | T.LoadAndSetupTypeParameters(&active_class_, *klass, type_parameter_count, |
1442 | Function::Handle(Z)); |
1443 | |
1444 | // Set super type. Some classes (e.g., Object) do not have one. |
1445 | Tag type_tag = helper_.ReadTag(); // read super class type (part 1). |
1446 | if (type_tag == kSomething) { |
1447 | AbstractType& super_type = |
1448 | T.BuildTypeWithoutFinalization(); // read super class type (part 2). |
1449 | klass->set_super_type(super_type); |
1450 | } |
1451 | |
1452 | class_helper->SetJustRead(ClassHelper::kSuperClass); |
1453 | class_helper->ReadUntilIncluding(ClassHelper::kMixinType); |
1454 | |
1455 | // Build implemented interface types |
1456 | intptr_t interface_count = helper_.ReadListLength(); |
1457 | const Array& interfaces = |
1458 | Array::Handle(Z, Array::New(interface_count, Heap::kOld)); |
1459 | for (intptr_t i = 0; i < interface_count; i++) { |
1460 | const AbstractType& type = |
1461 | T.BuildTypeWithoutFinalization(); // read ith type. |
1462 | interfaces.SetAt(i, type); |
1463 | } |
1464 | class_helper->SetJustRead(ClassHelper::kImplementedClasses); |
1465 | klass->set_interfaces(interfaces); |
1466 | |
1467 | if (class_helper->is_abstract()) klass->set_is_abstract(); |
1468 | |
1469 | if (class_helper->is_transformed_mixin_application()) { |
1470 | klass->set_is_transformed_mixin_application(); |
1471 | } |
1472 | if (class_helper->has_const_constructor()) { |
1473 | klass->set_is_const(); |
1474 | } |
1475 | } |
1476 | |
1477 | void KernelLoader::LoadClass(const Library& library, |
1478 | const Class& toplevel_class, |
1479 | intptr_t class_end, |
1480 | Class* out_class) { |
1481 | intptr_t class_offset = helper_.ReaderOffset(); |
1482 | ClassIndex class_index(program_->kernel_data(), program_->kernel_data_size(), |
1483 | class_offset, class_end - class_offset); |
1484 | |
1485 | ClassHelper class_helper(&helper_); |
1486 | class_helper.ReadUntilIncluding(ClassHelper::kCanonicalName); |
1487 | *out_class = LookupClass(library, class_helper.canonical_name_); |
1488 | out_class->set_kernel_offset(class_offset - correction_offset_); |
1489 | |
1490 | // The class needs to have a script because all the functions in the class |
1491 | // will inherit it. The predicate Function::IsOptimizable uses the absence of |
1492 | // a script to detect test functions that should not be optimized. |
1493 | if (out_class->script() == Script::null()) { |
1494 | class_helper.ReadUntilIncluding(ClassHelper::kSourceUriIndex); |
1495 | const Script& script = |
1496 | Script::Handle(Z, ScriptAt(class_helper.source_uri_index_)); |
1497 | out_class->set_script(script); |
1498 | } |
1499 | if (out_class->token_pos() == TokenPosition::kNoSource) { |
1500 | class_helper.ReadUntilIncluding(ClassHelper::kEndPosition); |
1501 | out_class->set_token_pos(class_helper.start_position_); |
1502 | out_class->set_end_token_pos(class_helper.end_position_); |
1503 | } |
1504 | |
1505 | class_helper.ReadUntilIncluding(ClassHelper::kFlags); |
1506 | if (class_helper.is_enum_class()) { |
1507 | out_class->set_is_enum_class(); |
1508 | } |
1509 | |
1510 | class_helper.ReadUntilExcluding(ClassHelper::kAnnotations); |
1511 | intptr_t annotation_count = helper_.ReadListLength(); |
1512 | bool has_pragma_annotation = false; |
1513 | { |
1514 | String& native_name_unused = String::Handle(Z); |
1515 | bool is_potential_native_unused = false; |
1516 | ReadVMAnnotations(library, annotation_count, &native_name_unused, |
1517 | &is_potential_native_unused, &has_pragma_annotation); |
1518 | } |
1519 | if (has_pragma_annotation) { |
1520 | out_class->set_has_pragma(true); |
1521 | } |
1522 | class_helper.SetJustRead(ClassHelper::kAnnotations); |
1523 | class_helper.ReadUntilExcluding(ClassHelper::kTypeParameters); |
1524 | intptr_t type_parameter_counts = |
1525 | helper_.ReadListLength(); // read type_parameters list length. |
1526 | |
1527 | ActiveClassScope active_class_scope(&active_class_, out_class); |
1528 | if (!out_class->is_declaration_loaded()) { |
1529 | LoadPreliminaryClass(&class_helper, type_parameter_counts); |
1530 | } else { |
1531 | ASSERT(type_parameter_counts == 0); |
1532 | class_helper.SetJustRead(ClassHelper::kTypeParameters); |
1533 | } |
1534 | |
1535 | if ((FLAG_enable_mirrors || has_pragma_annotation) && annotation_count > 0) { |
1536 | library.AddClassMetadata(*out_class, toplevel_class, |
1537 | TokenPosition::kNoSource, |
1538 | class_offset - correction_offset_, 0); |
1539 | } |
1540 | |
1541 | // We do not register expression evaluation classes with the VM: |
1542 | // The expression evaluation functions should be GC-able as soon as |
1543 | // they are not reachable anymore and we never look them up by name. |
1544 | const bool register_class = |
1545 | library.raw() != expression_evaluation_library_.raw(); |
1546 | |
1547 | if (loading_native_wrappers_library_ || !register_class) { |
1548 | FinishClassLoading(*out_class, library, toplevel_class, class_offset, |
1549 | class_index, &class_helper); |
1550 | } |
1551 | |
1552 | helper_.SetOffset(class_end); |
1553 | } |
1554 | |
1555 | void KernelLoader::FinishClassLoading(const Class& klass, |
1556 | const Library& library, |
1557 | const Class& toplevel_class, |
1558 | intptr_t class_offset, |
1559 | const ClassIndex& class_index, |
1560 | ClassHelper* class_helper) { |
1561 | if (klass.is_loaded()) { |
1562 | return; |
1563 | } |
1564 | |
1565 | TIMELINE_DURATION(Thread::Current(), Isolate, "FinishClassLoading" ); |
1566 | |
1567 | ActiveClassScope active_class_scope(&active_class_, &klass); |
1568 | |
1569 | // If this is a dart:internal.ClassID class ignore field declarations |
1570 | // contained in the Kernel file and instead inject our own const |
1571 | // fields. |
1572 | const bool discard_fields = klass.InjectCIDFields(); |
1573 | |
1574 | fields_.Clear(); |
1575 | functions_.Clear(); |
1576 | if (!discard_fields) { |
1577 | class_helper->ReadUntilExcluding(ClassHelper::kFields); |
1578 | int field_count = helper_.ReadListLength(); // read list length. |
1579 | for (intptr_t i = 0; i < field_count; ++i) { |
1580 | intptr_t field_offset = helper_.ReaderOffset() - correction_offset_; |
1581 | ActiveMemberScope active_member(&active_class_, NULL); |
1582 | FieldHelper field_helper(&helper_); |
1583 | |
1584 | field_helper.ReadUntilIncluding(FieldHelper::kSourceUriIndex); |
1585 | const Object& script_class = |
1586 | ClassForScriptAt(klass, field_helper.source_uri_index_); |
1587 | |
1588 | field_helper.ReadUntilExcluding(FieldHelper::kName); |
1589 | const String& name = helper_.ReadNameAsFieldName(); |
1590 | field_helper.SetJustRead(FieldHelper::kName); |
1591 | |
1592 | field_helper.ReadUntilExcluding(FieldHelper::kAnnotations); |
1593 | intptr_t annotation_count = helper_.ReadListLength(); |
1594 | bool has_pragma_annotation; |
1595 | { |
1596 | String& native_name_unused = String::Handle(); |
1597 | bool is_potential_native_unused; |
1598 | ReadVMAnnotations(library, annotation_count, &native_name_unused, |
1599 | &is_potential_native_unused, &has_pragma_annotation); |
1600 | } |
1601 | field_helper.SetJustRead(FieldHelper::kAnnotations); |
1602 | |
1603 | field_helper.ReadUntilExcluding(FieldHelper::kType); |
1604 | const AbstractType& type = |
1605 | T.BuildTypeWithoutFinalization(); // read type. |
1606 | field_helper.SetJustRead(FieldHelper::kType); |
1607 | |
1608 | const bool is_reflectable = |
1609 | field_helper.position_.IsReal() && |
1610 | !(library.is_dart_scheme() && library.IsPrivate(name)); |
1611 | // In the VM all const fields are implicitly final whereas in Kernel they |
1612 | // are not final because they are not explicitly declared that way. |
1613 | const bool is_final = field_helper.IsConst() || field_helper.IsFinal(); |
1614 | const bool is_late = field_helper.IsLate(); |
1615 | const bool is_extension_member = field_helper.IsExtensionMember(); |
1616 | Field& field = Field::Handle( |
1617 | Z, Field::New(name, field_helper.IsStatic(), is_final, |
1618 | field_helper.IsConst(), is_reflectable, is_late, |
1619 | script_class, type, field_helper.position_, |
1620 | field_helper.end_position_)); |
1621 | field.set_kernel_offset(field_offset); |
1622 | field.set_has_pragma(has_pragma_annotation); |
1623 | field.set_is_covariant(field_helper.IsCovariant()); |
1624 | field.set_is_generic_covariant_impl( |
1625 | field_helper.IsGenericCovariantImpl()); |
1626 | field.set_is_extension_member(is_extension_member); |
1627 | ReadInferredType(field, field_offset + library_kernel_offset_); |
1628 | CheckForInitializer(field); |
1629 | // In NNBD libraries, static fields with initializers are |
1630 | // implicitly late. |
1631 | if (field_helper.IsStatic() && field.has_initializer() && |
1632 | library.is_nnbd()) { |
1633 | field.set_is_late(true); |
1634 | } |
1635 | field_helper.ReadUntilExcluding(FieldHelper::kInitializer); |
1636 | intptr_t field_initializer_offset = helper_.ReaderOffset(); |
1637 | field_helper.ReadUntilExcluding(FieldHelper::kEnd); |
1638 | { |
1639 | // GenerateFieldAccessors reads (some of) the initializer. |
1640 | AlternativeReadingScope alt(&helper_.reader_, field_initializer_offset); |
1641 | GenerateFieldAccessors(klass, field, &field_helper); |
1642 | } |
1643 | if ((FLAG_enable_mirrors || has_pragma_annotation) && |
1644 | annotation_count > 0) { |
1645 | library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset, |
1646 | 0); |
1647 | } |
1648 | fields_.Add(&field); |
1649 | } |
1650 | class_helper->SetJustRead(ClassHelper::kFields); |
1651 | |
1652 | if (klass.is_enum_class()) { |
1653 | // Add static field 'const _deleted_enum_sentinel'. |
1654 | // This field does not need to be of type E. |
1655 | Field& deleted_enum_sentinel = Field::ZoneHandle(Z); |
1656 | deleted_enum_sentinel = |
1657 | Field::New(Symbols::_DeletedEnumSentinel(), |
1658 | /* is_static = */ true, |
1659 | /* is_final = */ true, |
1660 | /* is_const = */ true, |
1661 | /* is_reflectable = */ false, |
1662 | /* is_late = */ false, klass, Object::dynamic_type(), |
1663 | TokenPosition::kNoSource, TokenPosition::kNoSource); |
1664 | fields_.Add(&deleted_enum_sentinel); |
1665 | } |
1666 | |
1667 | // Due to ReadVMAnnotations(), the klass may have been loaded at this point |
1668 | // (loading the class while evaluating annotations). |
1669 | if (klass.is_loaded()) { |
1670 | return; |
1671 | } |
1672 | |
1673 | klass.SetFields(Array::Handle(Z, MakeFieldsArray())); |
1674 | } |
1675 | |
1676 | class_helper->ReadUntilExcluding(ClassHelper::kConstructors); |
1677 | int constructor_count = helper_.ReadListLength(); // read list length. |
1678 | for (intptr_t i = 0; i < constructor_count; ++i) { |
1679 | intptr_t constructor_offset = helper_.ReaderOffset() - correction_offset_; |
1680 | ActiveMemberScope active_member_scope(&active_class_, NULL); |
1681 | ConstructorHelper constructor_helper(&helper_); |
1682 | constructor_helper.ReadUntilExcluding(ConstructorHelper::kAnnotations); |
1683 | intptr_t annotation_count = helper_.ReadListLength(); |
1684 | bool has_pragma_annotation; |
1685 | { |
1686 | String& native_name_unused = String::Handle(); |
1687 | bool is_potential_native_unused; |
1688 | ReadVMAnnotations(library, annotation_count, &native_name_unused, |
1689 | &is_potential_native_unused, &has_pragma_annotation); |
1690 | } |
1691 | constructor_helper.SetJustRead(ConstructorHelper::kAnnotations); |
1692 | constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction); |
1693 | |
1694 | const String& name = |
1695 | H.DartConstructorName(constructor_helper.canonical_name_); |
1696 | |
1697 | // We can have synthetic constructors, which will not have a source uri |
1698 | // attached to them (which means the index into the source uri table is 0, |
1699 | // see `package:kernel/binary/ast_to_binary::writeUriReference`. |
1700 | const Object* owner = &klass; |
1701 | const intptr_t source_uri_index = constructor_helper.source_uri_index_; |
1702 | if (source_uri_index != 0) { |
1703 | owner = &ClassForScriptAt(klass, source_uri_index); |
1704 | } |
1705 | |
1706 | Function& function = Function::ZoneHandle( |
1707 | Z, Function::New(name, FunctionLayout::kConstructor, |
1708 | false, // is_static |
1709 | constructor_helper.IsConst(), |
1710 | false, // is_abstract |
1711 | constructor_helper.IsExternal(), |
1712 | false, // is_native |
1713 | *owner, constructor_helper.start_position_)); |
1714 | function.set_end_token_pos(constructor_helper.end_position_); |
1715 | functions_.Add(&function); |
1716 | function.set_kernel_offset(constructor_offset); |
1717 | function.set_result_type(T.ReceiverType(klass)); |
1718 | function.set_has_pragma(has_pragma_annotation); |
1719 | |
1720 | FunctionNodeHelper function_node_helper(&helper_); |
1721 | function_node_helper.ReadUntilExcluding( |
1722 | FunctionNodeHelper::kTypeParameters); |
1723 | T.SetupFunctionParameters(klass, function, |
1724 | true, // is_method |
1725 | false, // is_closure |
1726 | &function_node_helper); |
1727 | T.SetupUnboxingInfoMetadata(function, library_kernel_offset_); |
1728 | |
1729 | if (library.is_dart_scheme() && |
1730 | H.IsPrivate(constructor_helper.canonical_name_)) { |
1731 | function.set_is_reflectable(false); |
1732 | } |
1733 | |
1734 | if (constructor_helper.IsSynthetic()) { |
1735 | function.set_is_debuggable(false); |
1736 | } |
1737 | |
1738 | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd); |
1739 | constructor_helper.SetJustRead(ConstructorHelper::kFunction); |
1740 | constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd); |
1741 | |
1742 | if ((FLAG_enable_mirrors || has_pragma_annotation) && |
1743 | annotation_count > 0) { |
1744 | library.AddFunctionMetadata(function, TokenPosition::kNoSource, |
1745 | constructor_offset, 0); |
1746 | } |
1747 | } |
1748 | |
1749 | // Due to ReadVMAnnotations(), the klass may have been loaded at this point |
1750 | // (loading the class while evaluating annotations). |
1751 | if (klass.is_loaded()) { |
1752 | return; |
1753 | } |
1754 | |
1755 | // Everything up til the procedures are skipped implicitly, and class_helper |
1756 | // is no longer used. |
1757 | |
1758 | intptr_t procedure_count = class_index.procedure_count(); |
1759 | // Procedure offsets within a class index are whole program offsets and not |
1760 | // relative to the library of the class. Hence, we need a correction to get |
1761 | // the currect procedure offset within the current data. |
1762 | intptr_t correction = correction_offset_ - library_kernel_offset_; |
1763 | intptr_t next_procedure_offset = class_index.ProcedureOffset(0) + correction; |
1764 | for (intptr_t i = 0; i < procedure_count; ++i) { |
1765 | helper_.SetOffset(next_procedure_offset); |
1766 | next_procedure_offset = class_index.ProcedureOffset(i + 1) + correction; |
1767 | LoadProcedure(library, klass, true, next_procedure_offset); |
1768 | // LoadProcedure calls Library::GetMetadata which invokes Dart code |
1769 | // which may recursively trigger class finalization and FinishClassLoading. |
1770 | // In such case, return immediately and avoid overwriting already finalized |
1771 | // functions with freshly loaded and not yet finalized. |
1772 | if (klass.is_loaded()) { |
1773 | return; |
1774 | } |
1775 | } |
1776 | |
1777 | klass.SetFunctions(Array::Handle(MakeFunctionsArray())); |
1778 | |
1779 | ASSERT(!klass.is_loaded()); |
1780 | klass.set_is_loaded(true); |
1781 | } |
1782 | |
1783 | void KernelLoader::FinishLoading(const Class& klass) { |
1784 | ASSERT(!klass.is_declared_in_bytecode()); |
1785 | ASSERT(klass.IsTopLevel() || (klass.kernel_offset() > 0)); |
1786 | |
1787 | Zone* zone = Thread::Current()->zone(); |
1788 | const Script& script = Script::Handle(zone, klass.script()); |
1789 | const Library& library = Library::Handle(zone, klass.library()); |
1790 | const Class& toplevel_class = Class::Handle(zone, library.toplevel_class()); |
1791 | const ExternalTypedData& library_kernel_data = |
1792 | ExternalTypedData::Handle(zone, library.kernel_data()); |
1793 | ASSERT(!library_kernel_data.IsNull()); |
1794 | const intptr_t library_kernel_offset = library.kernel_offset(); |
1795 | ASSERT(library_kernel_offset > 0); |
1796 | |
1797 | const KernelProgramInfo& info = |
1798 | KernelProgramInfo::Handle(zone, script.kernel_program_info()); |
1799 | |
1800 | KernelLoader kernel_loader(script, library_kernel_data, library_kernel_offset, |
1801 | info.kernel_binary_version()); |
1802 | LibraryIndex library_index(library_kernel_data, info.kernel_binary_version()); |
1803 | |
1804 | if (klass.IsTopLevel()) { |
1805 | ASSERT(klass.raw() == toplevel_class.raw()); |
1806 | kernel_loader.FinishTopLevelClassLoading(klass, library, library_index); |
1807 | return; |
1808 | } |
1809 | |
1810 | const intptr_t class_offset = klass.kernel_offset(); |
1811 | ClassIndex class_index( |
1812 | library_kernel_data, class_offset, |
1813 | // Class offsets in library index are whole program offsets. |
1814 | // Hence, we need to add |library_kernel_offset| to |
1815 | // |class_offset| to lookup the entry for the class in the library |
1816 | // index. |
1817 | library_index.SizeOfClassAtOffset(class_offset + library_kernel_offset)); |
1818 | |
1819 | kernel_loader.helper_.SetOffset(class_offset); |
1820 | ClassHelper class_helper(&kernel_loader.helper_); |
1821 | |
1822 | kernel_loader.FinishClassLoading(klass, library, toplevel_class, class_offset, |
1823 | class_index, &class_helper); |
1824 | } |
1825 | |
1826 | // Read annotations on a procedure to identify potential VM-specific directives. |
1827 | // |
1828 | // Output parameters: |
1829 | // |
1830 | // `native_name`: non-null if `@ExternalName(...)` was identified. |
1831 | // |
1832 | // `is_potential_native`: non-null if there may be an `@ExternalName(...)` |
1833 | // annotation and we need to re-try after reading the constants table. |
1834 | // |
1835 | // `has_pragma_annotation`: non-null if @pragma(...) was found (no information |
1836 | // is given on the kind of pragma directive). |
1837 | // |
1838 | void KernelLoader::ReadVMAnnotations(const Library& library, |
1839 | intptr_t annotation_count, |
1840 | String* native_name, |
1841 | bool* is_potential_native, |
1842 | bool* has_pragma_annotation) { |
1843 | *is_potential_native = false; |
1844 | *has_pragma_annotation = false; |
1845 | Instance& constant = Instance::Handle(Z); |
1846 | String& detected_name = String::Handle(Z); |
1847 | for (intptr_t i = 0; i < annotation_count; ++i) { |
1848 | const intptr_t tag = helper_.PeekTag(); |
1849 | if (tag == kConstructorInvocation || tag == kConstConstructorInvocation) { |
1850 | const intptr_t start = helper_.ReaderOffset(); |
1851 | detected_name = DetectExternalNameCtor(); |
1852 | if (!detected_name.IsNull()) { |
1853 | *native_name = detected_name.raw(); |
1854 | continue; |
1855 | } |
1856 | |
1857 | helper_.SetOffset(start); |
1858 | if (DetectPragmaCtor()) { |
1859 | *has_pragma_annotation = true; |
1860 | } |
1861 | } else if (tag == kConstantExpression) { |
1862 | const Array& constant_table_array = |
1863 | Array::Handle(kernel_program_info_.constants()); |
1864 | if (constant_table_array.IsNull()) { |
1865 | // We can only read in the constant table once all classes have been |
1866 | // finalized (otherwise we can't create instances of the classes!). |
1867 | // |
1868 | // We therefore delay the scanning for `ExternalName {name: ... }` |
1869 | // constants in the annotation list to later. |
1870 | *is_potential_native = true; |
1871 | |
1872 | ASSERT(kernel_program_info_.constants_table() != |
1873 | ExternalTypedData::null()); |
1874 | |
1875 | // For pragma annotations, we seek into the constants table and peek |
1876 | // into the Kernel representation of the constant. |
1877 | // |
1878 | // TODO(sjindel): Refactor `ExternalName` handling to do this as well |
1879 | // and avoid the "potential natives" list. |
1880 | |
1881 | helper_.ReadByte(); // Skip the tag. |
1882 | helper_.ReadPosition(); // Skip fileOffset. |
1883 | helper_.SkipDartType(); // Skip type. |
1884 | const intptr_t offset_in_constant_table = helper_.ReadUInt(); |
1885 | |
1886 | AlternativeReadingScopeWithNewData scope( |
1887 | &helper_.reader_, |
1888 | &ExternalTypedData::Handle(Z, |
1889 | kernel_program_info_.constants_table()), |
1890 | 0); |
1891 | |
1892 | // Seek into the position within the constant table where we can inspect |
1893 | // this constant's Kernel representation. |
1894 | helper_.ReadUInt(); // skip constant table size |
1895 | helper_.SkipBytes(offset_in_constant_table); |
1896 | uint8_t tag = helper_.ReadTag(); |
1897 | if (tag == kInstanceConstant) { |
1898 | *has_pragma_annotation = |
1899 | *has_pragma_annotation || |
1900 | IsClassName(helper_.ReadCanonicalNameReference(), |
1901 | Symbols::DartCore(), Symbols::Pragma()); |
1902 | } |
1903 | } else { |
1904 | // Prepare lazy constant reading. |
1905 | const dart::Class& toplevel_class = |
1906 | Class::Handle(Z, library.toplevel_class()); |
1907 | ActiveClassScope active_class_scope(&active_class_, &toplevel_class); |
1908 | ConstantReader constant_reader(&helper_, &active_class_); |
1909 | |
1910 | helper_.ReadByte(); // Skip the tag. |
1911 | |
1912 | // Obtain `dart:_internal::ExternalName.name`. |
1913 | EnsureExternalClassIsLookedUp(); |
1914 | |
1915 | // Obtain `dart:_internal::pragma`. |
1916 | EnsurePragmaClassIsLookedUp(); |
1917 | |
1918 | if (tag == kConstantExpression) { |
1919 | helper_.ReadPosition(); // Skip fileOffset. |
1920 | helper_.SkipDartType(); // Skip type. |
1921 | } |
1922 | const intptr_t constant_table_offset = helper_.ReadUInt(); |
1923 | // We have a candidate. Let's look if it's an instance of the |
1924 | // ExternalName or Pragma class. |
1925 | if (constant_reader.IsInstanceConstant(constant_table_offset, |
1926 | external_name_class_)) { |
1927 | constant = constant_reader.ReadConstant(constant_table_offset); |
1928 | ASSERT(constant.clazz() == external_name_class_.raw()); |
1929 | *native_name ^= constant.GetField(external_name_field_); |
1930 | } else if (constant_reader.IsInstanceConstant(constant_table_offset, |
1931 | pragma_class_)) { |
1932 | *has_pragma_annotation = true; |
1933 | } |
1934 | } |
1935 | } else { |
1936 | helper_.SkipExpression(); |
1937 | continue; |
1938 | } |
1939 | } |
1940 | } |
1941 | |
1942 | void KernelLoader::LoadProcedure(const Library& library, |
1943 | const Class& owner, |
1944 | bool in_class, |
1945 | intptr_t procedure_end) { |
1946 | intptr_t procedure_offset = helper_.ReaderOffset() - correction_offset_; |
1947 | ProcedureHelper procedure_helper(&helper_); |
1948 | |
1949 | procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations); |
1950 | // CFE adds 'member signature' abstract functions to a legacy class deriving |
1951 | // or implementing an opted-in interface. The signature of these functions is |
1952 | // legacy erased and used as the target of interface calls. They are used for |
1953 | // static reasoning about the program by CFE, but not really needed by the VM. |
1954 | // In certain situations (e.g. issue 162073826), a large number of these |
1955 | // additional functions can cause strain on the VM. They are therefore skipped |
1956 | // in jit mode and their associated origin function is used instead as |
1957 | // interface call target. |
1958 | if (procedure_helper.IsRedirectingFactoryConstructor() || |
1959 | (!FLAG_precompiled_mode && procedure_helper.IsMemberSignature())) { |
1960 | helper_.SetOffset(procedure_end); |
1961 | return; |
1962 | } |
1963 | const String& name = H.DartProcedureName(procedure_helper.canonical_name_); |
1964 | bool is_method = in_class && !procedure_helper.IsStatic(); |
1965 | bool is_abstract = procedure_helper.IsAbstract(); |
1966 | bool is_external = procedure_helper.IsExternal(); |
1967 | bool is_extension_member = procedure_helper.IsExtensionMember(); |
1968 | String& native_name = String::Handle(Z); |
1969 | bool is_potential_native; |
1970 | bool has_pragma_annotation; |
1971 | const intptr_t annotation_count = helper_.ReadListLength(); |
1972 | ReadVMAnnotations(library, annotation_count, &native_name, |
1973 | &is_potential_native, &has_pragma_annotation); |
1974 | // If this is a potential native, we'll unset is_external in |
1975 | // AnnotateNativeProcedures instead. |
1976 | is_external = is_external && native_name.IsNull(); |
1977 | procedure_helper.SetJustRead(ProcedureHelper::kAnnotations); |
1978 | const Object& script_class = |
1979 | ClassForScriptAt(owner, procedure_helper.source_uri_index_); |
1980 | FunctionLayout::Kind kind = GetFunctionType(procedure_helper.kind_); |
1981 | |
1982 | // We do not register expression evaluation libraries with the VM: |
1983 | // The expression evaluation functions should be GC-able as soon as |
1984 | // they are not reachable anymore and we never look them up by name. |
1985 | const bool register_function = !name.Equals(Symbols::DebugProcedureName()); |
1986 | |
1987 | Function& function = Function::ZoneHandle( |
1988 | Z, Function::New(name, kind, |
1989 | !is_method, // is_static |
1990 | false, // is_const |
1991 | is_abstract, is_external, |
1992 | !native_name.IsNull(), // is_native |
1993 | script_class, procedure_helper.start_position_)); |
1994 | function.set_has_pragma(has_pragma_annotation); |
1995 | function.set_end_token_pos(procedure_helper.end_position_); |
1996 | function.set_is_synthetic(procedure_helper.IsNoSuchMethodForwarder() || |
1997 | procedure_helper.IsMemberSignature()); |
1998 | if (register_function) { |
1999 | functions_.Add(&function); |
2000 | } else { |
2001 | H.SetExpressionEvaluationFunction(function); |
2002 | } |
2003 | function.set_kernel_offset(procedure_offset); |
2004 | function.set_is_extension_member(is_extension_member); |
2005 | if ((library.is_dart_scheme() && |
2006 | H.IsPrivate(procedure_helper.canonical_name_)) || |
2007 | (function.is_static() && (library.raw() == Library::InternalLibrary()))) { |
2008 | function.set_is_reflectable(false); |
2009 | } |
2010 | if (procedure_helper.IsMemberSignature()) { |
2011 | function.set_is_reflectable(false); |
2012 | } |
2013 | |
2014 | ActiveMemberScope active_member(&active_class_, &function); |
2015 | |
2016 | procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction); |
2017 | |
2018 | Tag function_node_tag = helper_.ReadTag(); |
2019 | ASSERT(function_node_tag == kSomething); |
2020 | FunctionNodeHelper function_node_helper(&helper_); |
2021 | function_node_helper.ReadUntilIncluding(FunctionNodeHelper::kDartAsyncMarker); |
2022 | |
2023 | const bool is_async_await_completer_owner = |
2024 | Symbols::_AsyncAwaitCompleter().Equals( |
2025 | String::Handle(Z, owner.ScrubbedName())); |
2026 | |
2027 | // _AsyncAwaitCompleter.future should be made non-debuggable, otherwise |
2028 | // stepping out of async methods will keep hitting breakpoint resulting in |
2029 | // infinite loop. |
2030 | const bool is_async_await_completer_future = |
2031 | is_async_await_completer_owner && |
2032 | Symbols::CompleterGetFuture().Equals(name); |
2033 | function.set_is_debuggable(function_node_helper.dart_async_marker_ == |
2034 | FunctionNodeHelper::kSync && |
2035 | !is_async_await_completer_future); |
2036 | |
2037 | // _AsyncAwaitCompleter.start should be made non-visible in stack traces, |
2038 | // since it is an implementation detail of our await/async desugaring. |
2039 | if (is_async_await_completer_owner && |
2040 | Symbols::_AsyncAwaitStart().Equals(name)) { |
2041 | function.set_is_visible(!FLAG_causal_async_stacks && |
2042 | !FLAG_lazy_async_stacks); |
2043 | } |
2044 | |
2045 | switch (function_node_helper.dart_async_marker_) { |
2046 | case FunctionNodeHelper::kSyncStar: |
2047 | function.set_modifier(FunctionLayout::kSyncGen); |
2048 | function.set_is_visible(!FLAG_causal_async_stacks && |
2049 | !FLAG_lazy_async_stacks); |
2050 | break; |
2051 | case FunctionNodeHelper::kAsync: |
2052 | function.set_modifier(FunctionLayout::kAsync); |
2053 | function.set_is_inlinable(!FLAG_causal_async_stacks && |
2054 | !FLAG_lazy_async_stacks); |
2055 | function.set_is_visible(!FLAG_causal_async_stacks && |
2056 | !FLAG_lazy_async_stacks); |
2057 | break; |
2058 | case FunctionNodeHelper::kAsyncStar: |
2059 | function.set_modifier(FunctionLayout::kAsyncGen); |
2060 | function.set_is_inlinable(!FLAG_causal_async_stacks && |
2061 | !FLAG_lazy_async_stacks); |
2062 | function.set_is_visible(!FLAG_causal_async_stacks && |
2063 | !FLAG_lazy_async_stacks); |
2064 | break; |
2065 | default: |
2066 | // no special modifier |
2067 | break; |
2068 | } |
2069 | ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync); |
2070 | |
2071 | if (!native_name.IsNull()) { |
2072 | function.set_native_name(native_name); |
2073 | } |
2074 | if (is_potential_native) { |
2075 | // Cannot be processed right now, so put on "pending" list. |
2076 | EnsurePotentialNatives(); |
2077 | potential_natives_.Add(function); |
2078 | } |
2079 | |
2080 | function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters); |
2081 | T.SetupFunctionParameters(owner, function, is_method, |
2082 | false, // is_closure |
2083 | &function_node_helper); |
2084 | T.SetupUnboxingInfoMetadata(function, library_kernel_offset_); |
2085 | |
2086 | // Everything else is skipped implicitly, and procedure_helper and |
2087 | // function_node_helper are no longer used. |
2088 | helper_.SetOffset(procedure_end); |
2089 | |
2090 | if (annotation_count > 0) { |
2091 | library.AddFunctionMetadata(function, TokenPosition::kNoSource, |
2092 | procedure_offset, 0); |
2093 | } |
2094 | |
2095 | if (has_pragma_annotation) { |
2096 | if (kernel_program_info_.constants() == Array::null()) { |
2097 | // Any potential pragma function before point at which |
2098 | // constant table could be loaded goes to "pending". |
2099 | EnsurePotentialPragmaFunctions(); |
2100 | potential_pragma_functions_.Add(function); |
2101 | } else { |
2102 | Thread* thread = Thread::Current(); |
2103 | NoOOBMessageScope no_msg_scope(thread); |
2104 | NoReloadScope no_reload_scope(thread->isolate(), thread); |
2105 | library.GetMetadata(function); |
2106 | } |
2107 | } |
2108 | } |
2109 | |
2110 | const Object& KernelLoader::ClassForScriptAt(const Class& klass, |
2111 | intptr_t source_uri_index) { |
2112 | const Script& correct_script = Script::Handle(Z, ScriptAt(source_uri_index)); |
2113 | if (klass.script() != correct_script.raw()) { |
2114 | // Lazily create the [patch_classes_] array in case we need it. |
2115 | if (patch_classes_.IsNull()) { |
2116 | const Array& scripts = Array::Handle(Z, kernel_program_info_.scripts()); |
2117 | ASSERT(!scripts.IsNull()); |
2118 | patch_classes_ = Array::New(scripts.Length(), Heap::kOld); |
2119 | } |
2120 | |
2121 | // Use cache for patch classes. This works best for in-order usages. |
2122 | PatchClass& patch_class = PatchClass::ZoneHandle(Z); |
2123 | patch_class ^= patch_classes_.At(source_uri_index); |
2124 | if (patch_class.IsNull() || patch_class.origin_class() != klass.raw()) { |
2125 | ASSERT(!library_kernel_data_.IsNull()); |
2126 | patch_class = PatchClass::New(klass, correct_script); |
2127 | patch_class.set_library_kernel_data(library_kernel_data_); |
2128 | patch_class.set_library_kernel_offset(library_kernel_offset_); |
2129 | patch_classes_.SetAt(source_uri_index, patch_class); |
2130 | } |
2131 | return patch_class; |
2132 | } |
2133 | return klass; |
2134 | } |
2135 | |
2136 | ScriptPtr KernelLoader::LoadScriptAt(intptr_t index, |
2137 | UriToSourceTable* uri_to_source_table) { |
2138 | const String& uri_string = helper_.SourceTableUriFor(index); |
2139 | const String& import_uri_string = |
2140 | helper_.SourceTableImportUriFor(index, program_->binary_version()); |
2141 | |
2142 | String& sources = String::Handle(Z); |
2143 | TypedData& line_starts = TypedData::Handle(Z); |
2144 | |
2145 | if (uri_to_source_table != nullptr) { |
2146 | UriToSourceTableEntry wrapper; |
2147 | wrapper.uri = &uri_string; |
2148 | UriToSourceTableEntry* pair = uri_to_source_table->LookupValue(&wrapper); |
2149 | if (pair != nullptr) { |
2150 | sources = pair->sources->raw(); |
2151 | line_starts = pair->line_starts->raw(); |
2152 | } |
2153 | } |
2154 | |
2155 | if (sources.IsNull() || line_starts.IsNull()) { |
2156 | const String& script_source = helper_.GetSourceFor(index); |
2157 | line_starts = helper_.GetLineStartsFor(index); |
2158 | |
2159 | if (script_source.raw() == Symbols::Empty().raw() && |
2160 | line_starts.Length() == 0 && uri_string.Length() > 0) { |
2161 | // Entry included only to provide URI - actual source should already exist |
2162 | // in the VM, so try to find it. |
2163 | Library& lib = Library::Handle(Z); |
2164 | Script& script = Script::Handle(Z); |
2165 | const GrowableObjectArray& libs = |
2166 | GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
2167 | for (intptr_t i = 0; i < libs.Length(); i++) { |
2168 | lib ^= libs.At(i); |
2169 | script = lib.LookupScript(uri_string, /* useResolvedUri = */ true); |
2170 | if (!script.IsNull()) { |
2171 | sources = script.Source(); |
2172 | line_starts = script.line_starts(); |
2173 | break; |
2174 | } |
2175 | } |
2176 | } else { |
2177 | sources = script_source.raw(); |
2178 | } |
2179 | } |
2180 | |
2181 | const Script& script = |
2182 | Script::Handle(Z, Script::New(import_uri_string, uri_string, sources)); |
2183 | script.set_kernel_script_index(index); |
2184 | script.set_kernel_program_info(kernel_program_info_); |
2185 | script.set_line_starts(line_starts); |
2186 | script.set_debug_positions(Array::null_array()); |
2187 | return script.raw(); |
2188 | } |
2189 | |
2190 | void KernelLoader::GenerateFieldAccessors(const Class& klass, |
2191 | const Field& field, |
2192 | FieldHelper* field_helper) { |
2193 | const Tag tag = helper_.PeekTag(); |
2194 | const bool has_initializer = (tag == kSomething); |
2195 | if (has_initializer) { |
2196 | SimpleExpressionConverter converter(&H, &helper_); |
2197 | const bool has_simple_initializer = |
2198 | converter.IsSimple(helper_.ReaderOffset() + 1); // ignore the tag. |
2199 | if (has_simple_initializer) { |
2200 | if (field_helper->IsStatic()) { |
2201 | // We do not need a getter. |
2202 | field.SetStaticValue(converter.SimpleValue(), true); |
2203 | return; |
2204 | } else { |
2205 | // Note: optimizer relies on DoubleInitialized bit in its field-unboxing |
2206 | // heuristics. See JitCallSpecializer::VisitStoreInstanceField for more |
2207 | // details. |
2208 | field.RecordStore(converter.SimpleValue()); |
2209 | if (!converter.SimpleValue().IsNull() && |
2210 | converter.SimpleValue().IsDouble()) { |
2211 | field.set_is_double_initialized(true); |
2212 | } |
2213 | } |
2214 | } |
2215 | } |
2216 | |
2217 | if (field_helper->IsStatic()) { |
2218 | if (!has_initializer && !field_helper->IsLate()) { |
2219 | // Static fields without an initializer are implicitly initialized to |
2220 | // null. We do not need a getter. |
2221 | field.SetStaticValue(Instance::null_instance(), true); |
2222 | return; |
2223 | } |
2224 | |
2225 | // We do need a getter that evaluates the initializer if necessary. |
2226 | field.SetStaticValue(Object::sentinel(), true); |
2227 | } |
2228 | ASSERT(field.NeedsGetter()); |
2229 | |
2230 | const String& getter_name = H.DartGetterName(field_helper->canonical_name_); |
2231 | const Object& script_class = |
2232 | ClassForScriptAt(klass, field_helper->source_uri_index_); |
2233 | Function& getter = Function::ZoneHandle( |
2234 | Z, |
2235 | Function::New( |
2236 | getter_name, |
2237 | field_helper->IsStatic() ? FunctionLayout::kImplicitStaticGetter |
2238 | : FunctionLayout::kImplicitGetter, |
2239 | field_helper->IsStatic(), |
2240 | // The functions created by the parser have is_const for static fields |
2241 | // that are const (not just final) and they have is_const for |
2242 | // non-static fields that are final. |
2243 | field_helper->IsStatic() ? field_helper->IsConst() |
2244 | : field_helper->IsFinal(), |
2245 | false, // is_abstract |
2246 | false, // is_external |
2247 | false, // is_native |
2248 | script_class, field_helper->position_)); |
2249 | functions_.Add(&getter); |
2250 | getter.set_end_token_pos(field_helper->end_position_); |
2251 | getter.set_kernel_offset(field.kernel_offset()); |
2252 | const AbstractType& field_type = AbstractType::Handle(Z, field.type()); |
2253 | getter.set_result_type(field_type); |
2254 | getter.set_is_debuggable(false); |
2255 | getter.set_accessor_field(field); |
2256 | getter.set_is_extension_member(field.is_extension_member()); |
2257 | H.SetupFieldAccessorFunction(klass, getter, field_type); |
2258 | T.SetupUnboxingInfoMetadataForFieldAccessors(getter, library_kernel_offset_); |
2259 | |
2260 | if (field.NeedsSetter()) { |
2261 | // Only static fields can be const. |
2262 | ASSERT(!field_helper->IsConst()); |
2263 | const String& setter_name = H.DartSetterName(field_helper->canonical_name_); |
2264 | Function& setter = Function::ZoneHandle( |
2265 | Z, Function::New(setter_name, FunctionLayout::kImplicitSetter, |
2266 | field_helper->IsStatic(), |
2267 | false, // is_const |
2268 | false, // is_abstract |
2269 | false, // is_external |
2270 | false, // is_native |
2271 | script_class, field_helper->position_)); |
2272 | functions_.Add(&setter); |
2273 | setter.set_end_token_pos(field_helper->end_position_); |
2274 | setter.set_kernel_offset(field.kernel_offset()); |
2275 | setter.set_result_type(Object::void_type()); |
2276 | setter.set_is_debuggable(false); |
2277 | setter.set_accessor_field(field); |
2278 | setter.set_is_extension_member(field.is_extension_member()); |
2279 | H.SetupFieldAccessorFunction(klass, setter, field_type); |
2280 | T.SetupUnboxingInfoMetadataForFieldAccessors(getter, |
2281 | library_kernel_offset_); |
2282 | } |
2283 | } |
2284 | |
2285 | LibraryPtr KernelLoader::LookupLibraryOrNull(NameIndex library) { |
2286 | LibraryPtr result; |
2287 | name_index_handle_ = Smi::New(library); |
2288 | { |
2289 | result = kernel_program_info_.LookupLibrary(thread_, name_index_handle_); |
2290 | NoSafepointScope no_safepoint_scope(thread_); |
2291 | if (result != Library::null()) { |
2292 | return result; |
2293 | } |
2294 | } |
2295 | const String& url = H.DartString(H.CanonicalNameString(library)); |
2296 | { |
2297 | result = Library::LookupLibrary(thread_, url); |
2298 | NoSafepointScope no_safepoint_scope(thread_); |
2299 | if (result == Library::null()) { |
2300 | return result; |
2301 | } |
2302 | } |
2303 | const Library& handle = Library::Handle(Z, result); |
2304 | name_index_handle_ = Smi::New(library); |
2305 | return kernel_program_info_.InsertLibrary(thread_, name_index_handle_, |
2306 | handle); |
2307 | } |
2308 | |
2309 | LibraryPtr KernelLoader::LookupLibrary(NameIndex library) { |
2310 | name_index_handle_ = Smi::New(library); |
2311 | { |
2312 | LibraryPtr result = |
2313 | kernel_program_info_.LookupLibrary(thread_, name_index_handle_); |
2314 | NoSafepointScope no_safepoint_scope(thread_); |
2315 | if (result != Library::null()) { |
2316 | return result; |
2317 | } |
2318 | } |
2319 | |
2320 | Library& handle = Library::Handle(Z); |
2321 | const String& url = H.DartSymbolPlain(H.CanonicalNameString(library)); |
2322 | // We do not register expression evaluation libraries with the VM: |
2323 | // The expression evaluation functions should be GC-able as soon as |
2324 | // they are not reachable anymore and we never look them up by name. |
2325 | if (url.Equals(Symbols::EvalSourceUri())) { |
2326 | if (expression_evaluation_library_.IsNull()) { |
2327 | handle = Library::New(url); |
2328 | expression_evaluation_library_ = handle.raw(); |
2329 | } |
2330 | return expression_evaluation_library_.raw(); |
2331 | } |
2332 | handle = Library::LookupLibrary(thread_, url); |
2333 | if (handle.IsNull()) { |
2334 | handle = Library::New(url); |
2335 | handle.Register(thread_); |
2336 | } |
2337 | ASSERT(!handle.IsNull()); |
2338 | name_index_handle_ = Smi::New(library); |
2339 | return kernel_program_info_.InsertLibrary(thread_, name_index_handle_, |
2340 | handle); |
2341 | } |
2342 | |
2343 | LibraryPtr KernelLoader::LookupLibraryFromClass(NameIndex klass) { |
2344 | return LookupLibrary(H.CanonicalNameParent(klass)); |
2345 | } |
2346 | |
2347 | ClassPtr KernelLoader::LookupClass(const Library& library, NameIndex klass) { |
2348 | name_index_handle_ = Smi::New(klass); |
2349 | { |
2350 | ClassPtr raw_class = |
2351 | kernel_program_info_.LookupClass(thread_, name_index_handle_); |
2352 | NoSafepointScope no_safepoint_scope(thread_); |
2353 | if (raw_class != Class::null()) { |
2354 | return raw_class; |
2355 | } |
2356 | } |
2357 | |
2358 | ASSERT(!library.IsNull()); |
2359 | const String& name = H.DartClassName(klass); |
2360 | Class& handle = Class::Handle(Z, library.LookupLocalClass(name)); |
2361 | bool register_class = true; |
2362 | if (handle.IsNull()) { |
2363 | // We do not register expression evaluation classes with the VM: |
2364 | // The expression evaluation functions should be GC-able as soon as |
2365 | // they are not reachable anymore and we never look them up by name. |
2366 | register_class = library.raw() != expression_evaluation_library_.raw(); |
2367 | |
2368 | handle = Class::New(library, name, Script::Handle(Z), |
2369 | TokenPosition::kNoSource, register_class); |
2370 | if (register_class) { |
2371 | library.AddClass(handle); |
2372 | } |
2373 | } |
2374 | ASSERT(!handle.IsNull()); |
2375 | if (register_class) { |
2376 | name_index_handle_ = Smi::New(klass); |
2377 | kernel_program_info_.InsertClass(thread_, name_index_handle_, handle); |
2378 | } |
2379 | return handle.raw(); |
2380 | } |
2381 | |
2382 | FunctionLayout::Kind KernelLoader::GetFunctionType( |
2383 | ProcedureHelper::Kind procedure_kind) { |
2384 | intptr_t lookuptable[] = { |
2385 | FunctionLayout::kRegularFunction, // Procedure::kMethod |
2386 | FunctionLayout::kGetterFunction, // Procedure::kGetter |
2387 | FunctionLayout::kSetterFunction, // Procedure::kSetter |
2388 | FunctionLayout::kRegularFunction, // Procedure::kOperator |
2389 | FunctionLayout::kConstructor, // Procedure::kFactory |
2390 | }; |
2391 | intptr_t kind = static_cast<int>(procedure_kind); |
2392 | ASSERT(0 <= kind && kind <= ProcedureHelper::kFactory); |
2393 | return static_cast<FunctionLayout::Kind>(lookuptable[kind]); |
2394 | } |
2395 | |
2396 | FunctionPtr CreateFieldInitializerFunction(Thread* thread, |
2397 | Zone* zone, |
2398 | const Field& field) { |
2399 | ASSERT(field.InitializerFunction() == Function::null()); |
2400 | |
2401 | String& init_name = String::Handle(zone, field.name()); |
2402 | init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name); |
2403 | |
2404 | // Static field initializers are not added as members of their owning class, |
2405 | // so they must be pre-emptively given a patch class to avoid the meaning of |
2406 | // their kernel/token position changing during a reload. Compare |
2407 | // Class::PatchFieldsAndFunctions(). |
2408 | // This might also be necessary for lazy computation of local var descriptors. |
2409 | // Compare https://codereview.chromium.org//1317753004 |
2410 | const Script& script = Script::Handle(zone, field.Script()); |
2411 | const Class& field_owner = Class::Handle(zone, field.Owner()); |
2412 | const PatchClass& initializer_owner = |
2413 | PatchClass::Handle(zone, PatchClass::New(field_owner, script)); |
2414 | const Library& lib = Library::Handle(zone, field_owner.library()); |
2415 | if (!lib.is_declared_in_bytecode()) { |
2416 | initializer_owner.set_library_kernel_data( |
2417 | ExternalTypedData::Handle(zone, lib.kernel_data())); |
2418 | initializer_owner.set_library_kernel_offset(lib.kernel_offset()); |
2419 | } |
2420 | |
2421 | // Create a static initializer. |
2422 | const Function& initializer_fun = Function::Handle( |
2423 | zone, Function::New(init_name, FunctionLayout::kFieldInitializer, |
2424 | field.is_static(), // is_static |
2425 | false, // is_const |
2426 | false, // is_abstract |
2427 | false, // is_external |
2428 | false, // is_native |
2429 | initializer_owner, TokenPosition::kNoSource)); |
2430 | if (!field.is_static()) { |
2431 | initializer_fun.set_num_fixed_parameters(1); |
2432 | initializer_fun.set_parameter_types( |
2433 | Array::Handle(zone, Array::New(1, Heap::kOld))); |
2434 | initializer_fun.set_parameter_names( |
2435 | Array::Handle(zone, Array::New(1, Heap::kOld))); |
2436 | initializer_fun.SetParameterTypeAt( |
2437 | 0, AbstractType::Handle(zone, field_owner.DeclarationType())); |
2438 | initializer_fun.SetParameterNameAt(0, Symbols::This()); |
2439 | } |
2440 | initializer_fun.set_result_type(AbstractType::Handle(zone, field.type())); |
2441 | initializer_fun.set_is_reflectable(false); |
2442 | initializer_fun.set_is_inlinable(false); |
2443 | initializer_fun.set_token_pos(field.token_pos()); |
2444 | initializer_fun.set_end_token_pos(field.end_token_pos()); |
2445 | initializer_fun.set_accessor_field(field); |
2446 | initializer_fun.InheritBinaryDeclarationFrom(field); |
2447 | initializer_fun.set_is_extension_member(field.is_extension_member()); |
2448 | field.SetInitializerFunction(initializer_fun); |
2449 | return initializer_fun.raw(); |
2450 | } |
2451 | |
2452 | } // namespace kernel |
2453 | } // namespace dart |
2454 | #endif // !defined(DART_PRECOMPILED_RUNTIME) |
2455 | |