Skip to content

Commit f013751

Browse files
alexmarkovCommit Bot
authored and
Commit Bot
committed
[vm] Prepare for enhanced enums
This change prepares VM for enhanced enums language feature. List of enum values is now queried using 'values' static field and not inferred from the list of fields (as enhanced enums allow arbitrary fields). TEST=ci Issue: #47861 Change-Id: Id6eabb6c4ac5a5f03b22ceb67d57431082e22576 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/225020 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent da46f98 commit f013751

File tree

4 files changed

+76
-109
lines changed

4 files changed

+76
-109
lines changed

runtime/vm/class_finalizer.cc

+36-47
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
11331133
}
11341134
FinalizeMemberTypes(cls);
11351135

1136-
if (cls.is_enum_class()) {
1136+
if (cls.is_enum_class() && !FLAG_precompiled_mode) {
11371137
AllocateEnumValues(cls);
11381138
}
11391139

@@ -1216,69 +1216,58 @@ ErrorPtr ClassFinalizer::LoadClassMembers(const Class& cls) {
12161216
}
12171217
}
12181218

1219-
// Allocate instances for each enumeration value, and populate the
1220-
// static field 'values'.
1221-
// By allocating the instances programmatically, we save an implicit final
1222-
// getter function object for each enumeration value and for the
1223-
// values field. We also don't have to generate the code for these getters
1224-
// from thin air (no source code is available).
1219+
// Eagerly allocate instances for enumeration values by evaluating
1220+
// static const field 'values'. Also, pre-allocate
1221+
// deleted sentinel value. This is needed to correctly
1222+
// migrate enumeration values in case of hot reload.
12251223
void ClassFinalizer::AllocateEnumValues(const Class& enum_cls) {
12261224
Thread* thread = Thread::Current();
12271225
Zone* zone = thread->zone();
12281226

1227+
const auto& values_field =
1228+
Field::Handle(zone, enum_cls.LookupStaticField(Symbols::Values()));
1229+
ASSERT(!values_field.IsNull() && values_field.is_static() &&
1230+
values_field.is_const());
1231+
1232+
const auto& values =
1233+
Object::Handle(zone, values_field.StaticConstFieldValue());
1234+
if (values.IsError()) {
1235+
ReportError(Error::Cast(values));
1236+
}
1237+
ASSERT(values.IsArray());
1238+
12291239
// The enum_cls is the actual declared class.
12301240
// The shared super-class holds the fields for index and name.
1231-
const Class& super_cls = Class::Handle(zone, enum_cls.SuperClass());
1241+
const auto& super_cls = Class::Handle(zone, enum_cls.SuperClass());
12321242

1233-
const Field& index_field =
1243+
const auto& index_field =
12341244
Field::Handle(zone, super_cls.LookupInstanceField(Symbols::Index()));
12351245
ASSERT(!index_field.IsNull());
12361246

1237-
const Field& name_field = Field::Handle(
1247+
const auto& name_field = Field::Handle(
12381248
zone, super_cls.LookupInstanceFieldAllowPrivate(Symbols::_name()));
12391249
ASSERT(!name_field.IsNull());
12401250

1241-
const String& enum_name = String::Handle(zone, enum_cls.ScrubbedName());
1242-
1243-
const Array& fields = Array::Handle(zone, enum_cls.fields());
1244-
Field& field = Field::Handle(zone);
1245-
Instance& enum_value = Instance::Handle(zone);
1246-
String& enum_ident = String::Handle(zone);
1247-
1248-
enum_ident =
1249-
Symbols::FromConcat(thread, Symbols::_DeletedEnumPrefix(), enum_name);
1250-
enum_value = Instance::New(enum_cls, Heap::kOld);
1251-
enum_value.SetField(index_field, Smi::Handle(zone, Smi::New(-1)));
1252-
enum_value.SetField(name_field, enum_ident);
1253-
enum_value = enum_value.Canonicalize(thread);
1254-
ASSERT(!enum_value.IsNull());
1255-
ASSERT(enum_value.IsCanonical());
1256-
const Field& sentinel = Field::Handle(
1251+
const auto& enum_name = String::Handle(zone, enum_cls.ScrubbedName());
1252+
1253+
const auto& sentinel_ident = String::Handle(
1254+
zone,
1255+
Symbols::FromConcat(thread, Symbols::_DeletedEnumPrefix(), enum_name));
1256+
auto& sentinel_value =
1257+
Instance::Handle(zone, Instance::New(enum_cls, Heap::kOld));
1258+
sentinel_value.SetField(index_field, Smi::Handle(zone, Smi::New(-1)));
1259+
sentinel_value.SetField(name_field, sentinel_ident);
1260+
sentinel_value = sentinel_value.Canonicalize(thread);
1261+
ASSERT(!sentinel_value.IsNull());
1262+
ASSERT(sentinel_value.IsCanonical());
1263+
const auto& sentinel_field = Field::Handle(
12571264
zone, enum_cls.LookupStaticField(Symbols::_DeletedEnumSentinel()));
1258-
ASSERT(!sentinel.IsNull());
1265+
ASSERT(!sentinel_field.IsNull());
12591266

12601267
// The static const field contains `Object::null()` instead of
12611268
// `Object::sentinel()` - so it's not considered an initializing store.
1262-
sentinel.SetStaticConstFieldValue(enum_value,
1263-
/*assert_initializing_store*/ false);
1264-
1265-
ASSERT(enum_cls.kernel_offset() > 0);
1266-
Object& error = Error::Handle(zone);
1267-
for (intptr_t i = 0; i < fields.Length(); i++) {
1268-
field = Field::RawCast(fields.At(i));
1269-
if (!field.is_static() || !field.is_const() ||
1270-
(sentinel.ptr() == field.ptr())) {
1271-
continue;
1272-
}
1273-
// Hot-reload expects the static const fields to be evaluated when
1274-
// performing a reload.
1275-
if (!FLAG_precompiled_mode) {
1276-
error = field.StaticConstFieldValue();
1277-
if (error.IsError()) {
1278-
ReportError(Error::Cast(error));
1279-
}
1280-
}
1281-
}
1269+
sentinel_field.SetStaticConstFieldValue(sentinel_value,
1270+
/*assert_initializing_store*/ false);
12821271
}
12831272

12841273
void ClassFinalizer::PrintClassInformation(const Class& cls) {

runtime/vm/compiler/aot/precompiler.cc

-5
Original file line numberDiff line numberDiff line change
@@ -2455,11 +2455,6 @@ void Precompiler::TraceTypesFromRetainedClasses() {
24552455
if (cls.is_allocated()) {
24562456
retain = true;
24572457
}
2458-
if (cls.is_enum_class()) {
2459-
// Enum classes have live instances, so we cannot unregister
2460-
// them.
2461-
retain = true;
2462-
}
24632458

24642459
constants = cls.constants();
24652460
retained_constants = GrowableObjectArray::New();

runtime/vm/isolate_reload.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -1556,9 +1556,8 @@ void ProgramReloadContext::CommitBeforeInstanceMorphing() {
15561556
ASSERT(new_cls.is_enum_class() == old_cls.is_enum_class());
15571557
if (new_cls.is_enum_class() && new_cls.is_finalized()) {
15581558
new_cls.ReplaceEnum(this, old_cls);
1559-
} else {
1560-
new_cls.CopyStaticFieldValues(this, old_cls);
15611559
}
1560+
new_cls.CopyStaticFieldValues(this, old_cls);
15621561
old_cls.PatchFieldsAndFunctions();
15631562
old_cls.MigrateImplicitStaticClosures(this, new_cls);
15641563
}

runtime/vm/object_reload.cc

+39-55
Original file line numberDiff line numberDiff line change
@@ -192,9 +192,6 @@ void CallSiteResetter::ResetCaches(const ObjectPool& pool) {
192192

193193
void Class::CopyStaticFieldValues(ProgramReloadContext* reload_context,
194194
const Class& old_cls) const {
195-
// We only update values for non-enum classes.
196-
const bool update_values = !is_enum_class();
197-
198195
const Array& old_field_list = Array::Handle(old_cls.fields());
199196
Field& old_field = Field::Handle();
200197
String& old_name = String::Handle();
@@ -215,7 +212,7 @@ void Class::CopyStaticFieldValues(ProgramReloadContext* reload_context,
215212
if (field.is_static()) {
216213
// We only copy values if requested and if the field is not a const
217214
// field. We let const fields be updated with a reload.
218-
if (update_values && !field.is_const()) {
215+
if (!field.is_const()) {
219216
// Make new field point to the old field value so that both
220217
// old and new code see and update same value.
221218
reload_context->isolate_group()->FreeStaticField(field);
@@ -307,15 +304,15 @@ void Class::ReplaceEnum(ProgramReloadContext* reload_context,
307304

308305
Zone* zone = Thread::Current()->zone();
309306

310-
Array& enum_fields = Array::Handle(zone);
311307
Field& field = Field::Handle(zone);
308+
Class& cls = Class::Handle(zone);
312309
String& enum_ident = String::Handle();
313310
Instance& old_enum_value = Instance::Handle(zone);
314311
Instance& enum_value = Instance::Handle(zone);
315312
// The E.values array.
316-
Instance& old_enum_values = Instance::Handle(zone);
313+
Array& old_enum_values = Array::Handle(zone);
317314
// The E.values array.
318-
Instance& enum_values = Instance::Handle(zone);
315+
Array& enum_values = Array::Handle(zone);
319316
// The E._deleted_enum_sentinel instance.
320317
Instance& old_deleted_enum_sentinel = Instance::Handle(zone);
321318
// The E._deleted_enum_sentinel instance.
@@ -327,31 +324,26 @@ void Class::ReplaceEnum(ProgramReloadContext* reload_context,
327324
TIR_Print("Replacing enum `%s`\n", String::Handle(Name()).ToCString());
328325

329326
{
327+
field = old_enum.LookupStaticField(Symbols::Values());
328+
ASSERT(!field.IsNull() && field.is_static() && field.is_const());
329+
old_enum_values ^= field.StaticConstFieldValue();
330+
ASSERT(!old_enum_values.IsNull());
331+
332+
field = old_enum.LookupStaticField(Symbols::_DeletedEnumSentinel());
333+
ASSERT(!field.IsNull() && field.is_static() && field.is_const());
334+
old_deleted_enum_sentinel ^= field.StaticConstFieldValue();
335+
ASSERT(!old_deleted_enum_sentinel.IsNull());
336+
337+
cls = old_enum.SuperClass();
338+
field = cls.LookupInstanceFieldAllowPrivate(Symbols::_name());
339+
ASSERT(!field.IsNull());
340+
330341
UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.ptr());
331342
// Build a map of all enum name -> old enum instance.
332-
enum_fields = old_enum.fields();
333-
for (intptr_t i = 0; i < enum_fields.Length(); i++) {
334-
field = Field::RawCast(enum_fields.At(i));
335-
enum_ident = field.name();
336-
if (!field.is_static()) {
337-
// Enum instances are only held in static fields.
338-
continue;
339-
}
340-
ASSERT(field.is_const());
341-
if (enum_ident.Equals(Symbols::Values())) {
342-
old_enum_values = Instance::RawCast(field.StaticConstFieldValue());
343-
// Non-enum instance.
344-
continue;
345-
}
346-
if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
347-
old_deleted_enum_sentinel =
348-
Instance::RawCast(field.StaticConstFieldValue());
349-
// Non-enum instance.
350-
continue;
351-
}
352-
old_enum_value = Instance::RawCast(field.StaticConstFieldValue());
353-
343+
for (intptr_t i = 0, n = old_enum_values.Length(); i < n; ++i) {
344+
old_enum_value ^= old_enum_values.At(i);
354345
ASSERT(!old_enum_value.IsNull());
346+
enum_ident ^= old_enum_value.GetField(field);
355347
VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString());
356348
bool update = enum_map.UpdateOrInsert(enum_ident, old_enum_value);
357349
VTIR_Print("Element %s added to mapping\n", enum_ident.ToCString());
@@ -364,31 +356,27 @@ void Class::ReplaceEnum(ProgramReloadContext* reload_context,
364356

365357
bool enums_deleted = false;
366358
{
359+
field = LookupStaticField(Symbols::Values());
360+
ASSERT(!field.IsNull() && field.is_static() && field.is_const());
361+
enum_values ^= field.StaticConstFieldValue();
362+
ASSERT(!enum_values.IsNull());
363+
364+
field = LookupStaticField(Symbols::_DeletedEnumSentinel());
365+
ASSERT(!field.IsNull() && field.is_static() && field.is_const());
366+
deleted_enum_sentinel ^= field.StaticConstFieldValue();
367+
ASSERT(!deleted_enum_sentinel.IsNull());
368+
369+
cls = SuperClass();
370+
field = cls.LookupInstanceFieldAllowPrivate(Symbols::_name());
371+
ASSERT(!field.IsNull());
372+
367373
UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.ptr());
368374
// Add a become mapping from the old instances to the new instances.
369-
enum_fields = fields();
370-
for (intptr_t i = 0; i < enum_fields.Length(); i++) {
371-
field = Field::RawCast(enum_fields.At(i));
372-
enum_ident = field.name();
373-
if (!field.is_static()) {
374-
// Enum instances are only held in static fields.
375-
continue;
376-
}
377-
ASSERT(field.is_const());
378-
if (enum_ident.Equals(Symbols::Values())) {
379-
enum_values = Instance::RawCast(field.StaticConstFieldValue());
380-
// Non-enum instance.
381-
continue;
382-
}
383-
if (enum_ident.Equals(Symbols::_DeletedEnumSentinel())) {
384-
deleted_enum_sentinel =
385-
Instance::RawCast(field.StaticConstFieldValue());
386-
// Non-enum instance.
387-
continue;
388-
}
389-
enum_value = Instance::RawCast(field.StaticConstFieldValue());
390-
375+
for (intptr_t i = 0, n = enum_values.Length(); i < n; ++i) {
376+
enum_value ^= enum_values.At(i);
391377
ASSERT(!enum_value.IsNull());
378+
enum_ident ^= enum_value.GetField(field);
379+
392380
old_enum_value ^= enum_map.GetOrNull(enum_ident);
393381
if (old_enum_value.IsNull()) {
394382
VTIR_Print("New element %s was not found in mapping\n",
@@ -408,13 +396,9 @@ void Class::ReplaceEnum(ProgramReloadContext* reload_context,
408396
}
409397

410398
// Map the old E.values array to the new E.values array.
411-
ASSERT(!old_enum_values.IsNull());
412-
ASSERT(!enum_values.IsNull());
413399
reload_context->AddBecomeMapping(old_enum_values, enum_values);
414400

415401
// Map the old E._deleted_enum_sentinel to the new E._deleted_enum_sentinel.
416-
ASSERT(!old_deleted_enum_sentinel.IsNull());
417-
ASSERT(!deleted_enum_sentinel.IsNull());
418402
reload_context->AddBecomeMapping(old_deleted_enum_sentinel,
419403
deleted_enum_sentinel);
420404

0 commit comments

Comments
 (0)