Flutter Engine
The Flutter Engine
ffi_callback_metadata_test.cc
Go to the documentation of this file.
1// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
7#include <memory>
8#include <thread> // NOLINT(build/c++11)
9#include <unordered_set>
10#include <vector>
11
12#include "include/dart_api.h"
13#include "platform/assert.h"
14#include "vm/class_finalizer.h"
17#include "vm/message_handler.h"
18#include "vm/object.h"
19#include "vm/port.h"
20#include "vm/symbols.h"
21#include "vm/unit_test.h"
22
23namespace dart {
24
26 const auto& ffi_lib = Library::Handle(Library::FfiLibrary());
27 const auto& ffi_void = Class::Handle(ffi_lib.LookupClass(Symbols::FfiVoid()));
28 const auto& ffi_void_type =
30
31 auto* thread = Thread::Current();
32 const char* kScriptChars =
33 R"(
34 void testFunction() {
35 }
36 )";
37 Dart_Handle library;
38 {
39 TransitionVMToNative transition(thread);
40 library = TestCase::LoadTestScript(kScriptChars, nullptr);
41 EXPECT_VALID(library);
42 }
43
44 const auto& lib =
47 const auto& cls = Class::Handle(lib.toplevel_class());
48 EXPECT(!cls.IsNull());
49 const auto& error = cls.EnsureIsFinalized(thread);
51
52 auto& function_name = String::Handle(String::New("testFunction"));
53 const auto& func = Function::Handle(cls.LookupStaticFunction(function_name));
54 EXPECT(!func.IsNull());
55
57 signature.set_result_type(ffi_void_type);
58 signature.SetIsFinalized();
59 signature ^= signature.Canonicalize(thread);
60
62 signature, func, Instance::Handle(Instance::null()), kind));
63
64 const auto& result = Object::Handle(
65 thread->zone(), Compiler::CompileFunction(thread, callback));
66 EXPECT(!result.IsError());
67
68 return callback.ptr();
69}
72 public:
73 MessageStatus HandleMessage(std::unique_ptr<Message> message) override {
75 }
76};
77
78VM_UNIT_TEST_CASE(FfiCallbackMetadata_CreateSyncFfiCallback) {
82
83 {
84 TestIsolateScope isolate_scope;
85 Thread* thread = Thread::Current();
86 Isolate* isolate = thread->isolate();
87 ASSERT(isolate == isolate_scope.isolate());
88 TransitionNativeToVM transition(thread);
89 StackZone stack_zone(thread);
90 HandleScope handle_scope(thread);
91
92 auto* zone = thread->zone();
93
94 const auto& func = Function::Handle(
96 const auto& code = Code::Handle(func.EnsureHasCode());
97 EXPECT(!code.IsNull());
98
99 tramp1 = isolate->CreateIsolateLocalFfiCallback(
100 zone, func, Closure::Handle(Closure::null()), false);
101 EXPECT_NE(tramp1, 0u);
102
103 {
104 FfiCallbackMetadata::Metadata m1 =
105 fcm->LookupMetadataForTrampoline(tramp1);
106 EXPECT(m1.IsLive());
107 EXPECT_EQ(m1.target_isolate(), isolate);
108 EXPECT_EQ(m1.target_entry_point(), code.EntryPoint());
109 EXPECT_EQ(m1.closure_handle(), nullptr);
110 EXPECT_EQ(static_cast<int>(m1.trampoline_type()),
112
113 // head -> tramp1
114 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
115 EXPECT_EQ(isolate->ffi_callback_list_head(), e1);
116 EXPECT_EQ(e1->list_prev(), nullptr);
117 EXPECT_EQ(e1->list_next(), nullptr);
118 }
119
120 tramp2 = isolate->CreateIsolateLocalFfiCallback(
121 zone, func, Closure::Handle(Closure::null()), false);
122 EXPECT_NE(tramp2, 0u);
123 EXPECT_NE(tramp2, tramp1);
124
125 {
126 FfiCallbackMetadata::Metadata m2 =
127 fcm->LookupMetadataForTrampoline(tramp2);
128 EXPECT(m2.IsLive());
129 EXPECT_EQ(m2.target_isolate(), isolate);
130 EXPECT_EQ(m2.target_entry_point(), code.EntryPoint());
131 EXPECT_EQ(m2.closure_handle(), nullptr);
132 EXPECT_EQ(static_cast<int>(m2.trampoline_type()),
134 }
135
136 {
137 // head -> tramp2 -> tramp1
138 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
139 auto* e2 = fcm->MetadataOfTrampoline(tramp2);
140 EXPECT_EQ(isolate->ffi_callback_list_head(), e2);
141 EXPECT_EQ(e2->list_prev(), nullptr);
142 EXPECT_EQ(e2->list_next(), e1);
143 EXPECT_EQ(e1->list_prev(), e2);
144 EXPECT_EQ(e1->list_next(), nullptr);
145 }
146
147 {
148 isolate->DeleteFfiCallback(tramp1);
149 FfiCallbackMetadata::Metadata m1 =
150 fcm->LookupMetadataForTrampoline(tramp1);
151 EXPECT(!m1.IsLive());
152
153 // head -> tramp2
154 auto* e2 = fcm->MetadataOfTrampoline(tramp2);
155 EXPECT_EQ(isolate->ffi_callback_list_head(), e2);
156 EXPECT_EQ(e2->list_prev(), nullptr);
157 EXPECT_EQ(e2->list_next(), nullptr);
158 }
159 }
160
161 {
162 // Isolate has shut down, so all callbacks should be deleted.
163 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
164 EXPECT(!m1.IsLive());
165
166 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
167 EXPECT(!m2.IsLive());
169}
170
171VM_UNIT_TEST_CASE(FfiCallbackMetadata_CreateAsyncFfiCallback) {
172 auto* fcm = FfiCallbackMetadata::Instance();
175
176 {
177 TestIsolateScope isolate_scope;
178 Thread* thread = Thread::Current();
179 Isolate* isolate = thread->isolate();
180 ASSERT(thread->isolate() == isolate_scope.isolate());
181 TransitionNativeToVM transition(thread);
182 StackZone stack_zone(thread);
183 HandleScope handle_scope(thread);
184
185 auto* zone = thread->zone();
186
187 const Function& func =
189 const Code& code = Code::Handle(func.EnsureHasCode());
190 EXPECT(!code.IsNull());
191
192 EXPECT_EQ(isolate->ffi_callback_list_head(), nullptr);
193
194 auto port1 = PortMap::CreatePort(new FakeMessageHandler());
195 tramp1 = isolate->CreateAsyncFfiCallback(zone, func, port1);
196 EXPECT_NE(tramp1, 0u);
197
198 {
199 FfiCallbackMetadata::Metadata m1 =
200 fcm->LookupMetadataForTrampoline(tramp1);
201 EXPECT(m1.IsLive());
202 EXPECT_EQ(m1.target_isolate(), isolate);
203 EXPECT_EQ(m1.target_entry_point(), code.EntryPoint());
204 EXPECT_EQ(m1.send_port(), port1);
205 EXPECT_EQ(static_cast<int>(m1.trampoline_type()),
207
208 // head -> tramp1
209 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
210 EXPECT_EQ(isolate->ffi_callback_list_head(), e1);
211 EXPECT_EQ(e1->list_prev(), nullptr);
212 EXPECT_EQ(e1->list_next(), nullptr);
213 }
214
215 auto port2 = PortMap::CreatePort(new FakeMessageHandler());
216 tramp2 = isolate->CreateAsyncFfiCallback(zone, func, port2);
217 EXPECT_NE(tramp2, 0u);
218 EXPECT_NE(tramp2, tramp1);
219
220 {
221 FfiCallbackMetadata::Metadata m2 =
222 fcm->LookupMetadataForTrampoline(tramp2);
223 EXPECT(m2.IsLive());
224 EXPECT_EQ(m2.target_isolate(), isolate);
225 EXPECT_EQ(m2.target_entry_point(), code.EntryPoint());
226 EXPECT_EQ(m2.send_port(), port2);
227 EXPECT_EQ(static_cast<int>(m2.trampoline_type()),
229 }
230
231 {
232 // head -> tramp2 -> tramp1
233 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
234 auto* e2 = fcm->MetadataOfTrampoline(tramp2);
235 EXPECT_EQ(isolate->ffi_callback_list_head(), e2);
236 EXPECT_EQ(e2->list_prev(), nullptr);
237 EXPECT_EQ(e2->list_next(), e1);
238 EXPECT_EQ(e1->list_prev(), e2);
239 EXPECT_EQ(e1->list_next(), nullptr);
240 }
241
242 {
243 isolate->DeleteFfiCallback(tramp2);
244 FfiCallbackMetadata::Metadata m2 =
245 fcm->LookupMetadataForTrampoline(tramp2);
246 EXPECT(!m2.IsLive());
247
248 // head -> tramp1
249 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
250 EXPECT_EQ(isolate->ffi_callback_list_head(), e1);
251 EXPECT_EQ(e1->list_prev(), nullptr);
252 EXPECT_EQ(e1->list_next(), nullptr);
253 }
254 }
255
256 {
257 // Isolate has shut down, so all callbacks should be deleted.
258 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
259 EXPECT(!m1.IsLive());
260
261 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
262 EXPECT(!m2.IsLive());
264}
265
266VM_UNIT_TEST_CASE(FfiCallbackMetadata_CreateIsolateLocalFfiCallback) {
267 auto* fcm = FfiCallbackMetadata::Instance();
270
271 {
272 TestIsolateScope isolate_scope;
273 Thread* thread = Thread::Current();
274 Isolate* isolate = thread->isolate();
275 ASSERT(thread->isolate() == isolate_scope.isolate());
276 TransitionNativeToVM transition(thread);
277 StackZone stack_zone(thread);
278 HandleScope handle_scope(thread);
279
280 auto* zone = thread->zone();
281
282 const Function& func = Function::Handle(
284 const Code& code = Code::Handle(func.EnsureHasCode());
285 EXPECT(!code.IsNull());
286
287 // Using a FfiCallbackKind::kSync function as a dummy closure.
288 const Function& closure_func = Function::Handle(
290 const Context& context = Context::Handle(Context::null());
291 const Closure& closure1 = Closure::Handle(
292 Closure::New(Object::null_type_arguments(),
293 Object::null_type_arguments(), closure_func, context));
294
295 EXPECT_EQ(isolate->ffi_callback_list_head(), nullptr);
296
297 tramp1 = isolate->CreateIsolateLocalFfiCallback(zone, func, closure1, true);
298 EXPECT_NE(tramp1, 0u);
299
300 {
301 FfiCallbackMetadata::Metadata m1 =
302 fcm->LookupMetadataForTrampoline(tramp1);
303 EXPECT(m1.IsLive());
304 EXPECT_EQ(m1.target_isolate(), isolate);
305 EXPECT_EQ(m1.target_entry_point(), code.EntryPoint());
306 EXPECT_EQ(m1.closure_handle()->ptr(), closure1.ptr());
307 EXPECT_EQ(static_cast<int>(m1.trampoline_type()),
309
310 // head -> tramp1
311 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
312 EXPECT_EQ(isolate->ffi_callback_list_head(), e1);
313 EXPECT_EQ(e1->list_prev(), nullptr);
314 EXPECT_EQ(e1->list_next(), nullptr);
315 }
316
317 const Closure& closure2 = Closure::Handle(
318 Closure::New(Object::null_type_arguments(),
319 Object::null_type_arguments(), closure_func, context));
320 tramp2 = isolate->CreateIsolateLocalFfiCallback(zone, func, closure2, true);
321 EXPECT_NE(tramp2, 0u);
322 EXPECT_NE(tramp2, tramp1);
323
324 {
325 FfiCallbackMetadata::Metadata m2 =
326 fcm->LookupMetadataForTrampoline(tramp2);
327 EXPECT(m2.IsLive());
328 EXPECT_EQ(m2.target_isolate(), isolate);
329 EXPECT_EQ(m2.target_entry_point(), code.EntryPoint());
330 EXPECT_EQ(m2.closure_handle()->ptr(), closure2.ptr());
331 EXPECT_EQ(static_cast<int>(m2.trampoline_type()),
333 }
334
335 {
336 // head -> tramp2 -> tramp1
337 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
338 auto* e2 = fcm->MetadataOfTrampoline(tramp2);
339 EXPECT_EQ(isolate->ffi_callback_list_head(), e2);
340 EXPECT_EQ(e2->list_prev(), nullptr);
341 EXPECT_EQ(e2->list_next(), e1);
342 EXPECT_EQ(e1->list_prev(), e2);
343 EXPECT_EQ(e1->list_next(), nullptr);
344 }
345
346 {
347 isolate->DeleteFfiCallback(tramp2);
348 FfiCallbackMetadata::Metadata m2 =
349 fcm->LookupMetadataForTrampoline(tramp2);
350 EXPECT(!m2.IsLive());
351
352 // head -> tramp1
353 auto* e1 = fcm->MetadataOfTrampoline(tramp1);
354 EXPECT_EQ(isolate->ffi_callback_list_head(), e1);
355 EXPECT_EQ(e1->list_prev(), nullptr);
356 EXPECT_EQ(e1->list_next(), nullptr);
357 }
358 }
359
360 {
361 // Isolate has shut down, so all callbacks should be deleted.
362 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
363 EXPECT(!m1.IsLive());
364
365 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
366 EXPECT(!m2.IsLive());
368}
369
370ISOLATE_UNIT_TEST_CASE(FfiCallbackMetadata_TrampolineRecycling) {
371 Isolate* isolate = thread->isolate();
372 auto* zone = thread->zone();
373 auto* fcm = FfiCallbackMetadata::Instance();
374
375 const Function& func =
377 const Code& code = Code::Handle(func.EnsureHasCode());
378 EXPECT(!code.IsNull());
379
380 auto port = PortMap::CreatePort(new FakeMessageHandler());
381 FfiCallbackMetadata::Metadata* list_head = nullptr;
382
383 // Allocate and free one callback at a time, and verify that we don't reuse
384 // them. Allocate enough that the whole page fills up with dead trampolines.
385 std::vector<FfiCallbackMetadata::Trampoline> allocation_order;
386 std::unordered_set<FfiCallbackMetadata::Trampoline> allocated;
387 const intptr_t trampolines_per_page =
389 for (intptr_t i = 0; i < trampolines_per_page; ++i) {
390 auto tramp =
391 fcm->CreateAsyncFfiCallback(isolate, zone, func, port, &list_head);
392 EXPECT_EQ(allocated.count(tramp), 0u);
393 allocation_order.push_back(tramp);
394 allocated.insert(tramp);
395 fcm->DeleteCallback(tramp, &list_head);
396 }
397
398 // Now as we continue allocating and freeing, we start reusing them, in the
399 // same allocation order as before.
400 for (intptr_t i = 0; i < trampolines_per_page; ++i) {
401 auto tramp =
402 fcm->CreateAsyncFfiCallback(isolate, zone, func, port, &list_head);
403 EXPECT_EQ(allocated.count(tramp), 1u);
404 EXPECT_EQ(allocation_order[i], tramp);
405 fcm->DeleteCallback(tramp, &list_head);
406 }
407
408 // Now allocate enough to fill the page without freeing them. Again they
409 // should come out in the same order.
410 for (intptr_t i = 0; i < trampolines_per_page; ++i) {
411 auto tramp =
412 fcm->CreateAsyncFfiCallback(isolate, zone, func, port, &list_head);
413 EXPECT_EQ(allocated.count(tramp), 1u);
414 EXPECT_EQ(allocation_order[i], tramp);
415 }
416
417 // Now that the page is full, we should allocate a new page and see new
418 // trampolines we haven't seen before.
419 for (intptr_t i = 0; i < 3 * trampolines_per_page; ++i) {
420 auto tramp =
421 fcm->CreateAsyncFfiCallback(isolate, zone, func, port, &list_head);
422 EXPECT_EQ(allocated.count(tramp), 0u);
424}
425
426VM_UNIT_TEST_CASE(FfiCallbackMetadata_DeleteTrampolines) {
427 static constexpr int kCreations = 1000;
428 static constexpr int kDeletions = 100;
429
430 TestIsolateScope isolate_scope;
431 Thread* thread = Thread::Current();
432 Isolate* isolate = thread->isolate();
433 ASSERT(isolate == isolate_scope.isolate());
434 TransitionNativeToVM transition(thread);
435 StackZone stack_zone(thread);
436 HandleScope handle_scope(thread);
437
438 auto* fcm = FfiCallbackMetadata::Instance();
439 std::unordered_set<FfiCallbackMetadata::Trampoline> tramps;
440 FfiCallbackMetadata::Metadata* list_head = nullptr;
441
442 const auto& sync_func = Function::Handle(
444 const auto& sync_code = Code::Handle(sync_func.EnsureHasCode());
445 EXPECT(!sync_code.IsNull());
446
447 // Create some callbacks.
448 for (int itr = 0; itr < kCreations; ++itr) {
449 tramps.insert(fcm->CreateIsolateLocalFfiCallback(
450 isolate, thread->zone(), sync_func, Closure::Handle(Closure::null()),
451 &list_head));
452 }
453
454 // Delete some of the callbacks.
455 for (int itr = 0; itr < kDeletions; ++itr) {
456 auto tramp = *tramps.begin();
457 fcm->DeleteCallback(tramp, &list_head);
458 tramps.erase(tramp);
459 }
460
461 // Verify all the callbacks.
462 for (FfiCallbackMetadata::Trampoline tramp : tramps) {
463 auto metadata = fcm->LookupMetadataForTrampoline(tramp);
464 EXPECT(metadata.IsLive());
465 EXPECT_EQ(metadata.target_isolate(), isolate);
466 EXPECT_EQ(static_cast<int>(metadata.trampoline_type()),
468 EXPECT_EQ(metadata.target_entry_point(), sync_code.EntryPoint());
469 }
470
471 // Verify the list of callbacks.
472 uword list_length = 0;
473 for (FfiCallbackMetadata::Metadata* m = list_head; m != nullptr;) {
474 ++list_length;
475 auto tramp = fcm->TrampolineOfMetadata(m);
476 EXPECT(m->IsLive());
477 EXPECT_EQ(m->target_isolate(), isolate);
478 EXPECT_EQ(tramps.count(tramp), 1u);
479 auto* next = m->list_next();
480 auto* prev = m->list_prev();
481 if (prev != nullptr) {
482 EXPECT_EQ(prev->list_next(), m);
483 } else {
484 EXPECT_EQ(list_head, m);
485 }
486 if (next != nullptr) {
487 EXPECT_EQ(next->list_prev(), m);
488 }
489 m = m->list_next();
490 }
491 EXPECT_EQ(list_length, tramps.size());
492
493 // Delete all callbacks and verify they're destroyed.
494 fcm->DeleteAllCallbacks(&list_head);
495 EXPECT_EQ(list_head, nullptr);
496 for (FfiCallbackMetadata::Trampoline tramp : tramps) {
497 EXPECT(!fcm->LookupMetadataForTrampoline(tramp).IsLive());
499}
500
501static void RunBigRandomMultithreadedTest(uint64_t seed) {
502 static constexpr int kIterations = 1000;
503
504 TestIsolateScope isolate_scope;
505 Thread* thread = Thread::Current();
506 Isolate* isolate = thread->isolate();
507 ASSERT(isolate == isolate_scope.isolate());
508 TransitionNativeToVM transition(thread);
509 StackZone stack_zone(thread);
510 HandleScope handle_scope(thread);
511
512 struct TrampolineWithPort {
515 };
516
517 auto* fcm = FfiCallbackMetadata::Instance();
518 Random random(seed);
519 std::vector<TrampolineWithPort> tramps;
520 std::unordered_set<FfiCallbackMetadata::Trampoline> tramp_set;
521 FfiCallbackMetadata::Metadata* list_head = nullptr;
522
523 const Function& async_func =
525 const Code& async_code = Code::Handle(async_func.EnsureHasCode());
526 EXPECT(!async_code.IsNull());
527 const Function& sync_func = Function::Handle(
529 const auto& sync_code = Code::Handle(sync_func.EnsureHasCode());
530 EXPECT(!sync_code.IsNull());
531
532 for (int itr = 0; itr < kIterations; ++itr) {
533 // Do a random action:
534 // - Allocate a sync callback
535 // - Allocate an async callback
536 // - Delete a callback
537 // - Delete all the sync callbacks for an isolate
538
539 if ((random.NextUInt32() % 100) == 0) {
540 // 1% chance of deleting all the callbacks on the thread.
541 fcm->DeleteAllCallbacks(&list_head);
542
543 // It would be nice to verify that all the trampolines have been deleted,
544 // but this is flaky because other threads can recycle these trampolines
545 // before we finish checking all of them.
546 tramps.clear();
547 tramp_set.clear();
548 EXPECT_EQ(list_head, nullptr);
549 } else if (tramps.size() > 0 && (random.NextUInt32() % 4) == 0) {
550 // 25% chance of deleting a callback.
551 uint32_t r = random.NextUInt32() % tramps.size();
552 auto tramp = tramps[r].tramp;
553 fcm->DeleteCallback(tramp, &list_head);
554 tramps[r] = tramps[tramps.size() - 1];
555 tramps.pop_back();
556 tramp_set.erase(tramp);
557 } else {
558 TrampolineWithPort tramp;
559 if ((random.NextUInt32() % 2) == 0) {
560 // 50% chance of creating a sync callback.
561 tramp.port = ILLEGAL_PORT;
562 tramp.tramp = fcm->CreateIsolateLocalFfiCallback(
563 isolate, thread->zone(), sync_func,
564 Closure::Handle(Closure::null()), &list_head);
565 } else {
566 // 50% chance of creating an async callback.
567 tramp.port = PortMap::CreatePort(new FakeMessageHandler());
568 tramp.tramp = fcm->CreateAsyncFfiCallback(
569 isolate, thread->zone(), async_func, tramp.port, &list_head);
570 }
571 tramps.push_back(tramp);
572 tramp_set.insert(tramp.tramp);
573 }
574
575 // Verify all the callbacks.
576 for (const auto& tramp : tramps) {
577 auto metadata = fcm->LookupMetadataForTrampoline(tramp.tramp);
578 EXPECT(metadata.IsLive());
579 EXPECT_EQ(metadata.target_isolate(), isolate);
580 if (metadata.trampoline_type() ==
582 EXPECT_EQ(metadata.closure_handle(), nullptr);
583 EXPECT_EQ(metadata.target_entry_point(), sync_code.EntryPoint());
584 } else {
585 EXPECT_EQ(metadata.send_port(), tramp.port);
586 EXPECT_EQ(metadata.target_entry_point(), async_code.EntryPoint());
587 }
588 }
589
590 // Verify the isolate's list of callbacks.
591 uword list_length = 0;
592 for (FfiCallbackMetadata::Metadata* m = list_head; m != nullptr;) {
593 ++list_length;
594 auto tramp = fcm->TrampolineOfMetadata(m);
595 EXPECT(m->IsLive());
596 EXPECT_EQ(m->target_isolate(), isolate);
597 EXPECT_EQ(tramp_set.count(tramp), 1u);
598 m = m->list_next();
599 }
600 EXPECT_EQ(list_length, tramps.size());
601 EXPECT_EQ(list_length, tramp_set.size());
602 }
603
604 // Delete all remaining callbacks.
605 fcm->DeleteAllCallbacks(&list_head);
606 EXPECT_EQ(list_head, nullptr);
607}
608
609ISOLATE_UNIT_TEST_CASE(FfiCallbackMetadata_BigRandomMultithreadedTest) {
610 static constexpr int kThreads = 5;
611
612 std::vector<std::thread> threads;
613
614 Random random;
615 for (int i = 0; i < kThreads; ++i) {
616 threads.push_back(
617 std::thread(RunBigRandomMultithreadedTest, random.NextUInt64()));
618 }
619
620 for (auto& thread : threads) {
621 thread.join();
622 }
623}
624
625} // namespace dart
static float next(float f)
static float prev(float f)
float e1
#define EXPECT(type, expectedAlignment, expectedSize)
void SetIsFinalized() const
Definition: object.cc:21161
static ObjectPtr UnwrapHandle(Dart_Handle object)
static bool ProcessPendingClasses()
static ClosurePtr New(const TypeArguments &instantiator_type_arguments, const TypeArguments &function_type_arguments, const Function &function, const Object &context, Heap::Space space=Heap::kNew)
Definition: object.cc:25942
static ObjectPtr CompileFunction(Thread *thread, const Function &function)
Definition: compiler.cc:824
MessageStatus HandleMessage(std::unique_ptr< Message > message) override
static constexpr intptr_t NumCallbackTrampolinesPerPage()
static FfiCallbackMetadata * Instance()
void set_result_type(const AbstractType &value) const
Definition: object.cc:8575
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kNonNullable, Heap::Space space=Heap::kOld)
Definition: object.cc:11631
virtual AbstractTypePtr Canonicalize(Thread *thread) const
Definition: object.cc:22466
static LibraryPtr FfiLibrary()
Definition: object.cc:14799
static ObjectPtr null()
Definition: object.h:433
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
static Dart_Port CreatePort(MessageHandler *handler)
Definition: port.cc:55
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
static Thread * Current()
Definition: thread.h:362
static TypePtr NewNonParameterizedType(const Class &type_class)
#define ILLEGAL_PORT
Definition: dart_api.h:1535
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
#define ASSERT(E)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
GAsyncResult * result
Win32Message message
FunctionPtr NativeCallbackFunction(const FunctionType &c_signature, const Function &dart_target, const Instance &exceptional_return, FfiCallbackKind kind)
Definition: callback.cc:36
Definition: dart_vm.cc:33
FunctionPtr CreateTestFunction(FfiCallbackKind kind)
FfiCallbackKind
Definition: object.h:2984
uintptr_t uword
Definition: globals.h:501
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
const char *const function_name
static void RunBigRandomMultithreadedTest(uint64_t seed)
VM_UNIT_TEST_CASE(DirectoryCurrentNoScope)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
#define EXPECT_VALID(handle)
Definition: unit_test.h:643