Flutter Engine
The Flutter Engine
Public Member Functions | Static Public Member Functions | List of all members
dart::InstanceMorpher Class Reference

#include <isolate_reload.h>

Inheritance diagram for dart::InstanceMorpher:
dart::ZoneAllocated

Public Member Functions

 InstanceMorpher (Zone *zone, classid_t cid, const Class &old_class, const Class &new_class, FieldMappingArray *mapping, FieldOffsetArray *new_fields_offsets)
 
virtual ~InstanceMorpher ()
 
void AddObject (ObjectPtr object)
 
void CreateMorphedCopies (Become *become)
 
void AppendTo (JSONArray *array)
 
intptr_t cid () const
 
void Dump () const
 
- Public Member Functions inherited from dart::ZoneAllocated
 ZoneAllocated ()
 
void * operator new (size_t size)
 
void * operator new (size_t size, Zone *zone)
 
void operator delete (void *pointer)
 

Static Public Member Functions

static InstanceMorpherCreateFromClassDescriptors (Zone *zone, ClassTable *class_table, const Class &from, const Class &to)
 

Detailed Description

Definition at line 65 of file isolate_reload.h.

Constructor & Destructor Documentation

◆ InstanceMorpher()

dart::InstanceMorpher::InstanceMorpher ( Zone zone,
classid_t  cid,
const Class old_class,
const Class new_class,
FieldMappingArray mapping,
FieldOffsetArray new_fields_offsets 
)

Definition at line 219 of file isolate_reload.cc.

225 : zone_(zone),
226 cid_(cid),
227 old_class_(Class::Handle(zone, old_class.ptr())),
228 new_class_(Class::Handle(zone, new_class.ptr())),
229 mapping_(mapping),
230 new_fields_offsets_(new_fields_offsets),
231 before_(zone, 16) {}
intptr_t cid() const
static Object & Handle()
Definition: object.h:407

◆ ~InstanceMorpher()

virtual dart::InstanceMorpher::~InstanceMorpher ( )
inlinevirtual

Definition at line 80 of file isolate_reload.h.

80{}

Member Function Documentation

◆ AddObject()

void dart::InstanceMorpher::AddObject ( ObjectPtr  object)

Definition at line 233 of file isolate_reload.cc.

233 {
234 ASSERT(object->GetClassId() == cid_);
235 const Instance& instance = Instance::Cast(Object::Handle(Z, object));
236 before_.Add(&instance);
237}
#define ASSERT(E)
VkInstance instance
Definition: main.cc:48
#define Z

◆ AppendTo()

void dart::InstanceMorpher::AppendTo ( JSONArray array)

Definition at line 395 of file isolate_reload.cc.

395 {
396 JSONObject jsobj(array);
397 jsobj.AddProperty("type", "ShapeChangeMapping");
398 jsobj.AddProperty64("class-id", cid_);
399 jsobj.AddProperty("instanceCount", before_.length());
400 JSONArray map(&jsobj, "fieldOffsetMappings");
401 for (int i = 0; i < mapping_->length(); i += 2) {
402 const auto& from = mapping_->At(i);
403 const auto& to = mapping_->At(i + 1);
404
405 JSONArray pair(&map);
406 pair.AddValue(from.offset);
407 pair.AddValue(to.offset);
408 if (to.box_cid == kIllegalCid && from.box_cid != kIllegalCid) {
409 pair.AddValueF("box %s", BoxCidToCString(from.box_cid));
410 } else if (to.box_cid != kIllegalCid) {
411 pair.AddValueF("%s", BoxCidToCString(from.box_cid));
412 }
413 }
414}
const T & At(intptr_t index) const
intptr_t length() const
@ kIllegalCid
Definition: class_id.h:214
static const char * BoxCidToCString(intptr_t box_cid)
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680

◆ cid()

intptr_t dart::InstanceMorpher::cid ( ) const
inline

Definition at line 92 of file isolate_reload.h.

92{ return cid_; }

◆ CreateFromClassDescriptors()

