diff --git a/pkg/dart2bytecode/bin/kernel_service.dart b/pkg/dart2bytecode/bin/kernel_service.dart index 543fa5ddf70..6691e9a0bb1 100644 --- a/pkg/dart2bytecode/bin/kernel_service.dart +++ b/pkg/dart2bytecode/bin/kernel_service.dart @@ -29,9 +29,11 @@ Uint8List _generateBytecode( hierarchy: hierarchy, target: target, options: BytecodeOptions( - enableAsserts: enableAsserts, - emitSourcePositions: true, - emitLocalVarInfo: true)); + enableAsserts: enableAsserts, + emitSourcePositions: true, + emitLocalVarInfo: true, + emitInstanceFieldInitializers: true, + )); return byteSink.builder.takeBytes(); } diff --git a/runtime/vm/bytecode_reader.cc b/runtime/vm/bytecode_reader.cc index 242f25152bf..ef0c7c0e98b 100644 --- a/runtime/vm/bytecode_reader.cc +++ b/runtime/vm/bytecode_reader.cc @@ -84,8 +84,10 @@ BytecodeLoader::~BytecodeLoader() { FunctionPtr BytecodeLoader::LoadBytecode() { ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); - BytecodeReaderHelper component_reader(thread_, binary_); - bytecode_component_array_ = component_reader.ReadBytecodeComponent(); + if (bytecode_component_array_.IsNull()) { + BytecodeReaderHelper component_reader(thread_, binary_); + bytecode_component_array_ = component_reader.ReadBytecodeComponent(); + } BytecodeComponentData bytecode_component(bytecode_component_array_); BytecodeReaderHelper bytecode_reader(thread_, &bytecode_component); @@ -108,7 +110,7 @@ void BytecodeLoader::SetOffset(const Object& obj, intptr_t offset) { bytecode_offsets_map_ = map.Release().ptr(); } -intptr_t BytecodeLoader::GetOffset(const Object& obj) { +intptr_t BytecodeLoader::GetOffset(const Object& obj) const { BytecodeOffsetsMap map(bytecode_offsets_map_.ptr()); const auto value = map.GetOrNull(obj); ASSERT(value != Object::null()); @@ -117,6 +119,41 @@ intptr_t BytecodeLoader::GetOffset(const Object& obj) { return offset; } +bool BytecodeLoader::HasOffset(const Object& obj) const { + BytecodeOffsetsMap map(bytecode_offsets_map_.ptr()); + const auto value = map.GetOrNull(obj); + ASSERT(map.Release().ptr() == bytecode_offsets_map_.ptr()); + return value != Object::null(); +} + +void BytecodeLoader::FindModifiedLibraries(BitVector* modified_libs, + intptr_t* p_num_libraries, + intptr_t* p_num_classes, + intptr_t* p_num_procedures) { + if (bytecode_component_array_.IsNull()) { + BytecodeReaderHelper component_reader(thread_, binary_); + bytecode_component_array_ = component_reader.ReadBytecodeComponent(); + } + + BytecodeComponentData bytecode_component(bytecode_component_array_); + BytecodeReaderHelper bytecode_reader(thread_, &bytecode_component); + AlternativeReadingScope alt(&bytecode_reader.reader(), + bytecode_component.GetLibraryIndexOffset()); + + bytecode_reader.FindModifiedLibraries(modified_libs, + bytecode_component.GetNumLibraries()); + + if (p_num_libraries != nullptr) { + *p_num_libraries = bytecode_component.GetNumLibraries(); + } + if (p_num_classes != nullptr) { + *p_num_classes = bytecode_component.GetNumClasses(); + } + if (p_num_procedures != nullptr) { + *p_num_procedures = bytecode_component.GetNumCodes(); + } +} + BytecodeReaderHelper::BytecodeReaderHelper(Thread* thread, const TypedDataBase& typed_data) : reader_(typed_data), @@ -755,8 +792,6 @@ void BytecodeReaderHelper::ReadLocalVariables(const Bytecode& bytecode, } ArrayPtr BytecodeReaderHelper::ReadBytecodeComponent() { - ASSERT(IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter()); - AlternativeReadingScope alt(&reader_, 0); const intptr_t start_offset = reader_.offset(); @@ -1779,7 +1814,7 @@ void BytecodeReaderHelper::ReadFieldDeclarations(const Class& cls, /* is_reflectable = */ false, /* is_late = */ false, cls, Object::dynamic_type(), TokenPosition::kNoSource, TokenPosition::kNoSource); - + IG->RegisterStaticField(field, Object::null_object()); fields.SetAt(num_fields, field); } @@ -2284,17 +2319,35 @@ void BytecodeReaderHelper::ReadLibraryDeclarations(intptr_t num_libraries) { members = cls.fields(); for (intptr_t j = 0, m = members.Length(); j < m; ++j) { field ^= members.At(j); - if ((field.is_static() || field.is_late()) && - field.has_nontrivial_initializer()) { - function = field.EnsureInitializerFunction(); - if (!function.HasBytecode()) { - ReadCode(function, thread_->bytecode_loader()->GetOffset(field)); + if (field.has_nontrivial_initializer()) { + if (field.is_static() || field.is_late() || + thread_->bytecode_loader()->HasOffset(field)) { + function = field.EnsureInitializerFunction(); + if (!function.HasBytecode()) { + ReadCode(function, thread_->bytecode_loader()->GetOffset(field)); + } } } } } } +void BytecodeReaderHelper::FindModifiedLibraries(BitVector* modified_libs, + intptr_t num_libraries) { + auto& uri = String::Handle(Z); + auto& lib = Library::Handle(Z); + for (intptr_t i = 0; i < num_libraries; ++i) { + uri ^= ReadObject(); + reader_.ReadUInt(); // Skip offset. + + lib = Library::LookupLibrary(thread_, uri); + if (!lib.IsNull() && !lib.is_dart_scheme()) { + // This is a library that already exists so mark it as being modified. + modified_libs->Add(lib.index()); + } + } +} + void BytecodeReaderHelper::ReadParameterCovariance( const Function& function, intptr_t code_offset, diff --git a/runtime/vm/bytecode_reader.h b/runtime/vm/bytecode_reader.h index 12a669e782c..b87eb730cad 100644 --- a/runtime/vm/bytecode_reader.h +++ b/runtime/vm/bytecode_reader.h @@ -31,7 +31,13 @@ class BytecodeLoader { } void SetOffset(const Object& obj, intptr_t offset); - intptr_t GetOffset(const Object& obj); + intptr_t GetOffset(const Object& obj) const; + bool HasOffset(const Object& obj) const; + + void FindModifiedLibraries(BitVector* modified_libs, + intptr_t* p_num_libraries, + intptr_t* p_num_classes, + intptr_t* p_num_procedures); private: Thread* thread_; @@ -204,6 +210,7 @@ class BytecodeReaderHelper : public ValueObject { void ReadLibraryDeclaration(const Library& library, const GrowableObjectArray& pending_classes); void ReadLibraryDeclarations(intptr_t num_libraries); + void FindModifiedLibraries(BitVector* modified_libs, intptr_t num_libraries); LibraryPtr ReadMain(); diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc index 05798636972..1e85b4480dc 100644 --- a/runtime/vm/isolate_reload.cc +++ b/runtime/vm/isolate_reload.cc @@ -5,8 +5,10 @@ #include "vm/isolate_reload.h" #include +#include #include "vm/bit_vector.h" +#include "vm/bytecode_reader.h" #include "vm/compiler/jit/compiler.h" #include "vm/dart_api_impl.h" #if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) @@ -688,6 +690,97 @@ static ObjectPtr RejectCompilation(Thread* thread) { return Object::null(); } +class DeltaProgram { + public: + DeltaProgram() {} + virtual ~DeltaProgram() {} + + static std::unique_ptr ReadFromTypedData( + const ExternalTypedData& typed_data); + + virtual void FindModifiedLibraries(BitVector* modified_libs, + intptr_t* p_num_libraries, + intptr_t* p_num_classes, + intptr_t* p_num_procedures) = 0; + + virtual ObjectPtr Load() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(DeltaProgram); +}; + +class KernelDeltaProgram : public DeltaProgram { + public: + explicit KernelDeltaProgram(std::unique_ptr kernel_program) + : kernel_program_(std::move(kernel_program)) { + ASSERT(kernel_program_ != nullptr); + } + + void FindModifiedLibraries(BitVector* modified_libs, + intptr_t* p_num_libraries, + intptr_t* p_num_classes, + intptr_t* p_num_procedures) override { + kernel::KernelLoader::FindModifiedLibraries( + kernel_program_.get(), modified_libs, p_num_libraries, p_num_classes, + p_num_procedures); + } + + ObjectPtr Load() override { + return kernel::KernelLoader::LoadEntireProgram(kernel_program_.get()).ptr(); + } + + private: + std::unique_ptr kernel_program_; +}; + +#if defined(DART_DYNAMIC_MODULES) +class BytecodeDeltaProgram : public DeltaProgram { + public: + explicit BytecodeDeltaProgram(const ExternalTypedData& typed_data) + : loader_(Thread::Current(), typed_data) {} + + void FindModifiedLibraries(BitVector* modified_libs, + intptr_t* p_num_libraries, + intptr_t* p_num_classes, + intptr_t* p_num_procedures) override { + loader_.FindModifiedLibraries(modified_libs, p_num_libraries, p_num_classes, + p_num_procedures); + } + + ObjectPtr Load() override { + Thread* thread = Thread::Current(); + SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock()); + const auto& function = Function::Handle(loader_.LoadBytecode()); + if (!function.IsNull()) { + return Class::Handle(function.Owner()).library(); + } + return Object::null(); + } + + private: + bytecode::BytecodeLoader loader_; +}; +#endif // defined(DART_DYNAMIC_MODULES) + +std::unique_ptr DeltaProgram::ReadFromTypedData( + const ExternalTypedData& typed_data) { + if (Dart_IsKernel(reinterpret_cast(typed_data.DataAddr(0)), + typed_data.LengthInBytes())) { + auto kernel_program = kernel::Program::ReadFromTypedData(typed_data); + if (!kernel_program) { + return nullptr; + } + return std::make_unique(std::move(kernel_program)); + } +#if defined(DART_DYNAMIC_MODULES) + if (Dart_IsBytecode(reinterpret_cast(typed_data.DataAddr(0)), + typed_data.LengthInBytes())) { + return std::make_unique(typed_data); + } +#endif // defined(DART_DYNAMIC_MODULES) + return nullptr; +} + // If [root_script_url] is null, attempt to load from [kernel_buffer]. bool IsolateGroupReloadContext::Reload(bool force_reload, const char* root_script_url, @@ -706,7 +799,7 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, // Grab root library before calling CheckpointBeforeReload. GetRootLibUrl(root_script_url); - std::unique_ptr kernel_program; + std::unique_ptr delta_program; // Reset stats. num_received_libs_ = 0; @@ -718,20 +811,24 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, bool skip_reload = false; { // Load the kernel program and figure out the modified libraries. - intptr_t* p_num_received_classes = nullptr; - intptr_t* p_num_received_procedures = nullptr; + auto& program_binary = ExternalTypedData::Handle(Z); + bool collect_stats = false; - // ReadKernelFromFile checks to see if the file at - // root_script_url is a valid .dill file. If that's the case, a Program* - // is returned. Otherwise, this is likely a source file that needs to be - // compiled, so ReadKernelFromFile returns nullptr. - kernel_program = kernel::Program::ReadFromFile(root_script_url); - if (kernel_program != nullptr) { - num_received_libs_ = kernel_program->library_count(); - bytes_received_libs_ = kernel_program->binary().LengthInBytes(); - p_num_received_classes = &num_received_classes_; - p_num_received_procedures = &num_received_procedures_; - } else { + // Check if root_script_url is a valid program binary file. + // Otherwise treat it as a source file that needs to be compiled. + if (root_script_url != nullptr) { + ASSERT((kernel_buffer == nullptr) && (kernel_buffer_size == 0)); + program_binary = ReadFile(root_script_url); + if (!program_binary.IsNull()) { + delta_program = DeltaProgram::ReadFromTypedData(program_binary); + if (delta_program != nullptr) { + // Collect statistics only when loading a binary from script URI. + bytes_received_libs_ = program_binary.LengthInBytes(); + collect_stats = true; + } + } + } + if (delta_program == nullptr) { if (kernel_buffer == nullptr || kernel_buffer_size == 0) { char* error = CompileToKernel(force_reload, packages_url, &kernel_buffer, &kernel_buffer_size); @@ -749,22 +846,27 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, return false; } } - const auto& typed_data = ExternalTypedData::Handle( - Z, ExternalTypedData::NewFinalizeWithFree( - const_cast(kernel_buffer), kernel_buffer_size)); - kernel_program = kernel::Program::ReadFromTypedData(typed_data); + program_binary = ExternalTypedData::NewFinalizeWithFree( + const_cast(kernel_buffer), kernel_buffer_size); + delta_program = DeltaProgram::ReadFromTypedData(program_binary); + RELEASE_ASSERT(delta_program != nullptr); } NoActiveIsolateScope no_active_isolate_scope(thread); IsolateGroupSource* source = IsolateGroup::Current()->source(); - source->add_loaded_blob(Z, - ExternalTypedData::Cast(kernel_program->binary())); + source->add_loaded_blob(Z, program_binary); modified_libs_ = new (Z) BitVector(Z, num_old_libs_); - kernel::KernelLoader::FindModifiedLibraries( - kernel_program.get(), IG, modified_libs_, force_reload, &skip_reload, - p_num_received_classes, p_num_received_procedures); + if (force_reload) { + MarkAllLibrariesAsModified(modified_libs_); + } else { + delta_program->FindModifiedLibraries( + modified_libs_, &num_received_libs_, + collect_stats ? &num_received_classes_ : nullptr, + collect_stats ? &num_received_procedures_ : nullptr); + skip_reload = (num_received_libs_ == 0); + } modified_libs_transitive_ = new (Z) BitVector(Z, num_old_libs_); BuildModifiedLibrariesClosure(modified_libs_); @@ -856,14 +958,14 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, heap->CollectAllGarbage(GCReason::kDebugging, /*compact=*/true); } - // We synchronously load the hot-reload kernel diff (which includes changed + // We synchronously load the delta program (which includes changed // libraries and any libraries transitively depending on them). // - // If loading the hot-reload diff succeeded we'll finalize the loading, which + // If loading the delta program succeeded we'll finalize the loading, which // will either commit or reject the reload request. - const auto& result = - Object::Handle(Z, IG->program_reload_context()->ReloadPhase2LoadKernel( - kernel_program.get(), root_lib_url_)); + const auto& result = Object::Handle( + Z, IG->program_reload_context()->ReloadPhase2LoadDeltaProgram( + std::move(delta_program), root_lib_url_)); if (result.IsError()) { TIR_Print("---- LOAD FAILED, ABORTING RELOAD\n"); @@ -1034,6 +1136,20 @@ bool IsolateGroupReloadContext::Reload(bool force_reload, return success; } +// If a reload is being forced we mark all libraries as having been modified. +void IsolateGroupReloadContext::MarkAllLibrariesAsModified( + BitVector* modified_libs) { + const auto& libs = + GrowableObjectArray::Handle(Z, IG->object_store()->libraries()); + auto& lib = Library::Handle(Z); + for (intptr_t i = 0, n = libs.Length(); i < n; ++i) { + lib ^= libs.At(i); + if (!lib.is_dart_scheme()) { + modified_libs->Add(lib.index()); + } + } +} + /// Copied in from https://dart-review.googlesource.com/c/sdk/+/77722. static void PropagateLibraryModified( const ZoneGrowableArray*>* imported_by, @@ -1161,6 +1277,20 @@ void IsolateGroupReloadContext::GetRootLibUrl(const char* root_script_url) { } } +ExternalTypedDataPtr IsolateGroupReloadContext::ReadFile( + const char* script_uri) { + if (!IG->HasTagHandler()) { + return ExternalTypedData::null(); + } + const String& uri = String::Handle(Z, String::New(script_uri)); + const Object& ret = Object::Handle( + Z, IG->CallTagHandler(Dart_kKernelTag, Object::null_object(), uri)); + if (ret.IsExternalTypedData()) { + return ExternalTypedData::Cast(ret).ptr(); + } + return ExternalTypedData::null(); +} + char* IsolateGroupReloadContext::CompileToKernel(bool force_reload, const char* packages_url, const uint8_t** kernel_buffer, @@ -1212,27 +1342,25 @@ void ProgramReloadContext::ReloadPhase1AllocateStorageMapsAndCheckpoint() { } } -ObjectPtr ProgramReloadContext::ReloadPhase2LoadKernel( - kernel::Program* program, +ObjectPtr ProgramReloadContext::ReloadPhase2LoadDeltaProgram( + std::unique_ptr program, const String& root_lib_url) { Thread* thread = Thread::Current(); HANDLESCOPE(thread); LongJumpScope jump(thread); if (DART_SETJMP(*jump.Set()) == 0) { - const Object& tmp = kernel::KernelLoader::LoadEntireProgram(program); - if (tmp.IsError()) { - return tmp.ptr(); + Object& result = Object::Handle(Z, program->Load()); + if (result.IsError()) { + return result.ptr(); } - // If main method disappeared or were not there to begin with then - // KernelLoader will return null. In this case lookup library by - // URL. - auto& lib = Library::Handle(Library::RawCast(tmp.ptr())); - if (lib.IsNull()) { - lib = Library::LookupLibrary(thread, root_lib_url); + // If main method disappeared or were not there to begin with, + // then lookup root library by URL. + if (result.IsNull()) { + result = Library::LookupLibrary(thread, root_lib_url); } - IG->object_store()->set_root_library(lib); + IG->object_store()->set_root_library(Library::Cast(result)); return Object::null(); } else { return thread->StealStickyError(); @@ -1355,7 +1483,7 @@ ErrorPtr ProgramReloadContext::EnsuredUnoptimizedCodeForStack() { Function& func = Function::Handle(); while (it.HasNextFrame()) { StackFrame* frame = it.NextFrame(); - if (frame->IsDartFrame()) { + if (frame->IsDartFrame() && !frame->is_interpreted()) { func = frame->LookupDartFunction(); ASSERT(!func.IsNull()); // Force-optimized functions don't need unoptimized code because their @@ -1972,19 +2100,21 @@ void ProgramReloadContext::ResetUnoptimizedICsOnStack() { StackFrameIterator::kAllowCrossThreadIteration); StackFrame* frame = iterator.NextFrame(); while (frame != nullptr) { - code = frame->LookupDartCode(); - if (code.is_optimized() && !code.is_force_optimized()) { - // If this code is optimized, we need to reset the ICs in the - // corresponding unoptimized code, which will be executed when the stack - // unwinds to the optimized code. - function = code.function(); - code = function.unoptimized_code(); - ASSERT(!code.IsNull()); - resetter.ResetSwitchableCalls(code); - resetter.ResetCaches(code); - } else { - resetter.ResetSwitchableCalls(code); - resetter.ResetCaches(code); + if (!frame->is_interpreted()) { + code = frame->LookupDartCode(); + if (code.is_optimized() && !code.is_force_optimized()) { + // If this code is optimized, we need to reset the ICs in the + // corresponding unoptimized code, which will be executed + // when the stack unwinds to the optimized code. + function = code.function(); + code = function.unoptimized_code(); + ASSERT(!code.IsNull()); + resetter.ResetSwitchableCalls(code); + resetter.ResetCaches(code); + } else { + resetter.ResetSwitchableCalls(code); + resetter.ResetCaches(code); + } } frame = iterator.NextFrame(); } @@ -2052,6 +2182,13 @@ ErrorPtr ProgramReloadContext::RunInvalidationVisitors() { StackZone stack_zone(thread); Zone* zone = stack_zone.GetZone(); +#if defined(DART_DYNAMIC_MODULES) + Interpreter* interpreter = thread->interpreter(); + if (interpreter != nullptr) { + interpreter->ClearLookupCache(); + } +#endif // defined(DART_DYNAMIC_MODULES) + GrowableArray functions(4 * KB); GrowableArray kernel_infos(KB); GrowableArray fields(4 * KB); @@ -2126,6 +2263,10 @@ void ProgramReloadContext::InvalidateFunctions( Library& owning_lib = Library::Handle(zone); Code& code = Code::Handle(zone); Field& field = Field::Handle(zone); +#if defined(DART_DYNAMIC_MODULES) + Bytecode& bytecode = Bytecode::Handle(zone); +#endif // defined(DART_DYNAMIC_MODULES) + SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock()); for (intptr_t i = 0; i < functions.length(); i++) { const Function& func = *functions[i]; @@ -2160,6 +2301,13 @@ void ProgramReloadContext::InvalidateFunctions( // they're held. resetter.ZeroEdgeCounters(func); +#if defined(DART_DYNAMIC_MODULES) + if (func.HasBytecode()) { + bytecode = func.GetBytecode(); + resetter.RebindBytecode(bytecode); + } +#endif // defined(DART_DYNAMIC_MODULES) + if (stub_code) { // Nothing to reset. } else if (clear_unoptimized_code) { diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h index 82beae1e8d8..12ec2832693 100644 --- a/runtime/vm/isolate_reload.h +++ b/runtime/vm/isolate_reload.h @@ -45,6 +45,7 @@ DECLARE_FLAG(bool, trace_reload_verbose); namespace dart { class BitVector; +class DeltaProgram; class GrowableObjectArray; class Isolate; class Library; @@ -202,10 +203,12 @@ class IsolateGroupReloadContext { void VisitObjectPointers(ObjectPointerVisitor* visitor); void GetRootLibUrl(const char* root_script_url); + ExternalTypedDataPtr ReadFile(const char* script_uri); char* CompileToKernel(bool force_reload, const char* packages_url, const uint8_t** kernel_buffer, intptr_t* kernel_buffer_size); + void MarkAllLibrariesAsModified(BitVector* modified_libs); void BuildModifiedLibrariesClosure(BitVector* modified_libs); void FindModifiedSources(bool force_reload, Dart_SourceFile** modified_sources, @@ -324,8 +327,8 @@ class ProgramReloadContext { void ReloadPhase1AllocateStorageMapsAndCheckpoint(); void CheckpointClasses(); - ObjectPtr ReloadPhase2LoadKernel(kernel::Program* program, - const String& root_lib_url); + ObjectPtr ReloadPhase2LoadDeltaProgram(std::unique_ptr program, + const String& root_lib_url); void ReloadPhase3FinalizeLoading(); void ReloadPhase4CommitPrepare(); ErrorPtr ReloadPhase4CommitFinish(); @@ -414,6 +417,7 @@ class CallSiteResetter : public ValueObject { void ResetCaches(const ObjectPool& pool); void Reset(const ICData& ic); void ResetSwitchableCalls(const Code& code); + void RebindBytecode(const Bytecode& bytecode); private: Zone* zone_; diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc index 25670f50e2a..8187b040cd9 100644 --- a/runtime/vm/isolate_reload_test.cc +++ b/runtime/vm/isolate_reload_test.cc @@ -32,8 +32,9 @@ int64_t SimpleInvoke(Dart_Handle lib, const char* method) { const char* SimpleInvokeStr(Dart_Handle lib, const char* method) { Dart_Handle result = Dart_Invoke(lib, NewString(method), 0, nullptr); - const char* result_str = nullptr; + EXPECT_VALID(result); EXPECT(Dart_IsString(result)); + const char* result_str = nullptr; EXPECT_VALID(Dart_StringToCString(result, &result_str)); return result_str; } diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h index 26e201309ef..f8f928e0259 100644 --- a/runtime/vm/kernel.h +++ b/runtime/vm/kernel.h @@ -67,8 +67,6 @@ class Program { static std::unique_ptr ReadFrom(Reader* reader, const char** error = nullptr); - static std::unique_ptr ReadFromFile(const char* script_uri, - const char** error = nullptr); static std::unique_ptr ReadFromBuffer(const uint8_t* buffer, intptr_t buffer_length, const char** error = nullptr); diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc index 60dd26ad891..4061cedba33 100644 --- a/runtime/vm/kernel_binary.cc +++ b/runtime/vm/kernel_binary.cc @@ -173,37 +173,6 @@ std::unique_ptr Program::ReadFrom(Reader* reader, const char** error) { return program; } -std::unique_ptr Program::ReadFromFile( - const char* script_uri, - const char** error /* = nullptr */) { - Thread* thread = Thread::Current(); - auto isolate_group = thread->isolate_group(); - if (script_uri == nullptr) { - return nullptr; - } - if (!isolate_group->HasTagHandler()) { - return nullptr; - } - std::unique_ptr kernel_program; - - const String& uri = String::Handle(String::New(script_uri)); - const Object& ret = Object::Handle(isolate_group->CallTagHandler( - Dart_kKernelTag, Object::null_object(), uri)); - if (ret.IsExternalTypedData()) { - const auto& typed_data = ExternalTypedData::Cast(ret); - kernel_program = kernel::Program::ReadFromTypedData(typed_data); - return kernel_program; - } else if (error != nullptr) { - Api::Scope api_scope(thread); - Dart_Handle retval = Api::NewHandle(thread, ret.ptr()); - { - TransitionVMToNative transition(thread); - *error = Dart_GetError(retval); - } - } - return kernel_program; -} - std::unique_ptr Program::ReadFromBuffer(const uint8_t* buffer, intptr_t buffer_length, const char** error) { diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc index 4dcf4e3e28a..585566c57ac 100644 --- a/runtime/vm/kernel_loader.cc +++ b/runtime/vm/kernel_loader.cc @@ -626,32 +626,18 @@ ObjectPtr KernelLoader::LoadExpressionEvaluationFunction( } void KernelLoader::FindModifiedLibraries(Program* program, - IsolateGroup* isolate_group, BitVector* modified_libs, - bool force_reload, - bool* is_empty_program, + intptr_t* p_num_libraries, intptr_t* p_num_classes, intptr_t* p_num_procedures) { Thread* thread = Thread::Current(); LongJumpScope jump(thread); if (DART_SETJMP(*jump.Set()) == 0) { Zone* zone = thread->zone(); - if (force_reload) { - // If a reload is being forced we mark all libraries as having - // been modified. - const auto& libs = GrowableObjectArray::Handle( - zone, isolate_group->object_store()->libraries()); - intptr_t num_libs = libs.Length(); - Library& lib = dart::Library::Handle(zone); - for (intptr_t i = 0; i < num_libs; i++) { - lib ^= libs.At(i); - if (!lib.is_dart_scheme()) { - modified_libs->Add(lib.index()); - } - } - return; - } + if (p_num_libraries != nullptr) { + *p_num_libraries = 0; + } if (p_num_classes != nullptr) { *p_num_classes = 0; } @@ -661,10 +647,9 @@ void KernelLoader::FindModifiedLibraries(Program* program, // Now go through all the libraries that are present in the incremental // kernel files, these will constitute the modified libraries. - *is_empty_program = true; if (program->is_single_program()) { KernelLoader loader(program, /*uri_to_source_table=*/nullptr); - loader.walk_incremental_kernel(modified_libs, is_empty_program, + loader.walk_incremental_kernel(modified_libs, p_num_libraries, p_num_classes, p_num_procedures); } @@ -689,24 +674,23 @@ void KernelLoader::FindModifiedLibraries(Program* program, } ASSERT(subprogram->is_single_program()); KernelLoader loader(subprogram.get(), /*uri_to_source_table=*/nullptr); - loader.walk_incremental_kernel(modified_libs, is_empty_program, + loader.walk_incremental_kernel(modified_libs, p_num_libraries, p_num_classes, p_num_procedures); } } } void KernelLoader::walk_incremental_kernel(BitVector* modified_libs, - bool* is_empty_program, + intptr_t* p_num_libraries, intptr_t* p_num_classes, intptr_t* p_num_procedures) { - intptr_t length = program_->library_count(); - *is_empty_program = *is_empty_program && (length == 0); + const intptr_t num_libraries = program_->library_count(); bool collect_library_stats = p_num_classes != nullptr || p_num_procedures != nullptr; intptr_t num_classes = 0; intptr_t num_procedures = 0; Library& lib = Library::Handle(Z); - for (intptr_t i = 0; i < length; i++) { + for (intptr_t i = 0; i < num_libraries; i++) { intptr_t kernel_offset = library_offset(i); helper_.SetOffset(kernel_offset); LibraryHelper library_helper(&helper_); @@ -725,6 +709,9 @@ void KernelLoader::walk_incremental_kernel(BitVector* modified_libs, num_procedures += library_index.procedure_count(); } } + if (p_num_libraries != nullptr) { + *p_num_libraries += num_libraries; + } if (p_num_classes != nullptr) { *p_num_classes += num_classes; } diff --git a/runtime/vm/kernel_loader.h b/runtime/vm/kernel_loader.h index bcd9e1a3f2c..65550f9cf59 100644 --- a/runtime/vm/kernel_loader.h +++ b/runtime/vm/kernel_loader.h @@ -192,14 +192,11 @@ class KernelLoader : public ValueObject { // 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]. + // Optionally populate [p_num_libraries], [p_num_classes], [p_num_procedures] + // with number of libraries, 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_libraries, intptr_t* p_num_classes, intptr_t* p_num_procedures); @@ -293,7 +290,7 @@ class KernelLoader : public ValueObject { uint8_t CharacterAt(StringIndex string_index, intptr_t index); void walk_incremental_kernel(BitVector* modified_libs, - bool* is_empty_program, + intptr_t* p_num_libraries, intptr_t* p_num_classes, intptr_t* p_num_procedures); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index e8ce3be6636..e928d64f7ea 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -13134,6 +13134,18 @@ ObjectPtr Field::EvaluateInitializer() const { #if !defined(DART_PRECOMPILED_RUNTIME) if (is_static() && is_const()) { +#if defined(DART_DYNAMIC_MODULES) + if (is_declared_in_bytecode()) { + const auto& initializer = Function::Handle(InitializerFunction()); + ASSERT(!initializer.IsNull()); + const auto& bytecode = Bytecode::Handle(initializer.GetBytecode()); + ASSERT(!bytecode.IsNull()); + const auto& pool = ObjectPool::Handle(bytecode.object_pool()); + ASSERT(!pool.IsNull()); + ASSERT(pool.Length() == 1); + return pool.ObjectAt(0); + } +#endif // defined(DART_DYNAMIC_MODULES) return kernel::EvaluateStaticConstFieldInitializer(*this); } #endif // !defined(DART_PRECOMPILED_RUNTIME) diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc index 8a6545e60b4..7fa7e1c35d5 100644 --- a/runtime/vm/object_reload.cc +++ b/runtime/vm/object_reload.cc @@ -840,6 +840,71 @@ void CallSiteResetter::Reset(const ICData& ic) { } } +void CallSiteResetter::RebindBytecode(const Bytecode& bytecode) { +#if defined(DART_DYNAMIC_MODULES) + pool_ = bytecode.object_pool(); + ASSERT(!pool_.IsNull()); + + // Iterate over bytecode instructions and update + // references to static methods and fields. + const KBCInstr* instr = + reinterpret_cast(bytecode.PayloadStart()); + const KBCInstr* end = reinterpret_cast( + bytecode.PayloadStart() + bytecode.Size()); + while (instr < end) { + switch (KernelBytecode::DecodeOpcode(instr)) { + case KernelBytecode::kDirectCall: + case KernelBytecode::kDirectCall_Wide: + case KernelBytecode::kUncheckedDirectCall: + case KernelBytecode::kUncheckedDirectCall_Wide: { + const intptr_t idx = KernelBytecode::DecodeD(instr); + old_target_ ^= pool_.ObjectAt(idx); + args_desc_array_ ^= pool_.ObjectAt(idx + 1); + ArgumentsDescriptor args_desc(args_desc_array_); + name_ = old_target_.name(); + new_cls_ = old_target_.Owner(); + new_target_ = Resolver::ResolveFunction(zone_, new_cls_, name_); + if (new_target_.ptr() != old_target_.ptr()) { + if (!new_target_.IsNull() && + (new_target_.is_static() == old_target_.is_static()) && + (new_target_.kind() == old_target_.kind()) && + new_target_.AreValidArguments(args_desc, nullptr)) { + pool_.SetObjectAt(idx, new_target_); + } else { + VTIR_Print("Cannot rebind function %s\n", + old_target_.ToFullyQualifiedCString()); + } + } + break; + } + case KernelBytecode::kLoadStatic: + case KernelBytecode::kLoadStatic_Wide: + case KernelBytecode::kStoreStaticTOS: + case KernelBytecode::kStoreStaticTOS_Wide: { + const intptr_t idx = KernelBytecode::DecodeD(instr); + object_ = pool_.ObjectAt(idx); + const Field& old_field = Field::Cast(object_); + name_ = old_field.name(); + new_cls_ = old_field.Owner(); + new_field_ = new_cls_.LookupField(name_); + if (!new_field_.IsNull() && + (new_field_.is_static() == old_field.is_static())) { + pool_.SetObjectAt(idx, new_field_); + } else { + VTIR_Print("Cannot rebind field %s\n", old_field.ToCString()); + } + break; + } + default: + break; + } + instr = KernelBytecode::Next(instr); + } +#else + UNREACHABLE(); +#endif // defined(DART_DYNAMIC_MODULES) +} + #endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME) } // namespace dart