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);
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);
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 {
513 FfiCallbackMetadata::Trampoline tramp;
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());
static ClosurePtr New(const TypeArguments &instantiator_type_arguments, const TypeArguments &function_type_arguments, const Function &function, const Object &context, Heap::Space space=Heap::kNew)
const uint8_t uint32_t uint32_t GError ** error