Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(486)

Side by Side Diff: runtime/vm/object_reload.cc

Issue 2498863002: Map deleted enum values to a sentinel value. (Closed)
Patch Set: asiva review Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/isolate_reload_test.cc ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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.
OLDNEW
« no previous file with comments | « runtime/vm/isolate_reload_test.cc ('k') | runtime/vm/parser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698