| 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 |