| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #ifndef RUNTIME_VM_KERNEL_LOADER_H_ |
| #define RUNTIME_VM_KERNEL_LOADER_H_ |
| |
| #if !defined(DART_PRECOMPILED_RUNTIME) |
| |
| #include "vm/bit_vector.h" |
| #include "vm/compiler/frontend/constant_reader.h" |
| #include "vm/compiler/frontend/kernel_translation_helper.h" |
| #include "vm/hash_map.h" |
| #include "vm/kernel.h" |
| #include "vm/object.h" |
| #include "vm/symbols.h" |
| |
| namespace dart { |
| namespace kernel { |
| |
| class KernelLoader; |
| |
| class BuildingTranslationHelper : public TranslationHelper { |
| public: |
| BuildingTranslationHelper(KernelLoader* loader, |
| Thread* thread, |
| Heap::Space space) |
| : TranslationHelper(thread, space), |
| loader_(loader), |
| library_lookup_handle_(Library::Handle(thread->zone())) {} |
| virtual ~BuildingTranslationHelper() {} |
| |
| virtual LibraryPtr LookupLibraryByKernelLibrary(NameIndex library); |
| virtual ClassPtr LookupClassByKernelClass(NameIndex klass); |
| |
| private: |
| KernelLoader* loader_; |
| |
| #if defined(DEBUG) |
| class LibraryLookupHandleScope { |
| public: |
| explicit LibraryLookupHandleScope(Library& lib) : lib_(lib) { |
| ASSERT(lib_.IsNull()); |
| } |
| |
| ~LibraryLookupHandleScope() { lib_ = Library::null(); } |
| |
| private: |
| Library& lib_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LibraryLookupHandleScope); |
| }; |
| #endif // defined(DEBUG) |
| |
| // Preallocated handle for use in LookupClassByKernelClass(). |
| Library& library_lookup_handle_; |
| |
| DISALLOW_COPY_AND_ASSIGN(BuildingTranslationHelper); |
| }; |
| |
| template <typename VmType> |
| class Mapping { |
| public: |
| bool Lookup(intptr_t canonical_name, VmType** handle) { |
| typename MapType::Pair* pair = map_.LookupPair(canonical_name); |
| if (pair != NULL) { |
| *handle = pair->value; |
| return true; |
| } |
| return false; |
| } |
| |
| void Insert(intptr_t canonical_name, VmType* object) { |
| map_.Insert(canonical_name, object); |
| } |
| |
| private: |
| typedef IntMap<VmType*> MapType; |
| MapType map_; |
| }; |
| |
| class LibraryIndex { |
| public: |
| // |kernel_data| is the kernel data for one library alone. |
| explicit LibraryIndex(const ExternalTypedData& kernel_data, |
| uint32_t binary_version); |
| |
| intptr_t class_count() const { return class_count_; } |
| intptr_t procedure_count() const { return procedure_count_; } |
| |
| intptr_t ClassOffset(intptr_t index) const { |
| return reader_.ReadUInt32At(class_index_offset_ + index * 4); |
| } |
| |
| intptr_t ProcedureOffset(intptr_t index) const { |
| return reader_.ReadUInt32At(procedure_index_offset_ + index * 4); |
| } |
| |
| intptr_t SizeOfClassAtOffset(intptr_t class_offset) const { |
| for (intptr_t i = 0, offset = class_index_offset_; i < class_count_; |
| ++i, offset += 4) { |
| if (static_cast<intptr_t>(reader_.ReadUInt32At(offset)) == class_offset) { |
| return reader_.ReadUInt32At(offset + 4) - class_offset; |
| } |
| } |
| UNREACHABLE(); |
| return -1; |
| } |
| |
| intptr_t SourceReferencesOffset() { return source_references_offset_; } |
| |
| private: |
| Reader reader_; |
| uint32_t binary_version_; |
| intptr_t source_references_offset_; |
| intptr_t class_index_offset_; |
| intptr_t class_count_; |
| intptr_t procedure_index_offset_; |
| intptr_t procedure_count_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LibraryIndex); |
| }; |
| |
| class ClassIndex { |
| public: |
| // |class_offset| is the offset of class' kernel data in |buffer| of |
| // size |size|. The size of the class' kernel data is |class_size|. |
| ClassIndex(const ProgramBinary& binary, |
| intptr_t class_offset, |
| intptr_t class_size); |
| |
| // |class_offset| is the offset of class' kernel data in |kernel_data|. |
| // The size of the class' kernel data is |class_size|. |
| ClassIndex(const ExternalTypedData& kernel_data, |
| intptr_t class_offset, |
| intptr_t class_size); |
| |
| intptr_t procedure_count() const { return procedure_count_; } |
| |
| intptr_t ProcedureOffset(intptr_t index) const { |
| return reader_.ReadUInt32At(procedure_index_offset_ + index * 4); |
| } |
| |
| private: |
| void Init(intptr_t class_offset, intptr_t class_size); |
| |
| Reader reader_; |
| intptr_t procedure_count_; |
| intptr_t procedure_index_offset_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ClassIndex); |
| }; |
| |
| struct UriToSourceTableEntry : public ZoneAllocated { |
| UriToSourceTableEntry() {} |
| |
| const String* uri = nullptr; |
| const String* sources = nullptr; |
| const TypedData* line_starts = nullptr; |
| }; |
| |
| struct UriToSourceTableTrait { |
| typedef UriToSourceTableEntry* Value; |
| typedef const UriToSourceTableEntry* Key; |
| typedef UriToSourceTableEntry* Pair; |
| |
| static Key KeyOf(Pair kv) { return kv; } |
| |
| static Value ValueOf(Pair kv) { return kv; } |
| |
| static inline uword Hash(Key key) { return key->uri->Hash(); } |
| |
| static inline bool IsKeyEqual(Pair kv, Key key) { |
| // Only compare uri. |
| return kv->uri->CompareTo(*key->uri) == 0; |
| } |
| }; |
| |
| class KernelLoader : public ValueObject { |
| public: |
| explicit KernelLoader( |
| Program* program, |
| DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
| static Object& LoadEntireProgram(Program* program, |
| bool process_pending_classes = true); |
| |
| // Returns the library containing the main procedure, null if there |
| // was no main procedure, or a failure object if there was an error. |
| ObjectPtr LoadProgram(bool process_pending_classes = true); |
| |
| // Load given library. |
| void LoadLibrary(const Library& library); |
| |
| // Returns the function which will evaluate the expression, or a failure |
| // object if there was an error. |
| ObjectPtr LoadExpressionEvaluationFunction(const String& library_url, |
| const String& klass); |
| |
| // Finds all libraries that have been modified in this incremental |
| // version of the kernel program file. |
| // |
| // When [force_reload] is false and if [p_num_classes], [p_num_procedures] are |
| // not nullptr, then they are populated with number of classes and top-level |
| // procedures in [program]. |
| static void FindModifiedLibraries(Program* program, |
| IsolateGroup* isolate_group, |
| BitVector* modified_libs, |
| bool force_reload, |
| bool* is_empty_program, |
| intptr_t* p_num_classes, |
| intptr_t* p_num_procedures); |
| |
| static StringPtr FindSourceForScript(const uint8_t* kernel_buffer, |
| intptr_t kernel_buffer_length, |
| const String& url); |
| |
| static void FinishLoading(const Class& klass); |
| |
| void ReadObfuscationProhibitions(); |
| void ReadLoadingUnits(); |
| |
| private: |
| void FinishTopLevelClassLoading(const Class& toplevel_class, |
| const Library& library, |
| const LibraryIndex& library_index); |
| |
| bool IsClassName(NameIndex name, const String& library, const String& klass); |
| |
| void AnnotateNativeProcedures(); |
| void LoadNativeExtensionLibraries(); |
| void LoadNativeExtension(const Library& library, const String& uri_path); |
| void EvaluateDelayedPragmas(); |
| |
| void ReadVMAnnotations(const Library& library, |
| intptr_t annotation_count, |
| String* native_name, |
| bool* is_potential_native, |
| bool* has_pragma_annotation); |
| |
| KernelLoader(const Script& script, |
| const ExternalTypedData& kernel_data, |
| intptr_t data_program_offset, |
| uint32_t kernel_binary_version); |
| |
| void InitializeFields( |
| DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
| |
| LibraryPtr LoadLibrary(intptr_t index); |
| |
| const String& LibraryUri(intptr_t library_index) { |
| return translation_helper_.DartSymbolPlain( |
| translation_helper_.CanonicalNameString( |
| library_canonical_name(library_index))); |
| } |
| |
| intptr_t library_offset(intptr_t index) { |
| kernel::Reader reader(program_->binary()); |
| return reader.ReadFromIndexNoReset(reader.size(), |
| LibraryCountFieldCountFromEnd + 1, |
| program_->library_count() + 1, index); |
| } |
| |
| NameIndex library_canonical_name(intptr_t index) { |
| kernel::Reader reader(program_->binary()); |
| reader.set_offset(library_offset(index)); |
| |
| // Start reading library. |
| // Note that this needs to be keep in sync with LibraryHelper. |
| reader.ReadFlags(); |
| reader.ReadUInt(); // Read major language version. |
| reader.ReadUInt(); // Read minor language version. |
| return reader.ReadCanonicalNameReference(); |
| } |
| |
| uint8_t CharacterAt(StringIndex string_index, intptr_t index); |
| |
| static void index_programs(kernel::Reader* reader, |
| GrowableArray<intptr_t>* subprogram_file_starts); |
| void walk_incremental_kernel(BitVector* modified_libs, |
| bool* is_empty_program, |
| intptr_t* p_num_classes, |
| intptr_t* p_num_procedures); |
| |
| void LoadPreliminaryClass(ClassHelper* class_helper, |
| intptr_t type_parameter_count); |
| |
| void ReadInferredType(const Field& field, intptr_t kernel_offset); |
| void CheckForInitializer(const Field& field); |
| |
| void LoadClass(const Library& library, |
| const Class& toplevel_class, |
| intptr_t class_end, |
| Class* out_class); |
| |
| void FinishClassLoading(const Class& klass, |
| const Library& library, |
| const Class& toplevel_class, |
| intptr_t class_offset, |
| const ClassIndex& class_index, |
| ClassHelper* class_helper); |
| |
| void LoadProcedure(const Library& library, |
| const Class& owner, |
| bool in_class, |
| intptr_t procedure_end); |
| |
| ArrayPtr MakeFieldsArray(); |
| ArrayPtr MakeFunctionsArray(); |
| |
| ScriptPtr LoadScriptAt( |
| intptr_t index, |
| DirectChainedHashMap<UriToSourceTableTrait>* uri_to_source_table); |
| |
| // If klass's script is not the script at the uri index, return a PatchClass |
| // for klass whose script corresponds to the uri index. |
| // Otherwise return klass. |
| const Object& ClassForScriptAt(const Class& klass, intptr_t source_uri_index); |
| ScriptPtr ScriptAt(intptr_t source_uri_index) { |
| return kernel_program_info_.ScriptAt(source_uri_index); |
| } |
| |
| // Returns the initial field value for a static function (if applicable). |
| ObjectPtr GenerateFieldAccessors(const Class& klass, |
| const Field& field, |
| FieldHelper* field_helper); |
| bool FieldNeedsSetter(FieldHelper* field_helper); |
| |
| void LoadLibraryImportsAndExports(Library* library, |
| const Class& toplevel_class); |
| |
| LibraryPtr LookupLibraryOrNull(NameIndex library); |
| LibraryPtr LookupLibrary(NameIndex library); |
| LibraryPtr LookupLibraryFromClass(NameIndex klass); |
| ClassPtr LookupClass(const Library& library, NameIndex klass); |
| |
| UntaggedFunction::Kind GetFunctionType(ProcedureHelper::Kind procedure_kind); |
| |
| void EnsureExternalClassIsLookedUp() { |
| if (external_name_class_.IsNull()) { |
| ASSERT(external_name_field_.IsNull()); |
| const Library& internal_lib = |
| Library::Handle(zone_, dart::Library::InternalLibrary()); |
| external_name_class_ = internal_lib.LookupClass(Symbols::ExternalName()); |
| external_name_field_ = external_name_class_.LookupField(Symbols::name()); |
| } |
| ASSERT(!external_name_class_.IsNull()); |
| ASSERT(!external_name_field_.IsNull()); |
| ASSERT(external_name_class_.is_declaration_loaded()); |
| } |
| |
| void EnsurePragmaClassIsLookedUp() { |
| if (pragma_class_.IsNull()) { |
| const Library& core_lib = |
| Library::Handle(zone_, dart::Library::CoreLibrary()); |
| pragma_class_ = core_lib.LookupLocalClass(Symbols::Pragma()); |
| } |
| ASSERT(!pragma_class_.IsNull()); |
| ASSERT(pragma_class_.is_declaration_loaded()); |
| } |
| |
| void EnsurePotentialNatives() { |
| potential_natives_ = kernel_program_info_.potential_natives(); |
| if (potential_natives_.IsNull()) { |
| // To avoid too many grows in this array, we'll set it's initial size to |
| // something close to the actual number of potential native functions. |
| potential_natives_ = GrowableObjectArray::New(100, Heap::kNew); |
| kernel_program_info_.set_potential_natives(potential_natives_); |
| } |
| } |
| |
| void EnsurePotentialPragmaFunctions() { |
| potential_pragma_functions_ = |
| translation_helper_.EnsurePotentialPragmaFunctions(); |
| } |
| |
| Program* program_; |
| |
| Thread* thread_; |
| Zone* zone_; |
| Isolate* isolate_; |
| Array& patch_classes_; |
| ActiveClass active_class_; |
| // This is the offset of the current library within |
| // the whole kernel program. |
| intptr_t library_kernel_offset_; |
| uint32_t kernel_binary_version_; |
| // This is the offset by which offsets, which are set relative |
| // to their library's kernel data, have to be corrected. |
| intptr_t correction_offset_; |
| bool loading_native_wrappers_library_; |
| |
| NameIndex skip_vmservice_library_; |
| |
| ExternalTypedData& library_kernel_data_; |
| KernelProgramInfo& kernel_program_info_; |
| BuildingTranslationHelper translation_helper_; |
| KernelReaderHelper helper_; |
| ConstantReader constant_reader_; |
| TypeTranslator type_translator_; |
| InferredTypeMetadataHelper inferred_type_metadata_helper_; |
| |
| Class& external_name_class_; |
| Field& external_name_field_; |
| GrowableObjectArray& potential_natives_; |
| GrowableObjectArray& potential_pragma_functions_; |
| Object& static_field_value_; |
| |
| Class& pragma_class_; |
| |
| Smi& name_index_handle_; |
| |
| // We "re-use" the normal .dill file format for encoding compiled evaluation |
| // expressions from the debugger. This allows us to also reuse the normal |
| // a) kernel loader b) flow graph building code. The encoding is either one |
| // of the following two options: |
| // |
| // * Option a) The expression is evaluated inside an instance method call |
| // context: |
| // |
| // Program: |
| // |> library "evaluate:source" |
| // |> class "#DebugClass" |
| // |> procedure ":Eval" |
| // |
| // * Option b) The expression is evaluated outside an instance method call |
| // context: |
| // |
| // Program: |
| // |> library "evaluate:source" |
| // |> procedure ":Eval" |
| // |
| // See |
| // * pkg/front_end/lib/src/fasta/incremental_compiler.dart, |
| // compileExpression |
| // * pkg/front_end/lib/src/fasta/kernel/utils.dart, |
| // createExpressionEvaluationComponent |
| // |
| Library& expression_evaluation_library_; |
| |
| GrowableArray<const Function*> functions_; |
| GrowableArray<const Field*> fields_; |
| |
| friend class BuildingTranslationHelper; |
| |
| DISALLOW_COPY_AND_ASSIGN(KernelLoader); |
| }; |
| |
| FunctionPtr CreateFieldInitializerFunction(Thread* thread, |
| Zone* zone, |
| const Field& field); |
| |
| } // namespace kernel |
| } // namespace dart |
| |
| #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| #endif // RUNTIME_VM_KERNEL_LOADER_H_ |