@@ -144,6 +144,17 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
144
144
visited_ (visited),
145
145
working_set_(working_set) {}
146
146
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
+
147
158
private:
148
159
void VisitPointers (ObjectPtr* from, ObjectPtr* to) {
149
160
for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
@@ -159,17 +170,6 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
159
170
}
160
171
}
161
172
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
-
173
173
WeakTable* visited_;
174
174
MallocGrowableArray<ObjectPtr>* const working_set_;
175
175
};
@@ -185,55 +185,76 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
185
185
Function& erroneous_closure_function = Function::Handle (zone);
186
186
Class& erroneous_nativewrapper_class = Class::Handle (zone);
187
187
Class& erroneous_finalizable_class = Class::Handle (zone);
188
+ Array& array = Array::Handle (zone);
188
189
const char * error_message = nullptr ;
190
+ Thread* thread = Thread::Current();
189
191
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 ;
237
258
238
259
#define MESSAGE_SNAPSHOT_ILLEGAL (type ) \
239
260
case k##type##Cid: \
@@ -242,33 +263,32 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
242
263
error_found = true ; \
243
264
break ;
244
265
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 ;
268
283
}
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
+ }
271
290
}
291
+ raw->untag ()->VisitPointers (&visitor);
272
292
}
273
293
if (error_found) {
274
294
const char * exception_message;
@@ -292,9 +312,11 @@ static ObjectPtr ValidateMessageObject(Zone* zone,
292
312
" : (object implements Finalizable - %s)" ,
293
313
erroneous_finalizable_class.ToCString ());
294
314
}
315
+ working_set->Clear ();
295
316
return Exceptions::CreateUnhandledException (
296
317
zone, Exceptions::kArgumentValue , exception_message);
297
318
}
319
+ ASSERT (working_set->length () == 0);
298
320
isolate->set_forward_table_new (nullptr );
299
321
return obj.ptr();
300
322
}
0 commit comments