OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/object.h" | 5 #include "vm/object.h" |
6 | 6 |
7 #include "vm/hash_table.h" | 7 #include "vm/hash_table.h" |
8 #include "vm/isolate_reload.h" | 8 #include "vm/isolate_reload.h" |
9 #include "vm/log.h" | 9 #include "vm/log.h" |
10 #include "vm/resolver.h" | 10 #include "vm/resolver.h" |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 // When an enum is reloaded the following three things can happen, possibly | 197 // When an enum is reloaded the following three things can happen, possibly |
198 // simultaneously. | 198 // simultaneously. |
199 // | 199 // |
200 // 1) A new enum value is added. | 200 // 1) A new enum value is added. |
201 // This case is handled automatically. | 201 // This case is handled automatically. |
202 // 2) Enum values are reordered. | 202 // 2) Enum values are reordered. |
203 // We pair old and new enums and the old enums 'become' the new ones so | 203 // We pair old and new enums and the old enums 'become' the new ones so |
204 // the ordering is always correct (i.e. enum indicies match slots in values | 204 // the ordering is always correct (i.e. enum indicies match slots in values |
205 // array) | 205 // array) |
206 // 3) An existing enum value is removed. | 206 // 3) An existing enum value is removed. |
207 // We leave old enum values that have no mapping to the reloaded class | 207 // Each enum class has a canonical 'deleted' enum sentinel instance. |
208 // in the heap. This means that if a programmer does the following: | 208 // When an enum value is deleted, we 'become' all references to the 'deleted' |
209 // enum Foo { A, B }; var x = Foo.A; | 209 // sentinel value. The index value is -1. |
210 // *reload* | |
211 // enum Foo { B }; | |
212 // *reload* | |
213 // enum Foo { A, B }; expect(identical(x, Foo.A)); | |
214 // The program will fail because we were not able to pair Foo.A on the second | |
215 // reload. | |
216 // | 210 // |
217 // Deleted enum values still in the heap continue to function but their | |
218 // index field will not be valid. | |
219 void Class::ReplaceEnum(const Class& old_enum) const { | 211 void Class::ReplaceEnum(const Class& old_enum) const { |
220 // We only do this for finalized enum classes. | 212 // We only do this for finalized enum classes. |
221 ASSERT(is_enum_class()); | 213 ASSERT(is_enum_class()); |
222 ASSERT(old_enum.is_enum_class()); | 214 ASSERT(old_enum.is_enum_class()); |
223 ASSERT(is_finalized()); | 215 ASSERT(is_finalized()); |
224 ASSERT(old_enum.is_finalized()); | 216 ASSERT(old_enum.is_finalized()); |
225 | 217 |
226 Thread* thread = Thread::Current(); | 218 Thread* thread = Thread::Current(); |
227 Zone* zone = thread->zone(); | 219 Zone* zone = thread->zone(); |
228 IsolateReloadContext* reload_context = Isolate::Current()->reload_context(); | 220 IsolateReloadContext* reload_context = Isolate::Current()->reload_context(); |
229 ASSERT(reload_context != NULL); | 221 ASSERT(reload_context != NULL); |
230 | 222 |
231 Array& enum_fields = Array::Handle(zone); | 223 Array& enum_fields = Array::Handle(zone); |
232 Field& field = Field::Handle(zone); | 224 Field& field = Field::Handle(zone); |
233 String& enum_ident = String::Handle(); | 225 String& enum_ident = String::Handle(); |
234 Instance& old_enum_value = Instance::Handle(zone); | 226 Instance& old_enum_value = Instance::Handle(zone); |
235 Instance& enum_value = Instance::Handle(zone); | 227 Instance& enum_value = Instance::Handle(zone); |
236 // The E.values array. | 228 // The E.values array. |
237 Instance& old_enum_values = Instance::Handle(zone); | 229 Instance& old_enum_values = Instance::Handle(zone); |
238 // The E.values array. | 230 // The E.values array. |
239 Instance& enum_values = Instance::Handle(zone); | 231 Instance& enum_values = Instance::Handle(zone); |
| 232 // The E._deleted_enum_sentinel instance. |
| 233 Instance& old_deleted_enum_sentinel = Instance::Handle(zone); |
| 234 // The E._deleted_enum_sentinel instance. |
| 235 Instance& deleted_enum_sentinel = Instance::Handle(zone); |
240 Array& enum_map_storage = | 236 Array& enum_map_storage = |
241 Array::Handle(zone, HashTables::New<UnorderedHashMap<EnumMapTraits> >(4)); | 237 Array::Handle(zone, HashTables::New<UnorderedHashMap<EnumMapTraits> >(4)); |
242 ASSERT(!enum_map_storage.IsNull()); | 238 ASSERT(!enum_map_storage.IsNull()); |
243 | 239 |
244 TIR_Print("Replacing enum `%s`\n", String::Handle(Name()).ToCString()); | 240 TIR_Print("Replacing enum `%s`\n", String::Handle(Name()).ToCString()); |
245 | 241 |
246 { | 242 { |
247 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); | 243 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); |
248 // Build a map of all enum name -> old enum instance. | 244 // Build a map of all enum name -> old enum instance. |
249 enum_fields = old_enum.fields(); | 245 enum_fields = old_enum.fields(); |
250 for (intptr_t i = 0; i < enum_fields.Length(); i++) { | 246 for (intptr_t i = 0; i < enum_fields.Length(); i++) { |
251 field = Field::RawCast(enum_fields.At(i)); | 247 field = Field::RawCast(enum_fields.At(i)); |
252 enum_ident = field.name(); | 248 enum_ident = field.name(); |
253 if (!field.is_static()) { | 249 if (!field.is_static()) { |
254 // Enum instances are only held in static fields. | 250 // Enum instances are only held in static fields. |
255 continue; | 251 continue; |
256 } | 252 } |
257 if (enum_ident.Equals(Symbols::Values())) { | 253 if (enum_ident.Equals(Symbols::Values())) { |
258 old_enum_values = field.StaticValue(); | 254 old_enum_values = field.StaticValue(); |
259 // Non-enum instance. | 255 // Non-enum instance. |
260 continue; | 256 continue; |
261 } | 257 } |
| 258 if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) { |
| 259 old_deleted_enum_sentinel = field.StaticValue(); |
| 260 // Non-enum instance. |
| 261 continue; |
| 262 } |
262 old_enum_value = field.StaticValue(); | 263 old_enum_value = field.StaticValue(); |
263 ASSERT(!old_enum_value.IsNull()); | 264 ASSERT(!old_enum_value.IsNull()); |
264 VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString()); | 265 VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString()); |
265 bool update = enum_map.UpdateOrInsert(enum_ident, old_enum_value); | 266 bool update = enum_map.UpdateOrInsert(enum_ident, old_enum_value); |
266 VTIR_Print("Element %s added to mapping\n", enum_ident.ToCString()); | 267 VTIR_Print("Element %s added to mapping\n", enum_ident.ToCString()); |
267 ASSERT(!update); | 268 ASSERT(!update); |
268 } | 269 } |
269 // The storage given to the map may have been reallocated, remember the new | 270 // The storage given to the map may have been reallocated, remember the new |
270 // address. | 271 // address. |
271 enum_map_storage = enum_map.Release().raw(); | 272 enum_map_storage = enum_map.Release().raw(); |
272 } | 273 } |
273 | 274 |
274 bool enums_deleted = false; | 275 bool enums_deleted = false; |
275 { | 276 { |
276 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); | 277 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); |
277 // Add a become mapping from the old instances to the new instances. | 278 // Add a become mapping from the old instances to the new instances. |
278 enum_fields = fields(); | 279 enum_fields = fields(); |
279 for (intptr_t i = 0; i < enum_fields.Length(); i++) { | 280 for (intptr_t i = 0; i < enum_fields.Length(); i++) { |
280 field = Field::RawCast(enum_fields.At(i)); | 281 field = Field::RawCast(enum_fields.At(i)); |
281 enum_ident = field.name(); | 282 enum_ident = field.name(); |
282 if (!field.is_static()) { | 283 if (!field.is_static()) { |
283 // Enum instances are only held in static fields. | 284 // Enum instances are only held in static fields. |
284 continue; | 285 continue; |
285 } | 286 } |
286 if (enum_ident.Equals(Symbols::Values())) { | 287 if (enum_ident.Equals(Symbols::Values())) { |
287 enum_values = field.StaticValue(); | 288 enum_values = field.StaticValue(); |
288 // Non-enum instance. | 289 // Non-enum instance. |
289 continue; | 290 continue; |
290 } | 291 } |
| 292 if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) { |
| 293 deleted_enum_sentinel = field.StaticValue(); |
| 294 // Non-enum instance. |
| 295 continue; |
| 296 } |
291 enum_value = field.StaticValue(); | 297 enum_value = field.StaticValue(); |
292 ASSERT(!enum_value.IsNull()); | 298 ASSERT(!enum_value.IsNull()); |
293 old_enum_value ^= enum_map.GetOrNull(enum_ident); | 299 old_enum_value ^= enum_map.GetOrNull(enum_ident); |
294 if (old_enum_value.IsNull()) { | 300 if (old_enum_value.IsNull()) { |
295 VTIR_Print("New element %s was not found in mapping\n", | 301 VTIR_Print("New element %s was not found in mapping\n", |
296 enum_ident.ToCString()); | 302 enum_ident.ToCString()); |
297 } else { | 303 } else { |
298 VTIR_Print("Adding element `%s` to become mapping\n", | 304 VTIR_Print("Adding element `%s` to become mapping\n", |
299 enum_ident.ToCString()); | 305 enum_ident.ToCString()); |
300 bool removed = enum_map.Remove(enum_ident); | 306 bool removed = enum_map.Remove(enum_ident); |
301 ASSERT(removed); | 307 ASSERT(removed); |
302 reload_context->AddEnumBecomeMapping(old_enum_value, enum_value); | 308 reload_context->AddEnumBecomeMapping(old_enum_value, enum_value); |
303 } | 309 } |
304 } | 310 } |
305 enums_deleted = enum_map.NumOccupied() > 0; | 311 enums_deleted = enum_map.NumOccupied() > 0; |
306 // The storage given to the map may have been reallocated, remember the new | 312 // The storage given to the map may have been reallocated, remember the new |
307 // address. | 313 // address. |
308 enum_map_storage = enum_map.Release().raw(); | 314 enum_map_storage = enum_map.Release().raw(); |
309 } | 315 } |
310 | 316 |
311 // Map the old E.values array to the new E.values array. | 317 // Map the old E.values array to the new E.values array. |
312 ASSERT(!old_enum_values.IsNull()); | 318 ASSERT(!old_enum_values.IsNull()); |
313 ASSERT(!enum_values.IsNull()); | 319 ASSERT(!enum_values.IsNull()); |
314 reload_context->AddEnumBecomeMapping(old_enum_values, enum_values); | 320 reload_context->AddEnumBecomeMapping(old_enum_values, enum_values); |
315 | 321 |
316 if (enums_deleted && FLAG_trace_reload_verbose) { | 322 // Map the old E._deleted_enum_sentinel to the new E._deleted_enum_sentinel. |
| 323 ASSERT(!old_deleted_enum_sentinel.IsNull()); |
| 324 ASSERT(!deleted_enum_sentinel.IsNull()); |
| 325 reload_context->AddEnumBecomeMapping(old_deleted_enum_sentinel, |
| 326 deleted_enum_sentinel); |
| 327 |
| 328 if (enums_deleted) { |
| 329 // Map all deleted enums to the deleted enum senintel value. |
317 // TODO(johnmccutchan): Add this to the reload 'notices' list. | 330 // TODO(johnmccutchan): Add this to the reload 'notices' list. |
318 VTIR_Print( | 331 VTIR_Print( |
319 "The following enum values were deleted and are forever lost in " | 332 "The following enum values were deleted from %s and will become the " |
320 "the heap:\n"); | 333 "deleted enum sentinel:\n", |
| 334 old_enum.ToCString()); |
321 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); | 335 UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw()); |
322 UnorderedHashMap<EnumMapTraits>::Iterator it(&enum_map); | 336 UnorderedHashMap<EnumMapTraits>::Iterator it(&enum_map); |
323 while (it.MoveNext()) { | 337 while (it.MoveNext()) { |
324 const intptr_t entry = it.Current(); | 338 const intptr_t entry = it.Current(); |
325 enum_ident = String::RawCast(enum_map.GetKey(entry)); | 339 enum_ident = String::RawCast(enum_map.GetKey(entry)); |
326 ASSERT(!enum_ident.IsNull()); | 340 ASSERT(!enum_ident.IsNull()); |
| 341 old_enum_value ^= enum_map.GetOrNull(enum_ident); |
| 342 VTIR_Print("Element `%s` was deleted\n", enum_ident.ToCString()); |
| 343 reload_context->AddEnumBecomeMapping(old_enum_value, |
| 344 deleted_enum_sentinel); |
327 } | 345 } |
328 enum_map.Release(); | 346 enum_map.Release(); |
329 } | 347 } |
330 } | 348 } |
331 | 349 |
332 | 350 |
333 void Class::PatchFieldsAndFunctions() const { | 351 void Class::PatchFieldsAndFunctions() const { |
334 // Move all old functions and fields to a patch class so that they | 352 // Move all old functions and fields to a patch class so that they |
335 // still refer to their original script. | 353 // still refer to their original script. |
336 const PatchClass& patch = | 354 const PatchClass& patch = |
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 const Array& data_array = | 763 const Array& data_array = |
746 Array::Handle(zone, CachedEmptyICDataArray(num_args)); | 764 Array::Handle(zone, CachedEmptyICDataArray(num_args)); |
747 set_ic_data_array(data_array); | 765 set_ic_data_array(data_array); |
748 } | 766 } |
749 } | 767 } |
750 } | 768 } |
751 | 769 |
752 #endif // !PRODUCT | 770 #endif // !PRODUCT |
753 | 771 |
754 } // namespace dart. | 772 } // namespace dart. |
OLD | NEW |