@effekt-lang/effekt 0.24.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/effekt CHANGED
Binary file
@@ -8,14 +8,54 @@ import option
8
8
  /// A mutable 0-indexed fixed-sized array.
9
9
  extern type Array[T]
10
10
 
11
+ /** We represent arrays like positive types.
12
+ * The tag is 0 and the obj points to memory with the following layout:
13
+ *
14
+ * +--[ Header ]--+------+------------+
15
+ * | Rc | Eraser | Size | Fields ... |
16
+ * +--------------+------+------------+
17
+ */
18
+
19
+ extern llvm """
20
+ declare noalias ptr @calloc(i64, i64)
21
+
22
+ define void @array_erase_fields(ptr %array_pointer) {
23
+ entry:
24
+ %data_pointer = getelementptr inbounds i64, ptr %array_pointer, i64 1
25
+ %size = load i64, ptr %array_pointer, align 8
26
+ %size_eq_0 = icmp eq i64 %size, 0
27
+ br i1 %size_eq_0, label %exit, label %loop
28
+ loop:
29
+ %loop_phi = phi i64 [ %inc, %loop ], [ 0, %entry ]
30
+
31
+ %element_pointer = getelementptr inbounds %Pos, ptr %data_pointer, i64 %loop_phi
32
+ %element = load %Pos, ptr %element_pointer
33
+
34
+ call void @erasePositive(%Pos %element)
35
+ %inc = add nuw i64 %loop_phi, 1
36
+ %cmp = icmp ult i64 %inc, %size
37
+ br i1 %cmp, label %loop, label %exit
38
+ exit:
39
+ ret void
40
+ }
41
+ """
42
+
11
43
  /// Allocates a new array of size `size`, keeping its values _undefined_.
12
44
  /// Prefer using `array` constructor instead to ensure that values are defined.
13
45
  extern global def allocate[T](size: Int): Array[T] =
14
46
  js "(new Array(${size}))"
15
47
  chez "(make-vector ${size})" // creates an array filled with 0s on CS
16
48
  llvm """
17
- %z = call %Pos @c_array_new(%Int ${size})
18
- ret %Pos %z
49
+ %size0 = shl i64 ${size}, 4
50
+ %size1 = add i64 %size0, 24
51
+ %calloc = tail call noalias ptr @calloc(i64 %size1, i64 1)
52
+ %eraser_pointer = getelementptr ptr, ptr %calloc, i64 1
53
+ %size_pointer = getelementptr ptr, ptr %calloc, i64 2
54
+ store i64 0, ptr %calloc
55
+ store ptr @array_erase_fields, ptr %eraser_pointer
56
+ store i64 ${size}, ptr %size_pointer
57
+ %ret_pos = insertvalue %Pos { i64 0, ptr poison }, ptr %calloc, 1
58
+ ret %Pos %ret_pos
19
59
  """
20
60
  vm "array::allocate(Int)"
21
61
 
@@ -49,8 +89,12 @@ extern pure def size[T](arr: Array[T]): Int =
49
89
  js "${arr}.length"
50
90
  chez "(vector-length ${arr})"
51
91
  llvm """
52
- %z = call %Int @c_array_size(%Pos ${arr})
53
- ret %Int %z
92
+ %pos_data = extractvalue %Pos ${arr}, 1
93
+ %size_pointer = getelementptr inbounds i64, ptr %pos_data, i64 2
94
+ %size = load i64, ptr %size_pointer
95
+
96
+ tail call void @erasePositive(%Pos ${arr})
97
+ ret i64 %size
54
98
  """
55
99
  vm "array::size[T](Array[T])"
56
100
 
@@ -62,8 +106,15 @@ extern global def unsafeGet[T](arr: Array[T], index: Int): T =
62
106
  js "${arr}[${index}]"
63
107
  chez "(vector-ref ${arr} ${index})"
