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

Side by Side Diff: runtime/vm/object_reload.cc

Issue 1965823002: Initial isolate reload support (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 7 months 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/object.h"
6
7 #include "vm/isolate_reload.h"
8 #include "vm/log.h"
9 #include "vm/resolver.h"
10 #include "vm/symbols.h"
11
12 namespace dart {
13
14 #ifndef PRODUCT
15
16 DECLARE_FLAG(bool, trace_reload);
17 DECLARE_FLAG(bool, two_args_smi_icd);
18
19 #define IRC (Isolate::Current()->reload_context())
20
21 class ObjectReloadUtils : public AllStatic {
22 static void DumpLibraryDictionary(const Library& lib) {
23 DictionaryIterator it(lib);
24 Object& entry = Object::Handle();
25 String& name = String::Handle();
26 TIR_Print("Dumping dictionary for %s\n", lib.ToCString());
27 while (it.HasNext()) {
28 entry = it.GetNext();
29 name = entry.DictionaryName();
30 TIR_Print("%s -> %s\n", name.ToCString(), entry.ToCString());
31 }
32 }
33 };
34
35
36 void Function::Reparent(const Class& new_cls) const {
37 set_owner(new_cls);
38 }
39
40
41 void Function::ZeroEdgeCounters() const {
42 const Array& saved_ic_data = Array::Handle(ic_data_array());
43 if (saved_ic_data.IsNull()) {
44 return;
45 }
46 const intptr_t saved_ic_datalength = saved_ic_data.Length();
47 ASSERT(saved_ic_datalength > 0);
48 const Array& edge_counters_array =
49 Array::Handle(Array::RawCast(saved_ic_data.At(0)));
50 ASSERT(!edge_counters_array.IsNull());
51 // Fill edge counters array with zeros.
52 const Smi& zero = Smi::Handle(Smi::New(0));
53 for (intptr_t i = 0; i < edge_counters_array.Length(); i++) {
54 edge_counters_array.SetAt(i, zero);
55 }
56 }
57
58
59 static void ClearICs(const Function& function, const Code& code) {
60 if (function.ic_data_array() == Array::null()) {
61 return; // Already reset in an earlier round.
62 }
63
64 Thread* thread = Thread::Current();
65 Zone* zone = thread->zone();
66
67 ZoneGrowableArray<const ICData*>* ic_data_array =
68 new(zone) ZoneGrowableArray<const ICData*>();
69 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
70 if (ic_data_array->length() == 0) {
71 return;
72 }
73 const PcDescriptors& descriptors =
74 PcDescriptors::Handle(code.pc_descriptors());
75 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kIcCall |
76 RawPcDescriptors::kUnoptStaticCall);
77 while (iter.MoveNext()) {
78 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
79 if (ic_data == NULL) {
80 continue;
81 }
82 bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
83 ic_data->Reset(is_static_call);
84 }
85 }
86
87
88 void Function::FillICDataWithSentinels(const Code& code) const {
89 ASSERT(code.raw() == CurrentCode());
90 ClearICs(*this, code);
91 }
92
93
94 void Class::CopyStaticFieldValues(const Class& old_cls) const {
95 // We only update values for non-enum classes.
96 const bool update_values = !is_enum_class();
97
98 IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
99 ASSERT(reload_context != NULL);
100
101 const Array& old_field_list = Array::Handle(old_cls.fields());
102 Field& old_field = Field::Handle();
103 String& old_name = String::Handle();
104
105 const Array& field_list = Array::Handle(fields());
106 Field& field = Field::Handle();
107 String& name = String::Handle();
108
109 Instance& value = Instance::Handle();
110 for (intptr_t i = 0; i < field_list.Length(); i++) {
111 field = Field::RawCast(field_list.At(i));
112 name = field.name();
113 if (field.is_static()) {
114 // Find the corresponding old field, if it exists, and migrate
115 // over the field value.
116 for (intptr_t j = 0; j < old_field_list.Length(); j++) {
117 old_field = Field::RawCast(old_field_list.At(j));
118 old_name = old_field.name();
119 if (name.Equals(old_name)) {
120 if (update_values) {
121 value = old_field.StaticValue();
122 field.SetStaticValue(value);
123 }
124 reload_context->AddStaticFieldMapping(old_field, field);
125 }
126 }
127 }
128 }
129 }
130
131
132 void Class::CopyCanonicalConstants(const Class& old_cls) const {
133 if (is_enum_class()) {
134 return;
135 }
136 #if defined(DEBUG)
137 {
138 // Class has no canonical constants allocated.
139 const Array& my_constants = Array::Handle(constants());
140 ASSERT(my_constants.Length() == 0);
141 }
142 #endif // defined(DEBUG).
143 // Copy old constants into new class.
144 const Array& old_constants = Array::Handle(old_cls.constants());
145 if (old_constants.IsNull() || old_constants.Length() == 0) {
146 return;
147 }
148 TIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
149 old_constants.Length(),
150 ToCString());
151 set_constants(old_constants);
152 }
153
154
155 void Class::CopyCanonicalTypes(const Class& old_cls) const {
156 const Object& old_canonical_types = Object::Handle(old_cls.canonical_types());
157 if (old_canonical_types.IsNull()) {
158 return;
159 }
160 set_canonical_types(old_canonical_types);
161 }
162
163
164 static intptr_t IndexOfEnum(const Array& enum_names, const String& name) {
165 ASSERT(!enum_names.IsNull());
166 ASSERT(!name.IsNull());
167 String& enum_name = String::Handle();
168 for (intptr_t i = 0; i < enum_names.Length(); i++) {
169 enum_name = String::RawCast(enum_names.At(i));
170 ASSERT(!enum_name.IsNull());
171 if (enum_name.Equals(name)) {
172 return i;
173 }
174 }
175
176 return -1;
177 }
178
179
180 static void UpdateEnumIndex(const Instance& enum_value,
181 const Field& enum_index_field,
182 const intptr_t index) {
183 enum_value.SetField(enum_index_field, Smi::Handle(Smi::New(index)));
184 }
185
186
187 // TODO(johnmccutchan): The code in the class finalizer canonicalizes all
188 // instances and the values array. We probably should do the same thing.
189 void Class::ReplaceEnum(const Class& old_enum) const {
190 // We only do this for finalized enum classes.
191 ASSERT(is_enum_class());
192 ASSERT(old_enum.is_enum_class());
193 ASSERT(is_finalized());
194 ASSERT(old_enum.is_finalized());
195
196 Thread* thread = Thread::Current();
197 IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
198 ASSERT(reload_context != NULL);
199
200 TIR_Print("ReplaceEnum `%s` (%" Pd " and %" Pd ")\n",
201 ToCString(), id(), old_enum.id());
202
203 // Grab '_enum_names' from |old_enum|.
204 const Field& old_enum_names_field = Field::Handle(
205 old_enum.LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
206 ASSERT(!old_enum_names_field.IsNull());
207 const Array& old_enum_names =
208 Array::Handle(Array::RawCast(old_enum_names_field.StaticValue()));
209 ASSERT(!old_enum_names.IsNull());
210
211 // Grab 'values' from |old_enum|.
212 const Field& old_enum_values_field = Field::Handle(
213 old_enum.LookupStaticField(Symbols::Values()));
214 ASSERT(!old_enum_values_field.IsNull());
215 const Array& old_enum_values =
216 Array::Handle(Array::RawCast(old_enum_values_field.StaticValue()));
217 ASSERT(!old_enum_values.IsNull());
218
219 // Grab _enum_names from |this|.
220 const Field& enum_names_field = Field::Handle(
221 LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
222 ASSERT(!enum_names_field.IsNull());
223 Array& enum_names =
224 Array::Handle(Array::RawCast(enum_names_field.StaticValue()));
225 ASSERT(!enum_names.IsNull());
226
227 // Grab values from |this|.
228 const Field& enum_values_field = Field::Handle(
229 LookupStaticField(Symbols::Values()));
230 ASSERT(!enum_values_field.IsNull());
231 Array& enum_values =
232 Array::Handle(Array::RawCast(enum_values_field.StaticValue()));
233 ASSERT(!enum_values.IsNull());
234
235 // Grab the |index| field.
236 const Field& index_field =
237 Field::Handle(old_enum.LookupInstanceField(Symbols::Index()));
238 ASSERT(!index_field.IsNull());
239
240 // Build list of enum from |old_enum| that aren't present in |this|.
241 // This array holds pairs: (name, value).
242 const GrowableObjectArray& to_add =
243 GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld));
244 const String& enum_class_name = String::Handle(UserVisibleName());
245 String& enum_name = String::Handle();
246 String& enum_field_name = String::Handle();
247 Object& enum_value = Object::Handle();
248 Field& enum_field = Field::Handle();
249
250 TIR_Print("New version of enum has %" Pd " elements\n",
251 enum_values.Length());
252 TIR_Print("Old version of enum had %" Pd " elements\n",
253 old_enum_values.Length());
254
255 for (intptr_t i = 0; i < old_enum_names.Length(); i++) {
256 enum_name = String::RawCast(old_enum_names.At(i));
257 const intptr_t index_in_new_cls = IndexOfEnum(enum_names, enum_name);
258 if (index_in_new_cls < 0) {
259 // Doesn't exist in new enum, add.
260 TIR_Print("Adding enum value `%s` to %s\n",
261 enum_name.ToCString(),
262 this->ToCString());
263 enum_value = old_enum_values.At(i);
264 ASSERT(!enum_value.IsNull());
265 to_add.Add(enum_name);
266 to_add.Add(enum_value);
267 } else {
268 // Exists in both the new and the old.
269 TIR_Print("Moving enum value `%s` to %" Pd "\n",
270 enum_name.ToCString(),
271 index_in_new_cls);
272 // Grab old value.
273 enum_value = old_enum_values.At(i);
274 // Update index to the be new index.
275 UpdateEnumIndex(Instance::Cast(enum_value),
276 index_field,
277 index_in_new_cls);
278 // Chop off the 'EnumClass.'
279 enum_field_name = String::SubString(enum_name,
280 enum_class_name.Length() + 1);
281 ASSERT(!enum_field_name.IsNull());
282 // Grab the static field.
283 enum_field = LookupStaticField(enum_field_name);
284 ASSERT(!enum_field.IsNull());
285 // Use old value with updated index.
286 enum_field.SetStaticValue(Instance::Cast(enum_value), true);
287 enum_values.SetAt(index_in_new_cls, enum_value);
288 enum_names.SetAt(index_in_new_cls, enum_name);
289 }
290 }
291
292 if (to_add.Length() == 0) {
293 // Nothing to do.
294 TIR_Print("Found no missing enums in %s\n", ToCString());
295 return;
296 }
297
298 // Grow the values and enum_names arrays.
299 const intptr_t offset = enum_names.Length();
300 const intptr_t num_to_add = to_add.Length() / 2;
301 ASSERT(offset == enum_values.Length());
302 enum_names = Array::Grow(enum_names,
303 enum_names.Length() + num_to_add,
304 Heap::kOld);
305 enum_values = Array::Grow(enum_values,
306 enum_values.Length() + num_to_add,
307 Heap::kOld);
308
309 // Install new names and values into the grown arrays. Also, update
310 // the index of the new enum values and add static fields for the new
311 // enum values.
312 Field& enum_value_field = Field::Handle();
313 for (intptr_t i = 0; i < num_to_add; i++) {
314 const intptr_t target_index = offset + i;
315 enum_name = String::RawCast(to_add.At(i * 2));
316 enum_value = to_add.At(i * 2 + 1);
317
318 // Update the enum value's index into the new arrays.
319 TIR_Print("Updating index of %s in %s to %" Pd "\n",
320 enum_name.ToCString(),
321 ToCString(),
322 target_index);
323 UpdateEnumIndex(Instance::Cast(enum_value), index_field, target_index);
324
325 enum_names.SetAt(target_index, enum_name);
326 enum_values.SetAt(target_index, enum_value);
327
328 // Install new static field into class.
329 // Chop off the 'EnumClass.'
330 enum_field_name = String::SubString(enum_name,
331 enum_class_name.Length() + 1);
332 ASSERT(!enum_field_name.IsNull());
333 enum_field_name = Symbols::New(thread, enum_field_name);
334 enum_value_field = Field::New(enum_field_name,
335 /* is_static = */ true,
336 /* is_final = */ true,
337 /* is_const = */ true,
338 /* is_reflectable = */ true,
339 *this,
340 Object::dynamic_type(),
341 token_pos());
342 enum_value_field.set_has_initializer(false);
343 enum_value_field.SetStaticValue(Instance::Cast(enum_value), true);
344 enum_value_field.RecordStore(Instance::Cast(enum_value));
345 AddField(enum_value_field);
346 }
347
348 // Replace the arrays stored in the static fields.
349 enum_names_field.SetStaticValue(enum_names, true);
350 enum_values_field.SetStaticValue(enum_values, true);
351 }
352
353
354 void Class::PatchFieldsAndFunctions() const {
355 // Move all old functions and fields to a patch class so that they
356 // still refer to their original script.
357 const PatchClass& patch =
358 PatchClass::Handle(PatchClass::New(*this, Script::Handle(script())));
359 ASSERT(!patch.IsNull());
360
361 const Array& funcs = Array::Handle(functions());
362 Function& func = Function::Handle();
363 Object& owner = Object::Handle();
364 for (intptr_t i = 0; i < funcs.Length(); i++) {
365 func = Function::RawCast(funcs.At(i));
366 if ((func.token_pos() == TokenPosition::kMinSource) ||
367 func.IsClosureFunction()) {
368 // Eval functions do not need to have their script updated.
369 //
370 // Closure functions refer to the parent's script which we can
371 // rely on being updated for us, if necessary.
372 continue;
373 }
374
375 // If the source for this function is already patched, leave it alone.
376 owner = func.RawOwner();
377 ASSERT(!owner.IsNull());
378 if (!owner.IsPatchClass()) {
379 ASSERT(owner.raw() == this->raw());
380 func.set_owner(patch);
381 }
382 }
383
384 const Array& field_list = Array::Handle(fields());
385 Field& field = Field::Handle();
386 for (intptr_t i = 0; i < field_list.Length(); i++) {
387 field = Field::RawCast(field_list.At(i));
388 owner = field.RawOwner();
389 ASSERT(!owner.IsNull());
390 if (!owner.IsPatchClass()) {
391 ASSERT(owner.raw() == this->raw());
392 field.set_owner(patch);
393 }
394 field.ForceDynamicGuardedCidAndLength();
395 }
396 }
397
398
399 bool Class::CanReload(const Class& replacement) const {
400 ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
401
402 if (is_enum_class() && !replacement.is_enum_class()) {
403 IRC->ReportError(String::Handle(String::NewFormatted(
404 "Enum class cannot be redefined to be a non-enum class: %s",
405 ToCString())));
406 return false;
407 }
408
409 if (!is_enum_class() && replacement.is_enum_class()) {
410 IRC->ReportError(String::Handle(String::NewFormatted(
411 "Class cannot be redefined to be a enum class: %s",
412 ToCString())));
413 return false;
414 }
415
416 if (is_finalized()) {
417 const Error& error =
418 Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
419 if (!error.IsNull()) {
420 IRC->ReportError(error);
421 return false;
422 }
423 TIR_Print("Finalized replacement class for %s\n", ToCString());
424 }
425
426 if (is_finalized()) {
427 // Get the field maps for both classes. These field maps walk the class
428 // hierarchy.
429 const Array& fields =
430 Array::Handle(OffsetToFieldMap());
431 const Array& replacement_fields =
432 Array::Handle(replacement.OffsetToFieldMap());
433
434 // Check that we have the same number of fields.
435 if (fields.Length() != replacement_fields.Length()) {
436 IRC->ReportError(String::Handle(String::NewFormatted(
437 "Number of instance fields changed in %s", ToCString())));
438 return false;
439 }
440
441 if (NumTypeArguments() != replacement.NumTypeArguments()) {
442 IRC->ReportError(String::Handle(String::NewFormatted(
443 "Number of type arguments changed in %s", ToCString())));
444 return false;
445 }
446
447 // Verify that field names / offsets match across the entire hierarchy.
448 Field& field = Field::Handle();
449 String& field_name = String::Handle();
450 Field& replacement_field = Field::Handle();
451 String& replacement_field_name = String::Handle();
452 for (intptr_t i = 0; i < fields.Length(); i++) {
453 if (fields.At(i) == Field::null()) {
454 ASSERT(replacement_fields.At(i) == Field::null());
455 continue;
456 }
457 field = Field::RawCast(fields.At(i));
458 replacement_field = Field::RawCast(replacement_fields.At(i));
459 field_name = field.name();
460 replacement_field_name = replacement_field.name();
461 if (!field_name.Equals(replacement_field_name)) {
462 IRC->ReportError(String::Handle(String::NewFormatted(
463 "Name of instance field changed ('%s' vs '%s') in '%s'",
464 field_name.ToCString(),
465 replacement_field_name.ToCString(),
466 ToCString())));
467 return false;
468 }
469 }
470 } else if (is_prefinalized()) {
471 if (!replacement.is_prefinalized()) {
472 IRC->ReportError(String::Handle(String::NewFormatted(
473 "Original class ('%s') is prefinalized and replacement class ('%s')",
474 ToCString(), replacement.ToCString())));
475 return false;
476 }
477 if (instance_size() != replacement.instance_size()) {
478 IRC->ReportError(String::Handle(String::NewFormatted(
479 "Instance size mismatch between '%s' (%" Pd ") and replacement "
480 "'%s' ( %" Pd ")",
481 ToCString(),
482 instance_size(),
483 replacement.ToCString(),
484 replacement.instance_size())));
485 return false;
486 }
487 }
488
489 // native field count check.
490 if (num_native_fields() != replacement.num_native_fields()) {
491 IRC->ReportError(String::Handle(String::NewFormatted(
492 "Number of native fields changed in %s", ToCString())));
493 return false;
494 }
495
496 // TODO(johnmccutchan) type parameter count check.
497
498 TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
499 ToCString(),
500 id(),
501 replacement.id());
502 return true;
503 }
504
505
506 bool Library::CanReload(const Library& replacement) const {
507 return true;
508 }
509
510
511 static const Function* static_call_target = NULL;
512
513 void ICData::Reset(bool is_static_call) const {
514 // TODO(johnmccutchan): ICData should know whether or not it's for a
515 // static call.
516 if (is_static_call) {
517 const Function& old_target = Function::Handle(GetTargetAt(0));
518 if (old_target.IsNull()) {
519 FATAL("old_target is NULL.\n");
520 }
521 static_call_target = &old_target;
522 if (!old_target.is_static()) {
523 // TODO(johnmccutchan): Improve this.
524 TIR_Print("Cannot rebind super-call to %s from %s\n",
525 old_target.ToCString(),
526 Object::Handle(Owner()).ToCString());
527 return;
528 }
529 const String& selector = String::Handle(old_target.name());
530 const Class& cls = Class::Handle(old_target.Owner());
531 const Function& new_target =
532 Function::Handle(cls.LookupStaticFunction(selector));
533 if (new_target.IsNull()) {
534 // TODO(johnmccutchan): Improve this.
535 TIR_Print("Cannot rebind static call to %s from %s\n",
536 old_target.ToCString(),
537 Object::Handle(Owner()).ToCString());
538 return;
539 }
540 ClearAndSetStaticTarget(new_target);
541 } else {
542 ClearWithSentinel();
543 }
544 }
545
546 #endif // !PRODUCT
547
548 } // namespace dart.
OLDNEW
« runtime/vm/object.cc ('K') | « runtime/vm/object.cc ('k') | runtime/vm/object_service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698