Ivan What I am trying to highlight here is that Apple probably implemented their TFB using @defs() (ever heard of it?) - something that cannot be used cross-binary reliably but guarantees compatibility between pointers of TFB-enabled classes defined within a single binary, as @defs() guarantees identical layout of an Objective-C class and a C struct. Our current TFB mechanism depend on implementation detail of Base and does not scale well into Opal (CGPath path = …; CFRelease(path); crashes).
So here is my proposal, outline of how Apple implemented their TFB which not only works for CF but also CG, CA and more: 1) Memory management is always done using Objective-C runtime. CFRetain(), [NSObject retain], objc_retain() set, CFRelease(), [NSObject release], objc_release() set as well as a few sets regarding autorelease pools are synonymous and can be made aliases. (There are so many CFRetain((__bridge CFTypeRef)someObjectiveCObjectNotEvenTFBCompatible); in CGIJSONRPC code and it is surprisingly reliable despite being rich in black magic I never bothered to document. For once I overrode objc_retain() with CFRetain() and that caused a stack overflow, revealing the fact that CFRetain calls objc_retain()) More to come on this later. 2) All CF types have a companion Objective-C class, either lumped to _NSCFType with some additional memory allocated, or as their independent umbrella classes’ subclasses like _NSArrayI or _NSCFString. I would suggest never lumping things together in our code and never have a _NSCFType in the first place (@compatibility_alias _NSCFTypeRef NSObject;), and for each and every CF type create an Objective-C counterpart type, essentially make all our CF-like types TFB to some Objective-C type, public or not. 3) All polymorphic functions, namely CFHash(), CFDescription(), CFEqual(), CFGetTypeID() and more are handled in Objective-C using their respective NSObject properties NSObject.hash, NSObject.description and functions [NSObject isEqual:], [NSObject typeID] and more. 4) The “basic methods” documented for basic data types have some significance: the basic data type umbrella classes as well as their CF counterparts implement methods not on their basic methods list using those basic methods instead of any implementation detail, and the basic methods themselves call the counterparts when an instance of its counterpart is encountered - [NSArray objectAtIndex:] calls CFArrayGetValueAtIndex() if the underlying type is a real CFArrayRef (discovered by intentionally crashing [NSArray enumerateObjectsUsingBlock:].) 5) All those CF*Retain(), CF*Release() always end up calling CFRetain() and CFRelease() - we can just alias them (preferably using symbol re-export) to reduce code size. CF*GetTypeID() are used as implementations for CFGetTypeID() but we can alias them too as we implemented CFGetTypeID by going back to their Objective-C counterparts. The same applies to almost all types that have a *Ref type, especially CG, CA and AU, except NSZone and CFAllocatorRef. Those two, though, can also be TFB’d, and my example above depend on NSZone and CFAllocator being TFB pair. So since you mentioned CA, here is an example of CGPathRef using the trick: @interface _GSCGPath : NSObject <NSCopying> // Marking copyable CF types’ counterparts with NSCopying may be a good habit. The copyWithZone: method can be bridged over to CF*CreateCopy(). { // ivars } // … @end struct _CGPath { @defs(_GSCGPath); } CGMutablePathRef CGPathCreateMutable(CFAllocatorRef allocator) { _GSCGPath *path = [[_GSCGPath allocWithZone:allocator] initMutable]; // This is the trick return CFBridgingRetain(path); // ARC habits die hard, but still works } CGPathRef CGPathRetain(CGPathRef) __attribute__((alias(“CFRetain”))); void CGPathRelease(CGPathRef) __attribute__((alias(“CFRelease”))); In fact, given then location of functions, we can even do this if ARC in libobjc2 is mandated: CFTypeRef CFRetain(CFTypeRef) __attribute__((alias(“objc_retain”))); void CFRelease(CFTypeRef) __attribute__((alias(“objc_release”))); About how Apple implemented their CA it is unimportant indeed - their entire graphics stack is different. But as it is heavily CF-like code this TFB mechanism will affect it. Also since X11 is on its slow way out I would suggest write Opal on top of EGL as it is a graceful way of handling X11, Wayland and Mir at the same time without using a new “back” for the graphics stacks. The reason of suggesting direct EGL manipulation comes from the fact we may need SceneKit and SpriteKit down the road and those game-oriented frameworks will need direct OpenGL manipulation, and by doing this we can introduce our SpriteKit and SceneKit by inserting them between Opal and EGL, using Opal itself as a test suite. By the way, both Wayland and Mir drew inspiration from WindowServer as well as EGL from QuartzExtreme, at least to me (it wouldn’t be the first Linux community drew inspiration from Apple - I am looking at you, systemd, a launchd workalike.) If we end up writing our own Wayland-based compositor with this EGL-based graphics stack we can create something architecturally similar to OS X. Max > On Dec 6, 2015, at 03:49, Ivan Vučica <i...@vucica.net> wrote: > > 北宗, > > Your enthusiasm is commendable, but it is not important for GNUstep where > Cocoa's NSException symbol lives. As long as it is available when you link > with Foundation, the exact executable image in which it is distributed is > Cocoa's implementation detail. > > This was already discussed in previous instances where you outlined > implementation details of Cocoa which are not required for correct > functionality of GS. > > Similarly, Cocoa's Core Animation happens to be largely implemented in C++. > Does it matter that GNUstep's is implemented in Objective-C, or is it gaps in > functionality that are actually important? > > On Sat, Dec 5, 2015 at 6:08 PM 陈北宗 <xcvi...@gmail.com > <mailto:xcvi...@gmail.com>> wrote: > Testing for robustness of my Web development kit, and the default exception > handler caught this gem: > System Crash: NSException > > Name: NSInternalInconsistencyException > > Reason: [CGIAppDelegate application:handleContext:] > (/Users/……/Developer/CGIKit/CGIHello/CGIAppDelegate.m:44): This is just a > test, don't panic. > > User information: > > Key Value > (none) > Call stack: > > 0 CoreFoundation 0x00007fff8aed1ae2 > __exceptionPreprocess + 178 > 1 libobjc.A.dylib 0x00007fff99b8c73c > objc_exception_throw + 48 > 2 CoreFoundation 0x00007fff8aed198d +[NSException > raise:format:] + 205 > 3 CGIHello 0x0000000100002650 -[CGIAppDelegate > application:handleContext:] + 2640 > 4 CGIKit 0x000000010002706d > -[CGIApplication(CGIDelegatedMethods) handleContext:] + 93 > 5 CGIKit 0x000000010002000d -[CGIContext run] > + 109 > 6 Foundation 0x00007fff8a411d4b > __NSThreadPerformPerform + 279 > 7 CoreFoundation 0x00007fff8ade15c1 > __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 > 8 CoreFoundation 0x00007fff8add341c > __CFRunLoopDoSources0 + 556 > 9 CoreFoundation 0x00007fff8add293f __CFRunLoopRun + > 927 > 10 CoreFoundation 0x00007fff8add2338 > CFRunLoopRunSpecific + 296 > 11 Foundation 0x00007fff8a40fe61 > -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 270 > 12 CGIKit 0x000000010002679f -[CGIApplication > run] + 463 > 13 CGIKit 0x0000000100027238 CGIApplicationMain > + 248 > 14 CGIHello 0x0000000100001b6b main + 91 > 15 libdyld.dylib 0x00007fff98dac5ad start + 1 > > > So NSException is defined in CoreFoundation… Maybe I should generate more > crashes to probe OS X a bit... > _______________________________________________ > Gnustep-dev mailing list > Gnustep-dev@gnu.org <mailto:Gnustep-dev@gnu.org> > https://lists.gnu.org/mailman/listinfo/gnustep-dev > <https://lists.gnu.org/mailman/listinfo/gnustep-dev>
_______________________________________________ Gnustep-dev mailing list Gnustep-dev@gnu.org https://lists.gnu.org/mailman/listinfo/gnustep-dev