[vm,dyn_modules] Initial support for hot reloading bytecode

TEST=ci

Change-Id: I879ff1c085ee06dda7836d01e2018d93e075f132
Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try,vm-reload-linux-debug-x64-try,vm-reload-linux-release-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/439803
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2025-07-15 09:29:41 -07:00
committed by Commit Queue
parent 8a38216560
commit bbb5e731c3
12 changed files with 380 additions and 137 deletions
+5 -3
View File
@@ -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();
}
+64 -11
View File
@@ -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,
+8 -1
View File
@@ -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();
+202 -54
View File
@@ -5,8 +5,10 @@
#include "vm/isolate_reload.h"
#include <memory>
#include <utility>
#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<DeltaProgram> 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)
: 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> 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> DeltaProgram::ReadFromTypedData(
const ExternalTypedData& typed_data) {
if (Dart_IsKernel(reinterpret_cast<const uint8_t*>(typed_data.DataAddr(0)),
typed_data.LengthInBytes())) {
auto kernel_program = kernel::Program::ReadFromTypedData(typed_data);
if (!kernel_program) {
return nullptr;
}
return std::make_unique<KernelDeltaProgram>(std::move(kernel_program));
}
#if defined(DART_DYNAMIC_MODULES)
if (Dart_IsBytecode(reinterpret_cast<const uint8_t*>(typed_data.DataAddr(0)),
typed_data.LengthInBytes())) {
return std::make_unique<BytecodeDeltaProgram>(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> kernel_program;
std::unique_ptr<DeltaProgram> 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<uint8_t*>(kernel_buffer), kernel_buffer_size));
kernel_program = kernel::Program::ReadFromTypedData(typed_data);
program_binary = ExternalTypedData::NewFinalizeWithFree(
const_cast<uint8_t*>(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<ZoneGrowableArray<intptr_t>*>* 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<DeltaProgram> 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<const Function*> functions(4 * KB);
GrowableArray<const KernelProgramInfo*> kernel_infos(KB);
GrowableArray<const Field*> 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) {
+6 -2
View File
@@ -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<DeltaProgram> 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_;
+2 -1
View File
@@ -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;
}
-2
View File
@@ -67,8 +67,6 @@ class Program {
static std::unique_ptr<Program> ReadFrom(Reader* reader,
const char** error = nullptr);
static std::unique_ptr<Program> ReadFromFile(const char* script_uri,
const char** error = nullptr);
static std::unique_ptr<Program> ReadFromBuffer(const uint8_t* buffer,
intptr_t buffer_length,
const char** error = nullptr);
-31
View File
@@ -173,37 +173,6 @@ std::unique_ptr<Program> Program::ReadFrom(Reader* reader, const char** error) {
return program;
}
std::unique_ptr<Program> 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> 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> Program::ReadFromBuffer(const uint8_t* buffer,
intptr_t buffer_length,
const char** error) {
+12 -25
View File
@@ -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;
}
+4 -7
View File
@@ -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);
+12
View File
@@ -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)
+65
View File
@@ -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<const KBCInstr*>(bytecode.PayloadStart());
const KBCInstr* end = reinterpret_cast<const KBCInstr*>(
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