Skip to content

Commit 37abbb2

Browse files
aamcommit-bot@chromium.org
authored andcommitted
[vm/concurrency] Introduce program_lock to guard program structure changes.
This CL adds acquisiton of write lock and check for whether write lock is held when updating class functions, primarily populated during class finalization. Read locks will be added in successive CLs, so is extending of the locks coverage to all aspects of program structure changes. Bug: dart-lang/sdk#36097 Change-Id: I3dba6bc23db4e45599a20717226210f12e7fd2b3 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168140 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
1 parent b64d20e commit 37abbb2

File tree

14 files changed

+124
-46
lines changed

14 files changed

+124
-46
lines changed

runtime/vm/bootstrap.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ static void Finish(Thread* thread) {
5151
ObjectStore* object_store = thread->isolate()->object_store();
5252
Zone* zone = thread->zone();
5353
Class& cls = Class::Handle(zone, object_store->closure_class());
54-
ClassFinalizer::LoadClassMembers(cls);
54+
cls.EnsureIsFinalized(thread);
5555

5656
// Make sure _Closure fields are not marked as unboxing candidates
5757
// as they are accessed with plain loads.
@@ -88,7 +88,7 @@ static void Finish(Thread* thread) {
8888

8989
// Eagerly compile Bool class, bool constants are used from within compiler.
9090
cls = object_store->bool_class();
91-
ClassFinalizer::LoadClassMembers(cls);
91+
cls.EnsureIsFinalized(thread);
9292
}
9393

9494
static ErrorPtr BootstrapFromKernel(Thread* thread,

runtime/vm/class_finalizer_test.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
namespace dart {
1111

1212
static ClassPtr CreateTestClass(const char* name) {
13-
const String& class_name =
14-
String::Handle(Symbols::New(Thread::Current(), name));
13+
Thread* thread = Thread::Current();
14+
const String& class_name = String::Handle(Symbols::New(thread, name));
1515
const Script& script = Script::Handle();
1616
const Class& cls = Class::Handle(Class::New(
1717
Library::Handle(), class_name, script, TokenPosition::kNoSource));
1818
cls.set_interfaces(Object::empty_array());
1919
cls.set_is_declaration_loaded();
20+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
2021
cls.SetFunctions(Object::empty_array());
2122
cls.SetFields(Object::empty_array());
2223
return cls.raw();

runtime/vm/compiler/aot/precompiler.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,7 @@ void Precompiler::DropFunctions() {
17241724
}
17251725
};
17261726

1727+
SafepointWriteRwLocker ml(T, T->isolate_group()->program_lock());
17271728
auto& dispatchers_array = Array::Handle(Z);
17281729
auto& name = String::Handle(Z);
17291730
auto& desc = Array::Handle(Z);

runtime/vm/compiler/frontend/bytecode_reader.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2472,7 +2472,11 @@ void BytecodeReaderHelper::ReadFunctionDeclarations(const Class& cls) {
24722472
functions_->SetAt(function_index_++, function);
24732473
}
24742474

2475-
cls.SetFunctions(*functions_);
2475+
{
2476+
Thread* thread = Thread::Current();
2477+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
2478+
cls.SetFunctions(*functions_);
2479+
}
24762480

24772481
if (cls.IsTopLevel()) {
24782482
const Library& library = Library::Handle(Z, cls.library());

runtime/vm/debugger.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1919,7 +1919,8 @@ void Debugger::DeoptimizeWorld() {
19191919
// Iterate over all classes, deoptimize functions.
19201920
// TODO(hausner): Could possibly be combined with RemoveOptimizedCode()
19211921
const ClassTable& class_table = *isolate_->class_table();
1922-
Zone* zone = Thread::Current()->zone();
1922+
Thread* thread = Thread::Current();
1923+
Zone* zone = thread->zone();
19231924
CallSiteResetter resetter(zone);
19241925
Class& cls = Class::Handle(zone);
19251926
Array& functions = Array::Handle(zone);
@@ -1929,6 +1930,9 @@ void Debugger::DeoptimizeWorld() {
19291930

19301931
const intptr_t num_classes = class_table.NumCids();
19311932
const intptr_t num_tlc_classes = class_table.NumTopLevelCids();
1933+
// TODO(dartbug.com/36097): Need to stop other mutators running in same IG
1934+
// before deoptimizing the world.
1935+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
19321936
for (intptr_t i = 1; i < num_classes + num_tlc_classes; i++) {
19331937
const classid_t cid =
19341938
i < num_classes ? i : ClassTable::CidFromTopLevelIndex(i - num_classes);

runtime/vm/isolate.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,7 @@ IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
374374
NOT_IN_PRODUCT("IsolateGroup::type_canonicalization_mutex_")),
375375
type_arguments_canonicalization_mutex_(NOT_IN_PRODUCT(
376376
"IsolateGroup::type_arguments_canonicalization_mutex_")),
377+
program_lock_(new SafepointRwLock()),
377378
active_mutators_monitor_(new Monitor()),
378379
max_active_mutators_(Scavenger::MaxMutatorThreadCount()) {
379380
const bool is_vm_isolate = Dart::VmIsolateNameEquals(source_->name);

runtime/vm/isolate.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
435435
Mutex* initializer_functions_mutex() { return &initializer_functions_mutex_; }
436436
#endif // !defined(DART_PRECOMPILED_RUNTIME)
437437

438+
SafepointRwLock* program_lock() { return program_lock_.get(); }
439+
438440
static inline IsolateGroup* Current() {
439441
Thread* thread = Thread::Current();
440442
return thread == nullptr ? nullptr : thread->isolate_group();
@@ -725,6 +727,11 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
725727
Mutex initializer_functions_mutex_;
726728
#endif // !defined(DART_PRECOMPILED_RUNTIME)
727729

730+
// Ensures synchronized access to classes functions, fields and other
731+
// program structure elements to accommodate concurrent modification done
732+
// by multiple isolates and background compiler.
733+
std::unique_ptr<SafepointRwLock> program_lock_;
734+
728735
// Allow us to ensure the number of active mutators is limited by a maximum.
729736
std::unique_ptr<Monitor> active_mutators_monitor_;
730737
intptr_t active_mutators_ = 0;

runtime/vm/kernel_loader.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ void KernelLoader::LoadNativeExtension(const Library& library,
734734
}
735735

736736
ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) {
737+
SafepointWriteRwLocker ml(thread_, thread_->isolate_group()->program_lock());
737738
ASSERT(kernel_program_info_.constants() == Array::null());
738739

739740
if (!program_->is_single_program()) {

runtime/vm/object.cc

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,11 @@ void Object::Init(Isolate* isolate) {
11161116
cls = type_arguments_class_;
11171117
cls.set_interfaces(Object::empty_array());
11181118
cls.SetFields(Object::empty_array());
1119-
cls.SetFunctions(Object::empty_array());
1119+
{
1120+
Thread* thread = Thread::Current();
1121+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
1122+
cls.SetFunctions(Object::empty_array());
1123+
}
11201124

11211125
cls = Class::New<Bool, RTN::Bool>(isolate);
11221126
isolate->object_store()->set_bool_class(cls);
@@ -1654,6 +1658,7 @@ ErrorPtr Object::Init(Isolate* isolate,
16541658
// This will initialize isolate group object_store, shared by all isolates
16551659
// running in the isolate group.
16561660
ObjectStore* object_store = isolate->object_store();
1661+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
16571662

16581663
Class& cls = Class::Handle(zone);
16591664
Type& type = Type::Handle(zone);
@@ -3000,7 +3005,11 @@ class ClassFunctionsTraits {
30003005
typedef UnorderedHashSet<ClassFunctionsTraits> ClassFunctionsSet;
30013006

30023007
void Class::SetFunctions(const Array& value) const {
3003-
ASSERT(Thread::Current()->IsMutatorThread());
3008+
#if defined(DEBUG)
3009+
Thread* thread = Thread::Current();
3010+
ASSERT(thread->IsMutatorThread());
3011+
ASSERT(thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
3012+
#endif
30043013
ASSERT(!value.IsNull());
30053014
set_functions(value);
30063015
const intptr_t len = value.Length();
@@ -3020,7 +3029,11 @@ void Class::SetFunctions(const Array& value) const {
30203029
}
30213030

30223031
void Class::AddFunction(const Function& function) const {
3023-
ASSERT(Thread::Current()->IsMutatorThread());
3032+
#if defined(DEBUG)
3033+
Thread* thread = Thread::Current();
3034+
ASSERT(thread->IsMutatorThread());
3035+
ASSERT(thread->isolate_group()->program_lock()->IsCurrentThreadWriter());
3036+
#endif
30243037
const Array& arr = Array::Handle(functions());
30253038
const Array& new_array =
30263039
Array::Handle(Array::Grow(arr, arr.Length() + 1, Heap::kOld));
@@ -3616,13 +3629,19 @@ FunctionPtr Function::GetMethodExtractor(const String& getter_name) const {
36163629
const Function& closure_function =
36173630
Function::Handle(ImplicitClosureFunction());
36183631
const Class& owner = Class::Handle(closure_function.Owner());
3619-
if (owner.EnsureIsFinalized(Thread::Current()) != Error::null()) {
3632+
Thread* thread = Thread::Current();
3633+
if (owner.EnsureIsFinalized(thread) != Error::null()) {
36203634
return Function::null();
36213635
}
3636+
IsolateGroup* group = thread->isolate_group();
36223637
Function& result =
36233638
Function::Handle(owner.LookupDynamicFunctionUnsafe(getter_name));
36243639
if (result.IsNull()) {
3625-
result = CreateMethodExtractor(getter_name);
3640+
SafepointWriteRwLocker ml(thread, group->program_lock());
3641+
result = owner.LookupDynamicFunctionUnsafe(getter_name);
3642+
if (result.IsNull()) {
3643+
result = CreateMethodExtractor(getter_name);
3644+
}
36263645
}
36273646
ASSERT(result.kind() == FunctionLayout::kMethodExtractor);
36283647
return result.raw();
@@ -4288,6 +4307,10 @@ ErrorPtr Class::EnsureIsFinalized(Thread* thread) const {
42884307
Compiler::AbortBackgroundCompilation(DeoptId::kNone,
42894308
"Class finalization while compiling");
42904309
}
4310+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
4311+
if (is_finalized()) {
4312+
return Error::null();
4313+
}
42914314
ASSERT(thread->IsMutatorThread());
42924315
ASSERT(thread != NULL);
42934316
const Error& error =
@@ -13126,7 +13149,8 @@ static ObjectPtr EvaluateCompiledExpressionHelper(
1312613149
const String& klass,
1312713150
const Array& arguments,
1312813151
const TypeArguments& type_arguments) {
13129-
Zone* zone = Thread::Current()->zone();
13152+
Thread* thread = Thread::Current();
13153+
Zone* zone = thread->zone();
1313013154
#if defined(DART_PRECOMPILED_RUNTIME)
1313113155
const String& error_str = String::Handle(
1313213156
zone,

runtime/vm/object_test.cc

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ ISOLATE_UNIT_TEST_CASE(Class) {
121121
functions.SetAt(5, function);
122122

123123
// Setup the functions in the class.
124-
cls.SetFunctions(functions);
124+
{
125+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
126+
cls.SetFunctions(functions);
127+
}
125128

126129
// The class can now be finalized.
127130
cls.Finalize();
@@ -200,7 +203,11 @@ ISOLATE_UNIT_TEST_CASE(SixtyThousandDartClasses) {
200203
}
201204

202205
cls.set_interfaces(Array::empty_array());
203-
cls.SetFunctions(Array::empty_array());
206+
{
207+
SafepointWriteRwLocker ml(thread,
208+
thread->isolate_group()->program_lock());
209+
cls.SetFunctions(Array::empty_array());
210+
}
204211
cls.SetFields(fields);
205212
cls.Finalize();
206213

@@ -2516,7 +2523,10 @@ ISOLATE_UNIT_TEST_CASE(Closure) {
25162523
Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
25172524
false, false, false, cls, TokenPosition::kMinSource);
25182525
functions.SetAt(0, parent);
2519-
cls.SetFunctions(functions);
2526+
{
2527+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
2528+
cls.SetFunctions(functions);
2529+
}
25202530

25212531
Function& function = Function::Handle();
25222532
const String& function_name = String::Handle(Symbols::New(thread, "foo"));
@@ -3766,7 +3776,10 @@ ISOLATE_UNIT_TEST_CASE(FindClosureIndex) {
37663776
Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
37673777
false, false, false, cls, TokenPosition::kMinSource);
37683778
functions.SetAt(0, parent);
3769-
cls.SetFunctions(functions);
3779+
{
3780+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
3781+
cls.SetFunctions(functions);
3782+
}
37703783

37713784
Function& function = Function::Handle();
37723785
const String& function_name = String::Handle(Symbols::New(thread, "foo"));
@@ -3802,7 +3815,10 @@ ISOLATE_UNIT_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
38023815
Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
38033816
false, false, false, cls, TokenPosition::kMinSource);
38043817
functions.SetAt(0, parent);
3805-
cls.SetFunctions(functions);
3818+
{
3819+
SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
3820+
cls.SetFunctions(functions);
3821+
}
38063822
cls.Finalize();
38073823

38083824
// Add invocation dispatcher.

0 commit comments

Comments
 (0)