[vm] Adjust concurrent marker to re-enable code W^X.
Take 2: account for encountering Instructions in the write barrier.
Bug: https://github.com/dart-lang/sdk/issues/34002
Change-Id: I31a8fc8965042678a861a05b09070d52fa07e4a5
Reviewed-on: https://dart-review.googlesource.com/c/87082
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/vm/code_patcher.cc b/runtime/vm/code_patcher.cc
index f0ec1db..3546b60 100644
--- a/runtime/vm/code_patcher.cc
+++ b/runtime/vm/code_patcher.cc
@@ -10,7 +10,7 @@
namespace dart {
-DEFINE_FLAG(bool, write_protect_code, false, "Write protect jitted code");
+DEFINE_FLAG(bool, write_protect_code, true, "Write protect jitted code");
WritableInstructionsScope::WritableInstructionsScope(uword address,
intptr_t size)
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 3ea0f09..6f64118 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -101,7 +101,7 @@
// These offsets are embedded in precompiled instructions. We need simarm64
// (compiler) and arm64 (runtime) to agree.
CHECK_OFFSET(Thread::stack_limit_offset(), 8);
- CHECK_OFFSET(Thread::object_null_offset(), 112);
+ CHECK_OFFSET(Thread::object_null_offset(), 120);
CHECK_OFFSET(SingleTargetCache::upper_limit_offset(), 26);
CHECK_OFFSET(Isolate::object_store_offset(), 40);
NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 288));
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 3145090..1dcd875 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -172,6 +172,7 @@
MarkingVisitorBase(Isolate* isolate,
PageSpace* page_space,
MarkingStack* marking_stack,
+ MarkingStack* deferred_marking_stack,
SkippedCodeFunctions* skipped_code_functions)
: ObjectPointerVisitor(isolate),
thread_(Thread::Current()),
@@ -182,6 +183,7 @@
#endif // !PRODUCT
page_space_(page_space),
work_list_(marking_stack),
+ deferred_work_list_(deferred_marking_stack),
delayed_weak_properties_(NULL),
skipped_code_functions_(skipped_code_functions),
marked_bytes_(0),
@@ -260,8 +262,7 @@
if (class_id != kWeakPropertyCid) {
size = raw_obj->VisitPointersNonvirtual(this);
} else {
- RawWeakProperty* raw_weak =
- reinterpret_cast<RawWeakProperty*>(raw_obj);
+ RawWeakProperty* raw_weak = static_cast<RawWeakProperty*>(raw_obj);
size = ProcessWeakProperty(raw_weak);
}
marked_bytes_ += size;
@@ -315,6 +316,20 @@
return raw_weak->VisitPointersNonvirtual(this);
}
+ void FinalizeInstructions() {
+ RawObject* raw_obj;
+ while ((raw_obj = deferred_work_list_.Pop()) != NULL) {
+ ASSERT(raw_obj->IsInstructions());
+ RawInstructions* instr = static_cast<RawInstructions*>(raw_obj);
+ if (TryAcquireMarkBit(instr)) {
+ intptr_t size = instr->Size();
+ marked_bytes_ += size;
+ NOT_IN_PRODUCT(UpdateLiveOld(kInstructionsCid, size));
+ }
+ }
+ deferred_work_list_.Finalize();
+ }
+
// Called when all marking is complete.
void Finalize() {
work_list_.Finalize();
@@ -337,7 +352,10 @@
}
}
- void AbandonWork() { work_list_.AbandonWork(); }
+ void AbandonWork() {
+ work_list_.AbandonWork();
+ deferred_work_list_.AbandonWork();
+ }
private:
void PushMarked(RawObject* raw_obj) {
@@ -370,7 +388,15 @@
return;
}
- ASSERT(raw_obj->GetClassId() != kFreeListElement);
+ intptr_t class_id = raw_obj->GetClassId();
+ ASSERT(class_id != kFreeListElement);
+
+ if (sync && UNLIKELY(class_id == kInstructionsCid)) {
+ // If this is the concurrent marker, instruction pages may be
+ // non-writable.
+ deferred_work_list_.Push(raw_obj);
+ return;
+ }
if (!TryAcquireMarkBit(raw_obj)) {
// Already marked.
@@ -396,6 +422,7 @@
#endif // !PRODUCT
PageSpace* page_space_;
MarkerWorkList work_list_;
+ MarkerWorkList deferred_work_list_;
RawWeakProperty* delayed_weak_properties_;
SkippedCodeFunctions* skipped_code_functions_;
uintptr_t marked_bytes_;
@@ -636,6 +663,8 @@
barrier_->Sync();
} while (more_to_mark);
+ visitor_->FinalizeInstructions();
+
// Phase 2: Weak processing and follow-up marking on main thread.
barrier_->Sync();
@@ -815,7 +844,7 @@
}
void GCMarker::StartConcurrentMark(PageSpace* page_space, bool collect_code) {
- isolate_->EnableIncrementalBarrier(&marking_stack_);
+ isolate_->EnableIncrementalBarrier(&marking_stack_, &deferred_marking_stack_);
const intptr_t num_tasks = FLAG_marker_tasks;
@@ -838,6 +867,7 @@
SkippedCodeFunctions* skipped_code_functions =
collect_code ? new SkippedCodeFunctions() : NULL;
visitors_[i] = new SyncMarkingVisitor(isolate_, page_space, &marking_stack_,
+ &deferred_marking_stack_,
skipped_code_functions);
// Begin marking on a helper thread.
@@ -870,9 +900,11 @@
SkippedCodeFunctions* skipped_code_functions =
collect_code ? new SkippedCodeFunctions() : NULL;
UnsyncMarkingVisitor mark(isolate_, page_space, &marking_stack_,
+ &deferred_marking_stack_,
skipped_code_functions);
IterateRoots(&mark, 0, 1);
mark.DrainMarkingStack();
+ mark.FinalizeInstructions();
{
TIMELINE_FUNCTION_GC_DURATION(thread, "ProcessWeakHandles");
MarkingWeakVisitor mark_weak(thread);
@@ -897,7 +929,8 @@
SkippedCodeFunctions* skipped_code_functions =
collect_code ? new SkippedCodeFunctions() : NULL;
visitor = new SyncMarkingVisitor(
- isolate_, page_space, &marking_stack_, skipped_code_functions);
+ isolate_, page_space, &marking_stack_, &deferred_marking_stack_,
+ skipped_code_functions);
}
MarkTask* mark_task =
diff --git a/runtime/vm/heap/marker.h b/runtime/vm/heap/marker.h
index 10fde88..a4424cf 100644
--- a/runtime/vm/heap/marker.h
+++ b/runtime/vm/heap/marker.h
@@ -63,6 +63,7 @@
Isolate* const isolate_;
Heap* const heap_;
MarkingStack marking_stack_;
+ MarkingStack deferred_marking_stack_;
MarkingVisitorBase<true>** visitors_;
Mutex stats_mutex_;
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 087e1a0..b6335d5 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -1007,7 +1007,6 @@
#else
if (!FLAG_concurrent_mark) return; // Disabled.
if (FLAG_marker_tasks == 0) return; // Disabled.
- if (FLAG_write_protect_code) return; // Not implemented.
#endif
}
@@ -1081,7 +1080,7 @@
}
// Make code pages writable.
- WriteProtectCode(false);
+ if (finalize) WriteProtectCode(false);
// Save old value before GCMarker visits the weak persistent handles.
SpaceUsage usage_before = GetCurrentUsage();
@@ -1186,7 +1185,7 @@
}
// Make code pages read-only.
- WriteProtectCode(true);
+ if (finalize) WriteProtectCode(true);
int64_t end = OS::GetCurrentMonotonicMicros();
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index f3a9979..5b69675 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -2046,9 +2046,11 @@
thread_registry()->ReleaseStoreBuffers();
}
-void Isolate::EnableIncrementalBarrier(MarkingStack* marking_stack) {
+void Isolate::EnableIncrementalBarrier(MarkingStack* marking_stack,
+ MarkingStack* deferred_marking_stack) {
ASSERT(marking_stack_ == NULL);
marking_stack_ = marking_stack;
+ deferred_marking_stack_ = deferred_marking_stack;
thread_registry()->AcquireMarkingStacks();
ASSERT(Thread::Current()->is_marking());
}
@@ -2057,6 +2059,7 @@
thread_registry()->ReleaseMarkingStacks();
ASSERT(marking_stack_ != NULL);
marking_stack_ = NULL;
+ deferred_marking_stack_ = NULL;
ASSERT(!Thread::Current()->is_marking());
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index c07bf00..55b4bad 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -196,11 +196,15 @@
// Prepares all threads in an isolate for Garbage Collection.
void ReleaseStoreBuffers();
- void EnableIncrementalBarrier(MarkingStack* marking_stack);
+ void EnableIncrementalBarrier(MarkingStack* marking_stack,
+ MarkingStack* deferred_marking_stack);
void DisableIncrementalBarrier();
StoreBuffer* store_buffer() const { return store_buffer_; }
MarkingStack* marking_stack() const { return marking_stack_; }
+ MarkingStack* deferred_marking_stack() const {
+ return deferred_marking_stack_;
+ }
ThreadRegistry* thread_registry() const { return thread_registry_; }
SafepointHandler* safepoint_handler() const { return safepoint_handler_; }
@@ -860,6 +864,7 @@
StoreBuffer* store_buffer_;
MarkingStack* marking_stack_;
+ MarkingStack* deferred_marking_stack_;
Heap* heap_;
#define ISOLATE_FLAG_BITS(V) \
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 93cde94..891d7d9 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -747,6 +747,13 @@
// Incremental barrier: record when a store creates an
// old -> old-and-not-marked reference.
ASSERT(value->IsOldObject());
+#if !defined(TARGET_ARCH_IA32)
+ if (ClassIdTag::decode(target_tags) == kInstructionsCid) {
+ // Instruction pages may be non-writable. Defer marking.
+ thread->DeferredMarkingStackAddObject(value);
+ return;
+ }
+#endif
if (value->TryAcquireMarkBit()) {
thread->MarkingStackAddObject(value);
}
@@ -786,12 +793,19 @@
RememberCard(reinterpret_cast<RawObject* const*>(addr));
} else {
this->SetRememberedBit();
- Thread::Current()->StoreBufferAddObject(this);
+ thread->StoreBufferAddObject(this);
}
} else {
// Incremental barrier: record when a store creates an
// old -> old-and-not-marked reference.
ASSERT(value->IsOldObject());
+#if !defined(TARGET_ARCH_IA32)
+ if (ClassIdTag::decode(target_tags) == kInstructionsCid) {
+ // Instruction pages may be non-writable. Defer marking.
+ thread->DeferredMarkingStackAddObject(value);
+ return;
+ }
+#endif
if (value->TryAcquireMarkBit()) {
thread->MarkingStackAddObject(value);
}
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 30c0f51..b7a8f14 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -334,6 +334,7 @@
if (isolate->marking_stack() != NULL) {
// Concurrent mark in progress. Enable barrier for this thread.
thread->MarkingStackAcquire();
+ thread->DeferredMarkingStackAcquire();
}
return true;
}
@@ -352,6 +353,7 @@
thread->ClearReusableHandles();
if (thread->is_marking()) {
thread->MarkingStackRelease();
+ thread->DeferredMarkingStackRelease();
}
thread->StoreBufferRelease();
if (isolate->is_runnable()) {
@@ -379,6 +381,7 @@
if (isolate->marking_stack() != NULL) {
// Concurrent mark in progress. Enable barrier for this thread.
thread->MarkingStackAcquire();
+ thread->DeferredMarkingStackAcquire();
}
// This thread should not be the main mutator.
thread->task_kind_ = kind;
@@ -398,6 +401,7 @@
thread->ClearReusableHandles();
if (thread->is_marking()) {
thread->MarkingStackRelease();
+ thread->DeferredMarkingStackRelease();
}
thread->StoreBufferRelease();
Isolate* isolate = thread->isolate();
@@ -601,6 +605,11 @@
MarkingStackAcquire();
}
+void Thread::DeferredMarkingStackBlockProcess() {
+ DeferredMarkingStackRelease();
+ DeferredMarkingStackAcquire();
+}
+
void Thread::MarkingStackAddObject(RawObject* obj) {
marking_stack_block_->Push(obj);
if (marking_stack_block_->IsFull()) {
@@ -608,6 +617,13 @@
}
}
+void Thread::DeferredMarkingStackAddObject(RawObject* obj) {
+ deferred_marking_stack_block_->Push(obj);
+ if (deferred_marking_stack_block_->IsFull()) {
+ DeferredMarkingStackBlockProcess();
+ }
+}
+
void Thread::MarkingStackRelease() {
MarkingStackBlock* block = marking_stack_block_;
marking_stack_block_ = NULL;
@@ -621,6 +637,17 @@
RawObject::kGenerationalBarrierMask | RawObject::kIncrementalBarrierMask;
}
+void Thread::DeferredMarkingStackRelease() {
+ MarkingStackBlock* block = deferred_marking_stack_block_;
+ deferred_marking_stack_block_ = NULL;
+ isolate()->deferred_marking_stack()->PushBlock(block);
+}
+
+void Thread::DeferredMarkingStackAcquire() {
+ deferred_marking_stack_block_ =
+ isolate()->deferred_marking_stack()->PopEmptyBlock();
+}
+
bool Thread::IsMutatorThread() const {
return ((isolate_ != NULL) && (isolate_->mutator_thread() == this));
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index bb6fc9f..514d4d1 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -437,7 +437,9 @@
bool is_marking() const { return marking_stack_block_ != NULL; }
void MarkingStackAddObject(RawObject* obj);
+ void DeferredMarkingStackAddObject(RawObject* obj);
void MarkingStackBlockProcess();
+ void DeferredMarkingStackBlockProcess();
static intptr_t marking_stack_block_offset() {
return OFFSET_OF(Thread, marking_stack_block_);
}
@@ -818,6 +820,7 @@
uword top_exit_frame_info_;
StoreBufferBlock* store_buffer_block_;
MarkingStackBlock* marking_stack_block_;
+ MarkingStackBlock* deferred_marking_stack_block_;
uword vm_tag_;
RawStackTrace* async_stack_trace_;
// Memory location dedicated for passing unboxed int64 values from
@@ -926,6 +929,8 @@
void MarkingStackRelease();
void MarkingStackAcquire();
+ void DeferredMarkingStackRelease();
+ void DeferredMarkingStackAcquire();
void set_zone(Zone* zone) { zone_ = zone; }
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index bb02973..a390528 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -99,6 +99,7 @@
while (thread != NULL) {
if (!thread->BypassSafepoints()) {
thread->MarkingStackAcquire();
+ thread->DeferredMarkingStackAcquire();
}
thread = thread->next_;
}
@@ -110,6 +111,7 @@
while (thread != NULL) {
if (!thread->BypassSafepoints()) {
thread->MarkingStackRelease();
+ thread->DeferredMarkingStackRelease();
}
thread = thread->next_;
}