|
From: | 陈北宗 |
Subject: | Re: Intentionally crashed my Web development kit, got this gem. |
Date: | Sun, 6 Dec 2015 05:01:02 +0800 |
Ivan 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
|
[Prev in Thread] | Current Thread | [Next in Thread] |