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
19namespace dart {
20namespace kernel {
21
22class KernelLoader;
23
24class 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
62template <typename VmType>
63class 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
83class 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
125class 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
156struct UriToSourceTableEntry : public ZoneAllocated {
157 UriToSourceTableEntry() {}
158
159 const String* uri = nullptr;
160 const String* sources = nullptr;
161 const TypedData* line_starts = nullptr;
162};
163
164struct 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
181class 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
460FunctionPtr 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