| Index: runtime/vm/object_reload.cc
|
| diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
|
| index b48c46e4f3becb3694bad160029d3a1e0e303b93..b41ff6c03d77b3fafe4bc3088882dfd47eac2141 100644
|
| --- a/runtime/vm/object_reload.cc
|
| +++ b/runtime/vm/object_reload.cc
|
| @@ -204,18 +204,10 @@ class EnumMapTraits {
|
| // the ordering is always correct (i.e. enum indicies match slots in values
|
| // array)
|
| // 3) An existing enum value is removed.
|
| -// We leave old enum values that have no mapping to the reloaded class
|
| -// in the heap. This means that if a programmer does the following:
|
| -// enum Foo { A, B }; var x = Foo.A;
|
| -// *reload*
|
| -// enum Foo { B };
|
| -// *reload*
|
| -// enum Foo { A, B }; expect(identical(x, Foo.A));
|
| -// The program will fail because we were not able to pair Foo.A on the second
|
| -// reload.
|
| +// Each enum class has a canonical 'deleted' enum sentinel instance.
|
| +// When an enum value is deleted, we 'become' all references to the 'deleted'
|
| +// sentinel value. The index value is -1.
|
| //
|
| -// Deleted enum values still in the heap continue to function but their
|
| -// index field will not be valid.
|
| void Class::ReplaceEnum(const Class& old_enum) const {
|
| // We only do this for finalized enum classes.
|
| ASSERT(is_enum_class());
|
| @@ -237,6 +229,10 @@ void Class::ReplaceEnum(const Class& old_enum) const {
|
| Instance& old_enum_values = Instance::Handle(zone);
|
| // The E.values array.
|
| Instance& enum_values = Instance::Handle(zone);
|
| + // The E._deleted_enum_sentinel instance.
|
| + Instance& old_deleted_enum_sentinel = Instance::Handle(zone);
|
| + // The E._deleted_enum_sentinel instance.
|
| + Instance& deleted_enum_sentinel = Instance::Handle(zone);
|
| Array& enum_map_storage =
|
| Array::Handle(zone, HashTables::New<UnorderedHashMap<EnumMapTraits> >(4));
|
| ASSERT(!enum_map_storage.IsNull());
|
| @@ -259,6 +255,11 @@ void Class::ReplaceEnum(const Class& old_enum) const {
|
| // Non-enum instance.
|
| continue;
|
| }
|
| + if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
|
| + old_deleted_enum_sentinel = field.StaticValue();
|
| + // Non-enum instance.
|
| + continue;
|
| + }
|
| old_enum_value = field.StaticValue();
|
| ASSERT(!old_enum_value.IsNull());
|
| VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString());
|
| @@ -288,6 +289,11 @@ void Class::ReplaceEnum(const Class& old_enum) const {
|
| // Non-enum instance.
|
| continue;
|
| }
|
| + if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
|
| + deleted_enum_sentinel = field.StaticValue();
|
| + // Non-enum instance.
|
| + continue;
|
| + }
|
| enum_value = field.StaticValue();
|
| ASSERT(!enum_value.IsNull());
|
| old_enum_value ^= enum_map.GetOrNull(enum_ident);
|
| @@ -313,17 +319,29 @@ void Class::ReplaceEnum(const Class& old_enum) const {
|
| ASSERT(!enum_values.IsNull());
|
| reload_context->AddEnumBecomeMapping(old_enum_values, enum_values);
|
|
|
| - if (enums_deleted && FLAG_trace_reload_verbose) {
|
| + // Map the old E._deleted_enum_sentinel to the new E._deleted_enum_sentinel.
|
| + ASSERT(!old_deleted_enum_sentinel.IsNull());
|
| + ASSERT(!deleted_enum_sentinel.IsNull());
|
| + reload_context->AddEnumBecomeMapping(old_deleted_enum_sentinel,
|
| + deleted_enum_sentinel);
|
| +
|
| + if (enums_deleted) {
|
| + // Map all deleted enums to the deleted enum senintel value.
|
| // TODO(johnmccutchan): Add this to the reload 'notices' list.
|
| VTIR_Print(
|
| - "The following enum values were deleted and are forever lost in "
|
| - "the heap:\n");
|
| + "The following enum values were deleted from %s and will become the "
|
| + "deleted enum sentinel:\n",
|
| + old_enum.ToCString());
|
| UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw());
|
| UnorderedHashMap<EnumMapTraits>::Iterator it(&enum_map);
|
| while (it.MoveNext()) {
|
| const intptr_t entry = it.Current();
|
| enum_ident = String::RawCast(enum_map.GetKey(entry));
|
| ASSERT(!enum_ident.IsNull());
|
| + old_enum_value ^= enum_map.GetOrNull(enum_ident);
|
| + VTIR_Print("Element `%s` was deleted\n", enum_ident.ToCString());
|
| + reload_context->AddEnumBecomeMapping(old_enum_value,
|
| + deleted_enum_sentinel);
|
| }
|
| enum_map.Release();
|
| }
|
|
|