64
108
  llvm """
65
- %z = call %Pos @c_array_get(%Pos ${arr}, %Int ${index})
66
- ret %Pos %z
109
+ %pos_data = extractvalue %Pos ${arr}, 1
110
+
111
+ %data_pointer = getelementptr inbounds ptr, ptr %pos_data, i64 3
112
+ %element_pointer = getelementptr inbounds %Pos, ptr %data_pointer, i64 ${index}
113
+ %element = load %Pos, ptr %element_pointer
114
+
115
+ tail call void @sharePositive(%Pos %element)
116
+ tail call void @erasePositive(%Pos ${arr})
117
+ ret %Pos %element
67
118
  """
68
119
  vm "array::unsafeGet[T](Array[T], Int)"
69
120
 
@@ -82,8 +133,15 @@ extern global def unsafeSet[T](arr: Array[T], index: Int, value: T): Unit =
82
133
  js "array$set(${arr}, ${index}, ${value})"
83
134
  chez "(begin (vector-set! ${arr} ${index} ${value}) #f)"
84
135
  llvm """
85
- %z = call %Pos @c_array_set(%Pos ${arr}, %Int ${index}, %Pos ${value})
86
- ret %Pos %z
136
+ %array_data = extractvalue %Pos ${arr}, 1
137
+
138
+ %data_pointer = getelementptr inbounds i64, ptr %array_data, i64 3
139
+ %element_pointer = getelementptr inbounds %Pos, ptr %data_pointer, i64 ${index}
140
+ %element = load %Pos, ptr %element_pointer, align 8
141
+ tail call void @erasePositive(%Pos %element)
142
+ store %Pos ${value}, ptr %element_pointer, align 8
143
+ tail call void @erasePositive(%Pos ${arr})
144
+ ret %Pos zeroinitializer
87
145
  """
88
146
  vm "array::unsafeSet[T](Array[T], Int, T)"
89
147
 
@@ -3,7 +3,6 @@ module buffer
3
3
  import array
4
4
 
5
5
  // TODO (in Effekt compiler)
6
- // - [ ] fix allocating into actually global region
7
6
  // - [ ] fix exceptions on objects
8
7
  // - [X] allow omitting braces after `at` for singleton regions
9
8
 
@@ -35,12 +34,12 @@ def emptyBuffer[T](capacity: Int): Buffer[T] at {global} = {
35
34
  def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
36
35
  // TODO allocate buffer (and array) into a region r.
37
36
  val contents = array::allocate[T](initialCapacity)
38
- var head in global = 0
39
- var tail in global = 0
37
+ val head = ref(0)
38
+ val tail = ref(0)
40
39
 
41
40
  def size(): Int =
42
- if (tail >= head) { tail - head }
43
- else { initialCapacity - head + tail }
41
+ if (tail.get >= head.get) { tail.get - head.get }
42
+ else { initialCapacity - head.get + tail.get }
44
43
 
45
44
  def capacity(): Int = initialCapacity - size()
46
45
 
@@ -51,36 +50,36 @@ def arrayBuffer[T](initialCapacity: Int): Buffer[T] at {global} = {
51
50
  def read() = {
52
51
  if (buffer.empty?) None()
53
52
  else {
54
- val result: T = contents.unsafeGet(head);
55
- head = mod(head + 1, initialCapacity)
53
+ val result: T = contents.unsafeGet(head.get)
54
+ head.set(mod(head.get + 1, initialCapacity))
56
55
  Some(result)
57
56
  }
58
57
  }
59
58
  def write(el: T) = {
60
59
  if (buffer.full?) <> // raise(BufferOverflow())
61
60
 
62
- contents.unsafeSet(tail, el)
63
- tail = mod(tail + 1, initialCapacity)
61
+ contents.unsafeSet(tail.get, el)
62
+ tail.set(mod(tail.get + 1, initialCapacity))
64
63
  }
65
64
  }
66
65
  buffer
67
66
  }
