File: CanonicalDeallocation.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (117 lines) | stat: -rw-r--r-- 5,192 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/// A type that provides a deallocation operation for WIT values.
public protocol CanonicalDeallocation {
    /// A type of a core value and a type of a WIT value.
    associatedtype Operand

    /// A type of a pointer representation.
    associatedtype Pointer

    /// Deallocates a WIT string value.
    ///
    /// - Parameters:
    ///   - pointer: A pointer that contains the byte representation of the string.
    ///   - length: A number of bytes in the string.
    func deallocateString(pointer: Operand, length: Operand)

    /// Deallocates a WIT list value.
    ///
    /// - Parameters:
    ///   - pointer: A pointer that contains the byte representation of the list elements.
    ///   - length: A number of elements in the list.
    ///   - element: A type of the list elements.
    ///   - deallocateElement: A closure that deallocates an element from the given pointer.
    func deallocateList(
        pointer: Operand, length: Operand, element: WITType,
        deallocateElement: (Pointer) throws -> Void
    ) throws

    /// Deallocates a WIT variant value.
    ///
    /// - Parameters:
    ///   - discriminant: An lifted integer value that represents a discriminant of the variant.
    ///   - cases: A list of types of the variant cases.
    ///   - deallocatePayload: A closure that deallocates a payload of the variant case at the given index.
    func deallocateVariantLike(
        discriminant: Operand, cases: [WITType?],
        deallocatePayload: (Int) throws -> Void
    ) throws
}

extension CanonicalABI {
    /// Performs a deallocation operation for the given WIT value at the given pointer.
    /// It recursively deallocates all the nested values.
    public static func deallocate<Deallocation: CanonicalDeallocation, Loading: CanonicalLoading>(
        type: WITType,
        pointer: Loading.Pointer,
        deallocation: Deallocation,
        loading: Loading
    ) throws -> Bool where Deallocation.Operand == Loading.Operand, Deallocation.Pointer == Loading.Pointer {
        func deallocateRecordLike(fields: [WITType]) throws -> Bool {
            var needsDeallocation = false
            for (fieldType, offset) in fieldOffsets(fields: fields) {
                let result = try deallocate(
                    type: fieldType,
                    pointer: pointer.advanced(by: Deallocation.Pointer.Stride(exactly: offset)!),
                    deallocation: deallocation, loading: loading
                )
                needsDeallocation = needsDeallocation || result
            }
            return needsDeallocation
        }

        func deallocateVariantLike(cases: [WITType?]) throws -> Bool {
            let discriminant = loadVariantDiscriminant(pointer: pointer, numberOfCases: cases.count, loading: loading)
            let payloadOffset = CanonicalABI.payloadOffset(cases: cases)
            let payloadPtr = pointer.advanced(by: .init(exactly: payloadOffset)!)
            var needsDeallocation = false
            try deallocation.deallocateVariantLike(
                discriminant: discriminant, cases: cases,
                deallocatePayload: { caseIndex in
                    guard let variantCase = cases[caseIndex] else { return }
                    let result = try deallocate(
                        type: variantCase, pointer: payloadPtr,
                        deallocation: deallocation, loading: loading
                    )
                    needsDeallocation = needsDeallocation || result
                }
            )
            return needsDeallocation
        }

        switch type {
        case .bool, .u8, .u16, .u32, .u64,
            .s8, .s16, .s32, .s64,
            .float32, .float64, .char:
            return false
        case .string:
            let (buffer, length) = loadList(loading: loading, pointer: pointer)
            deallocation.deallocateString(pointer: buffer, length: length)
            return true
        case .list(let element):
            let (buffer, length) = loadList(loading: loading, pointer: pointer)
            try deallocation.deallocateList(
                pointer: buffer, length: length, element: element,
                deallocateElement: { pointer in
                    _ = try deallocate(type: element, pointer: pointer, deallocation: deallocation, loading: loading)
                }
            )
            return true
        case .handleOwn, .handleBorrow:
            fatalError("TODO: resource type is not supported yet")
        case .tuple(let types):
            return try deallocateRecordLike(fields: types)
        case .record(let record):
            return try deallocateRecordLike(fields: record.fields.map(\.type))
        case .option(let wrapped):
            return try deallocateVariantLike(cases: [nil, wrapped])
        case .result(let ok, let error):
            return try deallocateVariantLike(cases: [ok, error])
        case .variant(let variant):
            return try deallocateVariantLike(cases: variant.cases.map(\.type))
        case .flags: return false
        case .enum: return false
        default:
            fatalError("TODO: deallocation for \"\(type)\" is unimplemented")
        }
    }
}