1 package frost.unsafe
2
3 ====================================================================================================
4 Represents a system-level pointer to a block of memory. Pointers are inherently unsafe, bringing
5 all of the standard dangers of C pointers with them into Frost. They are primarily used internally
6 by Frost in the implementation of various data structures, and should generally be avoided in favor
7 of these high-level data structures.
8
9 The normal rules for typecasting do not apply to Pointers. A Pointer of any type may be cast into a
10 Pointer of any other type. Since non-value types are represented internally as pointers, a Pointer
11 to a non-value type (such as `Pointer<Object>`) is actually a pointer to a pointer to an `Object`.
12 This means it is safe to cast e.g. `Pointer<Object>` to `Pointer<String>`, or vice versa, despite
13 the fact that `String` and `Object` are different sizes (so long as the underlying objects being
14 pointed to are in fact `String`s, of course).
15 ====================================================================================================
16 class Pointer<T> : Value {
17 -*
18 This is a special class which requires extra support from the compiler. Most notably, there
19 is a unique annotation '@pointerSize' used here. @pointerSize means "we need to know the
20 size of the pointer's datatype within this method"; normally there would not be a way to
21 determine this. @pointerSize causes the method to take an extra, hidden parameter named
22 'pointerSize' which contains the pointer's size.
23 *-
24
25 @private
26 def value:builtin_uint
27
28 ================================================================================================
29 Creates a pointer with a specific integer value.
30 ================================================================================================
31 @unsafeAccess
32 init(value:UInt) {
33 self.value := value.value
34 }
35
36 ================================================================================================
37 Allocates a zero-filled block of memory big enough to hold `count` instances of its type and
38 returns a pointer to it. For instance, `Pointer<Int64>.alloc(8)` is equivalent to the C code
39 `calloc(sizeof(int64_t), 8)`.
40 ================================================================================================
41 @class
42 @pointerSize
43 method alloc(count:Int):Pointer<T> {
44 return Pointer<T>(Frost.alloc(count * pointerSize))
45 }
46
47 ================================================================================================
48 Returns the item pointed to by this pointer. Equivalent to `pointer[0]`.
49 ================================================================================================
50 function get():T {
51 unreachable, "Pointer.get() should have been compiled as an intrinsic"
52 }
53
54 ================================================================================================
55 Replaces the item pointed to by this pointer with a new value. Equivalent to
56 `pointer[0] := value`. For reference counted values, this handles unreffing the previous value
57 and reffing the new value automatically.
58 ================================================================================================
59 method set(value:T) {
60 unreachable, "Pointer.set() should have been compiled as an intrinsic"
61 }
62
63 ================================================================================================
64 Returns the n'th item pointed to by this pointer. Equivalent to `pointer.offset(count).get()`.
65 ================================================================================================
66 @pointerSize
67 function [](index:Int):T {
68 unreachable, "Pointer[] should have been compiled as an intrinsic"
69 }
70
71 ================================================================================================
72 Replaces the n'th item pointed to by this pointer. Equivalent to
73 `pointer.offset(count).set(value)`. For reference counted values, this handles unreffing the
74 previous value and reffing the new value automatically.
75 ================================================================================================
76 @pointerSize
77 method []:=(index:Int, value:T) {
78 unreachable, "Pointer[]:= should have been compiled as an intrinsic"
79 }
80
81 ================================================================================================
82 Changes the size of the block of memory pointed to by this pointer, equivalent to the C
83 `realloc` function. Just as with `realloc`, the original pointer is invalid after this call and
84 the returned pointer (which may or not be the same) must be used instead.
85 ================================================================================================
86 @pointerSize
87 method realloc(oldCount:Int, newCount:Int):Pointer<T> {
88 return Pointer<T>(Frost.realloc(value, oldCount * pointerSize, newCount * pointerSize))
89 }
90
91 ================================================================================================
92 Moves this pointer forward (or backward if `count` is negative) `count` steps. Each step is the
93 size of a single element of type `T`, rounded up to its alignment, so e.g. offsetting an `Int32`
94 pointer by 4 steps will generally move it by 16 total bytes. This call is not bounds-checked,
95 and moving the pointer outside of its associated block of memory can lead to undefined behavior.
96 ================================================================================================
97 @pointerSize
98 function +(count:Int):Pointer<T> {
99 return Pointer<T>(UInt(value) + (count * pointerSize).asUInt)
100 }
101
102 ================================================================================================
103 Moves this pointer backward (or forward if `count` is negative) `count` steps. Each step is the
104 size of a single element of type `T`, rounded up to its alignment, so e.g. offsetting an `Int32`
105 pointer by 4 steps will generally move it by 16 total bytes. This call is not bounds-checked,
106 and moving the pointer outside of its associated block of memory can lead to undefined behavior.
107 ================================================================================================
108 @pointerSize
109 function -(count:Int):Pointer<T> {
110 return Pointer<T>(UInt(value) - (count * pointerSize).asUInt)
111 }
112
113 ================================================================================================
114 Frees the block of memory that this pointer points to. This is exactly equivalent to the C
115 `free` function, and in particular **does not do any reference counting or cleanup of values in
116 the pointed-to memory**. If, for instance, you wish to destroy a `Pointer<Pointer<Char8>>`, you
117 must first `destroy` all of the inner `Pointer<Char8>`s or you will leak memory. If the values
118 pointed to by the pointer are reference counted objects, you must call `Frost.unref()` (or
119 use [clear(Int)]) to unref them.
120 ================================================================================================
121 method destroy() {
122 Frost.destroy(value)
123 }
124
125 property asUInt:UInt
126 function get_asUInt():UInt {
127 return value
128 }
129
130 ================================================================================================
131 If the pointer points to a reference counted object type, unrefs the object this pointer points
132 to. Otherwise, does nothing. This is used to permit safe handling of references from within
133 generic types which do not know whether or not they are dealing with a reference-counted type.
134 ================================================================================================
135 method clear() {
136 self.clear(0)
137 }
138
139 ================================================================================================
140 If the pointer points to a reference counted object type, unrefs the indicated slot and sets it
141 to `null`. Otherwise, does nothing. This is used to permit safe handling of references from
142 within generic types which do not know whether or not they are dealing with a reference-counted
143 type. This is equivalent to (pointer + index).clear().
144 ================================================================================================
145 method clear(index:Int) {
146 unreachable, "Pointer.clear() should have been compiled as an intrinsic"
147 }
148
149 ================================================================================================
150 Asks Frost to treat the memory pointed to by the Pointer as if it were an instance of the type
151 in question, returning the value pointed to by the pointer. This is *not the same* as
152 typecasting a pointer and dereferencing it. With normal pointer typecasts, such as
153 `Pointer<Object>->Pointer<String>`, the Pointer points to a block of memory containing a pointer
154 to an object. The actual object lives elsewhere on the heap, and it is safe to simply treat the
155 pointer as a different (compatible) type. But this method tells Frost that the pointer points
156 *directly* to an object of that type, not to a pointer which points to an object of that type.
157 This is, effectively, the difference between performing `Pointer<Object>->Pointer<String>`
158 (directly supported) and `Pointer<UInt8>->String` (this is what `convertTo` does).
159
160 The correct usage of this method is something along the lines of:
161
162 def memory := Pointer<UInt8>.alloc(<enough memory to hold the object's fields>)
163 <fill in memory with the object's fields>
164 def finalPointer := memory.convertTo<Type>()
165
166 Since there are no publicly-exposed facilities for figuring out the size and layout of a class,
167 this method is for internal use only.
168 ================================================================================================
169 @private
170 function convertTo<T>():T {
171 unreachable, "Pointer.convertTo() should have been compiled as an intrinsic"
172 }
173
174 @override
175 function get_toString():String {
176 return "Pointer<0x\{asUInt:x}>"
177 }
178 }
179