Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(808)

Unified Diff: runtime/vm/isolate_reload.cc

Issue 2489723003: Run field initializers for new instance fields after a reload (Closed)
Patch Set: Fix a comment Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/isolate_reload.h ('k') | runtime/vm/isolate_reload_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/isolate_reload.cc
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index cc9e113cae0dca2afe17e3fbe0fcd283477a6a11..f1bdabda9f3da93d50dbb87d096fbcab79e66784 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -58,11 +58,12 @@ InstanceMorpher::InstanceMorpher(Zone* zone, const Class& from, const Class& to)
: from_(Class::Handle(zone, from.raw())),
to_(Class::Handle(zone, to.raw())),
mapping_(zone, 0) {
- ComputeMapping();
- before_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
- after_ = new (zone) ZoneGrowableArray<const Instance*>(zone, 0);
+ before_ = new(zone) ZoneGrowableArray<const Instance*>(zone, 0);
+ after_ = new(zone) ZoneGrowableArray<const Instance*>(zone, 0);
+ new_fields_ = new(zone) ZoneGrowableArray<const Field*>(zone, 0);
ASSERT(from_.id() == to_.id());
cid_ = from_.id();
+ ComputeMapping();
}
@@ -86,27 +87,50 @@ void InstanceMorpher::ComputeMapping() {
// Add copying of the instance fields if matching by name.
// Note: currently the type of the fields are ignored.
- const Array& from_fields = Array::Handle(from_.OffsetToFieldMap());
+ const Array& from_fields =
+ Array::Handle(from_.OffsetToFieldMap(true /* original classes */));
const Array& to_fields = Array::Handle(to_.OffsetToFieldMap());
Field& from_field = Field::Handle();
Field& to_field = Field::Handle();
String& from_name = String::Handle();
String& to_name = String::Handle();
- for (intptr_t i = 0; i < from_fields.Length(); i++) {
- if (from_fields.At(i) == Field::null()) continue; // Ignore non-fields.
- from_field = Field::RawCast(from_fields.At(i));
- ASSERT(from_field.is_instance());
- from_name = from_field.name();
- // We now have to find where this field is in the to class.
- for (intptr_t j = 0; j < to_fields.Length(); j++) {
- if (to_fields.At(j) == Field::null()) continue; // Ignore non-fields.
- to_field = Field::RawCast(to_fields.At(j));
- ASSERT(to_field.is_instance());
- to_name = to_field.name();
+
+ // Scan across all the fields in the new class definition.
+ for (intptr_t i = 0; i < to_fields.Length(); i++) {
+ if (to_fields.At(i) == Field::null()) {
+ continue; // Ignore non-fields.
+ }
+
+ // Grab the field's name.
+ to_field = Field::RawCast(to_fields.At(i));
+ ASSERT(to_field.is_instance());
+ to_name = to_field.name();
+
+ // Did this field not exist in the old class definition?
+ bool new_field = true;
+
+ // Find this field in the old class.
+ for (intptr_t j = 0; j < from_fields.Length(); j++) {
+ if (from_fields.At(j) == Field::null()) {
+ continue; // Ignore non-fields.
+ }
+ from_field = Field::RawCast(from_fields.At(j));
+ ASSERT(from_field.is_instance());
+ from_name = from_field.name();
if (from_name.Equals(to_name)) {
// Success
mapping_.Add(from_field.Offset());
mapping_.Add(to_field.Offset());
+ // Field did exist in old class deifnition.
+ new_field = false;
+ }
+ }
+
+ if (new_field) {
+ if (to_field.has_initializer()) {
+ // This is a new field with an initializer.
+ const Field& field = Field::Handle(to_field.raw());
+ new_fields_->Add(&field);
}
}
}
@@ -129,6 +153,52 @@ RawInstance* InstanceMorpher::Morph(const Instance& instance) const {
}
+void InstanceMorpher::RunNewFieldInitializers() const {
+ if ((new_fields_->length() == 0) || (after_->length() == 0)) {
+ return;
+ }
+
+ TIR_Print("Running new field initializers for class: %s\n", to_.ToCString());
+ String& initializing_expression = String::Handle();
+ Function& eval_func = Function::Handle();
+ Object& result = Object::Handle();
+ Class& owning_class = Class::Handle();
+ // For each new field.
+ for (intptr_t i = 0; i < new_fields_->length(); i++) {
+ // Create a function that returns the expression.
+ const Field* field = new_fields_->At(i);
+ owning_class ^= field->Owner();
+ ASSERT(!owning_class.IsNull());
+ // Extract the initializing expression.
+ initializing_expression = field->InitializingExpression();
+ TIR_Print("New `%s` has initializing expression `%s`\n",
+ field->ToCString(),
+ initializing_expression.ToCString());
+ eval_func ^= Function::EvaluateHelper(owning_class,
+ initializing_expression,
+ Array::empty_array(),
+ true);
+ for (intptr_t j = 0; j < after_->length(); j++) {
+ const Instance* instance = after_->At(j);
+ TIR_Print("Initializing instance %" Pd " / %" Pd "\n",
+ j + 1, after_->length());
+ // Run the function and assign the field.
+ result = DartEntry::InvokeFunction(eval_func, Array::empty_array());
+ if (result.IsError()) {
+ // TODO(johnmccutchan): Report this error in the reload response?
+ OS::PrintErr(
+ "RELOAD: Running initializer for new field `%s` resulted in "
+ "an error: %s\n",
+ field->ToCString(),
+ Error::Cast(result).ToErrorCString());
+ continue;
+ }
+ instance->RawSetFieldAtOffset(field->Offset(), result);
+ }
+ }
+}
+
+
void InstanceMorpher::CreateMorphedCopies() const {
for (intptr_t i = 0; i < before()->length(); i++) {
const Instance& copy = Instance::Handle(Morph(*before()->At(i)));
@@ -1141,6 +1211,9 @@ void IsolateReloadContext::Commit() {
Become::ElementsForwardIdentity(before, after);
}
+ // Run the initializers for new instance fields.
+ RunNewFieldInitializers();
+
if (FLAG_identity_reload) {
if (saved_num_cids_ != I->class_table()->NumCids()) {
TIR_Print("Identity reload failed! B#C=%" Pd " A#C=%" Pd "\n",
@@ -1277,6 +1350,14 @@ void IsolateReloadContext::MorphInstances() {
}
+void IsolateReloadContext::RunNewFieldInitializers() {
+ // Run new field initializers on all instances.
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ instance_morphers_.At(i)->RunNewFieldInitializers();
+ }
+}
+
+
bool IsolateReloadContext::ValidateReload() {
TIMELINE_SCOPE(ValidateReload);
if (reload_aborted()) return false;
« no previous file with comments | « runtime/vm/isolate_reload.h ('k') | runtime/vm/isolate_reload_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698