// 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/bytecode_reader.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 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 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(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 uint8_t* buffer, intptr_t buffer_size, 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 intptr_t Hashcode(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* 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, Isolate* isolate, 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); void FinishTopLevelClassLoading(const Class& toplevel_class, const Library& library, const LibraryIndex& library_index); static void FinishLoading(const Class& klass); void ReadObfuscationProhibitions(); private: // Check for the presence of a (possibly const) constructor for the // 'ExternalName' class. If found, returns the name parameter to the // constructor. StringPtr DetectExternalNameCtor(); // Check for the presence of a (possibly const) constructor for the 'pragma' // class. Returns whether it was found (no details about the type of pragma). bool DetectPragmaCtor(); 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* 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_->kernel_data(), program_->kernel_data_size()); return reader.ReadFromIndexNoReset(reader.size(), LibraryCountFieldCountFromEnd + 1, program_->library_count() + 1, index); } NameIndex library_canonical_name(intptr_t index) { kernel::Reader reader(program_->kernel_data(), program_->kernel_data_size()); 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* 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* 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); } void 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); FunctionLayout::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_; BytecodeMetadataHelper bytecode_metadata_helper_; Class& external_name_class_; Field& external_name_field_; GrowableObjectArray& potential_natives_; GrowableObjectArray& potential_pragma_functions_; 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 functions_; GrowableArray 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_