Skip to content

Commit f681734

Browse files
aamCommit Bot
authored and
Commit Bot
committed
[vm/send_and_exit] Allow for safepoints when validating exit message.
``` before $ dart isolate_exit_pause_time_test.dart .Min(RunTimeRaw): 0.001 ms. .Avg(RunTimeRaw): 212.399592 ms. .Percentile50(RunTimeRaw): 49.055 ms. .Percentile90(RunTimeRaw): 809.049 ms. .Percentile95(RunTimeRaw): 1009.049 ms. .Percentile99(RunTimeRaw): 1169.049 ms. .Max(RunTimeRaw): 1208.049 ms. ``` ``` after $ dart isolate_exit_pause_time_test.dart .Min(RunTimeRaw): 0.001 ms. .Avg(RunTimeRaw): 53.87510125 ms. .Percentile50(RunTimeRaw): 8.05 ms. .Percentile90(RunTimeRaw): 174.005 ms. .Percentile95(RunTimeRaw): 217.975 ms. .Percentile99(RunTimeRaw): 275.033 ms. .Max(RunTimeRaw): 314.033 ms. ``` Remaining latency after the change is due to large root set formed by pointers_to_verify_at_exit_ that have to be visited during GC. Fixes #49050 TEST=ci Change-Id: I1ed7af017f80890900b137a1514e5ffdeb63f53f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/246482 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Alexander Aprelev <[email protected]>
1 parent 88c2f88 commit f681734

File tree

3 files changed

+116
-83
lines changed

3 files changed

+116
-83
lines changed

runtime/lib/isolate.cc

Lines changed: 105 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,17 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
144144
visited_(visited),
145145
working_set_(working_set) {}
146146

147+
void VisitObject(ObjectPtr obj) {
148+
if (!obj->IsHeapObject() || obj->untag()->IsCanonical()) {
149+
return;
150+
}
151+
if (visited_->GetValueExclusive(obj) == 1) {
152+
return;
153+
}
154+
visited_->SetValueExclusive(obj, 1);
155+
working_set_->Add(obj);
156+
}
157+
147158
private:
148159
void VisitPointers(ObjectPtr* from, ObjectPtr* to) {
149160
for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
@@ -159,17 +170,6 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
159170
}
160171
}
161172

162-
void VisitObject(ObjectPtr obj) {
163-
if (!obj->IsHeapObject() || obj->untag()->IsCanonical()) {
164-
return;
165-
}
166-
if (visited_->GetValueExclusive(obj) == 1) {
167-
return;
168-
}
169-
visited_->SetValueExclusive(obj, 1);
170-
working_set_->Add(obj);
171-
}
172-
173173
WeakTable* visited_;
174174
MallocGrowableArray<ObjectPtr>* const working_set_;
175175
};
@@ -185,55 +185,76 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
185185
Function& erroneous_closure_function = Function::Handle(zone);
186186
Class& erroneous_nativewrapper_class = Class::Handle(zone);
187187
Class& erroneous_finalizable_class = Class::Handle(zone);
188+
Array& array = Array::Handle(zone);
188189
const char* error_message = nullptr;
190+
Thread* thread = Thread::Current();
189191

