There haven't been any updates here for ages, so I first wanted to reassure everyone that we're not dead. I've been focussing a bit more on clang and the GNUstep Objective-C runtime than on Étoilé recently, in the run up to the LLVM 2.9 release. The majority of this has just been tidying and fixing some bugs in some corner cases.
I've also tidied up and simplified the GNU runtime code in clang. This doesn't impact the functionality (although the code is now simpler, so should be a tiny bit faster, although I doubt that the difference is noticeable), but it should make it easier for other people to get involved. I've also refactored some of the code so that we are using the same code paths as Apple, which means that any bugs are more likely to be found and fixed. The exception handling code, in particular, has gone from being about 300 lines of code specific to the GNU runtimes to being about half a dozen, calling a generic implementation that we share with the Apple Modern runtime.
Clang 2.9 And Objective-C++
Exception handling, by the way, is something that's been reworked in clang 2.9 and the upcoming libobjc2 release. We now have proper interoperability with Objective-C++. This means that:
- C++ and Objective-C exceptions can correctly propagate through each others' stack frames.
catchstatements can catch Objective-C objects thrown with
@catchstatements can now catch Objective-C objects thrown with
This is semantically equivalent to the Apple unified exception model, and does not break the ABI - existing C++ and Objective-C code will still work when linked with Objective-C++ code compiled with this model. To enable this, you must specify
-fobjc-nonfragile-abi when compiling Objective-C++, or you will get the old GCC-compatible (i.e. completely broken in most cases) mode.
That's not really what I wanted to talk about today though. One thing that we've talked about a few times over the past few years is adding something to GNUstep that sends PostScript-like commands to a browser, to be drawn in a canvas tag, and gets events back.
The GTK guys have now added a similar shim, and we still haven't got around to it. Part of the reason why not, is that I'm still not convinced that it's a good idea (in spite of the fact that it was my idea to start with).
To understand my objection, it's worth going back almost three decades, to a time when different UNIX vendors had their own windowing systems. Two of the competing systems at the time were the X Windowing System, from MIT, and NeWS, from Sun. Both used a client-server abstraction, where applications communicated with a display server.
In the case of X, this communication was very simple. The clients sent drawing commands, and the server sent events, like mouse clicks or keyboard button presses. With NeWS, the client sent PostScript programs, which handled drawing and low-level event handling.
To understand the difference, compare how a button would be implemented in the two approaches. With X, the client would send commands to draw the button to the server. When the user clicked on the button, the server sent a message to the client and the client sent a reply including instruction for drawing a pressed button.
In the NeWS model, the client sent a PostScript program representing a button. This drew a button and registered then waited for events. When the user clicked on the button, this program drew a pressed button and sent a 'button pressed' message to the server.
On a single machine, or even a local network, there isn't much difference between these two models. There becomes a difference, however, when you start using larger networks, such as the Internet.
When I'm using a remote machine over the Internet, it's not uncommon to get round trip times of 200ms or more. This means, with the X model, and assuming an infinitely fast server, it takes 200ms between clicking on the button and seeing the effect. Not a huge amount of time, but a noticeable lag. This is even worse on mobile networks: with GPRS, 2 second round trip times are not uncommon.
In contrast, the NeWS model meant that the response was always immediate. The view objects ran on the local machine, only the models ran on the server. Network latency was largely hidden from the end user. This is apparent in things like tree views: in the NeWS model, you only need to go to the server if the view is informed that new items have been added to the model. You can always expand and collapse tree nodes on the local machine. With the X model, every click-redraw cycle needs to go via the network.
Unfortunately, streaming canvas drawing commands brings us straight back to the X11 model. It has the advantage of being simple (we estimated it would be under 5000 lines of code to add this support to GNUstep), but it's not very sensible.
One of the really nice things about clang is that it is modular. We're using it as a compiler front end, generating LLVM bitcode, which LLVM then compiles to native code. We're also using it for syntax highlighting and code indexing. The clang abstract syntax tree (AST) is exposed via a plugin interface, so it's easy to use clang for other things.
To give a quick example of what works already, here's one of my test cases:
int *array = malloc(1024); float *alias; alias = (float*)array; alias = 1; array = alias; ((id*)array) = [NSObject new]; jsalert(sizeof(array)); jsalert(array); jsalert(array); jsalert(array); [((id*)alias) alert];
jsalert() function and the
alert() function to pop up a dialog, for testing whether the code actually worked. This example shows several features of the compiler:
- Aliasing memory allocations via pointer
- Storing and retrieving object pointers in memory of a different type
- Sending messages to Objective-C objects (and classes)
The core of the C language works - including things like arrays of structures, and structures containing unions containing pointers - and so does the core of Objective-C.
The biggest omission, which will probably never be fixed, is integer-to-pointer casts. You can cast pointers to integers, and you can do arithmetic on pointers, but if you try to dereference a pointer that was created by casting from an integer then you will get a run-time error. On the plus side, you do get array bounds checking and full garbage collection for free...