Skip to content

Commit b387ebc

Browse files
aamcommit-bot@chromium.org
authored andcommitted
[vm/finalize] Split code clean up from class finalization into separate step.
While most of the class finalization can be done without stopping mutators, code clean up has to be done with all mutators stopped. So that was split up into separate step invoked during allocation stub creation. Bug: #36097 Change-Id: I86ca9bf58aaad2ae1884d777a1cc06a22d1ce65c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/154060 Commit-Queue: Alexander Aprelev <[email protected]> Reviewed-by: Martin Kustermann <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent ba459f9 commit b387ebc

File tree

9 files changed

+116
-38
lines changed

9 files changed

+116
-38
lines changed

runtime/vm/class_finalizer.cc

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ static void RemoveCHAOptimizedCode(
5959
}
6060
}
6161

62-
void AddSuperType(const AbstractType& type,
63-
GrowableArray<intptr_t>* finalized_super_classes) {
62+
static void AddSuperType(const AbstractType& type,
63+
GrowableArray<intptr_t>* finalized_super_classes) {
6464
ASSERT(type.HasTypeClass());
6565
ASSERT(!type.IsDynamicType());
6666
if (type.IsObjectType()) {
@@ -1162,33 +1162,69 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
11621162
// Mark as loaded and finalized.
11631163
cls.Finalize();
11641164
FinalizeMemberTypes(cls);
1165-
// Run additional checks after all types are finalized.
1166-
if (FLAG_use_cha_deopt) {
1167-
GrowableArray<intptr_t> cids;
1168-
CollectFinalizedSuperClasses(cls, &cids);
1169-
CollectImmediateSuperInterfaces(cls, &cids);
1170-
RemoveCHAOptimizedCode(cls, cids);
1165+
1166+
if (cls.is_enum_class()) {
1167+
AllocateEnumValues(cls);
1168+
}
1169+
1170+
// The rest of finalization for non-top-level class has to be done with
1171+
// stopped mutators. It will be done by AllocateFinalizeClass. before new
1172+
// instance of a class is created in GetAllocationStubForClass.
1173+
if (cls.IsTopLevel()) {
1174+
cls.set_is_allocate_finalized();
1175+
}
1176+
}
1177+
1178+
ErrorPtr ClassFinalizer::AllocateFinalizeClass(const Class& cls) {
1179+
ASSERT(cls.is_finalized());
1180+
if (cls.is_allocate_finalized()) {
1181+
return Error::null();
1182+
}
1183+
1184+
Thread* thread = Thread::Current();
1185+
HANDLESCOPE(thread);
1186+
1187+
if (FLAG_trace_class_finalization) {
1188+
THR_Print("Allocate finalize %s\n", cls.ToCString());
11711189
}
11721190

1191+
#if defined(SUPPORT_TIMELINE)
1192+
TimelineBeginEndScope tbes(thread, Timeline::GetCompilerStream(),
1193+
"AllocateFinalizeClass");
1194+
if (tbes.enabled()) {
1195+
tbes.SetNumArguments(1);
1196+
tbes.CopyArgument(0, "class", cls.ToCString());
1197+
}
1198+
#endif // defined(SUPPORT_TIMELINE)
1199+
1200+
// Run additional checks after all types are finalized.
11731201
if (FLAG_use_cha_deopt && !cls.IsTopLevel()) {
1202+
{
1203+
GrowableArray<intptr_t> cids;
1204+
CollectFinalizedSuperClasses(cls, &cids);
1205+
CollectImmediateSuperInterfaces(cls, &cids);
1206+
RemoveCHAOptimizedCode(cls, cids);
1207+
}
1208+
11741209
Zone* zone = thread->zone();
11751210
ClassTable* class_table = thread->isolate()->class_table();
11761211
auto& interface_class = Class::Handle(zone);
11771212

1178-
// We scan every interface this [cls] implements and invalidate all CHA code
1179-
// which depends on knowing the implementors of that interface.
1180-
GrowableArray<intptr_t> cids;
1181-
InterfaceFinder finder(zone, class_table, &cids);
1182-
finder.FindAllInterfaces(cls);
1183-
for (intptr_t j = 0; j < cids.length(); ++j) {
1184-
interface_class = class_table->At(cids[j]);
1185-
interface_class.DisableCHAImplementorUsers();
1213+
// We scan every interface this [cls] implements and invalidate all CHA
1214+
// code which depends on knowing the implementors of that interface.
1215+
{
1216+
GrowableArray<intptr_t> cids;
1217+
InterfaceFinder finder(zone, class_table, &cids);
1218+
finder.FindAllInterfaces(cls);
1219+
for (intptr_t j = 0; j < cids.length(); ++j) {
1220+
interface_class = class_table->At(cids[j]);
1221+
interface_class.DisableCHAImplementorUsers();
1222+
}
11861223
}
11871224
}
11881225

1189-
if (cls.is_enum_class()) {
1190-
AllocateEnumValues(cls);
1191-
}
1226+
cls.set_is_allocate_finalized();
1227+
return Error::null();
11921228
}
11931229

11941230
ErrorPtr ClassFinalizer::LoadClassMembers(const Class& cls) {

runtime/vm/class_finalizer.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,11 @@ class ClassFinalizer : public AllStatic {
6262
// Register class in the lists of direct subclasses and direct implementors.
6363
static void RegisterClassInHierarchy(Zone* zone, const Class& cls);
6464

65-
// Finalize the class including its fields and functions.
65+
// Ensures members of the class are loaded, class layout is finalized and size
66+
// registered in class table.
6667
static void FinalizeClass(const Class& cls);
68+
// Makes class instantiatable and usable by generated code.
69+
static ErrorPtr AllocateFinalizeClass(const Class& cls);
6770

6871
// Completes loading of the class, this populates the function
6972
// and fields of the class.

runtime/vm/compiler/aot/precompiler.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2404,8 +2404,6 @@ static void GenerateNecessaryAllocationStubs(FlowGraph* flow_graph) {
24042404
}
24052405

24062406
// Return false if bailed out.
2407-
// If optimized_result_code is not NULL then it is caller's responsibility
2408-
// to install code.
24092407
bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
24102408
ASSERT(CompilerState::Current().is_aot());
24112409
if (optimized() && !parsed_function()->function().IsOptimizable()) {

runtime/vm/compiler/jit/compiler.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,6 @@ void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped(
502502
}
503503

504504
// Return null if bailed out.
505-
// If optimized_result_code is not NULL then it is caller's responsibility
506-
// to install code.
507505
CodePtr CompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
508506
ASSERT(!FLAG_precompiled_mode);
509507
const Function& function = parsed_function()->function();

runtime/vm/dart_entry.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ ObjectPtr DartEntry::InvokeFunction(const Function& function,
110110
#if !defined(DART_PRECOMPILED_RUNTIME)
111111
UNREACHABLE();
112112
#else
113-
if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
113+
if (FLAG_use_bare_instructions) {
114114
Thread* thread = Thread::Current();
115115
thread->set_global_object_pool(
116116
thread->isolate()->object_store()->global_object_pool());

runtime/vm/object.cc

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ void Object::Init(Isolate* isolate) {
737737
cls.set_next_field_offset(host_next_field_offset, target_next_field_offset);
738738
cls.set_id(Class::kClassId);
739739
cls.set_state_bits(0);
740-
cls.set_is_finalized();
740+
cls.set_is_allocate_finalized();
741741
cls.set_is_declaration_loaded();
742742
cls.set_is_type_finalized();
743743
cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments,
@@ -756,7 +756,7 @@ void Object::Init(Isolate* isolate) {
756756
// Allocate and initialize Never class.
757757
cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate);
758758
cls.set_num_type_arguments(0);
759-
cls.set_is_finalized();
759+
cls.set_is_allocate_finalized();
760760
cls.set_is_declaration_loaded();
761761
cls.set_is_type_finalized();
762762
isolate->object_store()->set_never_class(cls);
@@ -766,7 +766,7 @@ void Object::Init(Isolate* isolate) {
766766
Class::New<FreeListElement::FakeInstance,
767767
RTN::FreeListElement::FakeInstance>(kFreeListElement, isolate);
768768
cls.set_num_type_arguments(0);
769-
cls.set_is_finalized();
769+
cls.set_is_allocate_finalized();
770770
cls.set_is_declaration_loaded();
771771
cls.set_is_type_finalized();
772772

@@ -775,7 +775,7 @@ void Object::Init(Isolate* isolate) {
775775
RTN::ForwardingCorpse::FakeInstance>(kForwardingCorpse,
776776
isolate);
777777
cls.set_num_type_arguments(0);
778-
cls.set_is_finalized();
778+
cls.set_is_allocate_finalized();
779779
cls.set_is_declaration_loaded();
780780
cls.set_is_type_finalized();
781781

@@ -1061,20 +1061,20 @@ void Object::Init(Isolate* isolate) {
10611061
cls = Class::New<Instance, RTN::Instance>(kDynamicCid, isolate);
10621062
cls.set_is_abstract();
10631063
cls.set_num_type_arguments(0);
1064-
cls.set_is_finalized();
1064+
cls.set_is_allocate_finalized();
10651065
cls.set_is_declaration_loaded();
10661066
cls.set_is_type_finalized();
10671067
dynamic_class_ = cls.raw();
10681068

10691069
cls = Class::New<Instance, RTN::Instance>(kVoidCid, isolate);
10701070
cls.set_num_type_arguments(0);
1071-
cls.set_is_finalized();
1071+
cls.set_is_allocate_finalized();
10721072
cls.set_is_declaration_loaded();
10731073
cls.set_is_type_finalized();
10741074
void_class_ = cls.raw();
10751075

10761076
cls = Class::New<Type, RTN::Type>(isolate);
1077-
cls.set_is_finalized();
1077+
cls.set_is_allocate_finalized();
10781078
cls.set_is_declaration_loaded();
10791079
cls.set_is_type_finalized();
10801080

@@ -1850,7 +1850,7 @@ ErrorPtr Object::Init(Isolate* isolate,
18501850

18511851
cls = Class::New<Instance, RTN::Instance>(kNeverCid, isolate);
18521852
cls.set_num_type_arguments(0);
1853-
cls.set_is_finalized();
1853+
cls.set_is_allocate_finalized();
18541854
cls.set_is_declaration_loaded();
18551855
cls.set_is_type_finalized();
18561856
cls.set_name(Symbols::Never());
@@ -2847,7 +2847,7 @@ ClassPtr Class::New(Isolate* isolate, bool register_class) {
28472847
// possible in this case.
28482848
result.set_is_declaration_loaded();
28492849
result.set_is_type_finalized();
2850-
result.set_is_finalized();
2850+
result.set_is_allocate_finalized();
28512851
} else if (FakeObject::kClassId != kClosureCid) {
28522852
// VM backed classes are almost ready: run checks and resolve class
28532853
// references, but do not recompute size.
@@ -4222,6 +4222,32 @@ ErrorPtr Class::EnsureIsFinalized(Thread* thread) const {
42224222
return error.raw();
42234223
}
42244224

4225+
// Ensure that code outdated by finalized class is cleaned up, new instance of
4226+
// this class is ready to be allocated.
4227+
ErrorPtr Class::EnsureIsAllocateFinalized(Thread* thread) const {
4228+
ASSERT(!IsNull());
4229+
// Finalized classes have already been parsed.
4230+
if (is_allocate_finalized()) {
4231+
return Error::null();
4232+
}
4233+
if (Compiler::IsBackgroundCompilation()) {
4234+
Compiler::AbortBackgroundCompilation(
4235+
DeoptId::kNone, "Class allocate finalization while compiling");
4236+
}
4237+
ASSERT(thread->IsMutatorThread());
4238+
ASSERT(thread != NULL);
4239+
Error& error = Error::Handle(thread->zone(), EnsureIsFinalized(thread));
4240+
if (!error.IsNull()) {
4241+
ASSERT(thread == Thread::Current());
4242+
if (thread->long_jump_base() != NULL) {
4243+
Report::LongJump(error);
4244+
UNREACHABLE();
4245+
}
4246+
}
4247+
error ^= ClassFinalizer::AllocateFinalizeClass(*this);
4248+
return error.raw();
4249+
}
4250+
42254251
void Class::SetFields(const Array& value) const {
42264252
ASSERT(!value.IsNull());
42274253
#if defined(DEBUG)
@@ -4415,7 +4441,7 @@ ClassPtr Class::NewNativeWrapper(const Library& library,
44154441
compiler::target::RoundedAllocationSize(target_instance_size));
44164442
cls.set_next_field_offset(host_instance_size, target_instance_size);
44174443
cls.set_num_native_fields(field_count);
4418-
cls.set_is_finalized();
4444+
cls.set_is_allocate_finalized();
44194445
cls.set_is_declaration_loaded();
44204446
cls.set_is_type_finalized();
44214447
cls.set_is_synthesized_class();
@@ -4804,6 +4830,12 @@ void Class::set_is_finalized() const {
48044830
raw_ptr()->state_bits_));
48054831
}
48064832

4833+
void Class::set_is_allocate_finalized() const {
4834+
ASSERT(!is_allocate_finalized());
4835+
set_state_bits(ClassFinalizedBits::update(ClassLayout::kAllocateFinalized,
4836+
raw_ptr()->state_bits_));
4837+
}
4838+
48074839
void Class::set_is_prefinalized() const {
48084840
ASSERT(!is_finalized());
48094841
set_state_bits(ClassFinalizedBits::update(ClassLayout::kPreFinalized,

runtime/vm/object.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1371,10 +1371,18 @@ class Class : public Object {
13711371

13721372
bool is_finalized() const {
13731373
return ClassFinalizedBits::decode(raw_ptr()->state_bits_) ==
1374-
ClassLayout::kFinalized;
1374+
ClassLayout::kFinalized ||
1375+
ClassFinalizedBits::decode(raw_ptr()->state_bits_) ==
1376+
ClassLayout::kAllocateFinalized;
13751377
}
13761378
void set_is_finalized() const;
13771379

1380+
bool is_allocate_finalized() const {
1381+
return ClassFinalizedBits::decode(raw_ptr()->state_bits_) ==
1382+
ClassLayout::kAllocateFinalized;
1383+
}
1384+
void set_is_allocate_finalized() const;
1385+
13781386
bool is_prefinalized() const {
13791387
return ClassFinalizedBits::decode(raw_ptr()->state_bits_) ==
13801388
ClassLayout::kPreFinalized;
@@ -1528,6 +1536,7 @@ class Class : public Object {
15281536
void EnsureDeclarationLoaded() const;
15291537

15301538
ErrorPtr EnsureIsFinalized(Thread* thread) const;
1539+
ErrorPtr EnsureIsAllocateFinalized(Thread* thread) const;
15311540

15321541
// Allocate a class used for VM internal objects.
15331542
template <class FakeObject, class TargetFakeObject>

runtime/vm/raw_object.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,8 @@ class ClassLayout : public ObjectLayout {
704704
enum ClassFinalizedState {
705705
kAllocated = 0, // Initial state.
706706
kPreFinalized, // VM classes: size precomputed, but no checks done.
707-
kFinalized, // Class parsed, finalized and ready for use.
707+
kFinalized, // Class parsed, code compiled, not ready for allocation.
708+
kAllocateFinalized, // CHA invalidated, class is ready for allocation.
708709
};
709710
enum ClassLoadingState {
710711
// Class object is created, but it is not filled up.

runtime/vm/stub_code.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ CodePtr StubCode::GetAllocationStubForClass(const Class& cls) {
160160
Thread* thread = Thread::Current();
161161
auto object_store = thread->isolate()->object_store();
162162
Zone* zone = thread->zone();
163-
const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
163+
const Error& error =
164+
Error::Handle(zone, cls.EnsureIsAllocateFinalized(thread));
164165
ASSERT(error.IsNull());
165166
if (cls.id() == kArrayCid) {
166167
return object_store->allocate_array_stub();

0 commit comments

Comments
 (0)