190-
{
191-
NoSafepointScope no_safepoint;
192-
// working_set contains only elements that have not been visited yet that
193-
// need to be processed.
194-
// So before adding elements to working_set ensure to check visited flag,
195-
// set visited flag at the same time as the element is added.
196-
MallocGrowableArray<ObjectPtr> working_set;
197-
std::unique_ptr<WeakTable> visited(new WeakTable());
198-
199-
SendMessageValidator visitor(isolate->group(), visited.get(), &working_set);
200-
201-
visited->SetValueExclusive(obj.ptr(), 1);
202-
working_set.Add(obj.ptr());
203-
204-
while (!working_set.is_empty() && !error_found) {
205-
ObjectPtr raw = working_set.RemoveLast();
206-
207-
const intptr_t cid = raw->GetClassId();
208-
// Keep the list in sync with the one in runtime/vm/object_graph_copy.cc
209-
switch (cid) {
210-
// Can be shared.
211-
case kOneByteStringCid:
212-
case kTwoByteStringCid:
213-
case kExternalOneByteStringCid:
214-
case kExternalTwoByteStringCid:
215-
case kMintCid:
216-
case kImmutableArrayCid:
217-
case kNeverCid:
218-
case kSentinelCid:
219-
case kInt32x4Cid:
220-
case kSendPortCid:
221-
case kCapabilityCid:
222-
case kRegExpCid:
223-
case kStackTraceCid:
224-
continue;
225-
// Cannot be shared due to possibly being mutable boxes for unboxed
226-
// fields in JIT, but can be transferred via Isolate.exit()
227-
case kDoubleCid:
228-
case kFloat32x4Cid:
229-
case kFloat64x2Cid:
230-
continue;
231-
232-
case kClosureCid:
233-
closure ^= raw;
234-
// Only context has to be checked.
235-
working_set.Add(closure.context());
236-
continue;
192+
// working_set contains only elements that have not been visited yet that
193+
// need to be processed.
194+
// So before adding elements to working_set ensure to check visited flag,
195+
// set visited flag at the same time as the element is added.
196+
197+
// This working set of raw pointers is visited by GC, only one for a given
198+
// isolate should be in use.
199+
MallocGrowableArray<ObjectPtr>* const working_set =
200+
isolate->pointers_to_verify_at_exit();
201+
ASSERT(working_set->length() == 0);
202+
std::unique_ptr<WeakTable> visited(new WeakTable());
203+
204+
SendMessageValidator visitor(isolate->group(), visited.get(), working_set);
205+
206+
visited->SetValueExclusive(obj.ptr(), 1);
207+
working_set->Add(obj.ptr());
208+
209+
while (!working_set->is_empty() && !error_found) {
210+
thread->CheckForSafepoint();
211+
212+
ObjectPtr raw = working_set->RemoveLast();
213+
214+
const intptr_t cid = raw->GetClassId();
215+
// Keep the list in sync with the one in runtime/vm/object_graph_copy.cc
216+
switch (cid) {
217+
// Can be shared.
218+
case kOneByteStringCid:
219+
case kTwoByteStringCid:
220+
case kExternalOneByteStringCid:
221+
case kExternalTwoByteStringCid:
222+
case kMintCid:
223+
case kImmutableArrayCid:
224+
case kNeverCid:
225+
case kSentinelCid:
226+
case kInt32x4Cid:
227+
case kSendPortCid:
228+
case kCapabilityCid:
229+
case kRegExpCid:
230+
case kStackTraceCid:
231+
continue;
232+
// Cannot be shared due to possibly being mutable boxes for unboxed
233+
// fields in JIT, but can be transferred via Isolate.exit()
234+
case kDoubleCid:
235+
case kFloat32x4Cid:
236+
case kFloat64x2Cid:
237+
continue;
238+
239+
case kArrayCid:
240+
{
241+
array ^= Array::RawCast(raw);
242+
visitor.VisitObject(array.GetTypeArguments());
243+
const intptr_t batch_size = (2 << 14) - 1;
244+
for (intptr_t i = 0; i < array.Length(); ++i) {
245+
ObjectPtr ptr = array.At(i);
246+
visitor.VisitObject(ptr);
247+
if ((i & batch_size) == batch_size) {
248+
thread->CheckForSafepoint();
249+
}
250+
}
251+
continue;
252+
}
253+
case kClosureCid:
254+
closure ^= raw;
255+
// Only context has to be checked.
256+
working_set->Add(closure.context());
257+
continue;
237258

238259
#define MESSAGE_SNAPSHOT_ILLEGAL(type) \
239260
case k##type##Cid: \
@@ -242,33 +263,32 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
242263
error_found = true; \
243264
break;
244265

245-
MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
246-
// TODO(http://dartbug.com/47777): Send and exit support: remove this.
247-
MESSAGE_SNAPSHOT_ILLEGAL(Finalizer);
248-
MESSAGE_SNAPSHOT_ILLEGAL(NativeFinalizer);
249-
MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
250-
MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
251-
MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
252-
MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
253-
MESSAGE_SNAPSHOT_ILLEGAL(SuspendState);
254-
255-
default:
256-
if (cid >= kNumPredefinedCids) {
257-
klass = class_table->At(cid);
258-
if (klass.num_native_fields() != 0) {
259-
erroneous_nativewrapper_class = klass.ptr();
260-
error_found = true;
261-
break;
262-
}
263-
if (klass.implements_finalizable()) {
264-
erroneous_finalizable_class = klass.ptr();
265-
error_found = true;
266-
break;
267-
}
266+
MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
267+
// TODO(http://dartbug.com/47777): Send and exit support: remove this.
268+
MESSAGE_SNAPSHOT_ILLEGAL(Finalizer);
269+
MESSAGE_SNAPSHOT_ILLEGAL(NativeFinalizer);
270+
MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
271+
MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
272+
MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
273+
MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
274+
MESSAGE_SNAPSHOT_ILLEGAL(SuspendState);
275+
276+
default:
277+
if (cid >= kNumPredefinedCids) {
278+
klass = class_table->At(cid);
279+
if (klass.num_native_fields() != 0) {
280+
erroneous_nativewrapper_class = klass.ptr();
281+
error_found = true;
282+
break;
268283
}
269-
}
270-
raw->untag()->VisitPointers(&visitor);
284+
if (klass.implements_finalizable()) {
285+
erroneous_finalizable_class = klass.ptr();
286+
error_found = true;
287+
break;
288+
}
289+
}
271290
}
291+
raw->untag()->VisitPointers(&visitor);
272292
}
273293
if (error_found) {
274294
const char* exception_message;
@@ -292,9 +312,11 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
292312
" : (object implements Finalizable - %s)",
293313
erroneous_finalizable_class.ToCString());
294314
}
315+
working_set->Clear();
295316
return Exceptions::CreateUnhandledException(
296317
zone, Exceptions::kArgumentValue, exception_message);
297318
}
319+
ASSERT(working_set->length() == 0);
298320
isolate->set_forward_table_new(nullptr);
299321
return obj.ptr();
300322
}