InstanceMorpher * dart::InstanceMorpher::CreateFromClassDescriptors ( Zone zone,
ClassTable class_table,
const Class from,
const Class to 
)
static

Definition at line 98 of file isolate_reload.cc.

102 {
103 auto mapping = new (zone) FieldMappingArray();
104 auto new_fields_offsets = new (zone) FieldOffsetArray();
105
106 if (from.NumTypeArguments() > 0) {
107 // Add copying of the optional type argument field.
108 intptr_t from_offset = from.host_type_arguments_field_offset();
109 ASSERT(from_offset != Class::kNoTypeArguments);
110 intptr_t to_offset = to.host_type_arguments_field_offset();
111 ASSERT(to_offset != Class::kNoTypeArguments);
112 mapping->Add({from_offset, kIllegalCid});
113 mapping->Add({to_offset, kIllegalCid});
114 }
115
116 // Add copying of the instance fields if matching by name.
117 // Note: currently the type of the fields are ignored.
118 const Array& from_fields = Array::Handle(
119 from.OffsetToFieldMap(IsolateGroup::Current()->heap_walk_class_table()));
120 const Array& to_fields = Array::Handle(to.OffsetToFieldMap());
121 Field& from_field = Field::Handle();
122 Field& to_field = Field::Handle();
123 String& from_name = String::Handle();
124 String& to_name = String::Handle();
125
126 auto ensure_boxed_and_guarded = [&](const Field& field) {
127 field.set_needs_load_guard(true);
128 if (field.is_unboxed()) {
129 to.MarkFieldBoxedDuringReload(class_table, field);
130 }
131 };
132
133 // Scan across all the fields in the new class definition.
134 for (intptr_t i = 0; i < to_fields.Length(); i++) {
135 if (to_fields.At(i) == Field::null()) {
136 continue; // Ignore non-fields.
137 }
138
139 // Grab the field's name.
140 to_field = Field::RawCast(to_fields.At(i));
141 ASSERT(to_field.is_instance());
142 to_name = to_field.name();
143
144 // Did this field not exist in the old class definition?
145 bool new_field = true;
146
147 // Find this field in the old class.
148 for (intptr_t j = 0; j < from_fields.Length(); j++) {
149 if (from_fields.At(j) == Field::null()) {
150 continue; // Ignore non-fields.
151 }
152 from_field = Field::RawCast(from_fields.At(j));
153 ASSERT(from_field.is_instance());
154 from_name = from_field.name();
155 if (from_name.Equals(to_name)) {
156 intptr_t from_box_cid = kIllegalCid;
157 intptr_t to_box_cid = kIllegalCid;
158
159 // Check if either of the fields are unboxed.
160 if ((from_field.is_unboxed() && from_field.type() != to_field.type()) ||
161 (from_field.is_unboxed() != to_field.is_unboxed())) {
162 // For simplicity we just migrate to boxed fields if such
163 // situation occurs.
164 ensure_boxed_and_guarded(to_field);
165 }
166
167 if (from_field.is_unboxed()) {
168 const auto field_cid = from_field.guarded_cid();
169 switch (field_cid) {
170 case kDoubleCid:
171 case kFloat32x4Cid:
172 case kFloat64x2Cid:
173 from_box_cid = field_cid;
174 break;
175 default:
176 from_box_cid = kIntegerCid;
177 break;
178 }
179 }
180
181 if (to_field.is_unboxed()) {
182 const auto field_cid = to_field.guarded_cid();
183 switch (field_cid) {
184 case kDoubleCid:
185 case kFloat32x4Cid:
186 case kFloat64x2Cid:
187 to_box_cid = field_cid;
188 break;
189 default:
190 to_box_cid = kIntegerCid;
191 break;
192 }
193 }
194
195 // Field can't become unboxed if it was boxed.
196 ASSERT(from_box_cid != kIllegalCid || to_box_cid == kIllegalCid);
197
198 // Success
199 mapping->Add({from_field.HostOffset(), from_box_cid});
200 mapping->Add({to_field.HostOffset(), to_box_cid});
201
202 // Field did exist in old class definition.
203 new_field = false;
204 break;
205 }
206 }
207
208 if (new_field) {
209 ensure_boxed_and_guarded(to_field);
210 new_fields_offsets->Add(to_field.HostOffset());
211 }
212 }
213
214 ASSERT(from.id() == to.id());
215 return new (zone)
216 InstanceMorpher(zone, to.id(), from, to, mapping, new_fields_offsets);
217}
static constexpr intptr_t kNoTypeArguments
Definition: object.h:1374
InstanceMorpher(Zone *zone, classid_t cid, const Class &old_class, const Class &new_class, FieldMappingArray *mapping, FieldOffsetArray *new_fields_offsets)
static IsolateGroup * Current()
Definition: isolate.h:539
ClassTable * heap_walk_class_table() const
Definition: isolate.h:503
static ObjectPtr null()
Definition: object.h:433
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
ZoneGrowableArray< FieldMapping > FieldMappingArray
ZoneGrowableArray< intptr_t > FieldOffsetArray

