A Decent ObjectC Bridge
Last updated at 3:35 pm UTC on 14 January 2006
[Goran announces that he’s working on Gtk. This prompts a lot of thinking.]
Goran Krampe February 06, 2004 [Regarding Todd’s suggestion to do it with http://wxwindows.org/ so the Mac people could play too.] I know about wxWindows and many other alternatives too. I took Gtk for several reasons:
And last but not least - if we get this to work properly - there is nothing stopping us from trying other kits too like wx. Quite a few problems should be common in all this.
- 1. It is C-focused. So are Squeak plugins and the make structure etc in Squeak. AFAIK wxWin is C++, not sure if I want to go there... :)
- 2. I have heard here and there that wx is slow and also suffers a bit from the LCD problems (is that the right name? LeastCommon Denominator?). But that is just hearsay. Not sure about how wx evolves nowadays, is it live and kicking like Gtk?
- 3. I like Gtk. :) It looks very nice, seems to have a lot of momentum and is AFAIK very themeable.
- 4. The license, LGPL.
- 5. Gtk is getting more and more portable.
Avi Bryant February 04, 2004: But, really, we should just do a decent ObjC bridge one of these days...
[“If there is actual interest, I'd be happy to restart work on that... What do you find indecent about the current one? It really isn't all that pretty, but tends to do everything you can easily do without overcoming Squeak's not being re-entrant.’]
Avi Bryant I'm definitely interested... in fact I'm sitting here right now with VMMaker open thinking about starting to work on one. The main things I don't like about the current one:
- It doesn't seem to work with recent VMs. This is probably easily fixed, but it would be a good start to have a prebuilt 3.6 VM with a working ObjectiveCPlugin.
- It doesn't allow message sends from ObjC to Squeak objects. This is what you're talking about with "not re-entrant", but to me that's a very necessary part (the only point to me of an ObjC bridge is to build Cocoa UIs, and that requires being able to get callbacks and delegation messages AFAIK). This will require some thread and semaphore stuff, but it's certainly doable.
- Also nice would be compatibility methods for easy bridging between String/NSString, Array/NSArray, OrderedCollection/NSMutableArray, Dictionary/NSMutableDictionary, etc.
Andreas Raab [Regarding Squeak not being re-entrant] Actually, it's not all that hard to support callbacks. Back, when I wrote the FFI I considered supporting callbacks but the major reason against it was not the complexity but time constraints (the project we were working on really needed it). If you wanted to do callbacks all you need to keep in mind that the only, the exclusive place where a regular (not interrupt) callback can occur is during a primitive call (obviously - all other methods only run bytecodes and send further messages). Because of this, the entire internal interpreter state is perfectly externalized so that it is quite doable do simply "call back" into interpret(). So what you'd have to do is essentially:
This should work just nicely - a bit of trickery is certainly needed but not very much. Then, on the Squeak side what you do is:
- define a number of callback stubs (could be a fixed number) which
- remember the stack pointer for later use (to get the arguments)
- mark itself as the "top-most C frame" being used
- signal the callback semaphore associated with the stub
- mark the execution point by a setjmp()
- call interpret()
- (after return through longjmp()) restore the prior top-most C frame
- returns to caller
- define the "return from callback" primitive so that it
- horribly barfs if it's not the top-most callback (this would mean you try to return through another C stack frame)
- simply leaves interpret() by a longjmp to the callback stub
That's about it. If you want to get fancy you can add some stuff in the Squeak process that serializes the returns appropriately so that callbacks invoked from different processes work appropriately. But really, supporting callbacks isn't all THAT hard ;-)
- provide a Squeak process for each callback which
- requests a new callback stub
- sits waiting on the callback semaphore
- when it wakes up requests the stack pointer
- unpacks the arguments from the stack (via a few FFI primitives)
- runs the associate callback block
- returns via return from callback primitive
Goran Krampe: [Regarding Andreas’s idea about “a decent ObjC” interface”] Well, I only understood half of what you wrote... :) But anyway, for my little GtkPlugin I am sticking to STTCPW for now. So I will simply look at the other plugins and use some Semaphore etc to do the "callbacks".
Btw, I also actually managed to drive the Gtk loop from within Squeak. So no need to spawn a thread in the plugin just yet. Currently a background Process in Squeak that calls the GtkPlugin every 10ms (or whatever) seems to work good enough to move on.
Next step is of course the callback/signal/event-stuff. I have a plan, but will need to look into more pluginish stuff before getting something that works. Need to figure out how to handle the Gtkish C structs like the GdkEvent, GtkWidget etc. IIRC Andreas has whipped up some classes for those kind of things... ExternalStructure I guess.
Marcel Weiher February 06, 2004
OK, interest in CocoaSqueak seemed to have pretty much evaporated, so there didn't seem much point in making new releases.
[Regarding “the only point to me of an ObjC bridge is to build Cocoa UIs, and that requires being able to get callbacks and delegation messages”] Yup, precisely. Well, I can also see other uses, but that's a major part of it.
[Regarding “This will require some thread and semaphore stuff, but it's certainly doable.”] Yes, that is also the way I had seen:
The proxies representing Squeak objects on the Objective-C side have to refer to them via the (an?) external object table, in order to properly handle object-pointers moving around during GC.
- have (at least) two threads.
- when Squeak calls out
- save the message parameters
- pass on to second thread that sends the Objective-C message
- return into Squeak
- suspend the Squeak-internal process making the call (on a semaphore)
- when the Objective-C message returns, that thread signals the semaphore
- the Squeak process awakes and picks up the result
- for call-in to squeak, either
- (ab-)use the even mechanism
- or use a separate semaphore and pick up the necessary arguments, dispatch, return etc.
Of course, Andreas has raised an intriguing possibility of doing this without separate threads.
[Agree that “also nice would be compatibility methods”] Yes, and what would be really nice if the runtimes could just integrate...
Avi Bryant February 06, 2004
[Responding to Marcel] Why can't the ObjC plugin (be made to) work with the UNIX VM?
[“what would be really nice if the runtimes could just integrate...]Well, yes and no. I need continuations, so having Squeak use the C stack would be a no-go...
[Why can't the ObjC plugin (be made to) work with the unix VM?] Why should it? But more seriously, CocoaSqueak has the distinct advantage of actually being integrated with Cocoa, running a normal Cocoa event loop from a normal NSApplication, has normal NSViews etc. Grafting that onto the Unix VM, which has quite different notions of interaction, seems rather tricky to me. I also recall Ian mentioning having tried something with Objective-C and it not working. I presume he lost interest after that, but haven't kept track.
OK, so let's do it! Getting a 3.6 CocoaSqueak built shouldn't be too much of a problem, and developing the bridge can actually proceed in parallel.
Avi Bryant February 06, 2004
[Why should it?] Because maintaining two VMs for Mac OS X is enough duplicated effort already. Maintaining three is just silly. And the UNIX VM, AFAICT, does have a normal NSApplication event loop. Perhaps you haven't looked at it recently? [Marcel, agrees.] But it's not a big deal. If it's easier to build a 3.6 CocoaSqueak VM than an ObjC-enabled UNIX VM, fine by me. [Marcel, agrees to UNIX.]
Cees de Groot February 07, 2004 4:31 AM
[Aaron J Reichow said: “SWIG doesn't support Squeak”] Wouldn't that be a grand idea? Haven't looked at SWIG for ages, but this certainly would be doable and SWIG support that generates Squeak plugins plus some simple Smalltalk glue code would give us a lot of leverage, apart from UI's...