1 | // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #ifndef RUNTIME_VM_KERNEL_LOADER_H_ |
6 | #define RUNTIME_VM_KERNEL_LOADER_H_ |
7 | |
8 | #if !defined(DART_PRECOMPILED_RUNTIME) |
9 | |
10 | #include "vm/bit_vector.h" |
11 | #include "vm/compiler/frontend/bytecode_reader.h" |
12 | #include "vm/compiler/frontend/constant_reader.h" |
13 | #include "vm/compiler/frontend/kernel_translation_helper.h" |
14 | #include "vm/hash_map.h" |
15 | #include "vm/kernel.h" |
16 | #include "vm/object.h" |
17 | #include "vm/symbols.h" |
18 | |
19 | namespace dart { |
20 | namespace kernel { |
21 | |
22 | class KernelLoader; |
23 | |
24 | class BuildingTranslationHelper : public TranslationHelper { |
25 | public: |
26 | BuildingTranslationHelper(KernelLoader* loader, |
27 | Thread* thread, |
28 | Heap::Space space) |
29 | : TranslationHelper(thread, space), |
30 | loader_(loader), |
31 | library_lookup_handle_(Library::Handle(thread->zone())) {} |
32 | virtual ~BuildingTranslationHelper() {} |
33 | |
34 | virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library); |
35 | virtual ClassPtr LookupClassByKernelClass(NameIndex klass); |
36 | |
37 | private: |
38 | KernelLoader* loader_; |
39 | |
40 | #if defined(DEBUG) |
41 | class LibraryLookupHandleScope { |
42 | public: |
43 | explicit LibraryLookupHandleScope(Library& lib) : lib_(lib) { |
44 | ASSERT(lib_.IsNull()); |
45 | } |
46 | |
47 | ~LibraryLookupHandleScope() { lib_ = Library::null(); } |
48 | |
49 | private: |
50 | Library& lib_; |
51 | |
52 | DISALLOW_COPY_AND_ASSIGN(LibraryLookupHandleScope); |
53 | }; |
54 | #endif // defined(DEBUG) |
55 | |
56 | // Preallocated handle for use in LookupClassByKernelClass(). |
57 | Library& library_lookup_handle_; |
58 | |
59 | DISALLOW_COPY_AND_ASSIGN(BuildingTranslationHelper); |
60 | }; |
61 | |
62 | template <typename VmType> |
63 | class Mapping { |
64 | public: |
65 | bool Lookup(intptr_t canonical_name, VmType** handle) { |
66 | typename MapType::Pair* pair = map_.LookupPair(canonical_name); |
67 | if (pair != NULL) { |
68 | *handle = pair->value; |
69 | return true; |
70 | } |
71 | return false; |
72 | } |
73 | |
74 | void Insert(intptr_t canonical_name, VmType* object) { |
75 | map_.Insert(canonical_name, object); |
76 | } |
77 | |
78 | private: |
79 | typedef IntMap<VmType*> MapType; |
80 | MapType map_; |
81 | }; |
82 | |
83 | class LibraryIndex { |
84 | public: |
85 | // |kernel_data| is the kernel data for one library alone. |
86 | explicit LibraryIndex(const ExternalTypedData& kernel_data, |
87 | uint32_t binary_version); |
88 | |
89 | intptr_t class_count() const { return class_count_; } |
90 | intptr_t procedure_count() const { return procedure_count_; } |
91 | |
92 | intptr_t ClassOffset(intptr_t index) const { |
93 | return reader_.ReadUInt32At(class_index_offset_ + index * 4); |
94 | } |
95 | |
96 | intptr_t ProcedureOffset(intptr_t index) const { |
97 | return reader_.ReadUInt32At(procedure_index_offset_ + index * 4); |
98 | } |
99 | |
100 | intptr_t SizeOfClassAtOffset(intptr_t class_offset) const { |
101 | for (intptr_t i = 0, offset = class_index_offset_; i < class_count_; |
102 | ++i, offset += 4) { |
103 | if (static_cast<intptr_t>(reader_.ReadUInt32At(offset)) == class_offset) { |
104 | return reader_.ReadUInt32At(offset + 4) - class_offset; |
105 | } |
106 | } |
107 | UNREACHABLE(); |
108 | return -1; |
109 | } |
110 | |
111 | intptr_t SourceReferencesOffset() { return source_references_offset_; } |
112 | |
113 | private: |
114 | Reader reader_; |
115 | uint32_t binary_version_; |
116 | intptr_t source_references_offset_; |
117 | intptr_t class_index_offset_; |
118 | intptr_t class_count_; |
119 | intptr_t procedure_index_offset_; |
120 | intptr_t procedure_count_; |
121 | |
122 | DISALLOW_COPY_AND_ASSIGN(LibraryIndex); |
123 | }; |
124 | |
125 | class ClassIndex { |
126 | public: |
127 | // |class_offset| is the offset of class' kernel data in |buffer| of |
128 | // size |size|. The size of the class' kernel data is |class_size|. |
129 | ClassIndex(const uint8_t* buffer, |
130 | intptr_t buffer_size, |
131 | intptr_t class_offset, |
132 | intptr_t class_size); |
133 | |
134 | // |class_offset| is the offset of class' kernel data in |kernel_data|. |
135 | // The size of the class' kernel data is |class_size|. |
136 | ClassIndex(const ExternalTypedData& kernel_data, |
137 | intptr_t class_offset, |
138 | intptr_t class_size); |
139 | |
140 | intptr_t procedure_count() const { return procedure_count_; } |
141 | |
142 | intptr_t ProcedureOffset(intptr_t index) const { |
143 | return reader_.ReadUInt32At(procedure_index_offset_ + index * 4); |
144 | } |
145 | |
146 | private: |
147 | void Init(intptr_t class_offset, intptr_t class_size); |
148 | |
149 | Reader reader_; |
150 | intptr_t procedure_count_; |
151 | intptr_t procedure_index_offset_; |
152 | |
153 | DISALLOW_COPY_AND_ASSIGN(ClassIndex); |
154 | }; |
155 | |
156 | struct UriToSourceTableEntry : public ZoneAllocated { |
157 | UriToSourceTableEntry() {} |
158 | |
159 | const String* uri = nullptr; |
160 | const String* sources = nullptr; |
161 | const TypedData* line_starts = nullptr; |
162 | }; |
163 | |
164 | struct UriToSourceTableTrait { |
165 | typedef UriToSourceTableEntry* Value; |
166 | typedef const UriToSourceTableEntry* Key; |
167 | typedef UriToSourceTableEntry* Pair; |
168 | |
169 | static Key KeyOf(Pair kv) { return kv; } |
170 | |
171 | static Value ValueOf(Pair kv) { return kv; } |
172 | |
173 | static inline intptr_t Hashcode(Key key) { return key->uri->Hash(); } |
174 | |
175 | static inline bool IsKeyEqual(Pair kv, Key key) { |
176 | // Only compare uri. |
177 | return kv->uri->CompareTo(*key->uri) == 0; |
178 | } |
179 | }; |
180 | |
181 | class KernelLoader : public ValueObject { |
182 | public: |
183 | explicit KernelLoader( |
184 | Program* program, |
185 | DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
186 | static Object& LoadEntireProgram(Program* program, |
187 | bool process_pending_classes = true); |
188 | |
189 | // Returns the library containing the main procedure, null if there |
190 | // was no main procedure, or a failure object if there was an error. |
191 | ObjectPtr LoadProgram(bool process_pending_classes = true); |
192 | |
193 | // Load given library. |
194 | void LoadLibrary(const Library& library); |
195 | |
196 | // Returns the function which will evaluate the expression, or a failure |
197 | // object if there was an error. |
198 | ObjectPtr LoadExpressionEvaluationFunction(const String& library_url, |
199 | const String& klass); |
200 | |
201 | // Finds all libraries that have been modified in this incremental |
202 | // version of the kernel program file. |
203 | // |
204 | // When [force_reload] is false and if [p_num_classes], [p_num_procedures] are |
205 | // not nullptr, then they are populated with number of classes and top-level |
206 | // procedures in [program]. |
207 | static void FindModifiedLibraries(Program* program, |
208 | Isolate* isolate, |
209 | BitVector* modified_libs, |
210 | bool force_reload, |
211 | bool* is_empty_program, |
212 | intptr_t* p_num_classes, |
213 | intptr_t* p_num_procedures); |
214 | |
215 | static StringPtr FindSourceForScript(const uint8_t* kernel_buffer, |
216 | intptr_t kernel_buffer_length, |
217 | const String& url); |
218 | |
219 | void FinishTopLevelClassLoading(const Class& toplevel_class, |
220 | const Library& library, |
221 | const LibraryIndex& library_index); |
222 | |
223 | static void FinishLoading(const Class& klass); |
224 | |
225 | void ReadObfuscationProhibitions(); |
226 | void ReadLoadingUnits(); |
227 | |
228 | private: |
229 | // Check for the presence of a (possibly const) constructor for the |
230 | // 'ExternalName' class. If found, returns the name parameter to the |
231 | // constructor. |
232 | StringPtr DetectExternalNameCtor(); |
233 | |
234 | // Check for the presence of a (possibly const) constructor for the 'pragma' |
235 | // class. Returns whether it was found (no details about the type of pragma). |
236 | bool DetectPragmaCtor(); |
237 | |
238 | bool IsClassName(NameIndex name, const String& library, const String& klass); |
239 | |
240 | void AnnotateNativeProcedures(); |
241 | void LoadNativeExtensionLibraries(); |
242 | void LoadNativeExtension(const Library& library, const String& uri_path); |
243 | void EvaluateDelayedPragmas(); |
244 | |
245 | void ReadVMAnnotations(const Library& library, |
246 | intptr_t annotation_count, |
247 | String* native_name, |
248 | bool* is_potential_native, |
249 | bool* has_pragma_annotation); |
250 | |
251 | KernelLoader(const Script& script, |
252 | const ExternalTypedData& kernel_data, |
253 | intptr_t data_program_offset, |
254 | uint32_t kernel_binary_version); |
255 | |
256 | void InitializeFields( |
257 | DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
258 | |
259 | LibraryPtr LoadLibrary(intptr_t index); |
260 | |
261 | const String& LibraryUri(intptr_t library_index) { |
262 | return translation_helper_.DartSymbolPlain( |
263 | translation_helper_.CanonicalNameString( |
264 | library_canonical_name(library_index))); |
265 | } |
266 | |
267 | intptr_t library_offset(intptr_t index) { |
268 | kernel::Reader reader(program_->kernel_data(), |
269 | program_->kernel_data_size()); |
270 | return reader.ReadFromIndexNoReset(reader.size(), |
271 | LibraryCountFieldCountFromEnd + 1, |
272 | program_->library_count() + 1, index); |
273 | } |
274 | |
275 | NameIndex library_canonical_name(intptr_t index) { |
276 | kernel::Reader reader(program_->kernel_data(), |
277 | program_->kernel_data_size()); |
278 | reader.set_offset(library_offset(index)); |
279 | |
280 | // Start reading library. |
281 | // Note that this needs to be keep in sync with LibraryHelper. |
282 | reader.ReadFlags(); |
283 | reader.ReadUInt(); // Read major language version. |
284 | reader.ReadUInt(); // Read minor language version. |
285 | return reader.ReadCanonicalNameReference(); |
286 | } |
287 | |
288 | uint8_t CharacterAt(StringIndex string_index, intptr_t index); |
289 | |
290 | static void index_programs(kernel::Reader* reader, |
291 | GrowableArray<intptr_t>* subprogram_file_starts); |
292 | void walk_incremental_kernel(BitVector* modified_libs, |
293 | bool* is_empty_program, |
294 | intptr_t* p_num_classes, |
295 | intptr_t* p_num_procedures); |
296 | |
297 | void LoadPreliminaryClass(ClassHelper* class_helper, |
298 | intptr_t type_parameter_count); |
299 | |
300 | void ReadInferredType(const Field& field, intptr_t kernel_offset); |
301 | void CheckForInitializer(const Field& field); |
302 | |
303 | void LoadClass(const Library& library, |
304 | const Class& toplevel_class, |
305 | intptr_t class_end, |
306 | Class* out_class); |
307 | |
308 | void FinishClassLoading(const Class& klass, |
309 | const Library& library, |
310 | const Class& toplevel_class, |
311 | intptr_t class_offset, |
312 | const ClassIndex& class_index, |
313 | ClassHelper* class_helper); |
314 | |
315 | void LoadProcedure(const Library& library, |
316 | const Class& owner, |
317 | bool in_class, |
318 | intptr_t procedure_end); |
319 | |
320 | ArrayPtr MakeFieldsArray(); |
321 | ArrayPtr MakeFunctionsArray(); |
322 | |
323 | ScriptPtr LoadScriptAt( |
324 | intptr_t index, |
325 | DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
326 | |
327 | // If klass's script is not the script at the uri index, return a PatchClass |
328 | // for klass whose script corresponds to the uri index. |
329 | // Otherwise return klass. |
330 | const Object& ClassForScriptAt(const Class& klass, intptr_t source_uri_index); |
331 | ScriptPtr ScriptAt(intptr_t source_uri_index) { |
332 | return kernel_program_info_.ScriptAt(source_uri_index); |
333 | } |
334 | |
335 | void GenerateFieldAccessors(const Class& klass, |
336 | const Field& field, |
337 | FieldHelper* field_helper); |
338 | bool FieldNeedsSetter(FieldHelper* field_helper); |
339 | |
340 | void LoadLibraryImportsAndExports(Library* library, |
341 | const Class& toplevel_class); |
342 | |
343 | LibraryPtr LookupLibraryOrNull(NameIndex library); |
344 | LibraryPtr LookupLibrary(NameIndex library); |
345 | LibraryPtr LookupLibraryFromClass(NameIndex klass); |
346 | ClassPtr LookupClass(const Library& library, NameIndex klass); |
347 | |
348 | FunctionLayout::Kind GetFunctionType(ProcedureHelper::Kind procedure_kind); |
349 | |
350 | void EnsureExternalClassIsLookedUp() { |
351 | if (external_name_class_.IsNull()) { |
352 | ASSERT(external_name_field_.IsNull()); |
353 | const Library& internal_lib = |
354 | Library::Handle(zone_, dart::Library::InternalLibrary()); |
355 | external_name_class_ = internal_lib.LookupClass(Symbols::ExternalName()); |
356 | external_name_field_ = external_name_class_.LookupField(Symbols::name()); |
357 | } |
358 | ASSERT(!external_name_class_.IsNull()); |
359 | ASSERT(!external_name_field_.IsNull()); |
360 | ASSERT(external_name_class_.is_declaration_loaded()); |
361 | } |
362 | |
363 | void EnsurePragmaClassIsLookedUp() { |
364 | if (pragma_class_.IsNull()) { |
365 | const Library& core_lib = |
366 | Library::Handle(zone_, dart::Library::CoreLibrary()); |
367 | pragma_class_ = core_lib.LookupLocalClass(Symbols::Pragma()); |
368 | } |
369 | ASSERT(!pragma_class_.IsNull()); |
370 | ASSERT(pragma_class_.is_declaration_loaded()); |
371 | } |
372 | |
373 | void EnsurePotentialNatives() { |
374 | potential_natives_ = kernel_program_info_.potential_natives(); |
375 | if (potential_natives_.IsNull()) { |
376 | // To avoid too many grows in this array, we'll set it's initial size to |
377 | // something close to the actual number of potential native functions. |
378 | potential_natives_ = GrowableObjectArray::New(100, Heap::kNew); |
379 | kernel_program_info_.set_potential_natives(potential_natives_); |
380 | } |
381 | } |
382 | |
383 | void EnsurePotentialPragmaFunctions() { |
384 | potential_pragma_functions_ = |
385 | translation_helper_.EnsurePotentialPragmaFunctions(); |
386 | } |
387 | |
388 | Program* program_; |
389 | |
390 | Thread* thread_; |
391 | Zone* zone_; |
392 | Isolate* isolate_; |
393 | Array& patch_classes_; |
394 | ActiveClass active_class_; |
395 | // This is the offset of the current library within |
396 | // the whole kernel program. |
397 | intptr_t library_kernel_offset_; |
398 | uint32_t kernel_binary_version_; |
399 | // This is the offset by which offsets, which are set relative |
400 | // to their library's kernel data, have to be corrected. |
401 | intptr_t correction_offset_; |
402 | bool loading_native_wrappers_library_; |
403 | |
404 | NameIndex skip_vmservice_library_; |
405 | |
406 | ExternalTypedData& library_kernel_data_; |
407 | KernelProgramInfo& kernel_program_info_; |
408 | BuildingTranslationHelper translation_helper_; |
409 | KernelReaderHelper helper_; |
410 | ConstantReader constant_reader_; |
411 | TypeTranslator type_translator_; |
412 | InferredTypeMetadataHelper inferred_type_metadata_helper_; |
413 | BytecodeMetadataHelper bytecode_metadata_helper_; |
414 | |
415 | Class& external_name_class_; |
416 | Field& external_name_field_; |
417 | GrowableObjectArray& potential_natives_; |
418 | GrowableObjectArray& potential_pragma_functions_; |
419 | |
420 | Class& pragma_class_; |
421 | |
422 | Smi& name_index_handle_; |
423 | |
424 | // We "re-use" the normal .dill file format for encoding compiled evaluation |
425 | // expressions from the debugger. This allows us to also reuse the normal |
426 | // a) kernel loader b) flow graph building code. The encoding is either one |
427 | // of the following two options: |
428 | // |
429 | // * Option a) The expression is evaluated inside an instance method call |
430 | // context: |
431 | // |
432 | // Program: |
433 | // |> library "evaluate:source" |
434 | // |> class "#DebugClass" |
435 | // |> procedure ":Eval" |
436 | // |
437 | // * Option b) The expression is evaluated outside an instance method call |
438 | // context: |
439 | // |
440 | // Program: |
441 | // |> library "evaluate:source" |
442 | // |> procedure ":Eval" |
443 | // |
444 | // See |
445 | // * pkg/front_end/lib/src/fasta/incremental_compiler.dart, |
446 | // compileExpression |
447 | // * pkg/front_end/lib/src/fasta/kernel/utils.dart, |
448 | // createExpressionEvaluationComponent |
449 | // |
450 | Library& expression_evaluation_library_; |
451 | |
452 | GrowableArray<const Function*> functions_; |
453 | GrowableArray<const Field*> fields_; |
454 | |
455 | friend class BuildingTranslationHelper; |
456 | |
457 | DISALLOW_COPY_AND_ASSIGN(KernelLoader); |
458 | }; |
459 | |
460 | FunctionPtr CreateFieldInitializerFunction(Thread* thread, |
461 | Zone* zone, |
462 | const Field& field); |
463 | |
464 | } // namespace kernel |
465 | } // namespace dart |
466 | |
467 | #endif // !defined(DART_PRECOMPILED_RUNTIME) |
468 | #endif // RUNTIME_VM_KERNEL_LOADER_H_ |
469 | |