68
67
  def refBuffer[T](): Buffer[T] at {global} = {
69
- var content: Option[T] in global = None()
68
+ val content = ref(None())
70
69
  new Buffer[T] {
71
- def capacity() = if (content.isEmpty) 1 else 0
72
- def full?() = content.isDefined
73
- def empty?() = isEmpty(content)
70
+ def capacity() = if (content.get.isEmpty) 1 else 0
71
+ def full?() = content.get.isDefined
72
+ def empty?() = isEmpty(content.get)
74
73
  def read() = {
75
- val res = content
76
- content = None()
74
+ val res = content.get
75
+ content.set(None())
77
76
  res
78
77
  }
79
- def write(el: T) = content match {
78
+ def write(el: T) = content.get match {
80
79
  case Some(v) =>
81
80
  <> // do raise(BufferOverflow(), "Cannot read element from buffer")
82
81
  case None() =>
83
- content = Some(el)
82
+ content.set(Some(el))
84
83
  }
85
84
  }
86
85
  }
@@ -88,24 +87,24 @@ def refBuffer[T](): Buffer[T] at {global} = {
88
87
  namespace examples {
89
88
  def main() = ignore[BufferOverflow] {
90
89
  // Buffer with capacity 1
91
- def b = emptyBuffer[Int](1);
92
- println(b.capacity);
93
- println(b.full?);
90
+ def b = emptyBuffer[Int](1)
91
+ println(b.capacity)
92
+ println(b.full?)
94
93
 
95
- b.write(17);
96
- println(b.read());
94
+ b.write(17)
95
+ println(b.read())
97
96
 
98
97
  // buffer with capacity 3
99
- def ringbuffer = emptyBuffer[Int](3);
100
- ringbuffer.write(1);
101
- ringbuffer.write(2);
102
- println(ringbuffer.read());
103
- ringbuffer.write(3);
104
- println(ringbuffer.read());
105
- println(ringbuffer.read());
106
- ringbuffer.write(4);
107
- ringbuffer.write(5);
108
- println(ringbuffer.read());
109
- println(ringbuffer.read());
98
+ def ringbuffer = emptyBuffer[Int](3)
99
+ ringbuffer.write(1)
100
+ ringbuffer.write(2)
101
+ println(ringbuffer.read())
102
+ ringbuffer.write(3)
103
+ println(ringbuffer.read())
104
+ println(ringbuffer.read())
105
+ ringbuffer.write(4)
106
+ ringbuffer.write(5)
107
+ println(ringbuffer.read())
108
+ println(ringbuffer.read())
110
109
  }
111
110
  }
@@ -2,6 +2,17 @@ module bytearray
2
2
 
3
3
  /**
4
4
  * A memory managed, mutable, fixed-length array of bytes.
5
+ *
6
+ * We represent bytearrays like positive types.
7
+ *
8
+ * - The field `tag` contains the size
9
+ * - The field `obj` points to memory with the following layout:
10
+ *
11
+ * +--[ Header ]--+--------------+
12
+ * | Rc | Eraser | Contents ... |
13
+ * +--------------+--------------+
14
+ *
15
+ * The eraser does nothing.
5
16
  */
6
17
  extern type ByteArray
7
18
  // = llvm "%Pos"
@@ -12,32 +23,47 @@ extern type ByteArray
12
23
  extern global def allocate(size: Int): ByteArray =
13
24
  js "(new Uint8Array(${size}))"
14
25
  llvm """
15
- %arr = call %Pos @c_bytearray_new(%Int ${size})
16
- ret %Pos %arr
26
+ %object_size = add i64 ${size}, 16
27
+ %object_alloc = tail call noalias ptr @malloc(i64 noundef %object_size)
28
+ store i64 0, ptr %object_alloc, align 8
29
+ %object_data_ptr = getelementptr inbounds i8, ptr %object_alloc, i64 8
30
+ store ptr @bytearray_erase_noop, ptr %object_data_ptr, align 8
31
+ %ret_object1 = insertvalue %Pos poison, i64 ${size}, 0
32
+ %ret_object2 = insertvalue %Pos %ret_object1, ptr %object_alloc, 1
33
+ ret %Pos %ret_object2
17
34
  """
18
35
  chez "(make-bytevector ${size})"
19
36
 
20
37
  extern pure def size(arr: ByteArray): Int =
21
38
  js "${arr}.length"
22
39
  llvm """
23
- %size = call %Int @c_bytearray_size(%Pos ${arr})
24
- ret %Int %size
40
+ %size = extractvalue %Pos ${arr}, 0
41
+ tail call void @erasePositive(%Pos ${arr})
42
+ ret i64 %size
25
43
  """
26
44
  chez "(bytevector-length ${arr})"
27
45
 
28
46
  extern global def unsafeGet(arr: ByteArray, index: Int): Byte =
29
47
  js "(${arr})[${index}]"
30
48
  llvm """
31
- %byte = call %Byte @c_bytearray_get(%Pos ${arr}, %Int ${index})
32
- ret %Byte %byte
49
+ %arr_ptr = extractvalue %Pos ${arr}, 1
50
+ %arr_data_ptr = getelementptr inbounds i8, ptr %arr_ptr, i64 16
51
+ %element_ptr = getelementptr inbounds i8, ptr %arr_data_ptr, i64 ${index}
52
+ %element = load i8, ptr %element_ptr, align 1
53
+ tail call void @erasePositive(%Pos ${arr})
54
+ ret i8 %element
33
55
  """
34
56
  chez "(bytevector-u8-ref ${arr} ${index})"
35
57
 
36
58
  extern global def unsafeSet(arr: ByteArray, index: Int, value: Byte): Unit =
37
59
  js "bytearray$set(${arr}, ${index}, ${value})"
38
60
  llvm """
39
- %z = call %Pos @c_bytearray_set(%Pos ${arr}, %Int ${index}, %Byte ${value})
40
- ret %Pos %z
61
+ %arr_ptr = extractvalue %Pos ${arr}, 1
62
+ %arr_data_ptr = getelementptr inbounds i8, ptr %arr_ptr, i64 16
63
+ %element_ptr = getelementptr inbounds i8, ptr %arr_data_ptr, i64 ${index}
64
+ store i8 ${value}, ptr %element_ptr, align 1
65
+ tail call void @erasePositive(%Pos ${arr})
66
+ ret %Pos zeroinitializer
41
67
  """
42
68
  chez "(bytevector-u8-set! ${arr} ${index} ${value})"
43
69
 
@@ -121,6 +147,12 @@ extern js """
121
147
  }
122
148
  """
123
149
 
150
+ extern llvm """
151
+ define void @bytearray_erase_noop(ptr readnone %0) {
152
+ ret void
153
+ }
154
+ """
155
+
124
156
  extern chez """
125
157
  (define (bytearray$compare b1 b2)
126
158
  (let ([len1 (bytevector-length b1)]
@@ -25,82 +25,82 @@ def emptyQueue[T](): Queue[T] at {global} =
25
25
 
26
26
  def emptyQueue[T](initialCapacity: Int): Queue[T] at {global} = {
27
27
 
28
- var contents in global = array[Option[T]](initialCapacity, None())
29
- var head in global = 0
30
- var tail in global = 0
31
- var size in global = 0
32
- var capacity in global = initialCapacity
28
+ val contents = ref(array[Option[T]](initialCapacity, None()))
29
+ val head = ref(0)
30
+ val tail = ref(0)
31
+ val size = ref(0)
32
+ val capacity = ref(initialCapacity)
33
33
 
34
34
  def remove(arr: Array[Option[T]], index: Int): Option[T] = {
35
- with on[OutOfBounds].default { None() };
36
- val value = arr.get(index);
37
- arr.set(index, None());
35
+ with on[OutOfBounds].default { None() }
36
+ val value = arr.get(index)
37
+ arr.set(index, None())
38
38
  value
39
39
  }
40
40
 
41
41
  def nonEmpty[T] { p: => Option[T] / Exception[OutOfBounds] }: Option[T] =
42
- if (size <= 0) None() else on[OutOfBounds].default { None() } { p() }
42
+ if (size.get <= 0) None() else on[OutOfBounds].default { None() } { p() }
43
43
 
44
44
  // Exponential back-off
45
45
  def resizeTo(requiredSize: Int): Unit =
46
- if (requiredSize <= capacity) () else {
46
+ if (requiredSize <= capacity.get) () else {
47
47
  with on[OutOfBounds].ignore // should not happen
48
48
 
49
- val oldSize = capacity
50
- val newSize = capacity * 2
51
- val oldContents = contents
49
+ val oldSize = capacity.get
50
+ val newSize = capacity.get * 2
51
+ val oldContents = contents.get
52
52
  val newContents = array::allocate[Option[T]](newSize)
53
53
 
54
- if (head < tail) {
54
+ if (head.get < tail.get) {
55
55
  // The queue does not wrap around; direct copy is possible.
56
- copy(oldContents, head, newContents, 0, size) // changed tail to size
57
- } else if (size > 0) {
56
+ copy(oldContents, head.get, newContents, 0, size.get) // changed tail to size
57
+ } else if (size.get > 0) {
58
58
  // The queue wraps around; copy in two segments.
59
- copy(oldContents, head, newContents, 0, oldSize - head) // changed oldSize to oldSize - head
60
- copy(oldContents, 0, newContents, oldSize - head, tail) // changed oldSize - head to oldSize - head
59
+ copy(oldContents, head.get, newContents, 0, oldSize - head.get) // changed oldSize to oldSize - head
60
+ copy(oldContents, 0, newContents, oldSize - head.get, tail.get) // changed oldSize - head to oldSize - head
61
61
  }
62
62
 
63
- contents = newContents
64
- capacity = newSize
65
- head = 0
66
- tail = oldSize
63
+ contents.set(newContents)
64
+ capacity.set(newSize)
65
+ head.set(0)
66
+ tail.set(oldSize)
67
67
  }
68
68
 
69
69
  def queue = new Queue[T] {
70
- def empty?() = size <= 0
70
+ def empty?() = size.get <= 0
71
71
 
72
72
  def popFront() =
73
73
  nonEmpty {
74
- val result = contents.remove(head)
75
- head = mod(head + 1, capacity)
76
- size = size - 1
74
+ val result = contents.get.remove(head.get)
75
+ head.set(mod(head.get + 1, capacity.get))
76
+ size.set(size.get - 1)
77
77
  result
78
78
  }
79
79
 
80
80
  def popBack() =
81
81
  nonEmpty {
82
- tail = mod(tail - 1 + capacity, capacity)
83
- val result = contents.remove(tail)
84
- size = size - 1
82
+ tail.set(mod(tail.get - 1 + capacity.get, capacity.get))
83
+ val result = contents.get.remove(tail.get)
84
+ size.set(size.get - 1)
85
85
  result
86
86
  }
87
87
 
88
- def peekFront() = nonEmpty { contents.get(head) }
88
+ def peekFront() = nonEmpty { contents.get.get(head.get) }
89
89
 
90
- def peekBack() = nonEmpty { contents.get(tail) }
90
+ def peekBack() = nonEmpty { contents.get.get(tail.get) }
91
91
 
92
92
  def pushFront(el: T) = {
93
- resizeTo(size + 1);
94
- head = mod(head - 1 + capacity, capacity);
95
- size = size + 1;
96
- contents.unsafeSet(head, Some(el))
93
+ resizeTo(size.get + 1)
94
+ head.set(mod(head.get - 1 + capacity.get, capacity.get))
95
+ size.set(size.get + 1)
96
+ contents.get.unsafeSet(head.get, Some(el))
97
97
  }
98
98
 
99
99
  def pushBack(el: T) = {
100
- resizeTo(size + 1);
101
- contents.unsafeSet(tail, Some(el));
102
- size = size + 1;
103
- tail = mod(tail + 1, capacity)
100
+ resizeTo(size.get + 1)
101
+ contents.get.unsafeSet(tail.get, Some(el))
102
+ size.set(size.get + 1)
103
+ tail.set(mod(tail.get + 1, capacity.get))
104
104
  }
105
105
  }
106
106
  queue
@@ -109,30 +109,30 @@ def emptyQueue[T](initialCapacity: Int): Queue[T] at {global} = {
109
109
  namespace examples {
110
110
  def main() = {
111
111
  // queue with initial capacity 4
112
- def b = emptyQueue[Int](4);
113
- println(b.empty?);
114
- b.pushFront(1);
115
- b.pushBack(2);
116
- b.pushFront(3);
117
- b.pushBack(4);
112
+ def b = emptyQueue[Int](4)
113
+ println(b.empty?)
114
+ b.pushFront(1)
115
+ b.pushBack(2)
116
+ b.pushFront(3)
117
+ b.pushBack(4)
118
118
  // this will cause resizing:
119
- b.pushBack(5);
120
- b.pushBack(6);
121
- b.pushBack(7);
122
- b.pushBack(8);
119
+ b.pushBack(5)
120
+ b.pushBack(6)
121
+ b.pushBack(7)
122
+ b.pushBack(8)
123
123
  // and again:
124
- b.pushBack(9);
125
-
126
- println(b.empty?);
127
- println(b.popFront()); // Some(3)
128
- println(b.popFront()); // Some(1)
129
- println(b.popFront()); // Some(2)
130
- println(b.popFront()); // Some(4)
131
- println(b.popFront()); // Some(5)
132
- println(b.popFront()); // Some(6)
133
- println(b.popFront()); // Some(7)
134
- println(b.popFront()); // Some(8)
135
- println(b.popFront()); // Some(9)
136
- println(b.popFront()); // None()
124
+ b.pushBack(9)
125
+
126
+ println(b.empty?)
127
+ println(b.popFront()) // Some(3)
128
+ println(b.popFront()) // Some(1)
129
+ println(b.popFront()) // Some(2)
130
+ println(b.popFront()) // Some(4)
131
+ println(b.popFront()) // Some(5)
132
+ println(b.popFront()) // Some(6)
133
+ println(b.popFront()) // Some(7)
134
+ println(b.popFront()) // Some(8)
135
+ println(b.popFront()) // Some(9)
136
+ println(b.popFront()) // None()
137
137
  }
138
138
  }
@@ -9,17 +9,44 @@ extern js """
9
9
  }
10
10
  """
11
11
 
12
+ extern llvm """
13
+ define void @c_ref_erase_field(ptr %0) {
14
+ %field = load %Pos, ptr %0, align 8
15
+ tail call void @erasePositive(%Pos %field)
16
+ ret void
17
+ }
18
+ """
19
+
12
20
  /// Global, mutable references
13
21
  extern type Ref[T]
14
22
 
23
+ /** We represent references like positive types in LLVM
24
+ * The tag is 0 and the obj points to memory with the following layout:
25
+ *
26
+ * +--[ Header ]--------------+------------+
27
+ * | ReferenceCount | Eraser | Field |
28
+ * +--------------------------+------------+
29
+ */
30
+
15
31
  /// Allocates a new reference, keeping its value _undefined_.
16
32
  /// Prefer using `ref` constructor instead to ensure that the value is defined.
17
33
  extern global def allocate[T](): Ref[T] =
18
34
  js "{ value: undefined }"
19
35
  chez "(box #f)"
20
36
  llvm """
21
- %z = call %Pos @c_ref_fresh(%Pos zeroinitializer)
22
- ret %Pos %z
37
+ ; sizeof Header + sizeof Pos = 32
38
+ %ref = tail call noalias ptr @malloc(i64 noundef 32)
39
+ %refEraser = getelementptr ptr, ptr %ref, i64 1
40
+ %fieldTag = getelementptr ptr, ptr %ref, i64 2
41
+ %fieldData_pointer = getelementptr ptr, ptr %ref, i64 3
42
+
43
+ store i64 0, ptr %ref, align 8
44
+ store ptr @c_ref_erase_field, ptr %refEraser, align 8
45
+ store i64 0, ptr %fieldTag, align 8
46
+ store ptr null, ptr %fieldData_pointer, align 8
47
+
48
+ %refWrap = insertvalue %Pos { i64 0, ptr poison }, ptr %ref, 1
49
+ ret %Pos %refWrap
23
50
  """
24
51
 
25
52
  /// Creates a new reference with the initial value `init`.
@@ -27,8 +54,20 @@ extern global def ref[T](init: T): Ref[T] =
27
54
  js "{ value: ${init} }"
28
55
  chez "(box ${init})"
29
56
  llvm """
30
- %z = call %Pos @c_ref_fresh(%Pos ${init})
31
- ret %Pos %z
57
+ %initTag = extractvalue %Pos ${init}, 0
58
+ %initObject_pointer = extractvalue %Pos ${init}, 1
59
+ ; sizeof Header + sizeof Pos = 32
60
+ %ref = tail call noalias ptr @malloc(i64 noundef 32)
61
+ %refEraser = getelementptr ptr, ptr %ref, i64 1
62
+ %refField = getelementptr ptr, ptr %ref, i64 2
63
+
64
+ store i64 0, ptr %ref, align 8
65
+ store ptr @c_ref_erase_field, ptr %refEraser, align 8
66
+ store %Pos ${init}, ptr %refField, align 8
67
+
68
+ %refWrap = insertvalue %Pos { i64 0, ptr poison }, ptr %ref, 1
69
+
70
+ ret %Pos %refWrap
32
71
  """
33
72
  vm "ref::ref[T](T)"
34
73
 
@@ -36,9 +75,15 @@ extern global def ref[T](init: T): Ref[T] =
36
75
  extern global def get[T](ref: Ref[T]): T =
37
76
  js "${ref}.value"
38
77
  chez "(unbox ${ref})"
39
- llvm """
40
- %z = call %Pos @c_ref_get(%Pos ${ref})
41
- ret %Pos %z
78
+ llvm """
79
+ %ref_pointer = extractvalue %Pos ${ref}, 1
80
+ %refField_pointer = getelementptr inbounds ptr, ptr %ref_pointer, i64 2
81
+ %refField = load %Pos, ptr %refField_pointer, align 8
82
+
83
+ tail call void @sharePositive(%Pos %refField)
84
+ tail call void @erasePositive(%Pos ${ref})
85
+
86
+ ret %Pos %refField
42
87
  """
43
88
  vm "ref::get[T](Ref[T])"
44
89
 
@@ -47,7 +92,15 @@ extern global def set[T](ref: Ref[T], value: T): Unit =
47
92
  js "set$impl(${ref}, ${value})"
48
93
  chez "(set-box! ${ref} ${value})"
49
94
  llvm """
50
- %z = call %Pos @c_ref_set(%Pos ${ref}, %Pos ${value})
51
- ret %Pos %z
95
+ %refField_pointer = extractvalue %Pos ${ref}, 1
96
+
97
+ %field_pointer = getelementptr ptr, ptr %refField_pointer, i64 2
98
+ %field = load %Pos, ptr %field_pointer, align 8
99
+
100
+ tail call void @erasePositive(%Pos %field)
101
+ store %Pos ${value}, ptr %field_pointer
102
+ tail call void @erasePositive(%Pos ${ref})
103
+
104
+ ret %Pos zeroinitializer
52
105
  """
53
106
  vm "ref::set[T](Ref[T], T)"
@@ -14,7 +14,7 @@ def stringBuffer[A] { prog: => A / StringBuffer }: A = {
14
14
  var pos = 0
15
15
 
16
16
  def ensureCapacity(sizeToAdd: Int): Unit = {
17
- val cap = buffer.size - pos + 1
17
+ val cap = buffer.size - pos
18
18
  if (sizeToAdd <= cap) ()
19
19
  else {
20
20
  // Double the capacity while ensuring the required capacity