Skip to content

Commit 616a7fd

Browse files
authored
Merge pull request swiftlang#68695 from kubamracek/embedded-swift-runtime-test
[embedded] Add a test showcasing a small runtime handling refcounting and class allocations written in embedded Swift
2 parents 97937c5 + e82929f commit 616a7fd

File tree

4 files changed

+145
-2
lines changed

4 files changed

+145
-2
lines changed

stdlib/public/core/ContiguousArrayBuffer.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ internal final class __EmptyArrayStorage
6363
}
6464
}
6565

66+
#if $Embedded
67+
public var _swiftEmptyArrayStorage: (Int, Int, Int, Int) =
68+
(/*isa*/0, /*refcount*/-1, /*count*/0, /*flags*/1)
69+
#endif
70+
6671
/// The empty array prototype. We use the same object for all empty
6772
/// `[Native]Array<Element>`s.
6873
@inlinable

test/embedded/Inputs/tiny-runtime-dummy-refcounting.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
#include <stdlib.h>
44
#include <stdbool.h>
55

6-
size_t _swiftEmptyArrayStorage[] = { /*isa*/0, /*refcount*/-1, /*count*/0, /*flags*/1 };
7-
86
typedef struct ClassMetadata ClassMetadata;
97
typedef struct HeapObject HeapObject;
108

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
let _swift_MinAllocationAlignment: UInt = 16
2+
3+
@_silgen_name("posix_memalign")
4+
func posix_memalign(_: UnsafeMutablePointer<UnsafeMutableRawPointer?>, _: UInt, _: UInt) -> CInt
5+
6+
@_silgen_name("free")
7+
func free(_: UnsafeMutableRawPointer?)
8+
9+
func alignedAlloc(size: UInt, alignment: UInt) -> UnsafeMutableRawPointer? {
10+
let alignment = max(alignment, UInt(MemoryLayout<UnsafeRawPointer>.size))
11+
var r: UnsafeMutableRawPointer? = nil
12+
_ = posix_memalign(&r, alignment, size)
13+
return r
14+
}
15+
16+
/// Public APIs
17+
// void *swift_slowAlloc(size_t size, size_t alignMask);
18+
@_cdecl("swift_slowAlloc")
19+
public func swift_slowAlloc(_ size: UInt, _ alignMask: UInt) -> UnsafeMutableRawPointer? {
20+
let alignment: UInt
21+
if alignMask == UInt.max {
22+
alignment = _swift_MinAllocationAlignment
23+
} else {
24+
alignment = alignMask + 1
25+
}
26+
return alignedAlloc(size: size, alignment: alignment)
27+
}
28+
29+
// void swift_slowDealloc(void *ptr, size_t bytes, size_t alignMask);
30+
@_cdecl("swift_slowDealloc")
31+
public func swift_slowDealloc(_ ptr: UnsafeMutableRawPointer?, _ size: UInt, _ alignMask: UInt) {
32+
free(ptr)
33+
}
34+
35+
@_silgen_name("swift_allocObject")
36+
public func swift_allocObject(metadata: UnsafeMutableRawPointer, requiredSize: UInt, requiredAlignmentMask: UInt) -> UnsafeMutablePointer<HeapObject> {
37+
let p = swift_slowAlloc(requiredSize, requiredAlignmentMask)!
38+
let object = p.assumingMemoryBound(to: HeapObject.self)
39+
object.pointee.metadata = metadata
40+
object.pointee.refcount = 1
41+
return object
42+
}
43+
44+
@_silgen_name("swift_deallocClassInstance")
45+
public func swift_deallocClassInstance(object: UnsafeMutablePointer<HeapObject>, allocatedSize: UInt, allocatedAlignMask: UInt) {
46+
free(object)
47+
}
48+
49+
@_silgen_name("swift_initStackObject")
50+
public func swift_initStackObject(metadata: UnsafeMutableRawPointer, object: UnsafeMutablePointer<HeapObject>) -> UnsafeMutablePointer<HeapObject> {
51+
object.pointee.metadata = metadata
52+
object.pointee.refcount = -1
53+
return object
54+
}
55+
56+
@_silgen_name("swift_isUniquelyReferenced_nonNull_native")
57+
public func swift_isUniquelyReferenced_nonNull_native(object: UnsafeMutablePointer<HeapObject>) -> Bool {
58+
return object.pointee.refcount == 1
59+
}
60+
61+
public struct HeapObject {
62+
var metadata: UnsafeMutableRawPointer
63+
var refcount: Int
64+
}
65+
66+
@_silgen_name("swift_retain")
67+
public func swift_retain(object: UnsafeMutablePointer<HeapObject>) -> UnsafeMutablePointer<HeapObject> {
68+
if object.pointee.refcount == -1 { return object }
69+
object.pointee.refcount += 1
70+
return object
71+
}
72+
73+
@_silgen_name("swift_release")
74+
public func swift_release(object: UnsafeMutablePointer<HeapObject>) {
75+
if object.pointee.refcount == -1 { return }
76+
object.pointee.refcount -= 1
77+
if object.pointee.refcount == 0 {
78+
free(object)
79+
}
80+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend %s %S/Inputs/tiny-runtime-dummy-refcounting.swift -enable-experimental-feature Embedded -c -o %t/main.o
3+
// RUN: %target-clang -x c -c %S/Inputs/print.c -o %t/print.o
4+
// RUN: %target-clang %t/main.o %t/print.o -o %t/a.out -dead_strip
5+
// RUN: %target-run %t/a.out | %FileCheck %s
6+
7+
// REQUIRES: executable_test
8+
// REQUIRES: optimized_stdlib
9+
// REQUIRES: VENDOR=apple
10+
// REQUIRES: OS=macosx
11+
12+
@_silgen_name("putchar")
13+
func putchar(_: UInt8)
14+
15+
public func print(_ s: StaticString, terminator: StaticString = "\n") {
16+
var p = s.utf8Start
17+
while p.pointee != 0 {
18+
putchar(p.pointee)
19+
p += 1
20+
}
21+
p = terminator.utf8Start
22+
while p.pointee != 0 {
23+
putchar(p.pointee)
24+
p += 1
25+
}
26+
}
27+
28+
@_silgen_name("print_long")
29+
func print_long(_: Int)
30+
31+
public func print(_ n: Int, terminator: StaticString = "\n") {
32+
print_long(n)
33+
print("", terminator: terminator)
34+
}
35+
36+
func print(_ array: [Int]) {
37+
print("[", terminator: "")
38+
for i in 0 ..< array.count {
39+
print_long(array[i])
40+
if i != array.count - 1 { print(", ", terminator: "") }
41+
}
42+
print("]")
43+
}
44+
45+
func test() {
46+
var a = [1, 2, 3]
47+
a.append(8)
48+
a.append(contentsOf: [5, 4])
49+
let b = a.sorted()
50+
var c = b
51+
c = c.reversed().filter { $0 % 2 == 0 }
52+
print(c) // CHECK: [8, 4, 2]
53+
}
54+
55+
@main
56+
struct Main {
57+
static func main() {
58+
test()
59+
}
60+
}

0 commit comments

Comments
 (0)