DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Frameworks
  4. Swift 5.0 Class Internals

Swift 5.0 Class Internals

We look at how the implementation of the core of the object system for class implementation is the same in Swift as in Objective-C.

Christopher Lamb user avatar by
Christopher Lamb
CORE ·
Apr. 25, 19 · Analysis
Like (2)
Save
Tweet
Share
9.06K Views

Join the DZone community and get the full member experience.

Join For Free

We have seen a few things so far that are surprising with Swift. We also looked at some aspects of class implementations in Swift 4. Now that Swift 5 has been released, with a stable ABI, let's see how things compare to Objective-C, digging into internal data structures like we did in Objective-C.

Objective-C classes are defined elegantly, using C data structures that are relatively easy to follow and understand. A class definition is associated with a metaclass (to allow the class to be treated as a data object), as well as a group of functions treated as either class or member methods. Classes are associated with supported protocols and superclasses as well. We haven't specifically looked at protocol support nor at how methods are dynamically located, or how errors are handled. We'll look at all of these and start to filter conclusions through a security perspective.

The point of all this is to not only understand Objective-C internals, but to understand how Swift does similar things, so we can compare them and understand the real advantages and disadvantages of the two systems — we're not really looking at the languages, but rather how they're implemented internally so they can be executed.

Previously, the simple program we compiled was orders of magnitude larger than its Objective-C analog, for one thing, and it contains many, many more statically linked functions. This could very well be an artifact of how I compiled the program, but I used project defaults in Xcode with each example, so I don't feel that bad about it. What I have discovered though is the latest version of Xcode generates a MUCH smaller executable. In the interest of keeping things as easy as possible and preserving my reputation as lazy, we're going to use the smaller executable. I've looked at the Objective-C version compiled with the latest Xcode too, and it really hasn't changed, for what that's worth. But that's not too surprising really, Objective-C's been around a while. Swift really hasn't yet.

Here's our Swift program, so you don't need to re-reference:

import Foundation

class Printer {

  var str_to_print: String

  init() {
  str_to_print = ""
  }

  func printMsg() {
print(str_to_print)
  }

  func printString(message: String) {
  str_to_print = message
  printMsg()
  }

}

let printer = Printer()
printer.printString(message: "Hello World!")

I have to admit, I like the Objective-C syntax more. Could be because I (1) like C, and (2) don't like Java. Plus message passing syntax is cool.

Anyway, this yields this main() entry point on compilation:

_main:
  push rbp
  mov rbp, rsp
  push r13
  sub rsp, 0x38
  xor eax, eax
  mov ecx, eax 
  mov dword [rbp+var_C], edi
  mov rdi, rcx 
  mov qword [rbp+var_18], rsi
  call _$s9swift_cmd7PrinterCMa 
  mov r13, rax
  mov qword [rbp+var_20], rdx
  call _$s9swift_cmd7PrinterCACycfC
  mov r8d, 0xc
  mov esi, r8d
  mov qword [_$s9swift_cmd7printerAA7PrinterCvp], rax 
  mov rax, qword [_$s9swift_cmd7printerAA7PrinterCvp]
  lea rdi, qword [aHelloWorld] ; "Hello World!"
  mov edx, 0x1
  mov qword [rbp+var_28], rax
  call imp___stubs__$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC 
  mov rcx, qword [rbp+var_28]
  mov rsi, qword [rcx]
  mov rdi, rax
  mov qword [rbp+var_30], rsi
  mov rsi, rdx
  mov r13, rcx
  mov rax, qword [rbp+var_30]
  mov qword [rbp+var_38], rdx
  call qword [rax+0x80]
  mov rdi, qword [rbp+var_38]
  call imp___stubs__swift_bridgeObjectRelease 
  xor eax, eax
  add rsp, 0x38
  pop r13
  pop rbp
  ret

Okay, so message passing is gone, and the name decorating has changed. Here, we have straightforward functional semantics. What a shame. Anyway, let's try to track down how the class is defined. If we trace through the calls, we take a look at the first and see this disassembly (unfortunately, swift-demangle isn't working on these Swift 5 mangled methods yet, so we need to trace through manually):

_$s9swift_cmd7PrinterCMa:
  00000001000018d0 push rbp
  00000001000018d1 mov rbp, rsp
  00000001000018d4 sub rsp, 0x10
  00000001000018d8 mov rax, qword [_$s9swift_cmd7PrinterCML]
  00000001000018df cmp rax, 0x0
  00000001000018e3 mov qword [rbp+var_8], rax
  00000001000018e7 jne loc_100001903
  ----------------
  00000001000018e9 lea rdi, qword [_$s9swift_cmd7PrinterCN]
  00000001000018f0 call imp___stubs__swift_getInitializedObjCClass 
  00000001000018f5 mov rdi, rax
  00000001000018f8 mov qword [_$s9swift_cmd7PrinterCML], rax 
  00000001000018ff mov qword [rbp+var_8], rdi
  ----------------
  loc_100001903:
  0000000100001903 mov rax, qword [rbp+var_8] 
  0000000100001907 xor ecx, ecx
  0000000100001909 mov edx, ecx
  000000010000190b add rsp, 0x10
  000000010000190f pop rbp
  0000000100001910 ret

I've included addresses in this disassembly as we do have a jump. But if we examine what _$s9swift_cmd7PrinterCN points to, we find this:

_$s9swift_cmd7PrinterCN:
  struct __objc_class {
    _$s9swift_cmd7PrinterCMm, // metaclass
    _OBJC_CLASS_$__TtCs12_SwiftObject, // superclass
    __objc_empty_cache, // cache
    0x0, // vtable
    __objc_class__TtC9swift_cmd7Printer_data+1 // data
  }

Well, there we go! Some things from Objective-C are reused in Swift after all! And if we look at the metaclass, we see this:

_$s9swift_cmd7PrinterCMm:
  struct __objc_class {
    _OBJC_METACLASS_$__TtCs12_SwiftObject, // metaclass
    _OBJC_METACLASS_$__TtCs12_SwiftObject, // superclass
    __objc_empty_cache, // cache
    0x0, // vtable
    __objc_metaclass__TtC9swift_cmd7Printer_data // data
  }

Exactly the same design that Objective-C uses, even using some of the same data structures (e.g. __objc_empty_cache).

This means that the underlying class implementations between Objective-C and Swift are the same! Method call semantics may have changed (e.g. no more message passing), but the implementation of the core of the object system is the same in Swift as in Objective-C.

Swift (programming language) Objective C

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Handling Virtual Threads
  • Handling Automatic ID Generation in PostgreSQL With Node.js and Sequelize
  • The Enterprise, the Database, the Problem, and the Solution
  • Integration: Data, Security, Challenges, and Best Solutions

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: