public ObjCBlock toObjCBlock(Object o) { if (o == null) { return null; } // Create an Objective-C block struct which looks like it was // allocated on the stack. The struct will be GC reachable during // the duration of the call to the Objective-C side. The Objective-C // side will copy the block if it needs to call it later which will // trigger a call to the copy() method below. The GC will reclaim // the struct memory area some time after the call has finished but // the Java block instance (e.g. VoidBlock) will be retained on // every copy and only GCed after all copies have been deallocated. ObjCBlock block = new ObjCBlock() .isa(NSStackBlock) .flags(flags) .invoke(callbackImpl) .descriptor(DESCRIPTOR) .object(o) .wrapper(this); return block; }
@MarshalsPointer public static long toNative(Runnable o, long flags) { if (o == null) { return 0L; } if (o instanceof RunnableAsObjCBlockMarshaler) { return ((RunnableAsObjCBlockMarshaler) o).objCBlock.getHandle(); } // TODO: Retain if returned from callback? return WRAPPER.toObjCBlock(o).getHandle(); }
@Callback private static void dispose(ObjCBlock block) { // Called from the Objective-C side when a previously copied block // is released and about to be deallocated. Decrease the ref count // of the object on the Java side. Object blockObj = block.object(); Wrapper wrapper = block.wrapper(); IdentityHashMap<Object, AtomicInteger> refCounts = wrapper.refCounts; synchronized (refCounts) { if (refCounts.get(blockObj).decrementAndGet() == 0) { refCounts.remove(blockObj); } } } }
public Object toObject(long handle) { ObjCBlock block = Struct.toStruct(ObjCBlock.class, handle); if (block == null) { return null; } return block.object(); }
@MarshalsPointer public static Runnable toObject(Class<?> cls, long handle, long flags) { if (handle == 0L) { return null; } ObjCBlock block = Struct.toStruct(ObjCBlock.class, handle); if (block.hasObject()) { return (Runnable) block.object(); } handle = ObjCRuntime.ptr_objc_msgSend(handle, COPY_SELECTOR.getHandle()); ObjCBlock.setHandle(block, handle); return new RunnableAsObjCBlockMarshaler(block); }
public ObjCBlock object(Object o) { object_addr(VM.getObjectAddress(o)); return this; }
public void run() { invoke(objCBlock.invoke(), objCBlock); }
public boolean hasObject() { return descriptor().getHandle() == Wrapper.DESCRIPTOR.getHandle(); }
@Callback private static void copy(ObjCBlock dst, ObjCBlock src) { // Called from the Objective-C side every time the block is copied. // Increase the ref count of the block object on the Java side to // prevent it from being GCed. Object blockObj = src.object(); Wrapper wrapper = src.wrapper(); IdentityHashMap<Object, AtomicInteger> refCounts = wrapper.refCounts; synchronized (refCounts) { AtomicInteger count = refCounts.get(blockObj); if (count == null) { count = new AtomicInteger(0); refCounts.put(blockObj, count); } count.incrementAndGet(); } }
@Callback private static void invoked(ObjCBlock block) { ((Runnable) block.object()).run(); } }
public Object object() { return VM.castAddressToObject(object_addr()); }
public void run() { invoke(objCBlock.invoke(), objCBlock); }
public boolean hasObject() { return descriptor().getHandle() == Wrapper.DESCRIPTOR.getHandle(); }
public ObjCBlock toObjCBlock(Object o) { if (o == null) { return null; } // Create an Objective-C block struct which looks like it was // allocated on the stack. The struct will be GC reachable during // the duration of the call to the Objective-C side. The Objective-C // side will copy the block if it needs to call it later which will // trigger a call to the copy() method below. The GC will reclaim // the struct memory area some time after the call has finished but // the Java block instance (e.g. VoidBlock) will be retained on // every copy and only GCed after all copies have been deallocated. ObjCBlock block = new ObjCBlock() .isa(NSStackBlock) .flags(flags) .invoke(callbackImpl) .descriptor(descriptor) .object(o) .wrapper(this); return block; }
@Callback private static void dispose(ObjCBlock block) { // Called from the Objective-C side when a previously copied block // is released and about to be deallocated. Decrease the ref count // of the object on the Java side. Object blockObj = block.object(); Wrapper wrapper = block.wrapper(); IdentityHashMap<Object, AtomicInteger> refCounts = wrapper.refCounts; synchronized (refCounts) { if (refCounts.get(blockObj).decrementAndGet() == 0) { refCounts.remove(blockObj); } } } }
@Callback static void run(ObjCBlock block, boolean v) { ((VoidBooleanBlock) block.object()).invoke(v); } }
public ObjCBlock object(Object o) { object_addr(VM.getObjectAddress(o)); return this; }
@MarshalsPointer public static long toNative(Runnable o, long flags) { if (o == null) { return 0L; } if (o instanceof RunnableAsObjCBlockMarshaler) { return ((RunnableAsObjCBlockMarshaler) o).objCBlock.getHandle(); } // TODO: Retain if returned from callback? return WRAPPER.toObjCBlock(o).getHandle(); }
@Callback private static void copy(ObjCBlock dst, ObjCBlock src) { // Called from the Objective-C side every time the block is copied. // Increase the ref count of the block object on the Java side to // prevent it from being GCed. Object blockObj = src.object(); Wrapper wrapper = src.wrapper(); IdentityHashMap<Object, AtomicInteger> refCounts = wrapper.refCounts; synchronized (refCounts) { AtomicInteger count = refCounts.get(blockObj); if (count == null) { count = new AtomicInteger(0); refCounts.put(blockObj, count); } count.incrementAndGet(); } }