Mulle-objc: A New Objective-C Compiler and Runtime
mulle-objc.github.io
mulle-objc.github.io
https://github.com/Codeon-GmbH/mulle-clang
"The transformed methods will return objects that are autoreleased. Hence the name of the mode. The net effect is, that you have a mode that is ARC-like, yet understandable and much simpler."
This is like a halfway house between traditional Objective-C's "semi-manual" memory management, and the modern ARC (Automatic Reference Counting). Autorelease pools were a cornerstone of the traditional model: autoreleased objects will typically stick around until the end of the event loop cycle, which was a reasonable way to do garbage collection in mostly UI-centric Obj-C apps.
ARC replaced this model with static reference tracking in the compiler: instances are freed when the compiler knows that the last reference has gone out of scope. This is obviously more memory-efficient than the autorelease pool, and that was probably a big factor in Apple's decision to go with ARC (as the primary focus of Obj-C had shifted to iOS).
In summary, the Mulle compiler tries to combine the programmer ease-of-use of ARC with the simpler compiler/runtime implementation of traditional Obj-C memory management. The tradeoff is memory usage and incompatibility with some modern code that assumes an ARC compiler.
Here's a list of language features that the compiler will support:
https://www.mulle-kybernetik.com/weblog/2015/mulle_objc_pres...
Personally I agree with the author's positions in principle, but not entirely in practice. In particular, not supporting the property dot syntax will make it unnecessarily difficult to compile most Obj-C code written since about 2009. Same goes for blocks -- they're very integrated in Obj-C APIs by now, even though it does add substantial runtime complication.
> around until the end of the event loop cycle
They stick around until their reference count drops to zero. The -autorelease is turned into a -release when the containing autorelease pool is released, so you have full control over when that happens.
@autoreleasepool {
[[[NSObject alloc] init] autorelease];
}
The object is freed at the end of that block.Yes, there is a default autorelease pool for the event loop.
Another big factor was the failure of implementing a tracing GC.
It had even more corner cases than ARC, it was quite easy to make it crash given the underlying C semantics and developers mixing frameworks, not all of them GC enabled.
The good idea behind ARC is that just automates what framework developers were already manually doing with Cocoa.
"12. Trust the programmer, as a goal, is outdated in respect to the security and safety programming communities. While it should not be totally disregarded as a facet of the spirit of C, the C11 version of the C Standard should take into account that programmers need the ability to check their work."
All of these things simply help you 'check your work'. Bounds checking has been standard good practice for years now so its not a surprise they put that in the standard library. There is still no magic and its the programmer who has to put forward the effort to check for errors.
Not really, It has been removed from the standard library and made an optional Annex. A C11 compliant compiler is not required to provide them.
For me those "secure" functions are just as insecure as their cousins, because they still require C developers to track pointers and bounds separately.
The only thing they improve in regards to security is not forcing us to manually place a null character at the very end, in case the destinations are filled up. But the danger of passing the wrong length, origin or destination is still there.
If you have to deal with strings in C more then likely you have written a string interface with bounds checking. Its not clear if it needs to be standard so its good that its optional. Icc, gcc and clang support it so I would not hesitate to use it.
My point was that 'safety' in C is still more or less a process of training the programmer rather then a language feature. And that was and still is a design goal. But at least now you can point to the bounds checking functions and other new features as an example of how to get there.
I'm not going to argue whether C is safe. Or whether XYZ is safer then C. Thats way of topic.
What does this compiler do better/different than clang or gcc?
It isn't only written in Assembly, it is written in clever optimised Assembly fine tuned across several compiler releases, to minimise as much as possible the impact of dynamic dispatch.
With the NeXT/Apple runtime,
[object selector: arguments...]
is syntactic sugar for objc_msgSend(object, @selector(selector:), arguments)
With the GCC runtime, that's syntactic sugar for: IMP tmp = objc_msg_lookup(object, @selector(selector:));
tmp(object, @selector(selector:), arguments...)
No assembly necessary. I believe there are also compiler flags to assume the function won't be replaced behind your back so objc_msg_lookup can be hoisted out of a loop, etc.Lookup operates differently from the nominally tail-calling msgSend in that it cannot support transparent forwarding (where the receiver is switched to another object before dispatch.) Since objc_msgSend is given control over the final call, the destination can be swapped if necessary.
It's not possible[1] to implement objc_msgSend in plain (portable) C, as it needs to pass on an unknowable number of arguments without damaging the ones passed in registers, the stack frame, or the optional hidden return value pointer. Any methods attempting to do so using, say, naked functions and the method's type encoding will be more fragile than a perfect argument forwarding stub written in assembly.
[1]: __builtin_apply_args, __builtin_apply and __builtin_return (https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Constructing-Ca...) notwithstanding.
However, in the case of GCC's ObjC implementation, I don't see why it couldn't be implemented in GCC's dialect, thus obviating any need for assembly.
Pardon me while I reflect on (and lament) the fact that we're still stuck using such crude and ancient tools for systems programming...
id objc_msgSend(id object, id selector, ...) {
IMP tmp = objc_msg_lookup(object, selector);
return tmp(object, selector, ...);
}
(forgive me for any mistyping here, as I'm not an Obj-C programmer, and for the varargs shorthand, to keep things simple)? Especially given that GCC supports some extensions to C that could reduce the overhead a bit (tail-recursion elimination, for example), I don't see why such a function couldn't be implementable in (GCC) C.Would you be willing to enlighten me?
IMP tmp = objc_msg_lookup(object, selector);
goto *tmp;
but C can't handle that (and even with gcc computed gotos you need to preserve any argument registers and not screw up the stack).objc_msgSend has a variable number of arguments and no way to determine how many there are.
Example: when performing a context switch in a kernel, assembly is required since C abstracts away architecture-specific details necessary to swap out the register set, swap the page directory pointer, etc.
Traditionally objc_msgSend is in assembly because it doesn't know how many and what types the message parameters are. So it can't portably preserve them while it does the computations to find out where to send the message to.
This project's alternative obj_msgSend always passes parameters in a structure. That helps, because now you know that all message calls have three parameters; the destination object, the selector, and the parameter block.
However... they don't always pass the return value in the message block; instead it coerces any integer types to void* and returns them in the usual way, only using an extra field in the parameter block for those values which aren't coerceable to void.
This does make me kinda unhappy. I don't think* it'll be a problem, but... it's definitely pushing the limits of what C allows; round-tripping arbitrary integers through pointers is one of those things that's not technically allowed but all real-world compilers support, so, um. I'd much rather they just pass everything through the parameter block.
But yeah, it's a decent enough idea, which simplifies things considerably at not a lot of performance hit. I'm kind of surprised that ObjC doesn't already do that.
My main disappointment is that this is a clang variant and not a standalone preprocessor. Since poc died there isn't a working ObjC preprocessor, which means if you want to use ObjC you're limited to gcc or clang. An ObjC->C preprocessor would solve that.
> About mulle-objc
> When I wrote the Optimizing Objective-C Article Series, Objective-C had pretty much weathered its first hostile obsolesence attempt by Java. Now a decade later, it looks like the time has come, that I have to save Objective-C - at least for myself.
https://developer.apple.com/swift/
"Swift is a successor to both the C and Objective-C languages."
Of course this is something that will not happen overnight and the language is still has some corners to fine tune.
Objective-C improved a lot since the NeXT days, but the C part is still there, regardless of the safety improvements it got on top.
Also since Swift has been announced, the only language improvements Objective-C got were related to improving the interoperability between both languages.
So I imagine some devs that are passionate about Objective-C might not like the day Objective-C joins Carbon and MPW.
I surely did not like when that hapenned to Object Pascal, Mac Common Lisp or Dylan.
The difference here being that Objective-C is unsafe, and its relatively low level of abstraction in comparison to the aforementioned languages, make it less than ideal as an applications language, especially compared to those languages. As you say, "the C part is still there".
I'm with you. I want to be using safer languages, both because there is inherent value in safety, and because safety tends to come with more and better tools for building abstractions.
While I lament the loss of Obj-Pas, MCL, and Dylan, I whole-heartedly welcome the arrival of Swift. Even if it means nothing to me directly anymore as an apostate of the Apple platform, I hope that it will fuel a push for better, safer languages across the board. In many ways, I think technologies like MCL and Dylan were victims of being ahead of their time.
These are exciting times to live in as a programming language geek/snob, as the lessons of the past are finally rediscovered, absorbed, and made practical, popular, and cool :)