@grain/stdlib 0.5.13 → 0.6.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 +193 -0
- package/LICENSE +1 -1
- package/README.md +25 -2
- package/array.gr +1512 -199
- package/array.md +2032 -94
- package/bigint.gr +239 -140
- package/bigint.md +450 -106
- package/buffer.gr +595 -102
- package/buffer.md +903 -145
- package/bytes.gr +401 -110
- package/bytes.md +551 -63
- package/char.gr +228 -49
- package/char.md +373 -7
- package/exception.gr +26 -12
- package/exception.md +29 -5
- package/float32.gr +130 -109
- package/float32.md +185 -57
- package/float64.gr +112 -99
- package/float64.md +185 -57
- package/hash.gr +47 -37
- package/hash.md +21 -3
- package/int16.gr +430 -0
- package/int16.md +618 -0
- package/int32.gr +200 -269
- package/int32.md +254 -289
- package/int64.gr +142 -225
- package/int64.md +254 -289
- package/int8.gr +511 -0
- package/int8.md +786 -0
- package/json.gr +2084 -0
- package/json.md +608 -0
- package/list.gr +120 -68
- package/list.md +125 -80
- package/map.gr +560 -57
- package/map.md +672 -56
- package/marshal.gr +239 -227
- package/marshal.md +36 -4
- package/number.gr +626 -676
- package/number.md +738 -153
- package/option.gr +33 -35
- package/option.md +58 -42
- package/package.json +2 -2
- package/path.gr +148 -187
- package/path.md +47 -96
- package/pervasives.gr +75 -416
- package/pervasives.md +85 -180
- package/priorityqueue.gr +433 -74
- package/priorityqueue.md +422 -54
- package/queue.gr +362 -80
- package/queue.md +433 -38
- package/random.gr +67 -75
- package/random.md +68 -40
- package/range.gr +135 -63
- package/range.md +198 -43
- package/rational.gr +284 -0
- package/rational.md +545 -0
- package/regex.gr +933 -1066
- package/regex.md +59 -60
- package/result.gr +23 -25
- package/result.md +54 -39
- package/runtime/atof/common.gr +78 -82
- package/runtime/atof/common.md +22 -10
- package/runtime/atof/decimal.gr +102 -127
- package/runtime/atof/decimal.md +28 -7
- package/runtime/atof/lemire.gr +56 -71
- package/runtime/atof/lemire.md +9 -1
- package/runtime/atof/parse.gr +83 -110
- package/runtime/atof/parse.md +12 -2
- package/runtime/atof/slow.gr +28 -35
- package/runtime/atof/slow.md +9 -1
- package/runtime/atof/table.gr +19 -18
- package/runtime/atof/table.md +10 -2
- package/runtime/atoi/parse.gr +153 -136
- package/runtime/atoi/parse.md +50 -1
- package/runtime/bigint.gr +410 -517
- package/runtime/bigint.md +71 -57
- package/runtime/compare.gr +176 -85
- package/runtime/compare.md +31 -1
- package/runtime/dataStructures.gr +144 -32
- package/runtime/dataStructures.md +267 -31
- package/runtime/debugPrint.gr +34 -15
- package/runtime/debugPrint.md +37 -5
- package/runtime/equal.gr +53 -52
- package/runtime/equal.md +30 -1
- package/runtime/exception.gr +38 -47
- package/runtime/exception.md +10 -8
- package/runtime/gc.gr +23 -152
- package/runtime/gc.md +13 -17
- package/runtime/malloc.gr +31 -31
- package/runtime/malloc.md +11 -3
- package/runtime/numberUtils.gr +191 -172
- package/runtime/numberUtils.md +17 -9
- package/runtime/numbers.gr +1695 -1021
- package/runtime/numbers.md +1098 -134
- package/runtime/string.gr +540 -242
- package/runtime/string.md +76 -6
- package/runtime/unsafe/constants.gr +30 -13
- package/runtime/unsafe/constants.md +80 -0
- package/runtime/unsafe/conv.gr +55 -28
- package/runtime/unsafe/conv.md +41 -9
- package/runtime/unsafe/memory.gr +10 -30
- package/runtime/unsafe/memory.md +15 -19
- package/runtime/unsafe/tags.gr +37 -21
- package/runtime/unsafe/tags.md +88 -8
- package/runtime/unsafe/wasmf32.gr +30 -36
- package/runtime/unsafe/wasmf32.md +64 -56
- package/runtime/unsafe/wasmf64.gr +30 -36
- package/runtime/unsafe/wasmf64.md +64 -56
- package/runtime/unsafe/wasmi32.gr +49 -66
- package/runtime/unsafe/wasmi32.md +102 -94
- package/runtime/unsafe/wasmi64.gr +52 -79
- package/runtime/unsafe/wasmi64.md +108 -100
- package/runtime/utils/printing.gr +13 -15
- package/runtime/utils/printing.md +11 -3
- package/runtime/wasi.gr +294 -295
- package/runtime/wasi.md +62 -42
- package/set.gr +574 -64
- package/set.md +634 -54
- package/stack.gr +181 -64
- package/stack.md +271 -42
- package/string.gr +453 -533
- package/string.md +241 -151
- package/uint16.gr +369 -0
- package/uint16.md +585 -0
- package/uint32.gr +470 -0
- package/uint32.md +737 -0
- package/uint64.gr +471 -0
- package/uint64.md +737 -0
- package/uint8.gr +369 -0
- package/uint8.md +585 -0
- package/uri.gr +1093 -0
- package/uri.md +477 -0
- package/{sys → wasi}/file.gr +914 -500
- package/{sys → wasi}/file.md +454 -50
- package/wasi/process.gr +292 -0
- package/{sys → wasi}/process.md +164 -6
- package/wasi/random.gr +77 -0
- package/wasi/random.md +80 -0
- package/{sys → wasi}/time.gr +15 -22
- package/{sys → wasi}/time.md +5 -5
- package/immutablearray.gr +0 -929
- package/immutablearray.md +0 -1038
- package/immutablemap.gr +0 -493
- package/immutablemap.md +0 -479
- package/immutablepriorityqueue.gr +0 -360
- package/immutablepriorityqueue.md +0 -291
- package/immutableset.gr +0 -498
- package/immutableset.md +0 -449
- package/runtime/debug.gr +0 -2
- package/runtime/debug.md +0 -6
- package/runtime/unsafe/errors.gr +0 -36
- package/runtime/unsafe/errors.md +0 -204
- package/sys/process.gr +0 -254
- package/sys/random.gr +0 -79
- package/sys/random.md +0 -66
package/runtime/equal.gr
CHANGED
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
import { isNumber, numberEqual } from "runtime/numbers"
|
|
18
|
-
|
|
19
|
-
primitive (!): Bool -> Bool = "@not"
|
|
20
|
-
primitive (||): (Bool, Bool) -> Bool = "@or"
|
|
21
|
-
primitive (&&): (Bool, Bool) -> Bool = "@and"
|
|
1
|
+
@noPervasives
|
|
2
|
+
module Equal
|
|
3
|
+
|
|
4
|
+
from "runtime/unsafe/memory" include Memory
|
|
5
|
+
from "runtime/unsafe/wasmi32" include WasmI32
|
|
6
|
+
use WasmI32.{ (==), (!=), (&), (^), (+), (-), (*), (<), remS as (%), (<<) }
|
|
7
|
+
from "runtime/unsafe/wasmi64" include WasmI64
|
|
8
|
+
from "runtime/unsafe/wasmf32" include WasmF32
|
|
9
|
+
from "runtime/unsafe/tags" include Tags
|
|
10
|
+
from "runtime/numbers" include Numbers
|
|
11
|
+
use Numbers.{ isNumber, numberEqual }
|
|
12
|
+
|
|
13
|
+
primitive (!) = "@not"
|
|
14
|
+
primitive (||) = "@or"
|
|
15
|
+
primitive (&&) = "@and"
|
|
16
|
+
primitive ignore = "@ignore"
|
|
22
17
|
|
|
23
18
|
@unsafe
|
|
24
19
|
let cycleMarker = 0x80000000n
|
|
@@ -121,9 +116,7 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
121
116
|
result
|
|
122
117
|
}
|
|
123
118
|
},
|
|
124
|
-
t when
|
|
125
|
-
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
126
|
-
) => {
|
|
119
|
+
t when t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG => {
|
|
127
120
|
let xlength = WasmI32.load(xptr, 4n)
|
|
128
121
|
let ylength = WasmI32.load(yptr, 4n)
|
|
129
122
|
|
|
@@ -131,30 +124,7 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
131
124
|
if (xlength != ylength) {
|
|
132
125
|
false
|
|
133
126
|
} else {
|
|
134
|
-
|
|
135
|
-
let first = xlength - extra
|
|
136
|
-
let mut result = true
|
|
137
|
-
for (let mut i = 0n; i < first; i += 8n) {
|
|
138
|
-
if (
|
|
139
|
-
WasmI64.ne(WasmI64.load(xptr + i, 8n), WasmI64.load(yptr + i, 8n))
|
|
140
|
-
) {
|
|
141
|
-
result = false
|
|
142
|
-
break
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (result) {
|
|
146
|
-
for (let mut i = 0n; i < extra; i += 1n) {
|
|
147
|
-
if (
|
|
148
|
-
WasmI32.load8U(xptr + first + i, 8n) !=
|
|
149
|
-
WasmI32.load8U(yptr + first + i, 8n)
|
|
150
|
-
) {
|
|
151
|
-
result = false
|
|
152
|
-
break
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
result
|
|
127
|
+
Memory.compare(xptr + 8n, yptr + 8n, xlength) == 0n
|
|
158
128
|
}
|
|
159
129
|
},
|
|
160
130
|
t when t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
@@ -184,13 +154,25 @@ let rec heapEqualHelp = (heapTag, xptr, yptr) => {
|
|
|
184
154
|
result
|
|
185
155
|
}
|
|
186
156
|
},
|
|
157
|
+
t when t == Tags._GRAIN_UINT32_HEAP_TAG || t == Tags._GRAIN_INT32_HEAP_TAG => {
|
|
158
|
+
let xval = WasmI32.load(xptr, 4n)
|
|
159
|
+
let yval = WasmI32.load(yptr, 4n)
|
|
160
|
+
xval == yval
|
|
161
|
+
},
|
|
162
|
+
// Float32 is handled by equalHelp directly
|
|
163
|
+
t when t == Tags._GRAIN_UINT64_HEAP_TAG => {
|
|
164
|
+
use WasmI64.{ (==) }
|
|
165
|
+
let xval = WasmI64.load(xptr, 8n)
|
|
166
|
+
let yval = WasmI64.load(yptr, 8n)
|
|
167
|
+
xval == yval
|
|
168
|
+
},
|
|
187
169
|
_ => {
|
|
188
170
|
// No other implementation
|
|
189
171
|
xptr == yptr
|
|
190
172
|
},
|
|
191
173
|
}
|
|
192
|
-
}
|
|
193
|
-
equalHelp = (x, y) => {
|
|
174
|
+
}
|
|
175
|
+
and equalHelp = (x, y) => {
|
|
194
176
|
if (
|
|
195
177
|
(x & Tags._GRAIN_GENERIC_TAG_MASK) != 0n &&
|
|
196
178
|
(y & Tags._GRAIN_GENERIC_TAG_MASK) != 0n
|
|
@@ -200,6 +182,12 @@ equalHelp = (x, y) => {
|
|
|
200
182
|
} else if (isNumber(x)) {
|
|
201
183
|
// Numbers have special equality rules, e.g. NaN != NaN
|
|
202
184
|
numberEqual(x, y)
|
|
185
|
+
} else if (WasmI32.load(x, 0n) == Tags._GRAIN_FLOAT32_HEAP_TAG) {
|
|
186
|
+
// Short circuit for Float32 to correctly handle NaN != NaN
|
|
187
|
+
let xval = WasmF32.load(x, 4n)
|
|
188
|
+
let yval = WasmF32.load(y, 4n)
|
|
189
|
+
use WasmF32.{ (==) }
|
|
190
|
+
xval == yval
|
|
203
191
|
} else {
|
|
204
192
|
// Handle all other heap allocated things
|
|
205
193
|
// Can short circuit if pointers are the same
|
|
@@ -207,7 +195,20 @@ equalHelp = (x, y) => {
|
|
|
207
195
|
}
|
|
208
196
|
}
|
|
209
197
|
|
|
198
|
+
/**
|
|
199
|
+
* Check that two values are equal. This checks for structural equality,
|
|
200
|
+
* so it also works for comparing things like tuples and lists.
|
|
201
|
+
*
|
|
202
|
+
* @param value1: The first operand
|
|
203
|
+
* @param value2: The second operand
|
|
204
|
+
* @returns `true` if the values are structurally equal or `false` otherwise
|
|
205
|
+
*
|
|
206
|
+
* @since v0.1.0
|
|
207
|
+
*/
|
|
210
208
|
@unsafe
|
|
211
|
-
|
|
212
|
-
equalHelp(WasmI32.fromGrain(
|
|
209
|
+
provide let equal = (value1: a, value2: a) => {
|
|
210
|
+
let value = equalHelp(WasmI32.fromGrain(value1), WasmI32.fromGrain(value2))
|
|
211
|
+
ignore(value1)
|
|
212
|
+
ignore(value2)
|
|
213
|
+
value
|
|
213
214
|
}
|
package/runtime/equal.md
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Equal
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Values
|
|
6
|
+
|
|
7
|
+
Functions and constants included in the Equal module.
|
|
8
|
+
|
|
1
9
|
### Equal.**equal**
|
|
2
10
|
|
|
11
|
+
<details disabled>
|
|
12
|
+
<summary tabindex="-1">Added in <code>0.1.0</code></summary>
|
|
13
|
+
No other changes yet.
|
|
14
|
+
</details>
|
|
15
|
+
|
|
3
16
|
```grain
|
|
4
|
-
equal : (a, a)
|
|
17
|
+
equal : (value1: a, value2: a) => Bool
|
|
5
18
|
```
|
|
6
19
|
|
|
20
|
+
Check that two values are equal. This checks for structural equality,
|
|
21
|
+
so it also works for comparing things like tuples and lists.
|
|
22
|
+
|
|
23
|
+
Parameters:
|
|
24
|
+
|
|
25
|
+
|param|type|description|
|
|
26
|
+
|-----|----|-----------|
|
|
27
|
+
|`value1`|`a`|The first operand|
|
|
28
|
+
|`value2`|`a`|The second operand|
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
|
|
32
|
+
|type|description|
|
|
33
|
+
|----|-----------|
|
|
34
|
+
|`Bool`|`true` if the values are structurally equal or `false` otherwise|
|
|
35
|
+
|
package/runtime/exception.gr
CHANGED
|
@@ -1,35 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
@runtimeMode
|
|
2
|
+
module Exception
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
from "runtime/unsafe/wasmi32" include WasmI32
|
|
5
|
+
use WasmI32.{ (==), (+), (-) }
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
WasmI32,
|
|
7
|
-
WasmI32,
|
|
8
|
-
WasmI32,
|
|
9
|
-
WasmI32,
|
|
10
|
-
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
7
|
+
foreign wasm fd_write:
|
|
8
|
+
(WasmI32, WasmI32, WasmI32, WasmI32) => WasmI32 from "wasi_snapshot_preview1"
|
|
11
9
|
|
|
12
|
-
primitive unreachable
|
|
10
|
+
primitive unreachable = "@unreachable"
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
Some(a),
|
|
16
|
-
None,
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export let mut printers = 0n
|
|
12
|
+
provide let mut printers = 0n
|
|
20
13
|
|
|
21
14
|
// These functions are dangerous because they leak runtime memory and perform
|
|
22
15
|
// no GC operations. As such, they should only be called by this module and/or
|
|
23
16
|
// modules that understand these restrictions, namely Pervasives.
|
|
24
17
|
|
|
25
|
-
|
|
18
|
+
provide let dangerouslyRegisterBasePrinter = f => {
|
|
26
19
|
let mut current = printers
|
|
27
20
|
while (true) {
|
|
28
21
|
// There will be at least one printer registered by the time this is called
|
|
29
|
-
let (_, next) = WasmI32.toGrain(current):
|
|
30
|
-
Exception
|
|
31
|
-
WasmI32
|
|
32
|
-
)
|
|
22
|
+
let (_, next) = WasmI32.toGrain(current):
|
|
23
|
+
(Exception => Option<String>, WasmI32)
|
|
33
24
|
if (next == 0n) {
|
|
34
25
|
// Using a tuple in runtime mode is typically disallowed as there is no way
|
|
35
26
|
// to reclaim the memory, but this function is only called once
|
|
@@ -44,36 +35,38 @@ export let dangerouslyRegisterBasePrinter = f => {
|
|
|
44
35
|
void
|
|
45
36
|
}
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
provide let dangerouslyRegisterPrinter = f => {
|
|
48
39
|
printers = WasmI32.fromGrain((f, printers))
|
|
49
40
|
// We don't decRef the closure or arguments here to avoid a cyclic dep. on Memory.
|
|
50
41
|
// This is fine, as this function is only called seldomly.
|
|
51
42
|
void
|
|
52
43
|
}
|
|
53
44
|
|
|
45
|
+
// avoid cirular dependency on gc
|
|
46
|
+
let incRef = v => {
|
|
47
|
+
let ptr = WasmI32.fromGrain(v) - 8n
|
|
48
|
+
WasmI32.store(ptr, WasmI32.load(ptr, 0n) + 1n, 0n)
|
|
49
|
+
v
|
|
50
|
+
}
|
|
51
|
+
|
|
54
52
|
let _GENERIC_EXCEPTION_NAME = "GrainException"
|
|
55
53
|
|
|
56
54
|
let exceptionToString = (e: Exception) => {
|
|
57
55
|
let mut result = _GENERIC_EXCEPTION_NAME
|
|
58
56
|
let mut current = printers
|
|
59
57
|
while (true) {
|
|
60
|
-
if (current == 0n)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Some(str) => {
|
|
69
|
-
result = str
|
|
70
|
-
break
|
|
58
|
+
if (current == 0n) return result
|
|
59
|
+
let (printer, next) = WasmI32.toGrain(current):
|
|
60
|
+
(Exception => Option<String>, WasmI32)
|
|
61
|
+
// as GC is not available, manually increment the references
|
|
62
|
+
match (incRef(printer)(incRef(e))) {
|
|
63
|
+
Some(str) => return str,
|
|
64
|
+
None => {
|
|
65
|
+
current = next
|
|
71
66
|
},
|
|
72
|
-
None => void,
|
|
73
67
|
}
|
|
74
|
-
current = next
|
|
75
68
|
}
|
|
76
|
-
result
|
|
69
|
+
return result
|
|
77
70
|
}
|
|
78
71
|
|
|
79
72
|
// HACK: Allocate static buffer for printing (40 bytes)
|
|
@@ -81,7 +74,7 @@ let exceptionToString = (e: Exception) => {
|
|
|
81
74
|
// the runtime heap, but this is the only module that needs to do it
|
|
82
75
|
let iov = WasmI32.fromGrain([> 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n, 0n])
|
|
83
76
|
|
|
84
|
-
|
|
77
|
+
provide let panic = (msg: String) => {
|
|
85
78
|
let ptr = WasmI32.fromGrain(msg)
|
|
86
79
|
let written = iov + 32n
|
|
87
80
|
let lf = iov + 36n
|
|
@@ -94,18 +87,16 @@ export let panic = (msg: String) => {
|
|
|
94
87
|
unreachable()
|
|
95
88
|
}
|
|
96
89
|
|
|
97
|
-
|
|
90
|
+
provide let panicWithException = (e: Exception) => {
|
|
98
91
|
panic(exceptionToString(e))
|
|
99
92
|
}
|
|
100
93
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
export exception NumberNotRational
|
|
108
|
-
export exception MatchFailure
|
|
94
|
+
provide exception DivisionByZero
|
|
95
|
+
provide exception ModuloByZero
|
|
96
|
+
provide exception Overflow
|
|
97
|
+
provide exception NumberNotIntlike
|
|
98
|
+
provide exception NumberNotRational
|
|
99
|
+
provide exception MatchFailure
|
|
109
100
|
/*
|
|
110
101
|
* `assert <condition>` is essentially syntactic sugar for:
|
|
111
102
|
* `if (!<condition>) throw AssertionError(<message>)`
|
|
@@ -114,8 +105,8 @@ export exception MatchFailure
|
|
|
114
105
|
* this file to construct the error, but constructing a string in this module is impractical as we
|
|
115
106
|
* don't have access to memory allocation since malloc.gr depends on this module.
|
|
116
107
|
*/
|
|
117
|
-
|
|
118
|
-
|
|
108
|
+
|
|
109
|
+
provide exception InvalidArgument(String)
|
|
119
110
|
|
|
120
111
|
let runtimeErrorPrinter = e => {
|
|
121
112
|
match (e) {
|
package/runtime/exception.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Exception
|
|
3
|
+
---
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
## Values
|
|
6
|
+
|
|
7
|
+
Functions and constants included in the Exception module.
|
|
6
8
|
|
|
7
9
|
### Exception.**printers**
|
|
8
10
|
|
|
@@ -13,24 +15,24 @@ printers : WasmI32
|
|
|
13
15
|
### Exception.**dangerouslyRegisterBasePrinter**
|
|
14
16
|
|
|
15
17
|
```grain
|
|
16
|
-
dangerouslyRegisterBasePrinter : a
|
|
18
|
+
dangerouslyRegisterBasePrinter : (f: a) => Void
|
|
17
19
|
```
|
|
18
20
|
|
|
19
21
|
### Exception.**dangerouslyRegisterPrinter**
|
|
20
22
|
|
|
21
23
|
```grain
|
|
22
|
-
dangerouslyRegisterPrinter : a
|
|
24
|
+
dangerouslyRegisterPrinter : (f: a) => Void
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
### Exception.**panic**
|
|
26
28
|
|
|
27
29
|
```grain
|
|
28
|
-
panic : String
|
|
30
|
+
panic : (msg: String) => a
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
### Exception.**panicWithException**
|
|
32
34
|
|
|
33
35
|
```grain
|
|
34
|
-
panicWithException : Exception
|
|
36
|
+
panicWithException : (e: Exception) => a
|
|
35
37
|
```
|
|
36
38
|
|
package/runtime/gc.gr
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
@runtimeMode
|
|
2
|
+
module GC
|
|
2
3
|
|
|
3
4
|
/* Notes:
|
|
4
5
|
*
|
|
@@ -18,131 +19,28 @@
|
|
|
18
19
|
* userPtr : The pointer returned (and referenced by) to the Grain runtime
|
|
19
20
|
*/
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
sub as (-),
|
|
26
|
-
mul as (*),
|
|
27
|
-
and as (&),
|
|
28
|
-
eq as (==),
|
|
29
|
-
} from "runtime/unsafe/wasmi32"
|
|
22
|
+
from "runtime/malloc" include Malloc
|
|
23
|
+
from "runtime/unsafe/tags" include Tags
|
|
24
|
+
from "runtime/unsafe/wasmi32" include WasmI32
|
|
25
|
+
use WasmI32.{ (+), (-), (*), (&), (==), (!=) }
|
|
30
26
|
|
|
31
27
|
// Using foreigns directly here to avoid cyclic dependency
|
|
32
|
-
|
|
33
|
-
WasmI32,
|
|
34
|
-
WasmI32,
|
|
35
|
-
WasmI32,
|
|
36
|
-
WasmI32,
|
|
37
|
-
) -> WasmI32 from "wasi_snapshot_preview1"
|
|
28
|
+
foreign wasm fd_write:
|
|
29
|
+
(WasmI32, WasmI32, WasmI32, WasmI32) => WasmI32 from "wasi_snapshot_preview1"
|
|
38
30
|
|
|
39
|
-
primitive (&&)
|
|
40
|
-
primitive (||)
|
|
41
|
-
primitive throw
|
|
42
|
-
primitive ignore
|
|
43
|
-
primitive box
|
|
44
|
-
primitive unbox
|
|
31
|
+
primitive (&&) = "@and"
|
|
32
|
+
primitive (||) = "@or"
|
|
33
|
+
primitive throw = "@throw"
|
|
34
|
+
primitive ignore = "@ignore"
|
|
35
|
+
primitive box = "@box"
|
|
36
|
+
primitive unbox = "@unbox"
|
|
45
37
|
|
|
46
38
|
exception DecRefError
|
|
47
39
|
|
|
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)
|
|
60
|
-
|
|
61
40
|
let mut _DEBUG = false
|
|
62
41
|
|
|
63
42
|
let _HEADER_SIZE = 8n
|
|
64
43
|
|
|
65
|
-
/*
|
|
66
|
-
//Debugging functions:
|
|
67
|
-
import foreign wasm fd_sync : (WasmI32) -> WasmI32 from "wasi_snapshot_preview1"
|
|
68
|
-
|
|
69
|
-
// incRef debug messages: "decRef: 0xNNNNNN (prev count: nn)\n"
|
|
70
|
-
let _INCREF_DEBUG_STR_1 = "incRef: 0x"
|
|
71
|
-
let _INCREF_DEBUG_STR_2 = " (prev count: "
|
|
72
|
-
let _INCREF_DEBUG_STR_3 = "; tag: "
|
|
73
|
-
let _INCREF_DEBUG_STR_4 = ")\n"
|
|
74
|
-
|
|
75
|
-
// decRef debug messages: "decRef: 0xNNNNNN (prev count: nn)\n"
|
|
76
|
-
let _DECREF_DEBUG_STR_1 = "decRef: 0x"
|
|
77
|
-
let _DECREF_DEBUG_STR_2 = " (prev count: "
|
|
78
|
-
let _DECREF_DEBUG_STR_3 = "; ignoreZeros: true)\n"
|
|
79
|
-
let _DECREF_DEBUG_STR_4 = "; ignoreZeros: false)\n"
|
|
80
|
-
|
|
81
|
-
let logIncRef = (userPtr: WasmI32, refCount: WasmI32) => {
|
|
82
|
-
let ptrDecimals = WasmI32.shrU(31n - WasmI32.clz(userPtr), 2n) + 1n
|
|
83
|
-
let ptrStr = Malloc.malloc(ptrDecimals)
|
|
84
|
-
unbox(utoa32Buffered)(ptrStr, userPtr, 16n)
|
|
85
|
-
let refCountDecimals = unbox(decimalCount32)(refCount)
|
|
86
|
-
let refCountStr = Malloc.malloc(refCountDecimals)
|
|
87
|
-
unbox(utoa32Buffered)(refCountStr, refCount, 10n)
|
|
88
|
-
let tag = WasmI32.load(userPtr, 0n)
|
|
89
|
-
let tagDecimals = unbox(decimalCount32)(tag)
|
|
90
|
-
let tagStr = Malloc.malloc(tagDecimals)
|
|
91
|
-
unbox(utoa32Buffered)(tagStr, tag, 10n)
|
|
92
|
-
let iov = Malloc.malloc((8n * 5n) + 4n)
|
|
93
|
-
let written = iov + (8n * 7n)
|
|
94
|
-
WasmI32.store(iov, WasmI32.fromGrain(_INCREF_DEBUG_STR_1) + 8n, 0n)
|
|
95
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_INCREF_DEBUG_STR_1), 4n), 4n)
|
|
96
|
-
WasmI32.store(iov, ptrStr, 8n)
|
|
97
|
-
WasmI32.store(iov, ptrDecimals, 12n)
|
|
98
|
-
WasmI32.store(iov, WasmI32.fromGrain(_INCREF_DEBUG_STR_2) + 8n, 16n)
|
|
99
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_INCREF_DEBUG_STR_2), 4n), 20n)
|
|
100
|
-
WasmI32.store(iov, refCountStr, 24n)
|
|
101
|
-
WasmI32.store(iov, refCountDecimals, 28n)
|
|
102
|
-
WasmI32.store(iov, WasmI32.fromGrain(_INCREF_DEBUG_STR_3) + 8n, 32n)
|
|
103
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_INCREF_DEBUG_STR_3), 4n), 36n)
|
|
104
|
-
WasmI32.store(iov, tagStr, 40n)
|
|
105
|
-
WasmI32.store(iov, tagDecimals, 44n)
|
|
106
|
-
WasmI32.store(iov, WasmI32.fromGrain(_INCREF_DEBUG_STR_4) + 8n, 48n)
|
|
107
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_INCREF_DEBUG_STR_4), 4n), 52n)
|
|
108
|
-
fd_write(1n, iov, 7n, written)
|
|
109
|
-
fd_sync(1n)
|
|
110
|
-
Malloc.free(ptrStr)
|
|
111
|
-
Malloc.free(refCountStr)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
let logDecRef = (userPtr: WasmI32, refCount: WasmI32, ignoreZeros) => {
|
|
115
|
-
let ptrDecimals = WasmI32.shrU(31n - WasmI32.clz(userPtr), 2n) + 1n
|
|
116
|
-
let ptrStr = Malloc.malloc(ptrDecimals)
|
|
117
|
-
unbox(utoa32Buffered)(ptrStr, userPtr, 16n)
|
|
118
|
-
let refCountDecimals = unbox(decimalCount32)(refCount)
|
|
119
|
-
let refCountStr = Malloc.malloc(refCountDecimals)
|
|
120
|
-
unbox(utoa32Buffered)(refCountStr, refCount, 10n)
|
|
121
|
-
let iov = Malloc.malloc((8n * 5n) + 4n)
|
|
122
|
-
let written = iov + (8n * 5n)
|
|
123
|
-
WasmI32.store(iov, WasmI32.fromGrain(_DECREF_DEBUG_STR_1) + 8n, 0n)
|
|
124
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_DECREF_DEBUG_STR_1), 4n), 4n)
|
|
125
|
-
WasmI32.store(iov, ptrStr, 8n)
|
|
126
|
-
WasmI32.store(iov, ptrDecimals, 12n)
|
|
127
|
-
WasmI32.store(iov, WasmI32.fromGrain(_DECREF_DEBUG_STR_2) + 8n, 16n)
|
|
128
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_DECREF_DEBUG_STR_2), 4n), 20n)
|
|
129
|
-
WasmI32.store(iov, refCountStr, 24n)
|
|
130
|
-
WasmI32.store(iov, refCountDecimals, 28n)
|
|
131
|
-
if (ignoreZeros) {
|
|
132
|
-
WasmI32.store(iov, WasmI32.fromGrain(_DECREF_DEBUG_STR_3) + 8n, 32n)
|
|
133
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_DECREF_DEBUG_STR_3), 4n), 36n)
|
|
134
|
-
} else {
|
|
135
|
-
WasmI32.store(iov, WasmI32.fromGrain(_DECREF_DEBUG_STR_4) + 8n, 32n)
|
|
136
|
-
WasmI32.store(iov, WasmI32.load(WasmI32.fromGrain(_DECREF_DEBUG_STR_4), 4n), 36n)
|
|
137
|
-
}
|
|
138
|
-
fd_write(1n, iov, 5n, written)
|
|
139
|
-
fd_sync(1n)
|
|
140
|
-
Malloc.free(ptrStr)
|
|
141
|
-
Malloc.free(refCountStr)
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
*/
|
|
145
|
-
|
|
146
44
|
let getRefCount = (userPtr: WasmI32) => {
|
|
147
45
|
WasmI32.load(userPtr - _HEADER_SIZE, 0n)
|
|
148
46
|
}
|
|
@@ -151,7 +49,7 @@ let setRefCount = (userPtr: WasmI32, count: WasmI32) => {
|
|
|
151
49
|
WasmI32.store(userPtr - _HEADER_SIZE, count, 0n)
|
|
152
50
|
}
|
|
153
51
|
|
|
154
|
-
|
|
52
|
+
provide let malloc = (size: WasmI32) => {
|
|
155
53
|
// Add space for header
|
|
156
54
|
let rawPtr = Malloc.malloc(size + _HEADER_SIZE)
|
|
157
55
|
|
|
@@ -163,16 +61,13 @@ export let malloc = (size: WasmI32) => {
|
|
|
163
61
|
rawPtr + _HEADER_SIZE
|
|
164
62
|
}
|
|
165
63
|
|
|
166
|
-
|
|
64
|
+
provide let free = (userPtr: WasmI32) => {
|
|
167
65
|
// Free the raw pointer
|
|
168
66
|
Malloc.free(userPtr - _HEADER_SIZE)
|
|
169
67
|
}
|
|
170
68
|
|
|
171
|
-
|
|
172
|
-
if (
|
|
173
|
-
WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) &&
|
|
174
|
-
WasmI32.ne(userPtr, 0n)
|
|
175
|
-
) {
|
|
69
|
+
provide let incRef = (userPtr: WasmI32) => {
|
|
70
|
+
if (WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) && userPtr != 0n) {
|
|
176
71
|
// if (_DEBUG) {
|
|
177
72
|
// logIncRef(userPtr, getRefCount(userPtr))
|
|
178
73
|
// void;
|
|
@@ -183,10 +78,7 @@ export let incRef = (userPtr: WasmI32) => {
|
|
|
183
78
|
}
|
|
184
79
|
|
|
185
80
|
let rec decRef = (userPtr: WasmI32, ignoreZeros: Bool) => {
|
|
186
|
-
if (
|
|
187
|
-
WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) &&
|
|
188
|
-
WasmI32.ne(userPtr, 0n)
|
|
189
|
-
) {
|
|
81
|
+
if (WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) && userPtr != 0n) {
|
|
190
82
|
let refCount = getRefCount(userPtr)
|
|
191
83
|
// if (_DEBUG) {
|
|
192
84
|
// logDecRef(userPtr, refCount, ignoreZeros)
|
|
@@ -213,8 +105,8 @@ let rec decRef = (userPtr: WasmI32, ignoreZeros: Bool) => {
|
|
|
213
105
|
} else {
|
|
214
106
|
userPtr
|
|
215
107
|
}
|
|
216
|
-
}
|
|
217
|
-
decRefChildren = (userPtr: WasmI32) => {
|
|
108
|
+
}
|
|
109
|
+
and decRefChildren = (userPtr: WasmI32) => {
|
|
218
110
|
match (WasmI32.load(userPtr, 0n)) {
|
|
219
111
|
t when t == Tags._GRAIN_BOXED_NUM_HEAP_TAG => {
|
|
220
112
|
let tag = WasmI32.load(userPtr, 4n)
|
|
@@ -238,9 +130,7 @@ decRefChildren = (userPtr: WasmI32) => {
|
|
|
238
130
|
ignore(decRef(WasmI32.load(userPtr + i, 16n), false))
|
|
239
131
|
}
|
|
240
132
|
},
|
|
241
|
-
t when
|
|
242
|
-
t == Tags._GRAIN_ARRAY_HEAP_TAG || t == Tags._GRAIN_TUPLE_HEAP_TAG
|
|
243
|
-
) => {
|
|
133
|
+
t when t == Tags._GRAIN_ARRAY_HEAP_TAG || t == Tags._GRAIN_TUPLE_HEAP_TAG => {
|
|
244
134
|
let arity = WasmI32.load(userPtr, 4n)
|
|
245
135
|
let maxOffset = arity * 4n
|
|
246
136
|
for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
|
|
@@ -261,23 +151,4 @@ decRefChildren = (userPtr: WasmI32) => {
|
|
|
261
151
|
}
|
|
262
152
|
}
|
|
263
153
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
// For debugging:
|
|
267
|
-
|
|
268
|
-
// export let getRefCount = (value) => {
|
|
269
|
-
// let userPtr = WasmI32.fromGrain(value)
|
|
270
|
-
// let ret = if (WasmI32.eqz(userPtr & Tags._GRAIN_GENERIC_TAG_MASK) && WasmI32.ne(userPtr, 0n)) {
|
|
271
|
-
// WasmI32.toGrain((getRefCount(userPtr) * 2n) + 1n) : Number
|
|
272
|
-
// } else {
|
|
273
|
-
// 0
|
|
274
|
-
// }
|
|
275
|
-
// decRef(userPtr)
|
|
276
|
-
// ret
|
|
277
|
-
// }
|
|
278
|
-
|
|
279
|
-
// export let rec setDebug = (enabled: Bool) => {
|
|
280
|
-
// _DEBUG = enabled
|
|
281
|
-
// decRef(WasmI32.fromGrain(setDebug))
|
|
282
|
-
// void
|
|
283
|
-
// }
|
|
154
|
+
provide let decRef = userPtr => decRef(userPtr, false)
|
package/runtime/gc.md
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: GC
|
|
3
|
+
---
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
decimalCount32 : Box<WasmI32 -> WasmI32>
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
### Gc.**utoa32Buffered**
|
|
5
|
+
## Values
|
|
8
6
|
|
|
9
|
-
|
|
10
|
-
utoa32Buffered : Box<(WasmI32, WasmI32, WasmI32) -> Void>
|
|
11
|
-
```
|
|
7
|
+
Functions and constants included in the GC module.
|
|
12
8
|
|
|
13
|
-
###
|
|
9
|
+
### GC.**malloc**
|
|
14
10
|
|
|
15
11
|
```grain
|
|
16
|
-
malloc : WasmI32
|
|
12
|
+
malloc : (size: WasmI32) => WasmI32
|
|
17
13
|
```
|
|
18
14
|
|
|
19
|
-
###
|
|
15
|
+
### GC.**free**
|
|
20
16
|
|
|
21
17
|
```grain
|
|
22
|
-
free : WasmI32
|
|
18
|
+
free : (userPtr: WasmI32) => Void
|
|
23
19
|
```
|
|
24
20
|
|
|
25
|
-
###
|
|
21
|
+
### GC.**incRef**
|
|
26
22
|
|
|
27
23
|
```grain
|
|
28
|
-
incRef : WasmI32
|
|
24
|
+
incRef : (userPtr: WasmI32) => WasmI32
|
|
29
25
|
```
|
|
30
26
|
|
|
31
|
-
###
|
|
27
|
+
### GC.**decRef**
|
|
32
28
|
|
|
33
29
|
```grain
|
|
34
|
-
decRef : WasmI32
|
|
30
|
+
decRef : (userPtr: WasmI32) => WasmI32
|
|
35
31
|
```
|
|
36
32
|
|