runtime/vm/isolate.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2823,6 +2823,11 @@ void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
28232823

28242824
visitor->VisitPointer(
28252825
reinterpret_cast<ObjectPtr*>(&loaded_prefixes_set_storage_));
2826+
2827+
if (pointers_to_verify_at_exit_.length() != 0) {
2828+
visitor->VisitPointers(&pointers_to_verify_at_exit_[0],
2829+
pointers_to_verify_at_exit_.length());
2830+
}
28262831
}
28272832

28282833
void IsolateGroup::ReleaseStoreBuffers() {

runtime/vm/isolate.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,10 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
14771477
bool IsPrefixLoaded(const LibraryPrefix& prefix) const;
14781478
void SetPrefixIsLoaded(const LibraryPrefix& prefix);
14791479

1480+
MallocGrowableArray<ObjectPtr>* pointers_to_verify_at_exit() {
1481+
return &pointers_to_verify_at_exit_;
1482+
}
1483+
14801484
private:
14811485
friend class Dart; // Init, InitOnce, Shutdown.
14821486
friend class IsolateKillerVisitor; // Kill().
@@ -1735,6 +1739,8 @@ class Isolate : public BaseIsolate, public IntrusiveDListEntry<Isolate> {
17351739

17361740
ArrayPtr loaded_prefixes_set_storage_;
17371741

1742+
MallocGrowableArray<ObjectPtr> pointers_to_verify_at_exit_;
1743+
17381744
#define REUSABLE_FRIEND_DECLARATION(name) \
17391745
friend class Reusable##name##HandleScope;
17401746
REUSABLE_HANDLE_LIST(REUSABLE_FRIEND_DECLARATION)

0 commit comments

Comments
 (0)