Flutter Engine
The Flutter Engine
object_reload.cc
Go to the documentation of this file.
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
8#include "vm/code_patcher.h"
9#include "vm/dart_entry.h"
10#include "vm/hash_table.h"
11#include "vm/isolate_reload.h"
12#include "vm/log.h"
13#include "vm/object_store.h"
14#include "vm/resolver.h"
15#include "vm/stub_code.h"
16#include "vm/symbols.h"
17
18namespace dart {
19
20#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
21
22DECLARE_FLAG(bool, trace_reload);
23DECLARE_FLAG(bool, trace_reload_verbose);
24DECLARE_FLAG(bool, two_args_smi_icd);
25
27 ic_data_array_ = function.ic_data_array();
28 if (ic_data_array_.IsNull()) {
29 return;
30 }
31 ASSERT(ic_data_array_.Length() > 0);
32 edge_counters_ ^=
34 if (edge_counters_.IsNull()) {
35 return;
36 }
37 // Fill edge counters array with zeros.
38 for (intptr_t i = 0; i < edge_counters_.Length(); i++) {
39 edge_counters_.SetAt(i, Object::smi_zero());
40 }
41}
42
44 : zone_(zone),
45 instrs_(Instructions::Handle(zone)),
46 pool_(ObjectPool::Handle(zone)),
47 object_(Object::Handle(zone)),
48 name_(String::Handle(zone)),
49 new_cls_(Class::Handle(zone)),
50 new_lib_(Library::Handle(zone)),
51 new_function_(Function::Handle(zone)),
52 new_field_(Field::Handle(zone)),
53 entries_(Array::Handle(zone)),
54 old_target_(Function::Handle(zone)),
55 new_target_(Function::Handle(zone)),
56 caller_(Function::Handle(zone)),
57 args_desc_array_(Array::Handle(zone)),
58 ic_data_array_(Array::Handle(zone)),
59 edge_counters_(Array::Handle(zone)),
60 descriptors_(PcDescriptors::Handle(zone)),
61 ic_data_(ICData::Handle(zone)) {}
62
64 // Iterate over the Code's object pool and reset all ICDatas.
65 // SubtypeTestCaches are reset during the same heap traversal as type
66 // testing stub deoptimization.
67#ifdef TARGET_ARCH_IA32
68 // IA32 does not have an object pool, but, we can iterate over all
69 // embedded objects by using the variable length data section.
70 if (!code.is_alive()) {
71 return;
72 }
73 instrs_ = code.instructions();
74 ASSERT(!instrs_.IsNull());
75 uword base_address = instrs_.PayloadStart();
76 intptr_t offsets_length = code.pointer_offsets_length();
77 const int32_t* offsets = code.untag()->data();
78 for (intptr_t i = 0; i < offsets_length; i++) {
79 int32_t offset = offsets[i];
80 ObjectPtr* object_ptr = reinterpret_cast<ObjectPtr*>(base_address + offset);
81 ObjectPtr raw_object = LoadUnaligned(object_ptr);
82 if (!raw_object->IsHeapObject()) {
83 continue;
84 }
85 object_ = raw_object;
86 if (object_.IsICData()) {
87 Reset(ICData::Cast(object_));
88 }
89 }
90#else
91 pool_ = code.object_pool();
92 ASSERT(!pool_.IsNull());
93 ResetCaches(pool_);
94#endif
95}
96
97static void FindICData(const Array& ic_data_array,
98 intptr_t deopt_id,
99 ICData* ic_data) {
100 // ic_data_array is sorted because of how it is constructed in
101 // Function::SaveICDataMap.
103 intptr_t hi = ic_data_array.Length() - 1;
104 while (lo <= hi) {
105 intptr_t mid = (hi - lo + 1) / 2 + lo;
106 ASSERT(mid >= lo);
107 ASSERT(mid <= hi);
108 *ic_data ^= ic_data_array.At(mid);
109 if (ic_data->deopt_id() == deopt_id) {
110 return;
111 } else if (ic_data->deopt_id() > deopt_id) {
112 hi = mid - 1;
113 } else {
114 lo = mid + 1;
115 }
116 }
117 FATAL("Missing deopt id %" Pd "\n", deopt_id);
118}
119
121 if (code.is_optimized()) {
122 return; // No switchable calls in optimized code.
123 }
124
125 object_ = code.owner();
126 if (!object_.IsFunction()) {
127 return; // No switchable calls in stub code.
128 }
129 const Function& function = Function::Cast(object_);
130
131 if (function.kind() == UntaggedFunction::kIrregexpFunction) {
132 // Regex matchers do not support breakpoints or stepping, and they only call
133 // core library functions that cannot change due to reload. As a performance
134 // optimization, avoid this matching of ICData to PCs for these functions'
135 // large number of instance calls.
136 ASSERT(!function.is_debuggable());
137 return;
138 }
139
140 ic_data_array_ = function.ic_data_array();
141 if (ic_data_array_.IsNull()) {
142 // The megamorphic miss stub and some recognized function doesn't populate
143 // their ic_data_array. Check this only happens for functions without IC
144 // calls.
145#if defined(DEBUG)
146 descriptors_ = code.pc_descriptors();
147 PcDescriptors::Iterator iter(descriptors_, UntaggedPcDescriptors::kIcCall);
148 while (iter.MoveNext()) {
149 FATAL("%s has IC calls but no ic_data_array\n",
150 function.ToFullyQualifiedCString());
151 }
152#endif
153 return;
154 }
155
156 descriptors_ = code.pc_descriptors();
157 PcDescriptors::Iterator iter(descriptors_, UntaggedPcDescriptors::kIcCall);
158 while (iter.MoveNext()) {
159 uword pc = code.PayloadStart() + iter.PcOffset();
161 // This check both avoids unnecessary patching to reduce log spam and
162 // prevents patching over breakpoint stubs.
163 if (!object_.IsICData()) {
164 FindICData(ic_data_array_, iter.DeoptId(), &ic_data_);
165 ASSERT(ic_data_.rebind_rule() == ICData::kInstance);
166 ASSERT(ic_data_.NumArgsTested() == 1);
167 const Code& stub =
168 ic_data_.is_tracking_exactness()
169 ? StubCode::OneArgCheckInlineCacheWithExactnessCheck()
170 : StubCode::OneArgCheckInlineCache();
171 CodePatcher::PatchInstanceCallAt(pc, code, ic_data_, stub);
172 if (FLAG_trace_ic) {
173 OS::PrintErr("Instance call at %" Px
174 " resetting to polymorphic dispatch, %s\n",
175 pc, ic_data_.ToCString());
176 }
177 }
178 }
179}
180
182 for (intptr_t i = 0; i < pool.Length(); i++) {
183 ObjectPool::EntryType entry_type = pool.TypeAt(i);
184 if (entry_type != ObjectPool::EntryType::kTaggedObject) {
185 continue;
186 }
187 object_ = pool.ObjectAt(i);
188 if (object_.IsICData()) {
189 Reset(ICData::Cast(object_));
190 }
191 }
192}
193
195 const Class& old_cls) const {
196 const Array& old_field_list = Array::Handle(old_cls.fields());
197 Field& old_field = Field::Handle();
198 String& old_name = String::Handle();
199
200 const Array& field_list = Array::Handle(fields());
201 Field& field = Field::Handle();
203
204 for (intptr_t i = 0; i < field_list.Length(); i++) {
205 field = Field::RawCast(field_list.At(i));
206 name = field.name();
207 // Find the corresponding old field, if it exists, and migrate
208 // over the field value.
209 for (intptr_t j = 0; j < old_field_list.Length(); j++) {
210 old_field = Field::RawCast(old_field_list.At(j));
211 old_name = old_field.name();
212 if (name.Equals(old_name)) {
213 if (field.is_static()) {
214 // We only copy values if requested and if the field is not a const
215 // field. We let const fields be updated with a reload.
216 if (!field.is_const()) {
217 // Make new field point to the old field value so that both
218 // old and new code see and update same value.
219 reload_context->isolate_group()->FreeStaticField(field);
220 field.set_field_id_unsafe(old_field.field_id());
221 }
222 reload_context->AddStaticFieldMapping(old_field, field);
223 }
224 }
225 }
226 }
227}
228
229void Class::CopyCanonicalConstants(const Class& old_cls) const {
230#if defined(DEBUG)
231 {
232 // Class has no canonical constants allocated.
233 const Array& my_constants = Array::Handle(constants());
234 ASSERT(my_constants.IsNull() || my_constants.Length() == 0);
235 }
236#endif // defined(DEBUG).
237 // Copy old constants into new class.
238 const Array& old_constants = Array::Handle(old_cls.constants());
239 if (old_constants.IsNull() || old_constants.Length() == 0) {
240 return;
241 }
242 TIR_Print("Copied %" Pd " canonical constants for class `%s`\n",
243 old_constants.Length(), ToCString());
244 set_constants(old_constants);
245}
246
247void Class::CopyDeclarationType(const Class& old_cls) const {
248 const Type& old_declaration_type = Type::Handle(old_cls.declaration_type());
249 if (old_declaration_type.IsNull()) {
250 return;
251 }
252 set_declaration_type(old_declaration_type);
253}
254
256 public:
257 static bool ReportStats() { return false; }
258 static const char* Name() { return "EnumMapTraits"; }
259
260 static bool IsMatch(const Object& a, const Object& b) {
261 return a.ptr() == b.ptr();
262 }
263
264 static uword Hash(const Object& obj) {
265 ASSERT(obj.IsString());
266 return String::Cast(obj).Hash();
267 }
268};
269
271 // Move all old functions and fields to a patch class so that they
272 // still refer to their original script.
273 const auto& kernel_info = KernelProgramInfo::Handle(KernelProgramInfo());
274 const PatchClass& patch = PatchClass::Handle(
275 PatchClass::New(*this, kernel_info, Script::Handle(script())));
276 ASSERT(!patch.IsNull());
277 const Library& lib = Library::Handle(library());
279
280 const Array& funcs = Array::Handle(current_functions());
281 Function& func = Function::Handle();
282 Object& owner = Object::Handle();
283 for (intptr_t i = 0; i < funcs.Length(); i++) {
284 func = Function::RawCast(funcs.At(i));
285 if ((func.token_pos() == TokenPosition::kMinSource) ||
286 func.IsClosureFunction()) {
287 // Eval functions do not need to have their script updated.
288 //
289 // Closure functions refer to the parent's script which we can
290 // rely on being updated for us, if necessary.
291 continue;
292 }
293
294 // If the source for this function is already patched, leave it alone.
295 owner = func.RawOwner();
296 ASSERT(!owner.IsNull());
297 if (!owner.IsPatchClass()) {
298 ASSERT(owner.ptr() == this->ptr());
299 func.set_owner(patch);
300 }
301 }
302
303 Thread* thread = Thread::Current();
304 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
305 const Array& field_list = Array::Handle(fields());
306 Field& field = Field::Handle();
307 for (intptr_t i = 0; i < field_list.Length(); i++) {
308 field = Field::RawCast(field_list.At(i));
309 owner = field.RawOwner();
310 ASSERT(!owner.IsNull());
311 if (!owner.IsPatchClass()) {
312 ASSERT(owner.ptr() == this->ptr());
313 field.set_owner(patch);
314 }
315 field.ForceDynamicGuardedCidAndLength();
316 }
317}
318
320 const Class& new_cls) const {
321 const Array& funcs = Array::Handle(current_functions());
322 Thread* thread = Thread::Current();
323 Function& old_func = Function::Handle();
324 String& selector = String::Handle();
325 Function& new_func = Function::Handle();
326 Closure& old_closure = Closure::Handle();
327 Closure& new_closure = Closure::Handle();
328 for (intptr_t i = 0; i < funcs.Length(); i++) {
329 old_func ^= funcs.At(i);
330 if (old_func.is_static() && old_func.HasImplicitClosureFunction()) {
331 selector = old_func.name();
332 new_func = Resolver::ResolveFunction(thread->zone(), new_cls, selector);
333 if (!new_func.IsNull() && new_func.is_static()) {
334 old_func = old_func.ImplicitClosureFunction();
335 old_closure = old_func.ImplicitStaticClosure();
336 new_func = new_func.ImplicitClosureFunction();
337 new_closure = new_func.ImplicitStaticClosure();
338 if (old_closure.IsCanonical()) {
339 new_closure.SetCanonical();
340 }
341 irc->AddBecomeMapping(old_closure, new_closure);
342 }
343 }
344 }
345}
346
348 public:
349 EnumClassConflict(Zone* zone, const Class& from, const Class& to)
350 : ClassReasonForCancelling(zone, from, to) {}
351
352 StringPtr ToString() {
355 ? "Enum class cannot be redefined to be a non-enum class: %s"
356 : "Class cannot be redefined to be a enum class: %s",
357 from_.ToCString());
358 }
359};
360
362 public:
364 const Class& from,
365 const Class& to,
366 const Error& error)
367 : ClassReasonForCancelling(zone, from, to), error_(error) {}
368
369 private:
370 const Error& error_;
371
372 ErrorPtr ToError() { return error_.ptr(); }
373
374 StringPtr ToString() { return String::New(error_.ToErrorCString()); }
375};
376
378 public:
379 DeeplyImmutableChange(Zone* zone, const Class& from, const Class& to)
380 : ClassReasonForCancelling(zone, from, to) {}
381
382 private:
383 StringPtr ToString() {
385 "Classes cannot change their @pragma('vm:deeply-immutable'): %s",
386 from_.ToCString());
387 }
388};
389
391 public:
392 ConstToNonConstClass(Zone* zone, const Class& from, const Class& to)
393 : ClassReasonForCancelling(zone, from, to) {}
394
395 private:
396 StringPtr ToString() {
397 return String::NewFormatted("Const class cannot become non-const: %s",
398 from_.ToCString());
399 }
400};
401
403 public:
404 ConstClassFieldRemoved(Zone* zone, const Class& from, const Class& to)
405 : ClassReasonForCancelling(zone, from, to) {}
406
407 private:
408 StringPtr ToString() {
409 return String::NewFormatted("Const class cannot remove fields: %s",
410 from_.ToCString());
411 }
412};
413
415 public:
416 NativeFieldsConflict(Zone* zone, const Class& from, const Class& to)
417 : ClassReasonForCancelling(zone, from, to) {}
418
419 private:
420 StringPtr ToString() {
421 return String::NewFormatted("Number of native fields changed in %s",
422 from_.ToCString());
423 }
424};
425
427 public:
428 TypeParametersChanged(Zone* zone, const Class& from, const Class& to)
429 : ClassReasonForCancelling(zone, from, to) {}
430
431 StringPtr ToString() {
433 "Limitation: type parameters have changed for %s", from_.ToCString());
434 }
435
436 void AppendTo(JSONArray* array) {
437 JSONObject jsobj(array);
438 jsobj.AddProperty("type", "ReasonForCancellingReload");
439 jsobj.AddProperty("kind", "TypeParametersChanged");
440 jsobj.AddProperty("class", to_);
441 jsobj.AddProperty("message",
442 "Limitation: changing type parameters "
443 "does not work with hot reload.");
444 }
445};
446
448 public:
449 PreFinalizedConflict(Zone* zone, const Class& from, const Class& to)
450 : ClassReasonForCancelling(zone, from, to) {}
451
452 private:
453 StringPtr ToString() {
455 "Original class ('%s') is prefinalized and replacement class "
456 "('%s') is not ",
458 }
459};
460
462 public:
463 InstanceSizeConflict(Zone* zone, const Class& from, const Class& to)
464 : ClassReasonForCancelling(zone, from, to) {}
465
466 private:
467 StringPtr ToString() {
468 return String::NewFormatted("Instance size mismatch between '%s' (%" Pd
469 ") and replacement "
470 "'%s' ( %" Pd ")",
473 }
474};
475
476// This is executed before iterating over the instances.
477void Class::CheckReload(const Class& replacement,
478 ProgramReloadContext* context) const {
479 ASSERT(ProgramReloadContext::IsSameClass(*this, replacement));
480
481 if (!is_declaration_loaded()) {
482 // The old class hasn't been used in any meaningful way, so the VM is okay
483 // with any change.
484 return;
485 }
486
487 // Ensure is_enum_class etc have been set.
488 replacement.EnsureDeclarationLoaded();
489
490 // Class cannot change enum property.
491 if (is_enum_class() != replacement.is_enum_class()) {
492 context->group_reload_context()->AddReasonForCancelling(
493 new (context->zone())
494 EnumClassConflict(context->zone(), *this, replacement));
495 return;
496 }
497
498 if (is_finalized()) {
499 // Make sure the declaration types parameter count matches for the two
500 // classes.
501 // ex. class A<int,B> {} cannot be replace with class A<B> {}.
502 auto group_context = context->group_reload_context();
503 if (NumTypeParameters() != replacement.NumTypeParameters()) {
504 group_context->AddReasonForCancelling(
505 new (context->zone())
506 TypeParametersChanged(context->zone(), *this, replacement));
507 return;
508 }
509 }
510
512 auto thread = Thread::Current();
513
514 // Ensure the replacement class is also finalized.
515 const Error& error = Error::Handle(
517 : replacement.EnsureIsFinalized(thread));
518 if (!error.IsNull()) {
519 context->group_reload_context()->AddReasonForCancelling(
520 new (context->zone())
521 EnsureFinalizedError(context->zone(), *this, replacement, error));
522 return; // No reason to check other properties.
523 }
524 ASSERT(replacement.is_finalized());
525 TIR_Print("Finalized replacement class for %s\n", ToCString());
526 }
527
528 if (is_deeply_immutable() != replacement.is_deeply_immutable()) {
529 context->group_reload_context()->AddReasonForCancelling(
530 new (context->zone())
531 DeeplyImmutableChange(context->zone(), *this, replacement));
532 return; // No reason to check other properties.
533 }
534
535 if (is_finalized() && is_const() && (constants() != Array::null()) &&
536 (Array::LengthOf(constants()) > 0)) {
537 // Consts can't become non-consts.
538 if (!replacement.is_const()) {
539 context->group_reload_context()->AddReasonForCancelling(
540 new (context->zone())
541 ConstToNonConstClass(context->zone(), *this, replacement));
542 return;
543 }
544
545 // Consts can't lose fields.
546 bool field_removed = false;
547 const Array& old_fields = Array::Handle(
548 OffsetToFieldMap(IsolateGroup::Current()->heap_walk_class_table()));
549 const Array& new_fields = Array::Handle(replacement.OffsetToFieldMap());
550 if (new_fields.Length() < old_fields.Length()) {
551 field_removed = true;
552 } else {
553 Field& old_field = Field::Handle();
554 Field& new_field = Field::Handle();
555 String& old_name = String::Handle();
556 String& new_name = String::Handle();
557 for (intptr_t i = 0, n = old_fields.Length(); i < n; i++) {
558 old_field ^= old_fields.At(i);
559 new_field ^= new_fields.At(i);
560 if (old_field.IsNull()) {
561 continue;
562 }
563 if (new_field.IsNull()) {
564 field_removed = true;
565 break;
566 }
567 old_name = old_field.name();
568 new_name = new_field.name();
569 if (!old_name.Equals(new_name)) {
570 field_removed = true;
571 break;
572 }
573 }
574 }
575 if (field_removed) {
576 context->group_reload_context()->AddReasonForCancelling(
577 new (context->zone())
578 ConstClassFieldRemoved(context->zone(), *this, replacement));
579 return;
580 }
581 }
582
583 // Native field count cannot change.
584 if (num_native_fields() != replacement.num_native_fields()) {
585 context->group_reload_context()->AddReasonForCancelling(
586 new (context->zone())
587 NativeFieldsConflict(context->zone(), *this, replacement));
588 return;
589 }
590
591 // Just checking.
592 ASSERT(is_enum_class() == replacement.is_enum_class());
593 ASSERT(num_native_fields() == replacement.num_native_fields());
594
595 if (is_finalized()) {
596 if (!CanReloadFinalized(replacement, context)) return;
597 }
598 if (is_prefinalized()) {
599 if (!CanReloadPreFinalized(replacement, context)) return;
600 }
601 TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n", ToCString(),
602 id(), replacement.id());
603}
604
606 const Field& field) const {
607 if (!field.is_unboxed()) {
608 return;
609 }
610
611 field.set_is_unboxed_unsafe(false);
612
613 // Make sure to update the bitmap used for scanning.
614 auto unboxed_fields_map = class_table->GetUnboxedFieldsMapAt(id());
615 const auto start_index = field.HostOffset() >> kCompressedWordSizeLog2;
616 const auto end_index =
617 start_index + (Class::UnboxedFieldSizeInBytesByCid(field.guarded_cid()) >>
619 ASSERT(unboxed_fields_map.Get(start_index));
620 for (intptr_t i = start_index; i < end_index; i++) {
621 unboxed_fields_map.Clear(i);
622 }
623 class_table->SetUnboxedFieldsMapAt(id(), unboxed_fields_map);
624}
625
626bool Class::RequiresInstanceMorphing(ClassTable* class_table,
627 const Class& replacement) const {
628 if (!is_allocate_finalized()) {
629 // No instances of this class exists on the heap - nothing to morph.
630 return false;
631 }
632
633 // Get the field maps for both classes. These field maps walk the class
634 // hierarchy.
635 auto isolate_group = IsolateGroup::Current();
636
637 // heap_walk_class_table is the original class table before it was
638 // updated by reloading sources.
639 const Array& fields =
640 Array::Handle(OffsetToFieldMap(isolate_group->heap_walk_class_table()));
641 const Array& replacement_fields =
642 Array::Handle(replacement.OffsetToFieldMap());
643
644 // Check that the size of the instance is the same.
645 if (fields.Length() != replacement_fields.Length()) return true;
646
647 // Check that we have the same next field offset. This check is not
648 // redundant with the one above because the instance OffsetToFieldMap
649 // array length is based on the instance size (which may be aligned up).
650 if (host_next_field_offset() != replacement.host_next_field_offset()) {
651 return true;
652 }
653
654 // Verify that field names / offsets match across the entire hierarchy.
655 Field& field = Field::Handle();
656 String& field_name = String::Handle();
657 Field& replacement_field = Field::Handle();
658 String& replacement_field_name = String::Handle();
659
660 for (intptr_t i = 0; i < fields.Length(); i++) {
661 if (fields.At(i) == Field::null()) {
662 ASSERT(replacement_fields.At(i) == Field::null());
663 continue;
664 }
665 field = Field::RawCast(fields.At(i));
666 replacement_field = Field::RawCast(replacement_fields.At(i));
667 field_name = field.name();
668 replacement_field_name = replacement_field.name();
669 if (!field_name.Equals(replacement_field_name)) return true;
670 if (field.is_unboxed() && !replacement_field.is_unboxed()) {
671 return true;
672 }
673 if (field.is_unboxed() && (field.type() != replacement_field.type())) {
674 return true;
675 }
676 if (!field.is_unboxed() && replacement_field.is_unboxed()) {
677 // No actual morphing is required in this case but we need to mark
678 // the field boxed.
679 replacement.MarkFieldBoxedDuringReload(class_table, replacement_field);
680 }
681 if (field.needs_load_guard()) {
682 ASSERT(!field.is_unboxed());
683 ASSERT(!replacement_field.is_unboxed());
684 replacement_field.set_needs_load_guard(true);
685 }
686 }
687 return false;
688}
689
690bool Class::CanReloadFinalized(const Class& replacement,
691 ProgramReloadContext* context) const {
692 // Make sure the declaration types argument count matches for the two classes.
693 // ex. class A<int,B> {} cannot be replace with class A<B> {}.
694 auto group_context = context->group_reload_context();
695 auto class_table = group_context->isolate_group()->class_table();
696 if (NumTypeArguments() != replacement.NumTypeArguments()) {
697 group_context->AddReasonForCancelling(
698 new (context->zone())
699 TypeParametersChanged(context->zone(), *this, replacement));
700 return false;
701 }
702 if (RequiresInstanceMorphing(class_table, replacement)) {
703 ASSERT(id() == replacement.id());
704 const classid_t cid = id();
705 // We unconditionally create an instance morpher. As a side effect of
706 // building the morpher, we will mark all new fields as guarded on load.
707 auto instance_morpher = InstanceMorpher::CreateFromClassDescriptors(
708 context->zone(), class_table, *this, replacement);
709 group_context->EnsureHasInstanceMorpherFor(cid, instance_morpher);
710 }
711 return true;
712}
713
714bool Class::CanReloadPreFinalized(const Class& replacement,
715 ProgramReloadContext* context) const {
716 // The replacement class must also prefinalized.
717 if (!replacement.is_prefinalized()) {
718 context->group_reload_context()->AddReasonForCancelling(
719 new (context->zone())
720 PreFinalizedConflict(context->zone(), *this, replacement));
721 return false;
722 }
723 // Check the instance sizes are equal.
724 if (host_instance_size() != replacement.host_instance_size()) {
725 context->group_reload_context()->AddReasonForCancelling(
726 new (context->zone())
727 InstanceSizeConflict(context->zone(), *this, replacement));
728 return false;
729 }
730 return true;
731}
732
733void Library::CheckReload(const Library& replacement,
734 ProgramReloadContext* context) const {
735 // Carry over the loaded bit of any deferred prefixes.
736 Object& object = Object::Handle();
738 LibraryPrefix& original_prefix = LibraryPrefix::Handle();
740 String& original_name = String::Handle();
741 DictionaryIterator it(replacement);
742 while (it.HasNext()) {
743 object = it.GetNext();
744 if (!object.IsLibraryPrefix()) continue;
745 prefix ^= object.ptr();
746 if (!prefix.is_deferred_load()) continue;
747
748 name = prefix.name();
749 DictionaryIterator original_it(*this);
750 while (original_it.HasNext()) {
751 object = original_it.GetNext();
752 if (!object.IsLibraryPrefix()) continue;
753 original_prefix ^= object.ptr();
754 if (!original_prefix.is_deferred_load()) continue;
755 original_name = original_prefix.name();
756 if (!name.Equals(original_name)) continue;
757
758 // The replacement of the old prefix with the new prefix
759 // in Isolate::loaded_prefixes_set_ implicitly carried
760 // the loaded state over to the new prefix.
761 context->AddBecomeMapping(original_prefix, prefix);
762 }
763 }
764}
765
768 if (rule == ICData::kInstance) {
769 const intptr_t num_args = ic.NumArgsTested();
770 const intptr_t len = ic.Length();
771 // We need at least one non-sentinel entry to require a check
772 // for the smi fast path case.
773 if (num_args == 2 && len >= 2) {
774 if (ic.IsImmutable()) {
775 return;
776 }
777 name_ = ic.target_name();
778 const Class& smi_class = Class::Handle(zone_, Smi::Class());
779 const Function& smi_op_target = Function::Handle(
780 zone_, Resolver::ResolveDynamicAnyArgs(zone_, smi_class, name_,
781 /*allow_add=*/true));
782 GrowableArray<intptr_t> class_ids(2);
784 ic.GetCheckAt(0, &class_ids, &target);
785 if ((target.ptr() == smi_op_target.ptr()) && (class_ids[0] == kSmiCid) &&
786 (class_ids[1] == kSmiCid)) {
787 // The smi fast path case, preserve the initial entry but reset the
788 // count.
789 ic.ClearCountAt(0, *this);
790 ic.TruncateTo(/*num_checks=*/1, *this);
791 return;
792 }
793 // Fall back to the normal behavior with cached empty ICData arrays.
794 }
795 ic.Clear(*this);
796 ic.set_is_megamorphic(false);
797 return;
798 } else if (rule == ICData::kNoRebind || rule == ICData::kNSMDispatch) {
799 // TODO(30877) we should account for addition/removal of NSM.
800 // Don't rebind dispatchers.
801 return;
802 } else if (rule == ICData::kStatic || rule == ICData::kSuper) {
803 old_target_ = ic.GetTargetAt(0);
804 if (old_target_.IsNull()) {
805 FATAL("old_target is nullptr.\n");
806 }
807 name_ = old_target_.name();
808
809 if (rule == ICData::kStatic) {
810 ASSERT(old_target_.is_static() ||
811 old_target_.kind() == UntaggedFunction::kConstructor);
812 // This can be incorrect if the call site was an unqualified invocation.
813 new_cls_ = old_target_.Owner();
814 new_target_ = Resolver::ResolveFunction(zone_, new_cls_, name_);
815 if (new_target_.kind() != old_target_.kind()) {
816 new_target_ = Function::null();
817 }
818 } else {
819 // Super call.
820 caller_ = ic.Owner();
821 ASSERT(!caller_.is_static());
822 new_cls_ = caller_.Owner();
823 new_cls_ = new_cls_.SuperClass();
824 new_target_ = Resolver::ResolveDynamicAnyArgs(zone_, new_cls_, name_,
825 /*allow_add=*/true);
826 }
827 args_desc_array_ = ic.arguments_descriptor();
828 ArgumentsDescriptor args_desc(args_desc_array_);
829 if (new_target_.IsNull() ||
830 !new_target_.AreValidArguments(args_desc, nullptr)) {
831 // TODO(rmacnak): Patch to a NSME stub.
832 VTIR_Print("Cannot rebind static call to %s from %s\n",
833 old_target_.ToCString(),
834 Object::Handle(zone_, ic.Owner()).ToCString());
835 return;
836 }
837 ic.ClearAndSetStaticTarget(new_target_, *this);
838 } else {
839 FATAL("Unexpected rebind rule.");
840 }
841}
842
843#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
844
845} // namespace dart
AutoreleasePool pool
static intptr_t LengthOf(const ArrayPtr array)
Definition: object.h:10830
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:10880
StringPtr target_name() const
Definition: object.h:2372
ArrayPtr arguments_descriptor() const
Definition: object.h:2373
void ResetCaches(const Code &code)
void ResetSwitchableCalls(const Code &code)
void Reset(const ICData &ic)
void ZeroEdgeCounters(const Function &function)
CallSiteResetter(Zone *zone)
UnboxedFieldBitmap GetUnboxedFieldsMapAt(intptr_t cid) const
Definition: class_table.h:388
void SetUnboxedFieldsMapAt(intptr_t cid, UnboxedFieldBitmap map)
Definition: class_table.h:393
void PatchFieldsAndFunctions() const
void CopyDeclarationType(const Class &old_cls) const
intptr_t NumTypeParameters() const
Definition: object.h:1344
LibraryPtr library() const
Definition: object.h:1333
void CopyCanonicalConstants(const Class &old_cls) const
bool is_declaration_loaded() const
Definition: object.h:1703
bool is_const() const
Definition: object.h:1745
intptr_t host_next_field_offset() const
Definition: object.h:1190
intptr_t id() const
Definition: object.h:1233
static intptr_t UnboxedFieldSizeInBytesByCid(intptr_t cid)
Definition: object.cc:3702
intptr_t NumTypeArguments() const
Definition: object.cc:3640
ArrayPtr fields() const
Definition: object.h:1615
bool is_deeply_immutable() const
Definition: object.h:2174
ArrayPtr constants() const
Definition: object.cc:5806
uint16_t num_native_fields() const
Definition: object.h:1788
void MigrateImplicitStaticClosures(ProgramReloadContext *context, const Class &new_cls) const
ArrayPtr OffsetToFieldMap(ClassTable *class_table=nullptr) const
Definition: object.cc:3183
intptr_t host_instance_size() const
Definition: object.h:1143
ErrorPtr EnsureIsFinalized(Thread *thread) const
Definition: object.cc:4924
bool is_prefinalized() const
Definition: object.h:1738
KernelProgramInfoPtr KernelProgramInfo() const
Definition: object.cc:5560
void CopyStaticFieldValues(ProgramReloadContext *reload_context, const Class &old_cls) const
ErrorPtr EnsureIsAllocateFinalized(Thread *thread) const
Definition: object.cc:4954
ClassPtr SuperClass(ClassTable *class_table=nullptr) const
Definition: object.cc:3665
void set_constants(const Array &value) const
Definition: object.cc:5810
bool is_enum_class() const
Definition: object.h:1720
void MarkFieldBoxedDuringReload(ClassTable *class_table, const Field &field) const
bool is_allocate_finalized() const
Definition: object.h:1732
void CheckReload(const Class &replacement, ProgramReloadContext *context) const
intptr_t NumTypeParameters(Thread *thread) const
Definition: object.cc:3555
bool is_finalized() const
Definition: object.h:1723
ArrayPtr current_functions() const
Definition: object.h:1641
ScriptPtr script() const
Definition: object.h:1272
void EnsureDeclarationLoaded() const
Definition: object.cc:4913
static void PatchInstanceCallAt(uword return_address, const Code &caller_code, const Object &data, const Code &target)
static CodePtr GetInstanceCallAt(uword return_address, const Code &caller_code, Object *data)
ConstClassFieldRemoved(Zone *zone, const Class &from, const Class &to)
ConstToNonConstClass(Zone *zone, const Class &from, const Class &to)
DeeplyImmutableChange(Zone *zone, const Class &from, const Class &to)
bool HasNext() const
Definition: object.h:5049
EnsureFinalizedError(Zone *zone, const Class &from, const Class &to, const Error &error)
EnumClassConflict(Zone *zone, const Class &from, const Class &to)
static bool IsMatch(const Object &a, const Object &b)
static const char * Name()
static uword Hash(const Object &obj)
static bool ReportStats()
virtual const char * ToErrorCString() const
Definition: object.cc:19780
bool is_unboxed() const
Definition: object.h:4712
ObjectPtr RawOwner() const
Definition: object.cc:11849
bool is_static() const
Definition: object.h:4440
StringPtr name() const
Definition: object.h:4430
intptr_t guarded_cid() const
Definition: object.cc:11749
intptr_t field_id() const
Definition: object.h:13284
intptr_t HostOffset() const
Definition: object.h:13241
void set_is_unboxed_unsafe(bool b) const
Definition: object.h:4716
bool is_const() const
Definition: object.h:4443
void set_field_id_unsafe(intptr_t field_id) const
Definition: object.h:13294
void set_owner(const Object &value) const
Definition: object.cc:8464
ObjectPtr RawOwner() const
Definition: object.h:3083
StringPtr name() const
Definition: object.h:2992
bool AreValidArguments(intptr_t num_type_arguments, intptr_t num_arguments, const Array &argument_names, String *error_message) const
Definition: object.cc:9323
TokenPosition token_pos() const
Definition: object.h:3446
bool IsClosureFunction() const
Definition: object.h:3891
FunctionPtr ImplicitClosureFunction() const
Definition: object.cc:10385
ClassPtr Owner() const
Definition: object.cc:10841
UntaggedFunction::Kind kind() const
Definition: object.h:3349
ClosurePtr ImplicitStaticClosure() const
Definition: object.cc:10700
bool HasImplicitClosureFunction() const
Definition: object.h:3326
intptr_t deopt_id() const
Definition: object.h:2468
void TruncateTo(intptr_t num_checks, const CallSiteResetter &proof_of_reload) const
Definition: object.cc:16690
void ClearCountAt(intptr_t index, const CallSiteResetter &proof_of_reload) const
Definition: object.cc:16721
intptr_t NumArgsTested() const
Definition: object.cc:16471
RebindRule rebind_rule() const
Definition: object.cc:16547
FunctionPtr GetTargetAt(intptr_t index) const
Definition: object.cc:17029
bool IsImmutable() const
Definition: object.cc:17330
void GetCheckAt(intptr_t index, GrowableArray< intptr_t > *class_ids, Function *target) const
Definition: object.cc:16955
void Clear(const CallSiteResetter &proof_of_reload) const
Definition: object.h:2603
intptr_t Length() const
Definition: object.cc:16573
bool is_tracking_exactness() const
Definition: object.h:2483
void set_is_megamorphic(bool value) const
Definition: object.h:2555
void ClearAndSetStaticTarget(const Function &func, const CallSiteResetter &proof_of_reload) const
Definition: object.cc:16730
FunctionPtr Owner() const
Definition: object.cc:16423
static InstanceMorpher * CreateFromClassDescriptors(Zone *zone, ClassTable *class_table, const Class &from, const Class &to)
InstanceSizeConflict(Zone *zone, const Class &from, const Class &to)
uword PayloadStart() const
Definition: object.h:5745
void FreeStaticField(const Field &field)
Definition: isolate.cc:848
SafepointRwLock * program_lock()
Definition: isolate.h:537
static IsolateGroup * Current()
Definition: isolate.h:539
void AddProperty(const char *name, bool b) const
Definition: json_stream.h:395
bool is_deferred_load() const
Definition: object.h:8461
StringPtr name() const
Definition: object.h:8451
void CheckReload(const Library &replacement, ProgramReloadContext *context) const
StringPtr name() const
Definition: object.h:5094
intptr_t kernel_library_index() const
Definition: object.h:5309
NativeFieldsConflict(Zone *zone, const Class &from, const Class &to)
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
bool IsCanonical() const
Definition: object.h:335
void SetCanonical() const
Definition: object.h:336
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
void set_kernel_library_index(intptr_t index) const
Definition: object.h:2280
intptr_t DeoptId() const
Definition: object.h:6155
PreFinalizedConflict(Zone *zone, const Class &from, const Class &to)
static bool IsSameClass(const Class &a, const Class &b)
IsolateGroupReloadContext * group_reload_context()
static FunctionPtr ResolveDynamicAnyArgs(Zone *zone, const Class &receiver_class, const String &function_name, bool allow_add)
Definition: resolver.cc:185
static FunctionPtr ResolveFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition: resolver.cc:167
friend class Class
Definition: object.h:10047
static StringPtr NewFormatted(const char *format,...) PRINTF_ATTRIBUTE(1
Definition: object.cc:24004
bool Equals(const String &str) const
Definition: object.h:13337
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
IsolateGroup * isolate_group() const
Definition: thread.h:541
static const TokenPosition kMinSource
void AppendTo(JSONArray *array)
TypeParametersChanged(Zone *zone, const Class &from, const Class &to)
#define ASSERT(E)
static bool b
struct MyStruct a[10]
#define FATAL(error)
const uint8_t uint32_t uint32_t GError ** error
uint32_t * target
Dart_NativeFunction function
Definition: fuchsia.cc:51
#define VTIR_Print(format,...)
#define TIR_Print(format,...)
Definition: dart_vm.cc:33
static void FindICData(const Array &ic_data_array, intptr_t deopt_id, ICData *ic_data)
const char *const name
static constexpr intptr_t kCompressedWordSizeLog2
Definition: globals.h:43
int32_t classid_t
Definition: globals.h:524
uintptr_t uword
Definition: globals.h:501
static T LoadUnaligned(const T *ptr)
Definition: unaligned.h:14
const intptr_t cid
DECLARE_FLAG(bool, show_invisible_frames)
list offsets
Definition: mskp_parser.py:37
#define Px
Definition: globals.h:410
#define Pd
Definition: globals.h:408
SeparatedVector2 offset
static constexpr intptr_t kFirstICData
Definition: object.h:4060
static constexpr intptr_t kEdgeCounters
Definition: object.h:4058