// 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_ISOLATE_RELOAD_H_ #define RUNTIME_VM_ISOLATE_RELOAD_H_ #include "include/dart_tools_api.h" #include "vm/globals.h" #include "vm/growable_array.h" #include "vm/hash_map.h" #include "vm/log.h" #include "vm/object.h" DECLARE_FLAG(bool, trace_reload); DECLARE_FLAG(bool, trace_reload_verbose); // 'Trace Isolate Reload' TIR_Print #if defined(_MSC_VER) #define TIR_Print(format, ...) \ if (FLAG_trace_reload) Log::Current()->Print(format, __VA_ARGS__) #else #define TIR_Print(format, ...) \ if (FLAG_trace_reload) Log::Current()->Print(format, ##__VA_ARGS__) #endif // 'Verbose Trace Isolate Reload' VTIR_Print #if defined(_MSC_VER) #define VTIR_Print(format, ...) \ if (FLAG_trace_reload_verbose) Log::Current()->Print(format, __VA_ARGS__) #else #define VTIR_Print(format, ...) \ if (FLAG_trace_reload_verbose) Log::Current()->Print(format, ##__VA_ARGS__) #endif #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) namespace dart { class BitVector; class GrowableObjectArray; class Isolate; class Library; class ObjectPointerVisitor; class ObjectStore; class RawError; class RawGrowableObjectArray; class RawLibrary; class RawObject; class RawString; class Script; class UpdateClassesVisitor; class InstanceMorpher : public ZoneAllocated { public: InstanceMorpher(Zone* zone, const Class& from, const Class& to); virtual ~InstanceMorpher() {} // Called on each instance that needs to be morphed. RawInstance* Morph(const Instance& instance) const; void RunNewFieldInitializers() const; // Adds an object to be morphed. void AddObject(RawObject* object) const; // Create the morphed objects based on the before() list. void CreateMorphedCopies() const; // Dump the state of the morpher. void Dump() const; // Append the morper info to JSON array. void AppendTo(JSONArray* array); // Returns the list of objects that need to be morphed. ZoneGrowableArray* before() const { return before_; } // Returns the list of morphed objects (matches order in before()). ZoneGrowableArray* after() const { return after_; } // Returns the list of new fields. ZoneGrowableArray* new_fields() const { return new_fields_; } // Returns the cid associated with the from_ and to_ class. intptr_t cid() const { return cid_; } private: const Class& from_; const Class& to_; ZoneGrowableArray mapping_; ZoneGrowableArray* before_; ZoneGrowableArray* after_; ZoneGrowableArray* new_fields_; intptr_t cid_; void ComputeMapping(); void DumpFormatFor(const Class& cls) const; }; class ReasonForCancelling : public ZoneAllocated { public: explicit ReasonForCancelling(Zone* zone) {} virtual ~ReasonForCancelling() {} // Reports a reason for cancelling reload. void Report(IsolateReloadContext* context); // Conversion to a VM error object. // Default implementation calls ToString. virtual RawError* ToError(); // Conversion to a string object. // Default implementation calls ToError. virtual RawString* ToString(); // Append the reason to JSON array. virtual void AppendTo(JSONArray* array); // Concrete subclasses must override either ToError or ToString. }; // Abstract class for also capturing the from_ and to_ class. class ClassReasonForCancelling : public ReasonForCancelling { public: ClassReasonForCancelling(Zone* zone, const Class& from, const Class& to); void AppendTo(JSONArray* array); protected: const Class& from_; const Class& to_; }; class IsolateReloadContext { public: explicit IsolateReloadContext(Isolate* isolate, JSONStream* js); ~IsolateReloadContext(); // If kernel_buffer is provided, the VM takes ownership when Reload is called. void Reload(bool force_reload, const char* root_script_url = NULL, const char* packages_url = NULL, const uint8_t* kernel_buffer = NULL, intptr_t kernel_buffer_size = 0); // All zone allocated objects must be allocated from this zone. Zone* zone() const { return zone_; } bool reload_skipped() const { return reload_skipped_; } bool reload_aborted() const { return reload_aborted_; } RawError* error() const; int64_t reload_timestamp() const { return reload_timestamp_; } static Dart_FileModifiedCallback file_modified_callback() { return file_modified_callback_; } static void SetFileModifiedCallback(Dart_FileModifiedCallback callback) { file_modified_callback_ = callback; } static bool IsSameField(const Field& a, const Field& b); static bool IsSameLibrary(const Library& a_lib, const Library& b_lib); static bool IsSameClass(const Class& a, const Class& b); private: RawLibrary* saved_root_library() const; RawGrowableObjectArray* saved_libraries() const; RawClass* FindOriginalClass(const Class& cls); bool IsDirty(const Library& lib); // Prefers old classes when we are in the middle of a reload. RawClass* GetClassForHeapWalkAt(intptr_t cid); intptr_t GetClassSizeForHeapWalkAt(intptr_t cid); void DiscardSavedClassTable(); void RegisterClass(const Class& new_cls); // Finds the library private key for |replacement_or_new| or return null // if |replacement_or_new| is new. RawString* FindLibraryPrivateKey(const Library& replacement_or_new); int64_t start_time_micros() const { return start_time_micros_; } // Tells whether there are reasons for cancelling the reload. bool HasReasonsForCancelling() const { return !reasons_to_cancel_reload_.is_empty(); } // Record problem for this reload. void AddReasonForCancelling(ReasonForCancelling* reason); // Reports all reasons for cancelling reload. void ReportReasonsForCancelling(); // Reports the details of a reload operation. void ReportOnJSON(JSONStream* stream); // Store morphing operation. void AddInstanceMorpher(InstanceMorpher* morpher); // Tells whether instance in the heap must be morphed. bool HasInstanceMorphers() const { return !instance_morphers_.is_empty(); } // NOTE: FinalizeLoading will be called *before* Reload() returns. This // function will not be called if the embedder does not call // Dart_FinalizeLoading. void FinalizeLoading(); // NOTE: FinalizeFailedLoad will be called *before* Reload returns. This // function will not be called if the embedder calls Dart_FinalizeLoading. void FinalizeFailedLoad(const Error& error); // Called by both FinalizeLoading and FinalizeFailedLoad. void CommonFinalizeTail(); // Report back through the observatory channels. void ReportError(const Error& error); void ReportSuccess(); void set_saved_root_library(const Library& value); void set_saved_libraries(const GrowableObjectArray& value); void VisitObjectPointers(ObjectPointerVisitor* visitor); Isolate* isolate() { return isolate_; } ObjectStore* object_store(); void EnsuredUnoptimizedCodeForStack(); void DeoptimizeDependentCode(); void Checkpoint(); void CheckpointClasses(); bool ScriptModifiedSince(const Script& script, int64_t since); BitVector* FindModifiedLibraries(bool force_reload, bool root_lib_modified); void FindModifiedSources(Thread* thread, bool force_reload, Dart_SourceFile** modified_sources, intptr_t* count, const char* packages_url); void CheckpointLibraries(); void MorphInstancesAndApplyNewClassTable(); void RunNewFieldInitializers(); bool ValidateReload(); void Rollback(); void RollbackClasses(); void RollbackLibraries(); #ifdef DEBUG void VerifyMaps(); #endif void Commit(); void PostCommit(); void ClearReplacedObjectBits(); // atomic_install: void RunInvalidationVisitors(); void ResetUnoptimizedICsOnStack(); void ResetMegamorphicCaches(); void InvalidateWorld(); // The zone used for all reload related allocations. Zone* zone_; int64_t start_time_micros_; int64_t reload_timestamp_; Isolate* isolate_; bool reload_skipped_; bool reload_aborted_; bool reload_finalized_; JSONStream* js_; intptr_t saved_num_cids_; ClassAndSize* saved_class_table_; intptr_t num_saved_libs_; intptr_t num_received_libs_; intptr_t bytes_received_libs_; intptr_t num_received_classes_; intptr_t num_received_procedures_; // Collect the necessary instance transformation for schema changes. ZoneGrowableArray instance_morphers_; // Collects the reasons for cancelling the reload. ZoneGrowableArray reasons_to_cancel_reload_; // Required trait for the cid_mapper_; struct MorpherTrait { typedef InstanceMorpher* Value; typedef intptr_t Key; typedef InstanceMorpher* Pair; static Key KeyOf(Pair kv) { return kv->cid(); } static Value ValueOf(Pair kv) { return kv; } static intptr_t Hashcode(Key key) { return key; } static bool IsKeyEqual(Pair kv, Key key) { return kv->cid() == key; } }; // Hash map from cid to InstanceMorpher. DirectChainedHashMap cid_mapper_; struct LibraryInfo { bool dirty; }; MallocGrowableArray library_infos_; // A bit vector indicating which of the original libraries were modified. BitVector* modified_libs_; RawClass* OldClassOrNull(const Class& replacement_or_new); RawLibrary* OldLibraryOrNull(const Library& replacement_or_new); RawLibrary* OldLibraryOrNullBaseMoved(const Library& replacement_or_new); void BuildLibraryMapping(); void BuildRemovedClassesSet(); void AddClassMapping(const Class& replacement_or_new, const Class& original); void AddLibraryMapping(const Library& replacement_or_new, const Library& original); void AddStaticFieldMapping(const Field& old_field, const Field& new_field); void AddBecomeMapping(const Object& old, const Object& neu); void AddEnumBecomeMapping(const Object& old, const Object& neu); void RebuildDirectSubclasses(); RawClass* MappedClass(const Class& replacement_or_new); RawLibrary* MappedLibrary(const Library& replacement_or_new); RawObject** from() { return reinterpret_cast(&script_url_); } RawString* script_url_; RawError* error_; RawArray* old_classes_set_storage_; RawArray* class_map_storage_; RawArray* removed_class_set_storage_; RawArray* old_libraries_set_storage_; RawArray* library_map_storage_; RawArray* become_map_storage_; RawGrowableObjectArray* become_enum_mappings_; RawLibrary* saved_root_library_; RawGrowableObjectArray* saved_libraries_; RawString* root_url_prefix_; RawString* old_root_url_prefix_; RawObject** to() { return reinterpret_cast(&old_root_url_prefix_); } friend class Isolate; friend class Class; // AddStaticFieldMapping, AddEnumBecomeMapping. friend class Library; friend class ObjectLocator; friend class MarkFunctionsForRecompilation; // IsDirty. friend class ReasonForCancelling; static Dart_FileModifiedCallback file_modified_callback_; }; } // namespace dart #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) #endif // RUNTIME_VM_ISOLATE_RELOAD_H_