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

Reply via email to