rev: ebafc720a90fa0562f276f82113a43e8e7c3ee88 scopes/lib/scopes/Rc.sc -rw-r--r-- 7.7 KiB View raw Log this file
ebafc720a90f — Leonard Ritter * merged default branch 7 days ago
                                                                                
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
#
    The Scopes Compiler Infrastructure
    This file is distributed under the MIT License.
    See LICENSE.md for details.

""""Rc
    ==

    A reference counted value that is dropped when all users are dropped. This
    module provides a strong reference type `Rc`, as well as a weak reference
    type `Weak`.

let
    PAYLOAD_INDEX = 0
    METADATA_INDEX = 1
    STRONGRC_INDEX = 0
    WEAKRC_INDEX = 1

typedef ReferenceCounted
    let RefType = i32
    let MetaDataType =
        tuple RefType RefType

typedef Weak < ReferenceCounted
typedef Rc < ReferenceCounted

@@ memo
inline gen-type (T)
    let storage-type =
        tuple
            mutable pointer T
            mutable pointer Weak.MetaDataType
    let WeakType =
        typedef (.. "<Weak " (tostring T) ">") < Weak
            \ :: storage-type
    let RcType =
        typedef (.. "<Rc " (tostring T) ">") < Rc
            \ :: storage-type

    typedef+ WeakType
        let Type = T
        let RcType = RcType

        inline... __typecall
        case (cls, value : RcType)
            let md = (extractvalue value METADATA_INDEX)
            let refcount =
                getelementptr
                    extractvalue value METADATA_INDEX
                    \ 0 WEAKRC_INDEX
            let rc = (add (load refcount) 1)
            store rc refcount
            bitcast (dupe (view value)) this-type
        case (cls)
            # null-weak that will never upgrade
            let self = (nullof storage-type)
            bitcast self this-type

    typedef+ RcType
        let Type = T
        let WeakType = WeakType

        fn wrap (value)
            let self = (nullof storage-type)
            let ptr = (malloc T)
            store value ptr
            let self = (insertvalue self ptr PAYLOAD_INDEX)
            let mdptr = (malloc super-type.MetaDataType)
            store 1 (getelementptr mdptr 0 STRONGRC_INDEX)
            store 0 (getelementptr mdptr 0 WEAKRC_INDEX)
            let self = (insertvalue self mdptr METADATA_INDEX)
            bitcast self this-type

        inline __typecall (cls args...)
            wrap (T args...)
    RcType

typedef UpgradeError : (tuple)
    inline __typecall (cls)
        bitcast none this-type

typedef+ ReferenceCounted
    fn strong-count (value)
        viewing value
        let md = (extractvalue value METADATA_INDEX)
        if (not (ptrtoint md usize))
            return 0
        load (getelementptr md 0 STRONGRC_INDEX)

    fn weak-count (value)
        viewing value
        let md = (extractvalue value METADATA_INDEX)
        if (not (ptrtoint md usize))
            return 1
        load (getelementptr md 0 WEAKRC_INDEX)

typedef+ Weak
    inline... __typecall
    case (cls, T : type)
        (gen-type T) . WeakType

    fn _drop (self)
        let md = (extractvalue self METADATA_INDEX)
        if (not (ptrtoint md usize))
            return;
        let refcount = (getelementptr md 0 WEAKRC_INDEX)
        let rc = (sub (load refcount) 1)
        assert (rc >= 0) "corrupt refcount encountered"
        store rc refcount
        if (rc == 0)
            let strongrefcount = (getelementptr md 0 STRONGRC_INDEX)
            if ((load strongrefcount) == 0)
                free md
            # otherwise last strong reference will clean this up

    inline __drop (self)
        _drop (deref self)

    @@ memo
    inline __== (cls other-cls)
        static-if (cls == other-cls)
            fn (self other)
                == (extractvalue self METADATA_INDEX) (extractvalue other METADATA_INDEX)

    fn... clone (self : Weak,)
        viewing self
        let md = (extractvalue self METADATA_INDEX)
        if (ptrtoint md usize)
            let refcount =
                getelementptr md 0 WEAKRC_INDEX
            let rc = (add (load refcount) 1)
            store rc refcount
        deref (dupe self)

    fn upgrade (self)
        viewing self
        let md = (extractvalue self METADATA_INDEX)
        if (not (ptrtoint md usize))
            raise (UpgradeError)
        let refcount = (getelementptr md 0 STRONGRC_INDEX)
        let rc = (load refcount)
        assert (rc >= 0) "corrupt refcount encountered"
        if (rc == 0)
            raise (UpgradeError)
        let RcType = ((typeof self) . RcType)
        let rc = (add rc 1)
        store rc refcount
        deref (bitcast (dupe self) RcType)

    fn force-upgrade (self)
        viewing self
        let md = (extractvalue self METADATA_INDEX)
        assert (ptrtoint md usize) "upgrading Weak failed"
        let refcount = (getelementptr md 0 STRONGRC_INDEX)
        let rc = (load refcount)
        assert (rc >= 0) "corrupt refcount encountered"
        assert (rc > 0) "upgrading Weak failed"
        let RcType = ((typeof self) . RcType)
        let rc = (add rc 1)
        store rc refcount
        deref (bitcast (dupe self) RcType)


typedef+ Rc
    inline... __typecall
    case (cls, T : type)
        gen-type T

    inline new (T args...)
        (gen-type T) args...

    fn... clone
    case (value : Rc,)
        viewing value
        let refcount =
            getelementptr
                extractvalue value METADATA_INDEX
                \ 0 STRONGRC_INDEX
        let rc = (load refcount)
        assert (rc >= 0) "corrupt refcount encountered"
        let rc = (add rc 1)
        store rc refcount
        deref (dupe value)
    case (value : Weak,)
        viewing value
        'clone value

    inline wrap (value)
        ((gen-type (typeof value)) . wrap) value

    let _view = view
    inline... view (self : Rc,)
        ptrtoref (deref (extractvalue self PAYLOAD_INDEX))

    inline __countof (self)
        countof (view self)

    inline __= (selfT otherT)
        static-if (selfT == otherT)
            super-type.__= selfT otherT
        else
            inline (lhs rhs)
                (view lhs) = rhs

    inline __@ (self keys...)
        @ (view self) keys...

    spice __methodcall (symbol self args...)
        'tag `(symbol (view self) args...) ('anchor args)

    spice __getattr (self key)
        'tag `(getattr (view self) key) ('anchor args)

    spice __repr (self)
        'tag `(forward-repr (view self)) ('anchor args)

    @@ memo
    inline __== (cls other-cls)
        static-if (cls == other-cls)
            inline (self other)
                == (extractvalue self PAYLOAD_INDEX) (extractvalue other PAYLOAD_INDEX)

    inline make-cast-op (f const?)
        spice "box-cast" (selfT otherT)
            selfT as:= type
            otherT as:= type
            static-if (not const?)
                let WeakT = ('@ selfT 'WeakType)
                if ((otherT == Weak) or (otherT == (WeakT as type)))
                    return WeakT
            let selfT = (('@ selfT 'Type) as type)
            let conv = (f selfT otherT const?)
            if (operator-valid? conv)
                return `(inline (value) (conv (view value)))
            return `()

    let __imply = (make-cast-op imply-converter false)
    let __static-imply = (make-cast-op imply-converter true)
    let __as = (make-cast-op as-converter false)

    fn _drop (self)
        returning void
        let md = (extractvalue self METADATA_INDEX)
        let refcount = (getelementptr md 0 STRONGRC_INDEX)
        let rc = (sub (load refcount) 1)
        assert (rc >= 0) "corrupt refcount encountered"
        if (rc == 0)
            let payload = (view self)
            __drop payload
            free (reftoptr payload)
            store 0 refcount
            let weakrefcount = (getelementptr md 0 WEAKRC_INDEX)
            if ((load weakrefcount) == 0)
                free md
            # otherwise last weak reference will clean this up
        else
            store rc refcount

    inline __drop (self)
        _drop (deref self)

    unlet _view _drop

do
    let Rc Weak UpgradeError
    locals;