◆ CreateMorphedCopies()

void dart::InstanceMorpher::CreateMorphedCopies ( Become become)

Definition at line 239 of file isolate_reload.cc.

239 {
240 Instance& after = Instance::Handle(Z);
241 Object& value = Object::Handle(Z);
242 for (intptr_t i = 0; i < before_.length(); i++) {
243 const Instance& before = *before_.At(i);
244
245 // Code can reference constants / canonical objects either directly in the
246 // instruction stream (ia32) or via an object pool.
247 //
248 // We have the following invariants:
249 //
250 // a) Those canonical objects don't change state (i.e. are not mutable):
251 // our optimizer can e.g. execute loads of such constants at
252 // compile-time.
253 //
254 // => We ensure that const-classes with live constants cannot be
255 // reloaded to become non-const classes (see Class::CheckReload).
256 //
257 // b) Those canonical objects live in old space: e.g. on ia32 the
258 // scavenger does not make the RX pages writable and therefore cannot
259 // update pointers embedded in the instruction stream.
260 //
261 // In order to maintain these invariants we ensure to always morph canonical
262 // objects to old space.
263 const bool is_canonical = before.IsCanonical();
264 const Heap::Space space = is_canonical ? Heap::kOld : Heap::kNew;
265 after = Instance::NewAlreadyFinalized(new_class_, space);
266
267 // We preserve the canonical bit of the object, since this object is present
268 // in the class's constants.
269 if (is_canonical) {
270 after.SetCanonical();
271 }
272#if defined(HASH_IN_OBJECT_HEADER)
273 const uint32_t hash = Object::GetCachedHash(before.ptr());
274 Object::SetCachedHashIfNotSet(after.ptr(), hash);
275#endif
276
277 // Morph the context from [before] to [after] using mapping_.
278 for (intptr_t i = 0; i < mapping_->length(); i += 2) {
279 const auto& from = mapping_->At(i);
280 const auto& to = mapping_->At(i + 1);
281 ASSERT(from.offset > 0);
282 ASSERT(to.offset > 0);
283 if (from.box_cid == kIllegalCid) {
284 // Boxed to boxed field migration.
285 ASSERT(to.box_cid == kIllegalCid);
286 // No handle: raw_value might be a ForwardingCorpse for an object
287 // processed earlier in instance morphing
288 ObjectPtr raw_value = before.RawGetFieldAtOffset(from.offset);
289 after.RawSetFieldAtOffset(to.offset, raw_value);
290 } else if (to.box_cid == kIllegalCid) {
291 // Unboxed to boxed field migration.
292 switch (from.box_cid) {
293 case kDoubleCid: {
294 const auto unboxed_value =
295 before.RawGetUnboxedFieldAtOffset<double>(from.offset);
296 value = Double::New(unboxed_value);
297 break;
298 }
299 case kFloat32x4Cid: {
300 const auto unboxed_value =
301 before.RawGetUnboxedFieldAtOffset<simd128_value_t>(from.offset);
302 value = Float32x4::New(unboxed_value);
303 break;
304 }
305 case kFloat64x2Cid: {
306 const auto unboxed_value =
307 before.RawGetUnboxedFieldAtOffset<simd128_value_t>(from.offset);
308 value = Float64x2::New(unboxed_value);
309 break;
310 }
311 case kIntegerCid: {
312 const auto unboxed_value =
313 before.RawGetUnboxedFieldAtOffset<int64_t>(from.offset);
314 value = Integer::New(unboxed_value);
315 break;
316 }
317 }
318 if (is_canonical) {
319 value = Instance::Cast(value).Canonicalize(Thread::Current());
320 }
321 after.RawSetFieldAtOffset(to.offset, value);
322 } else {
323 // Unboxed to unboxed field migration.
324 ASSERT(to.box_cid == from.box_cid);
325 switch (from.box_cid) {
326 case kDoubleCid: {
327 const auto unboxed_value =
328 before.RawGetUnboxedFieldAtOffset<double>(from.offset);
329 after.RawSetUnboxedFieldAtOffset<double>(to.offset, unboxed_value);
330 break;
331 }
332 case kFloat32x4Cid:
333 case kFloat64x2Cid: {
334 const auto unboxed_value =
335 before.RawGetUnboxedFieldAtOffset<simd128_value_t>(from.offset);
336 after.RawSetUnboxedFieldAtOffset<simd128_value_t>(to.offset,
337 unboxed_value);
338 break;
339 }
340 case kIntegerCid: {
341 const auto unboxed_value =
342 before.RawGetUnboxedFieldAtOffset<int64_t>(from.offset);
343 after.RawSetUnboxedFieldAtOffset<int64_t>(to.offset, unboxed_value);
344 break;
345 }
346 }
347 }
348 }
349
350 for (intptr_t i = 0; i < new_fields_offsets_->length(); i++) {
351 const auto& field_offset = new_fields_offsets_->At(i);
352 after.RawSetFieldAtOffset(field_offset, Object::sentinel());
353 }
354
355 // Convert the old instance into a filler object. We will switch to the
356 // new class table before the next heap walk, so there must be no
357 // instances of any class with the old size.
359
360 become->Add(before, after);
361 }
362}
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static void MakeDummyObject(const Instance &instance)
Definition: become.cc:242
static DoublePtr New(double d, Heap::Space space=Heap::kNew)
Definition: object.cc:23402
static Float32x4Ptr New(float value0, float value1, float value2, float value3, Heap::Space space=Heap::kNew)
Definition: object.cc:25307
static Float64x2Ptr New(double value0, double value1, Heap::Space space=Heap::kNew)
Definition: object.cc:25475
@ kNew
Definition: heap.h:38
@ kOld
Definition: heap.h:39
static InstancePtr NewAlreadyFinalized(const Class &cls, Heap::Space space=Heap::kNew)
Definition: object.cc:20943
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition: object.cc:22984
static Thread * Current()
Definition: thread.h:362
uint8_t value

◆ Dump()

void dart::InstanceMorpher::Dump ( ) const

Definition at line 378 of file isolate_reload.cc.

378 {
379 LogBlock blocker;
380 THR_Print("Morphing objects with cid: %d via this mapping: ", cid_);
381 for (int i = 0; i < mapping_->length(); i += 2) {
382 const auto& from = mapping_->At(i);
383 const auto& to = mapping_->At(i + 1);
384 THR_Print(" %" Pd "->%" Pd "", from.offset, to.offset);
385 THR_Print(" (%" Pd " -> %" Pd ")", from.box_cid, to.box_cid);
386 if (to.box_cid == kIllegalCid && from.box_cid != kIllegalCid) {
387 THR_Print("[box %s]", BoxCidToCString(from.box_cid));
388 } else if (to.box_cid != kIllegalCid) {
389 THR_Print("[%s]", BoxCidToCString(from.box_cid));
390 }
391 }
392 THR_Print("\n");
393}
#define THR_Print(format,...)
Definition: log.h:20
#define Pd
Definition: globals.h:408

The documentation for this class was generated from the following files: