Questions about ARC and manual allocation of class instances

A cool project, if one stretching Swift past what it currently supports. Let’s see: for #3, the language is definitely working against you. Swift assumes that a class instance does not move around—if it has, it’s a different instance. The weak sidetable is the most general form of that, but it’s not the only place; === and ObjectIdentifier, for example, are wrappers around comparing addresses. You’d also have to restrict your movable classes from having any Objective-C-compatible weak members, since ObjC weak does not use an indirection but instead registers the address of the weak reference itself with the runtime. And of course you’d have to not persist any manual pointers into the class storage, like what ManagedBuffer provides. To top it off, the sidetable isn’t just for weak, although I don’t know offhand what else would use the backreference to the class instance.

(I’m not actually sure how you’re moving objects around, but I can imagine something very basic like realloc on a slab and assuming you’re doing something more complicated than that.)

For #2, the destructor in the class value witness table should be running any manually-written deinitializer, releasing any stored properties with ARC (the compiler knows what stored properties a class has), and finally deallocating the object (free(self), conceptually). The order in which these things happen is a little different between pure Swift classes and Swift classes with Objective-C ancestors, but all three tasks have to get done. In your case, I guess you’d substitute the last memory allocation step with something else? But I’m not quite sure how you’d end up with the behavior you’re describing.

For #1, Swift does not exactly expose the entry point you need. Most of Swift’s initializers are “allocating” initializers, which include the allocation of memory as the implicit first step. Only designated initializers get “initialize-only” entry points, so they can be called from subclasses using super.init. These entry points will get optimized away if the class is non-open, because they’re a waste of code size if nothing will call them.

That said, there’s nothing special today about the Swift allocator (well, there wasn’t in 5.1), so if you could call the initializing entry point directly it should work for your placement-new, possibly with some additional minor setup to set the isa and refcount fields correctly. I’m not sure offhand what it would take to reference that entry point directly, though.

A terminology nitpick: in Swift documentation, instance refers to any value of a nominal type (struct, enum, or class), while object is specifically “class instance”.

6 Likes