blob: ebfff577db08548ee8d24ba34c6846309601b886 [file] [edit]
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "objective_c.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <dispatch/dispatch.h>
#include "include/dart_api_dl.h"
#include "objective_c_runtime.h"
_Atomic bool _mainThreadIsListening = false;
static void setListening(void* arg) {
_mainThreadIsListening = true;
}
FFI_EXPORT intptr_t DOBJC_initializeApi(void* data) {
dispatch_async_f(dispatch_get_main_queue(), NULL, setListening);
return Dart_InitializeApiDL(data);
}
// Copy and dispose helper for ObjC blocks that wrap a Dart closure. For these
// blocks, the target is an int ID, and the dispose_port is listening for these
// IDs.
FFI_EXPORT void DOBJC_copyObjCBlockWithClosure(ObjCBlockImpl* dst,
ObjCBlockImpl* src) {
dst->target = src->target;
dst->dispose_port = src->dispose_port;
}
FFI_EXPORT void DOBJC_disposeObjCBlockWithClosure(ObjCBlockImpl* block) {
Dart_PostInteger_DL(block->dispose_port, (int64_t)block->target);
}
FFI_EXPORT void DOBJC_finalizeObject(void* isolate_callback_data, void* peer) {
// objc_release works for Objects and Blocks.
DOBJC_runOnMainThread((void (*)(void*))objc_release, peer);
}
FFI_EXPORT Dart_FinalizableHandle
DOBJC_newFinalizableHandle(Dart_Handle owner, ObjCObjectImpl* object) {
return Dart_NewFinalizableHandle_DL(owner, object, 0, DOBJC_finalizeObject);
}
FFI_EXPORT void DOBJC_deleteFinalizableHandle(Dart_FinalizableHandle handle,
Dart_Handle owner) {
Dart_DeleteFinalizableHandle_DL(handle, owner);
}
static void finalizeMalloc(void* isolate_callback_data, void* peer) {
free(peer);
}
FFI_EXPORT bool* DOBJC_newFinalizableBool(Dart_Handle owner) {
bool* pointer = (bool*)malloc(1);
*pointer = false;
Dart_NewFinalizableHandle_DL(owner, pointer, 1, finalizeMalloc);
return pointer;
}
FFI_EXPORT bool DOBJC_postCObject(int64_t port_id, void* peer,
void (*callback)(void*, void*)) {
Dart_CObject c_post;
c_post.type = Dart_CObject_kNativePointer;
c_post.value.as_native_pointer.ptr = (intptr_t)peer;
c_post.value.as_native_pointer.size = 0;
c_post.value.as_native_pointer.callback = (Dart_HandleFinalizer)callback;
if (!Dart_PostCObject_DL(port_id, &c_post)) {
if (c_post.value.as_native_pointer.callback != NULL) {
c_post.value.as_native_pointer.callback(
NULL, (void*)c_post.value.as_native_pointer.ptr);
}
return false;
}
return true;
}
FFI_EXPORT DOBJC_Context* DOBJC_fillContext(DOBJC_Context* context) {
context->version = 3;
context->newWaiter = DOBJC_newWaiter;
context->awaitWaiter = DOBJC_awaitWaiter;
context->currentIsolate = Dart_CurrentIsolate_DL;
context->enterIsolate = Dart_EnterIsolate_DL;
context->exitIsolate = Dart_ExitIsolate_DL;
context->getMainPortId = Dart_GetMainPortId_DL;
context->getCurrentThreadOwnsIsolate = Dart_GetCurrentThreadOwnsIsolate_DL;
context->postCObject = DOBJC_postCObject;
context->runOnMainThread = DOBJC_runOnMainThread;
context->signalWaiter = DOBJC_signalWaiter;
context->getBlockPortId = DOBJC_getBlockPortId;
context->getBlockContext = DOBJC_getBlockContext;
return context;
}
FFI_EXPORT int64_t DOBJC_getBlockPortId(void* block) {
ObjCBlockImpl* b = (ObjCBlockImpl*)block;
PortBlockTarget* target = (PortBlockTarget*)b->target;
return target->port_id;
}
FFI_EXPORT void* DOBJC_getBlockContext(void* block) {
ObjCBlockImpl* b = (ObjCBlockImpl*)block;
PortBlockTarget* target = (PortBlockTarget*)b->target;
return target->ctx;
}
extern void* _NSConcreteStackBlock[];
extern void* _NSConcreteMallocBlock[];
extern void* _NSConcreteAutoBlock[];
extern void* _NSConcreteFinalizingBlock[];
extern void* _NSConcreteGlobalBlock[];
extern void* _NSConcreteWeakBlockVariable[];
FFI_EXPORT bool DOBJC_isValidBlock(ObjCBlockImpl* block) {
if (block == NULL) return false;
void* isa = (void*)(((uintptr_t)block->isa) & 0x0000000fffffffffull);
return isa == &_NSConcreteStackBlock || isa == &_NSConcreteMallocBlock ||
isa == &_NSConcreteAutoBlock || isa == &_NSConcreteFinalizingBlock ||
isa == &_NSConcreteGlobalBlock || isa == &_NSConcreteWeakBlockVariable;
}
FFI_EXPORT void DOBJC_noop(void) {}