Class layout

(Carlo Kok) #1

As a follow up to

Is there any info on how to layout my classes if I were to emit classes that descent from or implement protocols defined in Swift?

(Ben Cohen) #2

What is it you're trying to do?

(Carlo Kok) #3

Trying to make my compiler be able to fully interact with swift modules like it already can for objc.

1 Like
(marc hoffman) #4

To elaborate, we work on, a multi-language multi-platform compiler that, among other platforms, supports building apps for iOS, currently on the Objective-C Runtime ABI level, using C#, Java, Oxygene, Go (and also Swift).

Now that Apple Swift has ABI Stability and (soon) Module Stability, we want to extend the compiler to also be able to participate at the Swift ABI level; more specifically, we'd like to be able to (a) compile/link against and use types from Swift-created libraries and frameworks and (b) generate libraries and frameworks (and executables) that define and expose Swift API-compatible types and can then in theory be referenced from Swift as if they were created by "native" Apple Swift.

(John McCall) #5

We don't have detailed documentation for many aspects of the ABI yet, sorry. If you'd like that work on that, that would be great, and we'd be happy to provide guidance.

Generating Swift libraries should be straightforward with the right documentation and once we have stable (textual) module interface descriptions.

1 Like
(marc hoffman) #6

That'd be great and any pointers would be much appreciated, yes. thanx!

(John McCall) #7

Okay. I would probably start with struct layout.

(Carlo Kok) #8

Any chance of some hints on where to look (for this + the stuff in the original thread)?

(John McCall) #9

The Swift 5 struct layout algorithm is to lay out the stored properties using naive, in-order C layout. Class layout is the same, except the first field is either the base class (recursively) or a fixed header (a pointer plus 64 unaligned bits). The only significant difference from C, besides the lack of bit-fields, is that we distinguish size vs. stride and so don't round a struct (or base class's) size up to the maximum alignment of any stored property. But you can also look at lib/IRGen/StructLayout.cpp in the source code.

The ABI rule for tuples always uses the Swift 5 layout algorithm, and that is a permanent guarantee. For structs, officially the layout algorithm is determined by an algorithm that's somehow parameterized by the struct and the build settings; however, right now that algorithm is always "use the Swift 5 layout algorithm".

1 Like
SE-0260: Library Evolution for Stable ABIs
(Carlo Kok) #10

Yet that's simple enough. My research shows that when targetting Darwin:

  • CMa (type accessor) returns a singleton copy of *CMn (swift type info, it's called the nominal type descriptor by the demangler)
  • allocation goes through the the ctor helper (CycfC), which calls swift_allocObject with the result of above and calls the real ctor Cycfc.
  • swift_retain and swift_release are used to retain things

When targetting Objc the allocation goes a bit the same except:

  • the type accessor uses the swift_getInitializedObjCClass instead and uses the full type metadata (CMf) from field 2 on (where the Objc header starts)
  • Allocates through objc_allocWithZone and uses objc_retain/release instead ; somehow at runtime I end up with something called a "Bridged object" where the top bits are set in the isa pointer referring to the type info passed to swift_getInitializedObjCClass

My questions are:

  • Why all the different type infos and which one is used for what?
  • How do I do calls if I don't know for sure if I have the full metadata or the nominal type description?
  • Which one will be used at runtime (ie what does isa point to, the full type metadata, or the nominal one)?

(It could be I missed some steps, it's quite hard to read this code)

(John McCall) #11

There's a TypeMetadata.rst which explains the basics of that. You're confusing type descriptors and type metadata, which are different.