Disabling ARC for custom literals

Is there a way to disable ARC for "custom" literals? For example:

class B {
let value: Bool
private init(_ b: Bool) { value = b }
public static let TRUE = B(true)
public static let FALSE = B(false)
}

If the objects referenced by TRUE and FALSE could be marked as permanent, then ARC operations could avoid the overheads of atomic reference counting.

There is such a mechanism, currently used only by the empty Array, Dictionary, and Set singletons, but it's not exposed in a useful way right now.

OK so does it make sense to make an evolution proposal?

I think it'd be reasonable to write up a pitch for an attribute or something. I don't know if it's a common enough / important enough need that it would be accepted, but it can't hurt to try if you've got the time and energy.

One caveat is that it won't work on anything that inherits from NSObject (more specifically anything that doesn't use Swift native refcounting).

Thinking further, I wonder if this could be done without any language changes, simply by noting:

class SomeClass {
static let myValue: MyType = ...
}

If MyType is a reference type, in the absence of "class GC" (easy, since we don't do GC), then myValue is clearly an immortal object. If the ARC runtime already supports marking certain objects as not requiring thread-safe reference counting (having some kind of "immortal flag"), then such marking could surely be easily applied to static reference-typed definitions using 'let'.

I see immortality is also discussed in Swift Performance, but it doesn't look to have gone any further.

3 Likes

Fwiw, if you wanna play around and see what performance gains you might find, this seems to do the trick (no guarantees though, I just dug through the stdlib code and took the first best thing I found):

@_silgen_name("_swift_stdlib_immortalize")
func _swift_stdlib_immortalize(_ p: UnsafeMutableRawPointer)

func immortalize(_ o: AnyObject) {
	withExtendedLifetime(o) { // not sure this is required
		_swift_stdlib_immortalize(Unmanaged.passUnretained(o).toOpaque())
	}
}
1 Like

Yup that looks right

Thanks very much, I'll check this out and report back later.

I gave this technique a try out, for a case actually with non-let-defined values, but rather an in-memory metadata structure that was underneath an ORM. (Rationale: the metadata is constant for the duration of the application process).

Result: 25% reduction in time taken to initialize objects (which needs to refer to the underlying metadata).

Will look at the let-constant application of the technique later.

Terms of Service

Privacy Policy

Cookie Policy