rev: f131c57bfc2a7d462c61667e160d3988dfcffd53 scopes/lib/scopes/Rc.sc -rw-r--r-- 8.0 KiB View raw Log this file
f131c57bfc2a — Leonard Ritter * prover: `inttoptr` correctly propagates view state or instantiates unique type 13 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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
#
    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
    STRONGRC_INDEX = 0
    WEAKRC_INDEX = 1

let RefType = i32
let MetaDataType =
    tuple RefType RefType

let HEADERSIZE = 16:usize

typedef ReferenceCounted
    let RefType = RefType
    let MetaDataType = MetaDataType

inline _mdptr (self)
    inttoptr (sub (ptrtoint (view self) usize) (sizeof MetaDataType)) (mutable @MetaDataType)
inline _baseptr (self)
    let T = (elementof (typeof self))
    let ptr =
        inttoptr (sub (ptrtoint (view self) usize) HEADERSIZE) (mutable @u8)
    ptr

typedef Weak < ReferenceCounted
typedef Rc < ReferenceCounted

inline free-rc (self)
    viewing self
    free (_baseptr self)

@@ memo
inline gen-type (T)
    let storage-type =
        mutable pointer T
    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 = (_mdptr value)
            let refcount =
                getelementptr md 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
            inttoptr 0:usize this-type

    typedef+ RcType
        let Type = T
        let WeakType = WeakType

        fn wrap (value)
            let self = (nullof storage-type)
            let MDT = super-type.MetaDataType
            let mdsize = (sizeof MDT)
            let fullsize = (HEADERSIZE + (sizeof T))
            let ptr = (malloc-array u8 fullsize)
            let self = (inttoptr (add (ptrtoint ptr usize) HEADERSIZE) storage-type)
            store value self
            let mdptr = (_mdptr self)
            store 1 (getelementptr mdptr 0 STRONGRC_INDEX)
            store 0 (getelementptr mdptr 0 WEAKRC_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
        if (not (ptrtoint value usize))
            return 0
        let md = (_mdptr value)
        dupe (load (getelementptr md 0 STRONGRC_INDEX))

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

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

    fn _drop (self)
        if (not (ptrtoint (view self) usize))
            return;
        let md = (_mdptr self)
        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-rc self
            # otherwise last strong reference will clean this up

    inline __rimply (T cls)
        static-if (T == Nothing)
            inline (value) (cls)

    inline __drop (self)
        _drop (deref self)

    @@ memo
    inline __== (cls other-cls)
        static-if (cls == other-cls)
            fn (self other)
                == (storagecast (view self)) (storagecast (view other))

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

    fn upgrade (self)
        viewing self
        if (not (ptrtoint self usize))
            raise (UpgradeError)
        let md = (_mdptr self)
        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
        assert (ptrtoint self usize) "upgrading Weak failed"
        let md = (_mdptr self)
        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... __copy (value : Rc,)
        viewing value
        let md = (_mdptr value)
        let refcount =
            getelementptr md 0 STRONGRC_INDEX
        let rc = (load refcount)
        assert (rc >= 0) "corrupt refcount encountered"
        let rc = (add rc 1)
        store rc refcount
        deref (dupe value)

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

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

    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...

    inline __call (self ...)
        (view self) ...

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

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

    inline __repr (self)
        .. "(Rc " (repr (view self)) ")"

    @@ memo
    inline __== (cls other-cls)
        static-if (cls == other-cls)
            inline (self other)
                == (storagecast (_view self)) (storagecast (_view other))

    inline __hash (self)
        hash (storagecast (_view self))

    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)
        viewing self
        returning void
        let md = (_mdptr self)
        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
            # update refcount after drop so weak pointers don't attempt to
                delete this pointer prematurely
            store 0 refcount
            let weakrefcount = (getelementptr md 0 WEAKRC_INDEX)
            if ((load weakrefcount) == 0)
                free-rc self
            # otherwise the last weak reference will free this value
        else
            store rc refcount

    inline __drop (self)
        _drop (deref self)

    unlet _view _drop

do
    let Rc Weak UpgradeError
    locals;