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