9#include <unordered_set>
27 const auto& ffi_void =
Class::Handle(ffi_lib.LookupClass(Symbols::FfiVoid()));
28 const auto& ffi_void_type =
32 const char* kScriptChars =
49 const auto&
error = cls.EnsureIsFinalized(thread);
84 TestIsolateScope isolate_scope;
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);
92 auto* zone = thread->zone();
99 tramp1 = isolate->CreateIsolateLocalFfiCallback(
101 EXPECT_NE(tramp1, 0u);
104 FfiCallbackMetadata::Metadata m1 =
105 fcm->LookupMetadataForTrampoline(tramp1);
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()),
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);
120 tramp2 = isolate->CreateIsolateLocalFfiCallback(
122 EXPECT_NE(tramp2, 0u);
123 EXPECT_NE(tramp2, tramp1);
126 FfiCallbackMetadata::Metadata m2 =
127 fcm->LookupMetadataForTrampoline(tramp2);
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()),
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);
148 isolate->DeleteFfiCallback(tramp1);
149 FfiCallbackMetadata::Metadata m1 =
150 fcm->LookupMetadataForTrampoline(tramp1);
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);
163 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
166 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
177 TestIsolateScope isolate_scope;
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);
185 auto* zone = thread->zone();
187 const Function& func =
192 EXPECT_EQ(isolate->ffi_callback_list_head(),
nullptr);
195 tramp1 = isolate->CreateAsyncFfiCallback(zone, func, port1);
196 EXPECT_NE(tramp1, 0u);
199 FfiCallbackMetadata::Metadata m1 =
200 fcm->LookupMetadataForTrampoline(tramp1);
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()),
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);
216 tramp2 = isolate->CreateAsyncFfiCallback(zone, func, port2);
217 EXPECT_NE(tramp2, 0u);
218 EXPECT_NE(tramp2, tramp1);
221 FfiCallbackMetadata::Metadata m2 =
222 fcm->LookupMetadataForTrampoline(tramp2);
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()),
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);
243 isolate->DeleteFfiCallback(tramp2);
244 FfiCallbackMetadata::Metadata m2 =
245 fcm->LookupMetadataForTrampoline(tramp2);
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);
258 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
261 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
272 TestIsolateScope isolate_scope;
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);
280 auto* zone = thread->zone();
293 Object::null_type_arguments(), closure_func, context));
295 EXPECT_EQ(isolate->ffi_callback_list_head(),
nullptr);
297 tramp1 = isolate->CreateIsolateLocalFfiCallback(zone, func, closure1,
true);
298 EXPECT_NE(tramp1, 0u);
301 FfiCallbackMetadata::Metadata m1 =
302 fcm->LookupMetadataForTrampoline(tramp1);
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()),
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);
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);
325 FfiCallbackMetadata::Metadata m2 =
326 fcm->LookupMetadataForTrampoline(tramp2);
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()),
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);
347 isolate->DeleteFfiCallback(tramp2);
348 FfiCallbackMetadata::Metadata m2 =
349 fcm->LookupMetadataForTrampoline(tramp2);
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);
362 FfiCallbackMetadata::Metadata m1 = fcm->LookupMetadataForTrampoline(tramp1);
365 FfiCallbackMetadata::Metadata m2 = fcm->LookupMetadataForTrampoline(tramp2);
371 Isolate* isolate = thread->isolate();
372 auto* zone = thread->zone();
375 const Function& func =
381 FfiCallbackMetadata::Metadata* list_head =
nullptr;
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) {
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);
400 for (intptr_t
i = 0;
i < trampolines_per_page; ++
i) {
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);
410 for (intptr_t
i = 0;
i < trampolines_per_page; ++
i) {
412 fcm->CreateAsyncFfiCallback(isolate, zone, func,
port, &list_head);
413 EXPECT_EQ(allocated.count(tramp), 1u);
414 EXPECT_EQ(allocation_order[
i], tramp);
419 for (intptr_t
i = 0;
i < 3 * trampolines_per_page; ++
i) {
421 fcm->CreateAsyncFfiCallback(isolate, zone, func,
port, &list_head);
422 EXPECT_EQ(allocated.count(tramp), 0u);
427 static constexpr int kCreations = 1000;
428 static constexpr int kDeletions = 100;
430 TestIsolateScope isolate_scope;
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);
439 std::unordered_set<FfiCallbackMetadata::Trampoline> tramps;
440 FfiCallbackMetadata::Metadata* list_head =
nullptr;
444 const auto& sync_code =
Code::Handle(sync_func.EnsureHasCode());
445 EXPECT(!sync_code.IsNull());
448 for (
int itr = 0; itr < kCreations; ++itr) {
449 tramps.insert(fcm->CreateIsolateLocalFfiCallback(
455 for (
int itr = 0; itr < kDeletions; ++itr) {
456 auto tramp = *tramps.begin();
457 fcm->DeleteCallback(tramp, &list_head);
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());
472 uword list_length = 0;
473 for (FfiCallbackMetadata::Metadata*
m = list_head;
m !=
nullptr;) {
475 auto tramp = fcm->TrampolineOfMetadata(
m);
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);
484 EXPECT_EQ(list_head,
m);
486 if (
next !=
nullptr) {
487 EXPECT_EQ(
next->list_prev(),
m);
491 EXPECT_EQ(list_length, tramps.size());
494 fcm->DeleteAllCallbacks(&list_head);
495 EXPECT_EQ(list_head,
nullptr);
497 EXPECT(!fcm->LookupMetadataForTrampoline(tramp).IsLive());
502 static constexpr int kIterations = 1000;
504 TestIsolateScope isolate_scope;
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);
512 struct TrampolineWithPort {
519 std::vector<TrampolineWithPort> tramps;
520 std::unordered_set<FfiCallbackMetadata::Trampoline> tramp_set;
521 FfiCallbackMetadata::Metadata* list_head =
nullptr;
523 const Function& async_func =
525 const Code& async_code =
Code::Handle(async_func.EnsureHasCode());
526 EXPECT(!async_code.IsNull());
529 const auto& sync_code =
Code::Handle(sync_func.EnsureHasCode());
530 EXPECT(!sync_code.IsNull());
532 for (
int itr = 0; itr < kIterations; ++itr) {
539 if ((random.NextUInt32() % 100) == 0) {
541 fcm->DeleteAllCallbacks(&list_head);
548 EXPECT_EQ(list_head,
nullptr);
549 }
else if (tramps.size() > 0 && (random.NextUInt32() % 4) == 0) {
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];
556 tramp_set.erase(tramp);
558 TrampolineWithPort tramp;
559 if ((random.NextUInt32() % 2) == 0) {
562 tramp.tramp = fcm->CreateIsolateLocalFfiCallback(
563 isolate, thread->zone(), sync_func,
568 tramp.tramp = fcm->CreateAsyncFfiCallback(
569 isolate, thread->zone(), async_func, tramp.port, &list_head);
571 tramps.push_back(tramp);
572 tramp_set.insert(tramp.tramp);
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());
585 EXPECT_EQ(metadata.send_port(), tramp.port);
586 EXPECT_EQ(metadata.target_entry_point(), async_code.EntryPoint());
591 uword list_length = 0;
592 for (FfiCallbackMetadata::Metadata*
m = list_head;
m !=
nullptr;) {
594 auto tramp = fcm->TrampolineOfMetadata(
m);
596 EXPECT_EQ(
m->target_isolate(), isolate);
597 EXPECT_EQ(tramp_set.count(tramp), 1u);
600 EXPECT_EQ(list_length, tramps.size());
601 EXPECT_EQ(list_length, tramp_set.size());
605 fcm->DeleteAllCallbacks(&list_head);
606 EXPECT_EQ(list_head,
nullptr);
610 static constexpr int kThreads = 5;
612 std::vector<std::thread> threads;
615 for (
int i = 0;
i < kThreads; ++
i) {
620 for (
auto& thread : threads) {
static float next(float f)
static float prev(float f)
void SetIsFinalized() const
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)
static ObjectPtr CompileFunction(Thread *thread, const Function &function)
MessageStatus HandleMessage(std::unique_ptr< Message > message) override
void set_result_type(const AbstractType &value) const
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kNonNullable, Heap::Space space=Heap::kOld)
virtual AbstractTypePtr Canonicalize(Thread *thread) const
static LibraryPtr FfiLibrary()
static ObjectPtr RawCast(ObjectPtr obj)
static Dart_Port CreatePort(MessageHandler *handler)
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
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)
static Thread * Current()
static TypePtr NewNonParameterizedType(const Class &type_class)
struct _Dart_Handle * Dart_Handle
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
const uint8_t uint32_t uint32_t GError ** error
FunctionPtr NativeCallbackFunction(const FunctionType &c_signature, const Function &dart_target, const Instance &exceptional_return, FfiCallbackKind kind)
FunctionPtr CreateTestFunction(FfiCallbackKind kind)
@ kIsolateLocalClosureCallback
@ kIsolateLocalStaticCallback
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
#define EXPECT_VALID(handle)