@grain/stdlib 0.4.4 → 0.5.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/CHANGELOG.md +87 -0
- package/LICENSE +1 -1
- package/array.gr +92 -73
- package/array.md +18 -18
- package/bigint.gr +497 -0
- package/bigint.md +811 -0
- package/buffer.gr +56 -217
- package/buffer.md +24 -17
- package/bytes.gr +103 -205
- package/bytes.md +19 -0
- package/char.gr +152 -166
- package/char.md +200 -0
- package/exception.md +6 -0
- package/float32.gr +159 -82
- package/float32.md +315 -0
- package/float64.gr +163 -82
- package/float64.md +315 -0
- package/hash.gr +53 -49
- package/int32.gr +479 -230
- package/int32.md +937 -0
- package/int64.gr +479 -230
- package/int64.md +937 -0
- package/list.gr +530 -116
- package/list.md +1141 -0
- package/map.gr +302 -121
- package/map.md +525 -0
- package/number.gr +51 -57
- package/number.md +37 -3
- package/option.gr +25 -25
- package/option.md +1 -1
- package/package.json +3 -3
- package/pervasives.gr +504 -52
- package/pervasives.md +1116 -0
- package/queue.gr +8 -1
- package/queue.md +10 -0
- package/random.gr +196 -0
- package/random.md +179 -0
- package/range.gr +26 -26
- package/regex.gr +1833 -842
- package/regex.md +11 -11
- package/result.md +1 -1
- package/runtime/bigint.gr +2045 -0
- package/runtime/bigint.md +326 -0
- package/runtime/dataStructures.gr +99 -279
- package/runtime/dataStructures.md +391 -0
- package/runtime/debug.gr +0 -1
- package/runtime/debug.md +6 -0
- package/runtime/equal.gr +40 -37
- package/runtime/equal.md +6 -0
- package/runtime/exception.gr +28 -15
- package/runtime/exception.md +30 -0
- package/runtime/gc.gr +50 -20
- package/runtime/gc.md +36 -0
- package/runtime/malloc.gr +32 -22
- package/runtime/malloc.md +55 -0
- package/runtime/numberUtils.gr +297 -142
- package/runtime/numberUtils.md +54 -0
- package/runtime/numbers.gr +1204 -453
- package/runtime/numbers.md +300 -0
- package/runtime/string.gr +193 -228
- package/runtime/string.md +24 -0
- package/runtime/stringUtils.gr +62 -38
- package/runtime/stringUtils.md +6 -0
- package/runtime/unsafe/constants.gr +17 -0
- package/runtime/unsafe/constants.md +72 -0
- package/runtime/unsafe/conv.gr +10 -10
- package/runtime/unsafe/conv.md +71 -0
- package/runtime/unsafe/errors.md +204 -0
- package/runtime/unsafe/memory.gr +14 -3
- package/runtime/unsafe/memory.md +54 -0
- package/runtime/unsafe/printWasm.gr +4 -4
- package/runtime/unsafe/printWasm.md +24 -0
- package/runtime/unsafe/tags.gr +11 -10
- package/runtime/unsafe/tags.md +120 -0
- package/runtime/unsafe/wasmf32.gr +9 -2
- package/runtime/unsafe/wasmf32.md +168 -0
- package/runtime/unsafe/wasmf64.gr +9 -2
- package/runtime/unsafe/wasmf64.md +168 -0
- package/runtime/unsafe/wasmi32.gr +65 -47
- package/runtime/unsafe/wasmi32.md +282 -0
- package/runtime/unsafe/wasmi64.gr +78 -50
- package/runtime/unsafe/wasmi64.md +300 -0
- package/runtime/utils/printing.gr +62 -0
- package/runtime/utils/printing.md +18 -0
- package/runtime/wasi.gr +200 -46
- package/runtime/wasi.md +839 -0
- package/set.gr +125 -121
- package/set.md +24 -21
- package/stack.gr +29 -29
- package/stack.md +4 -6
- package/string.gr +434 -415
- package/string.md +3 -3
- package/sys/file.gr +477 -482
- package/sys/process.gr +33 -47
- package/sys/random.gr +48 -20
- package/sys/random.md +38 -0
- package/sys/time.gr +12 -28
package/runtime/gc.gr
CHANGED
|
@@ -25,23 +25,38 @@ import WasmI32, {
|
|
|
25
25
|
sub as (-),
|
|
26
26
|
mul as (*),
|
|
27
27
|
and as (&),
|
|
28
|
-
eq as (==)
|
|
28
|
+
eq as (==),
|
|
29
29
|
} from "runtime/unsafe/wasmi32"
|
|
30
30
|
|
|
31
31
|
// Using foreigns directly here to avoid cyclic dependency
|
|
32
|
-
import foreign wasm fd_write
|
|
32
|
+
import foreign wasm fd_write: (
|
|
33
|
+
WasmI32,
|
|
34
|
+
WasmI32,
|
|
35
|
+
WasmI32,
|
|
36
|
+
WasmI32,
|
|
37
|
+
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
33
38
|
|
|
34
|
-
primitive (&&)
|
|
35
|
-
primitive (||)
|
|
36
|
-
primitive throw
|
|
37
|
-
primitive ignore
|
|
38
|
-
primitive box
|
|
39
|
-
primitive unbox
|
|
39
|
+
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
40
|
+
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
41
|
+
primitive throw: Exception -> a = "@throw"
|
|
42
|
+
primitive ignore: a -> Void = "@ignore"
|
|
43
|
+
primitive box: a -> Box<a> = "@box"
|
|
44
|
+
primitive unbox: Box<a> -> a = "@unbox"
|
|
40
45
|
|
|
41
46
|
exception DecRefError
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
|
|
48
|
+
let decimalCount32Dummy = (n: WasmI32) => 0n
|
|
49
|
+
let utoa32BufferedDummy = (a: WasmI32, b: WasmI32, c: WasmI32) => void
|
|
50
|
+
|
|
51
|
+
// When these boxes are backpatched, the reference count of each function will
|
|
52
|
+
// fall to zero which would cause them to be freed. We can't free anything that
|
|
53
|
+
// got allocated in runtime mode (since that memory space is not managed by the
|
|
54
|
+
// GC, so here we prevent that by manually setting a higher refcount.
|
|
55
|
+
WasmI32.store(WasmI32.fromGrain(decimalCount32Dummy) - 8n, 2n, 0n)
|
|
56
|
+
WasmI32.store(WasmI32.fromGrain(utoa32BufferedDummy) - 8n, 2n, 0n)
|
|
57
|
+
|
|
58
|
+
export let decimalCount32 = box(decimalCount32Dummy)
|
|
59
|
+
export let utoa32Buffered = box(utoa32BufferedDummy)
|
|
45
60
|
|
|
46
61
|
let mut _DEBUG = false
|
|
47
62
|
|
|
@@ -154,7 +169,10 @@ export let free = (userPtr: WasmI32) => {
|
|
|
154
169
|
}
|
|
155
170
|
|
|
156
171
|
export let incRef = (userPtr: WasmI32) => {
|
|
157
|
-
if (
|
|
172
|
+
if (
|
|
173
|
+
WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) &&
|
|
174
|
+
WasmI32.ne(userPtr, 0n)
|
|
175
|
+
) {
|
|
158
176
|
// if (_DEBUG) {
|
|
159
177
|
// logIncRef(userPtr, getRefCount(userPtr))
|
|
160
178
|
// void;
|
|
@@ -165,7 +183,10 @@ export let incRef = (userPtr: WasmI32) => {
|
|
|
165
183
|
}
|
|
166
184
|
|
|
167
185
|
let rec decRef = (userPtr: WasmI32, ignoreZeros: Bool) => {
|
|
168
|
-
if (
|
|
186
|
+
if (
|
|
187
|
+
WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) &&
|
|
188
|
+
WasmI32.ne(userPtr, 0n)
|
|
189
|
+
) {
|
|
169
190
|
let refCount = getRefCount(userPtr)
|
|
170
191
|
// if (_DEBUG) {
|
|
171
192
|
// logDecRef(userPtr, refCount, ignoreZeros)
|
|
@@ -194,43 +215,52 @@ let rec decRef = (userPtr: WasmI32, ignoreZeros: Bool) => {
|
|
|
194
215
|
}
|
|
195
216
|
}, decRefChildren = (userPtr: WasmI32) => {
|
|
196
217
|
match (WasmI32.load(userPtr, 0n)) {
|
|
218
|
+
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
219
|
+
let tag = WasmI32.load(userPtr, 4n)
|
|
220
|
+
if (userPtr == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) {
|
|
221
|
+
// decRef underlying BigInts
|
|
222
|
+
ignore(decRef(WasmI32.load(userPtr, 8n), false))
|
|
223
|
+
ignore(decRef(WasmI32.load(userPtr, 12n), false))
|
|
224
|
+
}
|
|
225
|
+
},
|
|
197
226
|
t when t == Tags._GRAIN_ADT_HEAP_TAG => {
|
|
198
227
|
let arity = WasmI32.load(userPtr, 16n)
|
|
199
228
|
let maxOffset = arity * 4n
|
|
200
|
-
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i
|
|
229
|
+
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
|
|
201
230
|
ignore(decRef(WasmI32.load(userPtr + i, 20n), false))
|
|
202
231
|
}
|
|
203
232
|
},
|
|
204
233
|
t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
|
|
205
234
|
let arity = WasmI32.load(userPtr, 12n)
|
|
206
235
|
let maxOffset = arity * 4n
|
|
207
|
-
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i
|
|
236
|
+
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
|
|
208
237
|
ignore(decRef(WasmI32.load(userPtr + i, 16n), false))
|
|
209
238
|
}
|
|
210
239
|
},
|
|
211
|
-
t when
|
|
240
|
+
t when (
|
|
241
|
+
t == Tags._GRAIN_ARRAY_HEAP_TAG || t == Tags._GRAIN_TUPLE_HEAP_TAG
|
|
242
|
+
) => {
|
|
212
243
|
let arity = WasmI32.load(userPtr, 4n)
|
|
213
244
|
let maxOffset = arity * 4n
|
|
214
|
-
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i
|
|
245
|
+
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
|
|
215
246
|
ignore(decRef(WasmI32.load(userPtr + i, 8n), false))
|
|
216
247
|
}
|
|
217
248
|
},
|
|
218
249
|
t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
|
|
219
250
|
let arity = WasmI32.load(userPtr, 12n)
|
|
220
251
|
let maxOffset = arity * 4n
|
|
221
|
-
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i
|
|
252
|
+
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
|
|
222
253
|
ignore(decRef(WasmI32.load(userPtr + i, 16n), false))
|
|
223
254
|
}
|
|
224
255
|
},
|
|
225
256
|
_ => {
|
|
226
257
|
// No travelsal necessary for other tags
|
|
227
258
|
void
|
|
228
|
-
}
|
|
259
|
+
},
|
|
229
260
|
}
|
|
230
261
|
}
|
|
231
262
|
|
|
232
|
-
export let
|
|
233
|
-
export let decRef = (userPtr) => decRef(userPtr, false)
|
|
263
|
+
export let decRef = userPtr => decRef(userPtr, false)
|
|
234
264
|
|
|
235
265
|
// For debugging:
|
|
236
266
|
|
package/runtime/gc.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
### Gc.**decimalCount32**
|
|
2
|
+
|
|
3
|
+
```grain
|
|
4
|
+
decimalCount32 : Box<WasmI32 -> WasmI32>
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
### Gc.**utoa32Buffered**
|
|
8
|
+
|
|
9
|
+
```grain
|
|
10
|
+
utoa32Buffered : Box<(WasmI32, WasmI32, WasmI32) -> Void>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Gc.**malloc**
|
|
14
|
+
|
|
15
|
+
```grain
|
|
16
|
+
malloc : WasmI32 -> WasmI32
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Gc.**free**
|
|
20
|
+
|
|
21
|
+
```grain
|
|
22
|
+
free : WasmI32 -> Void
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Gc.**incRef**
|
|
26
|
+
|
|
27
|
+
```grain
|
|
28
|
+
incRef : WasmI32 -> WasmI32
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Gc.**decRef**
|
|
32
|
+
|
|
33
|
+
```grain
|
|
34
|
+
decRef : WasmI32 -> WasmI32
|
|
35
|
+
```
|
|
36
|
+
|
package/runtime/malloc.gr
CHANGED
|
@@ -17,18 +17,20 @@ import WasmI32, {
|
|
|
17
17
|
shl as (<<),
|
|
18
18
|
shrU as (>>),
|
|
19
19
|
eq as (==),
|
|
20
|
-
ne as (!=)
|
|
20
|
+
ne as (!=),
|
|
21
21
|
} from "runtime/unsafe/wasmi32"
|
|
22
22
|
import Exception from "runtime/exception"
|
|
23
23
|
|
|
24
24
|
primitive memorySize: () -> WasmI32 = "@wasm.memory_size"
|
|
25
|
-
primitive memoryGrow:
|
|
25
|
+
primitive memoryGrow: WasmI32 -> WasmI32 = "@wasm.memory_grow"
|
|
26
26
|
|
|
27
|
-
primitive (!)
|
|
28
|
-
primitive (&&)
|
|
29
|
-
primitive (||)
|
|
27
|
+
primitive (!): Bool -> Bool = "@not"
|
|
28
|
+
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
29
|
+
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
30
30
|
|
|
31
|
-
primitive throw
|
|
31
|
+
primitive throw: Exception -> a = "@throw"
|
|
32
|
+
|
|
33
|
+
primitive heapBase: WasmI32 = "@heap.base"
|
|
32
34
|
|
|
33
35
|
/* UNDERSTANDING THE STRUCTURE OF THE FREE LIST
|
|
34
36
|
* The original K&R definition for the free list entry type was the following:
|
|
@@ -80,7 +82,7 @@ export let _RESERVED_RUNTIME_SPACE = 0x4000n
|
|
|
80
82
|
* The base the heap. The block at this address will be size 0 and
|
|
81
83
|
* serve as the root of the free list.
|
|
82
84
|
*/
|
|
83
|
-
let _BASE = _RESERVED_RUNTIME_SPACE
|
|
85
|
+
let _BASE = heapBase + _RESERVED_RUNTIME_SPACE
|
|
84
86
|
|
|
85
87
|
/**
|
|
86
88
|
* The start pointer of the heap.
|
|
@@ -114,8 +116,8 @@ let setSize = (ptr: WasmI32, val: WasmI32) => {
|
|
|
114
116
|
/**
|
|
115
117
|
* Requests that the heap be grown by the given number of bytes.
|
|
116
118
|
*
|
|
117
|
-
* @param nbytes:
|
|
118
|
-
* @
|
|
119
|
+
* @param nbytes: The number of bytes requested
|
|
120
|
+
* @returns The pointer to the beginning of the extended region if successful or -1 otherwise
|
|
119
121
|
*/
|
|
120
122
|
let growHeap = (nbytes: WasmI32) => {
|
|
121
123
|
let mut reqSize = 0n
|
|
@@ -130,7 +132,7 @@ let growHeap = (nbytes: WasmI32) => {
|
|
|
130
132
|
// so we need to request more anyway.
|
|
131
133
|
reqSize = nbytes - heapSize
|
|
132
134
|
reqSize = reqSize >> 16n
|
|
133
|
-
reqSize
|
|
135
|
+
reqSize += 1n
|
|
134
136
|
reqResult = memoryGrow(reqSize)
|
|
135
137
|
if (reqResult == -1n) {
|
|
136
138
|
-1n
|
|
@@ -147,7 +149,7 @@ let growHeap = (nbytes: WasmI32) => {
|
|
|
147
149
|
|
|
148
150
|
reqSize = nbytes
|
|
149
151
|
reqSize = reqSize >> 16n
|
|
150
|
-
reqSize
|
|
152
|
+
reqSize += 1n
|
|
151
153
|
|
|
152
154
|
reqResult = memoryGrow(reqSize)
|
|
153
155
|
if (reqResult == -1n) {
|
|
@@ -162,7 +164,7 @@ let growHeap = (nbytes: WasmI32) => {
|
|
|
162
164
|
/**
|
|
163
165
|
* Frees the given allocated pointer.
|
|
164
166
|
*
|
|
165
|
-
* @param ap:
|
|
167
|
+
* @param ap: The pointer to free
|
|
166
168
|
*/
|
|
167
169
|
export let free = (ap: WasmI32) => {
|
|
168
170
|
let mut blockPtr = ap - 8n // 8 bytes for malloc header
|
|
@@ -174,7 +176,10 @@ export let free = (ap: WasmI32) => {
|
|
|
174
176
|
// Find the location to insert this block into the free list
|
|
175
177
|
while (true) {
|
|
176
178
|
let nextp = getNext(p)
|
|
177
|
-
if (
|
|
179
|
+
if (
|
|
180
|
+
blockPtr > p && blockPtr < nextp ||
|
|
181
|
+
p >= nextp && (blockPtr > p || blockPtr < nextp)
|
|
182
|
+
) {
|
|
178
183
|
break
|
|
179
184
|
}
|
|
180
185
|
p = nextp
|
|
@@ -207,8 +212,8 @@ export let free = (ap: WasmI32) => {
|
|
|
207
212
|
* (if you can't tell from the fact that the name is reminiscient
|
|
208
213
|
* of the 1970s, the name of this function is taken from K&R).
|
|
209
214
|
*
|
|
210
|
-
* @param nbytes:
|
|
211
|
-
* @
|
|
215
|
+
* @param nbytes: The number of bytes to try to grow the heap by
|
|
216
|
+
* @returns A pointer to the start of the free list if successful or -1 otherwise
|
|
212
217
|
*/
|
|
213
218
|
let morecore = (nbytes: WasmI32) => {
|
|
214
219
|
let origSize = heapSize
|
|
@@ -232,8 +237,8 @@ let morecore = (nbytes: WasmI32) => {
|
|
|
232
237
|
/**
|
|
233
238
|
* Allocates the requested number of bytes, returning a pointer.
|
|
234
239
|
*
|
|
235
|
-
* @param nbytes:
|
|
236
|
-
* @
|
|
240
|
+
* @param nbytes: The number of bytes to allocate
|
|
241
|
+
* @returns The pointer to the allocated region (8-byte aligned) or -1 if the allocation failed
|
|
237
242
|
*/
|
|
238
243
|
export let malloc = (nb: WasmI32) => {
|
|
239
244
|
let mut nbytes = nb
|
|
@@ -255,7 +260,12 @@ export let malloc = (nb: WasmI32) => {
|
|
|
255
260
|
let mut ret = -1n
|
|
256
261
|
|
|
257
262
|
// Search the freelist for any blocks large enough.
|
|
258
|
-
for (
|
|
263
|
+
for (
|
|
264
|
+
let mut p = getNext(prevp); ; {
|
|
265
|
+
prevp = p
|
|
266
|
+
p = getNext(p)
|
|
267
|
+
}
|
|
268
|
+
) {
|
|
259
269
|
let size = getSize(p)
|
|
260
270
|
if (size >= nbytes) {
|
|
261
271
|
// If this block is big enough, allocate from it.
|
|
@@ -266,7 +276,7 @@ export let malloc = (nb: WasmI32) => {
|
|
|
266
276
|
// Shrink it as needed
|
|
267
277
|
let newSize = size - nbytes
|
|
268
278
|
setSize(p, newSize)
|
|
269
|
-
p
|
|
279
|
+
p += newSize
|
|
270
280
|
setSize(p, nbytes)
|
|
271
281
|
}
|
|
272
282
|
// Update the pointer to the free list.
|
|
@@ -292,10 +302,10 @@ export let malloc = (nb: WasmI32) => {
|
|
|
292
302
|
}
|
|
293
303
|
|
|
294
304
|
/**
|
|
295
|
-
* Returns the current free list pointer
|
|
296
|
-
*
|
|
305
|
+
* Returns the current free list pointer.
|
|
306
|
+
* Used for debugging.
|
|
297
307
|
*
|
|
298
|
-
* @
|
|
308
|
+
* @returns The free list pointer
|
|
299
309
|
*/
|
|
300
310
|
export let getFreePtr = () => {
|
|
301
311
|
freePtr
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
### Malloc.**_RESERVED_RUNTIME_SPACE**
|
|
2
|
+
|
|
3
|
+
```grain
|
|
4
|
+
_RESERVED_RUNTIME_SPACE : WasmI32
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
### Malloc.**free**
|
|
8
|
+
|
|
9
|
+
```grain
|
|
10
|
+
free : WasmI32 -> Void
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Frees the given allocated pointer.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
|
|
17
|
+
|param|type|description|
|
|
18
|
+
|-----|----|-----------|
|
|
19
|
+
|`ap`|`WasmI32`|The pointer to free|
|
|
20
|
+
|
|
21
|
+
### Malloc.**malloc**
|
|
22
|
+
|
|
23
|
+
```grain
|
|
24
|
+
malloc : WasmI32 -> WasmI32
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Allocates the requested number of bytes, returning a pointer.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
|
|
31
|
+
|param|type|description|
|
|
32
|
+
|-----|----|-----------|
|
|
33
|
+
|`nbytes`|`WasmI32`|The number of bytes to allocate|
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
|
|
37
|
+
|type|description|
|
|
38
|
+
|----|-----------|
|
|
39
|
+
|`WasmI32`|The pointer to the allocated region (8-byte aligned) or -1 if the allocation failed|
|
|
40
|
+
|
|
41
|
+
### Malloc.**getFreePtr**
|
|
42
|
+
|
|
43
|
+
```grain
|
|
44
|
+
getFreePtr : () -> WasmI32
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Returns the current free list pointer.
|
|
48
|
+
Used for debugging.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
|
|
52
|
+
|type|description|
|
|
53
|
+
|----|-----------|
|
|
54
|
+
|`WasmI32`|The free list pointer|
|
|
55
|
+
|