@grain/stdlib 0.6.2 → 0.6.4
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 +14 -0
- package/LICENSE +1 -1
- package/int16.gr +85 -0
- package/int16.md +168 -0
- package/int8.gr +1 -1
- package/int8.md +1 -1
- package/package.json +1 -1
- package/runtime/malloc.gr +269 -135
- package/runtime/malloc.md +3 -10
- package/set.gr +0 -5
- package/wasi/process.gr +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.6.4](https://github.com/grain-lang/grain/compare/stdlib-v0.6.3...stdlib-v0.6.4) (2024-06-27)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **stdlib:** Faster memory allocator ([#2124](https://github.com/grain-lang/grain/issues/2124)) ([03e10c4](https://github.com/grain-lang/grain/commit/03e10c49d204a488f8bd56c7b7262e717ee61762))
|
|
9
|
+
|
|
10
|
+
## [0.6.3](https://github.com/grain-lang/grain/compare/stdlib-v0.6.2...stdlib-v0.6.3) (2024-04-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Miscellaneous Chores
|
|
14
|
+
|
|
15
|
+
* **stdlib:** Synchronize Grain versions
|
|
16
|
+
|
|
3
17
|
## [0.6.2](https://github.com/grain-lang/grain/compare/stdlib-v0.6.1...stdlib-v0.6.2) (2024-04-01)
|
|
4
18
|
|
|
5
19
|
|
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c) 2017-
|
|
3
|
+
Copyright (c) 2017-2024 Oscar Spencer <oscar@grain-lang.org> and Philip Blair <philip@grain-lang.org>
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/int16.gr
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
* Utilities for working with the Int16 type.
|
|
3
3
|
* @example from "int16" include Int16
|
|
4
4
|
*
|
|
5
|
+
* @example 1S
|
|
6
|
+
* @example -1S
|
|
7
|
+
*
|
|
5
8
|
* @since v0.6.0
|
|
6
9
|
*/
|
|
7
10
|
module Int16
|
|
@@ -51,6 +54,8 @@ let signExtend = x => (x << _DATA_OFFSET) >> _DATA_OFFSET
|
|
|
51
54
|
* @param number: The value to convert
|
|
52
55
|
* @returns The Uint16 represented as an Int16
|
|
53
56
|
*
|
|
57
|
+
* @example Int16.fromUint16(1uS) == 1S
|
|
58
|
+
*
|
|
54
59
|
* @since v0.6.0
|
|
55
60
|
*/
|
|
56
61
|
@unsafe
|
|
@@ -67,6 +72,9 @@ provide let fromUint16 = (number: Uint16) => {
|
|
|
67
72
|
* @param value: The value to increment
|
|
68
73
|
* @returns The incremented value
|
|
69
74
|
*
|
|
75
|
+
* @example Int16.incr(1S) == 2S
|
|
76
|
+
* @example Int16.incr(-2S) == -1S
|
|
77
|
+
*
|
|
70
78
|
* @since v0.6.0
|
|
71
79
|
*/
|
|
72
80
|
@unsafe
|
|
@@ -83,6 +91,9 @@ provide let incr = (value: Int16) => {
|
|
|
83
91
|
* @param value: The value to decrement
|
|
84
92
|
* @returns The decremented value
|
|
85
93
|
*
|
|
94
|
+
* @example Int16.decr(2S) == 1S
|
|
95
|
+
* @example Int16.decr(0S) == -1S
|
|
96
|
+
*
|
|
86
97
|
* @since v0.6.0
|
|
87
98
|
*/
|
|
88
99
|
@unsafe
|
|
@@ -100,6 +111,10 @@ provide let decr = (value: Int16) => {
|
|
|
100
111
|
* @param y: The second operand
|
|
101
112
|
* @returns The sum of the two operands
|
|
102
113
|
*
|
|
114
|
+
* @example
|
|
115
|
+
* use Int16.{ (+) }
|
|
116
|
+
* assert 1S + 1S == 2S
|
|
117
|
+
*
|
|
103
118
|
* @since v0.6.0
|
|
104
119
|
*/
|
|
105
120
|
@unsafe
|
|
@@ -121,6 +136,10 @@ provide let (+) = (x: Int16, y: Int16) => {
|
|
|
121
136
|
* @param y: The second operand
|
|
122
137
|
* @returns The difference of the two operands
|
|
123
138
|
*
|
|
139
|
+
* @example
|
|
140
|
+
* use Int16.{ (-) }
|
|
141
|
+
* assert 2S - 1S == 1S
|
|
142
|
+
*
|
|
124
143
|
* @since v0.6.0
|
|
125
144
|
*/
|
|
126
145
|
@unsafe
|
|
@@ -139,6 +158,10 @@ provide let (-) = (x: Int16, y: Int16) => {
|
|
|
139
158
|
* @param y: The second operand
|
|
140
159
|
* @returns The product of the two operands
|
|
141
160
|
*
|
|
161
|
+
* @example
|
|
162
|
+
* use Int16.{ (*) }
|
|
163
|
+
* assert 2S * 2S == 4S
|
|
164
|
+
*
|
|
142
165
|
* @since v0.6.0
|
|
143
166
|
*/
|
|
144
167
|
@unsafe
|
|
@@ -156,6 +179,10 @@ provide let (*) = (x: Int16, y: Int16) => {
|
|
|
156
179
|
* @param y: The second operand
|
|
157
180
|
* @returns The quotient of its operands
|
|
158
181
|
*
|
|
182
|
+
* @example
|
|
183
|
+
* use Int16.{ (/) }
|
|
184
|
+
* assert 8S / 2S == 4S
|
|
185
|
+
*
|
|
159
186
|
* @since v0.6.0
|
|
160
187
|
*/
|
|
161
188
|
@unsafe
|
|
@@ -174,6 +201,8 @@ provide let (/) = (x: Int16, y: Int16) => {
|
|
|
174
201
|
* @param y: The second operand
|
|
175
202
|
* @returns The remainder of its operands
|
|
176
203
|
*
|
|
204
|
+
* @example Int16.rem(8S, 3S) == 2S
|
|
205
|
+
*
|
|
177
206
|
* @since v0.6.0
|
|
178
207
|
*/
|
|
179
208
|
@unsafe
|
|
@@ -202,6 +231,10 @@ let abs = n => {
|
|
|
202
231
|
*
|
|
203
232
|
* @throws ModuloByZero: When `y` is zero
|
|
204
233
|
*
|
|
234
|
+
* @example
|
|
235
|
+
* use Int16.{ (%) }
|
|
236
|
+
* assert -5S % 3S == 1S
|
|
237
|
+
*
|
|
205
238
|
* @since v0.6.0
|
|
206
239
|
*/
|
|
207
240
|
@unsafe
|
|
@@ -233,6 +266,10 @@ provide let (%) = (x: Int16, y: Int16) => {
|
|
|
233
266
|
* @param amount: The number of bits to shift by
|
|
234
267
|
* @returns The shifted value
|
|
235
268
|
*
|
|
269
|
+
* @example
|
|
270
|
+
* use Int16.{ (<<) }
|
|
271
|
+
* assert (5S << 1S) == 10S
|
|
272
|
+
*
|
|
236
273
|
* @since v0.6.0
|
|
237
274
|
*/
|
|
238
275
|
@unsafe
|
|
@@ -252,6 +289,10 @@ provide let (<<) = (value: Int16, amount: Int16) => {
|
|
|
252
289
|
* @param amount: The amount to shift by
|
|
253
290
|
* @returns The shifted value
|
|
254
291
|
*
|
|
292
|
+
* @example
|
|
293
|
+
* use Int16.{ (>>) }
|
|
294
|
+
* assert (5S >> 1S) == 2S
|
|
295
|
+
*
|
|
255
296
|
* @since v0.6.0
|
|
256
297
|
*/
|
|
257
298
|
@unsafe
|
|
@@ -271,6 +312,10 @@ provide let (>>) = (value: Int16, amount: Int16) => {
|
|
|
271
312
|
* @param y: The second value
|
|
272
313
|
* @returns `true` if the first value is equal to the second value or `false` otherwise
|
|
273
314
|
*
|
|
315
|
+
* @example
|
|
316
|
+
* use Int16.{ (==) }
|
|
317
|
+
* assert 1S == 1S
|
|
318
|
+
*
|
|
274
319
|
* @since v0.6.0
|
|
275
320
|
*/
|
|
276
321
|
@unsafe
|
|
@@ -287,6 +332,10 @@ provide let (==) = (x: Int16, y: Int16) => {
|
|
|
287
332
|
* @param y: The second value
|
|
288
333
|
* @returns `true` if the first value is not equal to the second value or `false` otherwise
|
|
289
334
|
*
|
|
335
|
+
* @example
|
|
336
|
+
* use Int16.{ (!=) }
|
|
337
|
+
* assert 1S != 2S
|
|
338
|
+
*
|
|
290
339
|
* @since v0.6.0
|
|
291
340
|
*/
|
|
292
341
|
@unsafe
|
|
@@ -303,6 +352,10 @@ provide let (!=) = (x: Int16, y: Int16) => {
|
|
|
303
352
|
* @param y: The second value
|
|
304
353
|
* @returns `true` if the first value is less than the second value or `false` otherwise
|
|
305
354
|
*
|
|
355
|
+
* @example
|
|
356
|
+
* use Int16.{ (<) }
|
|
357
|
+
* assert 1S < 2S
|
|
358
|
+
*
|
|
306
359
|
* @since v0.6.0
|
|
307
360
|
*/
|
|
308
361
|
@unsafe
|
|
@@ -319,6 +372,10 @@ provide let (<) = (x: Int16, y: Int16) => {
|
|
|
319
372
|
* @param y: The second value
|
|
320
373
|
* @returns `true` if the first value is greater than the second value or `false` otherwise
|
|
321
374
|
*
|
|
375
|
+
* @example
|
|
376
|
+
* use Int16.{ (>) }
|
|
377
|
+
* assert 2S > 1S
|
|
378
|
+
*
|
|
322
379
|
* @since v0.6.0
|
|
323
380
|
*/
|
|
324
381
|
@unsafe
|
|
@@ -335,6 +392,13 @@ provide let (>) = (x: Int16, y: Int16) => {
|
|
|
335
392
|
* @param y: The second value
|
|
336
393
|
* @returns `true` if the first value is less than or equal to the second value or `false` otherwise
|
|
337
394
|
*
|
|
395
|
+
* @example
|
|
396
|
+
* use Int16.{ (<=) }
|
|
397
|
+
* assert 1S <= 2S
|
|
398
|
+
* @example
|
|
399
|
+
* use Int16.{ (<=) }
|
|
400
|
+
* assert 1S <= 1S
|
|
401
|
+
*
|
|
338
402
|
* @since v0.6.0
|
|
339
403
|
*/
|
|
340
404
|
@unsafe
|
|
@@ -351,6 +415,13 @@ provide let (<=) = (x: Int16, y: Int16) => {
|
|
|
351
415
|
* @param y: The second value
|
|
352
416
|
* @returns `true` if the first value is greater than or equal to the second value or `false` otherwise
|
|
353
417
|
*
|
|
418
|
+
* @example
|
|
419
|
+
* use Int16.{ (>=) }
|
|
420
|
+
* assert 2S >= 1S
|
|
421
|
+
* @example
|
|
422
|
+
* use Int16.{ (>=) }
|
|
423
|
+
* assert 1S >= 1S
|
|
424
|
+
*
|
|
354
425
|
* @since v0.6.0
|
|
355
426
|
*/
|
|
356
427
|
@unsafe
|
|
@@ -366,6 +437,8 @@ provide let (>=) = (x: Int16, y: Int16) => {
|
|
|
366
437
|
* @param value: The given value
|
|
367
438
|
* @returns Containing the inverted bits of the given value
|
|
368
439
|
*
|
|
440
|
+
* @example Int16.lnot(-5S) == 4S
|
|
441
|
+
*
|
|
369
442
|
* @since v0.6.0
|
|
370
443
|
*/
|
|
371
444
|
@unsafe
|
|
@@ -381,6 +454,10 @@ provide let lnot = (value: Int16) => {
|
|
|
381
454
|
* @param y: The second operand
|
|
382
455
|
* @returns Containing a `1` in each bit position for which the corresponding bits of both operands are `1`
|
|
383
456
|
*
|
|
457
|
+
* @example
|
|
458
|
+
* use Int16.{ (&) }
|
|
459
|
+
* assert (3S & 4S) == 0S
|
|
460
|
+
*
|
|
384
461
|
* @since v0.6.0
|
|
385
462
|
*/
|
|
386
463
|
@unsafe
|
|
@@ -399,6 +476,10 @@ provide let (&) = (x: Int16, y: Int16) => {
|
|
|
399
476
|
* @param y: The second operand
|
|
400
477
|
* @returns Containing a `1` in each bit position for which the corresponding bits of either or both operands are `1`
|
|
401
478
|
*
|
|
479
|
+
* @example
|
|
480
|
+
* use Int16.{ (|) }
|
|
481
|
+
* assert (3S | 4S) == 7S
|
|
482
|
+
*
|
|
402
483
|
* @since v0.6.0
|
|
403
484
|
*/
|
|
404
485
|
@unsafe
|
|
@@ -417,6 +498,10 @@ provide let (|) = (x: Int16, y: Int16) => {
|
|
|
417
498
|
* @param y: The second operand
|
|
418
499
|
* @returns Containing a `1` in each bit position for which the corresponding bits of either but not both operands are `1`
|
|
419
500
|
*
|
|
501
|
+
* @example
|
|
502
|
+
* use Int16.{ (^) }
|
|
503
|
+
* assert (3S ^ 5S) == 6S
|
|
504
|
+
*
|
|
420
505
|
* @since v0.6.0
|
|
421
506
|
*/
|
|
422
507
|
@unsafe
|
package/int16.md
CHANGED
|
@@ -13,6 +13,14 @@ No other changes yet.
|
|
|
13
13
|
from "int16" include Int16
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
```grain
|
|
17
|
+
1S
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```grain
|
|
21
|
+
-1S
|
|
22
|
+
```
|
|
23
|
+
|
|
16
24
|
## Values
|
|
17
25
|
|
|
18
26
|
Functions and constants included in the Int16 module.
|
|
@@ -92,6 +100,12 @@ Returns:
|
|
|
92
100
|
|----|-----------|
|
|
93
101
|
|`Int16`|The Uint16 represented as an Int16|
|
|
94
102
|
|
|
103
|
+
Examples:
|
|
104
|
+
|
|
105
|
+
```grain
|
|
106
|
+
Int16.fromUint16(1uS) == 1S
|
|
107
|
+
```
|
|
108
|
+
|
|
95
109
|
### Int16.**incr**
|
|
96
110
|
|
|
97
111
|
<details disabled>
|
|
@@ -117,6 +131,16 @@ Returns:
|
|
|
117
131
|
|----|-----------|
|
|
118
132
|
|`Int16`|The incremented value|
|
|
119
133
|
|
|
134
|
+
Examples:
|
|
135
|
+
|
|
136
|
+
```grain
|
|
137
|
+
Int16.incr(1S) == 2S
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```grain
|
|
141
|
+
Int16.incr(-2S) == -1S
|
|
142
|
+
```
|
|
143
|
+
|
|
120
144
|
### Int16.**decr**
|
|
121
145
|
|
|
122
146
|
<details disabled>
|
|
@@ -142,6 +166,16 @@ Returns:
|
|
|
142
166
|
|----|-----------|
|
|
143
167
|
|`Int16`|The decremented value|
|
|
144
168
|
|
|
169
|
+
Examples:
|
|
170
|
+
|
|
171
|
+
```grain
|
|
172
|
+
Int16.decr(2S) == 1S
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```grain
|
|
176
|
+
Int16.decr(0S) == -1S
|
|
177
|
+
```
|
|
178
|
+
|
|
145
179
|
### Int16.**(+)**
|
|
146
180
|
|
|
147
181
|
<details disabled>
|
|
@@ -168,6 +202,13 @@ Returns:
|
|
|
168
202
|
|----|-----------|
|
|
169
203
|
|`Int16`|The sum of the two operands|
|
|
170
204
|
|
|
205
|
+
Examples:
|
|
206
|
+
|
|
207
|
+
```grain
|
|
208
|
+
use Int16.{ (+) }
|
|
209
|
+
assert 1S + 1S == 2S
|
|
210
|
+
```
|
|
211
|
+
|
|
171
212
|
### Int16.**(-)**
|
|
172
213
|
|
|
173
214
|
<details disabled>
|
|
@@ -194,6 +235,13 @@ Returns:
|
|
|
194
235
|
|----|-----------|
|
|
195
236
|
|`Int16`|The difference of the two operands|
|
|
196
237
|
|
|
238
|
+
Examples:
|
|
239
|
+
|
|
240
|
+
```grain
|
|
241
|
+
use Int16.{ (-) }
|
|
242
|
+
assert 2S - 1S == 1S
|
|
243
|
+
```
|
|
244
|
+
|
|
197
245
|
### Int16.**(*)**
|
|
198
246
|
|
|
199
247
|
<details disabled>
|
|
@@ -220,6 +268,13 @@ Returns:
|
|
|
220
268
|
|----|-----------|
|
|
221
269
|
|`Int16`|The product of the two operands|
|
|
222
270
|
|
|
271
|
+
Examples:
|
|
272
|
+
|
|
273
|
+
```grain
|
|
274
|
+
use Int16.{ (*) }
|
|
275
|
+
assert 2S * 2S == 4S
|
|
276
|
+
```
|
|
277
|
+
|
|
223
278
|
### Int16.**(/)**
|
|
224
279
|
|
|
225
280
|
<details disabled>
|
|
@@ -246,6 +301,13 @@ Returns:
|
|
|
246
301
|
|----|-----------|
|
|
247
302
|
|`Int16`|The quotient of its operands|
|
|
248
303
|
|
|
304
|
+
Examples:
|
|
305
|
+
|
|
306
|
+
```grain
|
|
307
|
+
use Int16.{ (/) }
|
|
308
|
+
assert 8S / 2S == 4S
|
|
309
|
+
```
|
|
310
|
+
|
|
249
311
|
### Int16.**rem**
|
|
250
312
|
|
|
251
313
|
<details disabled>
|
|
@@ -272,6 +334,12 @@ Returns:
|
|
|
272
334
|
|----|-----------|
|
|
273
335
|
|`Int16`|The remainder of its operands|
|
|
274
336
|
|
|
337
|
+
Examples:
|
|
338
|
+
|
|
339
|
+
```grain
|
|
340
|
+
Int16.rem(8S, 3S) == 2S
|
|
341
|
+
```
|
|
342
|
+
|
|
275
343
|
### Int16.**(%)**
|
|
276
344
|
|
|
277
345
|
<details disabled>
|
|
@@ -305,6 +373,13 @@ Throws:
|
|
|
305
373
|
|
|
306
374
|
* When `y` is zero
|
|
307
375
|
|
|
376
|
+
Examples:
|
|
377
|
+
|
|
378
|
+
```grain
|
|
379
|
+
use Int16.{ (%) }
|
|
380
|
+
assert -5S % 3S == 1S
|
|
381
|
+
```
|
|
382
|
+
|
|
308
383
|
### Int16.**(<<)**
|
|
309
384
|
|
|
310
385
|
<details disabled>
|
|
@@ -331,6 +406,13 @@ Returns:
|
|
|
331
406
|
|----|-----------|
|
|
332
407
|
|`Int16`|The shifted value|
|
|
333
408
|
|
|
409
|
+
Examples:
|
|
410
|
+
|
|
411
|
+
```grain
|
|
412
|
+
use Int16.{ (<<) }
|
|
413
|
+
assert (5S << 1S) == 10S
|
|
414
|
+
```
|
|
415
|
+
|
|
334
416
|
### Int16.**(>>)**
|
|
335
417
|
|
|
336
418
|
<details disabled>
|
|
@@ -357,6 +439,13 @@ Returns:
|
|
|
357
439
|
|----|-----------|
|
|
358
440
|
|`Int16`|The shifted value|
|
|
359
441
|
|
|
442
|
+
Examples:
|
|
443
|
+
|
|
444
|
+
```grain
|
|
445
|
+
use Int16.{ (>>) }
|
|
446
|
+
assert (5S >> 1S) == 2S
|
|
447
|
+
```
|
|
448
|
+
|
|
360
449
|
### Int16.**(==)**
|
|
361
450
|
|
|
362
451
|
<details disabled>
|
|
@@ -383,6 +472,13 @@ Returns:
|
|
|
383
472
|
|----|-----------|
|
|
384
473
|
|`Bool`|`true` if the first value is equal to the second value or `false` otherwise|
|
|
385
474
|
|
|
475
|
+
Examples:
|
|
476
|
+
|
|
477
|
+
```grain
|
|
478
|
+
use Int16.{ (==) }
|
|
479
|
+
assert 1S == 1S
|
|
480
|
+
```
|
|
481
|
+
|
|
386
482
|
### Int16.**(!=)**
|
|
387
483
|
|
|
388
484
|
<details disabled>
|
|
@@ -409,6 +505,13 @@ Returns:
|
|
|
409
505
|
|----|-----------|
|
|
410
506
|
|`Bool`|`true` if the first value is not equal to the second value or `false` otherwise|
|
|
411
507
|
|
|
508
|
+
Examples:
|
|
509
|
+
|
|
510
|
+
```grain
|
|
511
|
+
use Int16.{ (!=) }
|
|
512
|
+
assert 1S != 2S
|
|
513
|
+
```
|
|
514
|
+
|
|
412
515
|
### Int16.**(<)**
|
|
413
516
|
|
|
414
517
|
<details disabled>
|
|
@@ -435,6 +538,13 @@ Returns:
|
|
|
435
538
|
|----|-----------|
|
|
436
539
|
|`Bool`|`true` if the first value is less than the second value or `false` otherwise|
|
|
437
540
|
|
|
541
|
+
Examples:
|
|
542
|
+
|
|
543
|
+
```grain
|
|
544
|
+
use Int16.{ (<) }
|
|
545
|
+
assert 1S < 2S
|
|
546
|
+
```
|
|
547
|
+
|
|
438
548
|
### Int16.**(>)**
|
|
439
549
|
|
|
440
550
|
<details disabled>
|
|
@@ -461,6 +571,13 @@ Returns:
|
|
|
461
571
|
|----|-----------|
|
|
462
572
|
|`Bool`|`true` if the first value is greater than the second value or `false` otherwise|
|
|
463
573
|
|
|
574
|
+
Examples:
|
|
575
|
+
|
|
576
|
+
```grain
|
|
577
|
+
use Int16.{ (>) }
|
|
578
|
+
assert 2S > 1S
|
|
579
|
+
```
|
|
580
|
+
|
|
464
581
|
### Int16.**(<=)**
|
|
465
582
|
|
|
466
583
|
<details disabled>
|
|
@@ -487,6 +604,18 @@ Returns:
|
|
|
487
604
|
|----|-----------|
|
|
488
605
|
|`Bool`|`true` if the first value is less than or equal to the second value or `false` otherwise|
|
|
489
606
|
|
|
607
|
+
Examples:
|
|
608
|
+
|
|
609
|
+
```grain
|
|
610
|
+
use Int16.{ (<=) }
|
|
611
|
+
assert 1S <= 2S
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
```grain
|
|
615
|
+
use Int16.{ (<=) }
|
|
616
|
+
assert 1S <= 1S
|
|
617
|
+
```
|
|
618
|
+
|
|
490
619
|
### Int16.**(>=)**
|
|
491
620
|
|
|
492
621
|
<details disabled>
|
|
@@ -513,6 +642,18 @@ Returns:
|
|
|
513
642
|
|----|-----------|
|
|
514
643
|
|`Bool`|`true` if the first value is greater than or equal to the second value or `false` otherwise|
|
|
515
644
|
|
|
645
|
+
Examples:
|
|
646
|
+
|
|
647
|
+
```grain
|
|
648
|
+
use Int16.{ (>=) }
|
|
649
|
+
assert 2S >= 1S
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
```grain
|
|
653
|
+
use Int16.{ (>=) }
|
|
654
|
+
assert 1S >= 1S
|
|
655
|
+
```
|
|
656
|
+
|
|
516
657
|
### Int16.**lnot**
|
|
517
658
|
|
|
518
659
|
<details disabled>
|
|
@@ -538,6 +679,12 @@ Returns:
|
|
|
538
679
|
|----|-----------|
|
|
539
680
|
|`Int16`|Containing the inverted bits of the given value|
|
|
540
681
|
|
|
682
|
+
Examples:
|
|
683
|
+
|
|
684
|
+
```grain
|
|
685
|
+
Int16.lnot(-5S) == 4S
|
|
686
|
+
```
|
|
687
|
+
|
|
541
688
|
### Int16.**(&)**
|
|
542
689
|
|
|
543
690
|
<details disabled>
|
|
@@ -564,6 +711,13 @@ Returns:
|
|
|
564
711
|
|----|-----------|
|
|
565
712
|
|`Int16`|Containing a `1` in each bit position for which the corresponding bits of both operands are `1`|
|
|
566
713
|
|
|
714
|
+
Examples:
|
|
715
|
+
|
|
716
|
+
```grain
|
|
717
|
+
use Int16.{ (&) }
|
|
718
|
+
assert (3S & 4S) == 0S
|
|
719
|
+
```
|
|
720
|
+
|
|
567
721
|
### Int16.**(|)**
|
|
568
722
|
|
|
569
723
|
<details disabled>
|
|
@@ -590,6 +744,13 @@ Returns:
|
|
|
590
744
|
|----|-----------|
|
|
591
745
|
|`Int16`|Containing a `1` in each bit position for which the corresponding bits of either or both operands are `1`|
|
|
592
746
|
|
|
747
|
+
Examples:
|
|
748
|
+
|
|
749
|
+
```grain
|
|
750
|
+
use Int16.{ (|) }
|
|
751
|
+
assert (3S | 4S) == 7S
|
|
752
|
+
```
|
|
753
|
+
|
|
593
754
|
### Int16.**(^)**
|
|
594
755
|
|
|
595
756
|
<details disabled>
|
|
@@ -616,3 +777,10 @@ Returns:
|
|
|
616
777
|
|----|-----------|
|
|
617
778
|
|`Int16`|Containing a `1` in each bit position for which the corresponding bits of either but not both operands are `1`|
|
|
618
779
|
|
|
780
|
+
Examples:
|
|
781
|
+
|
|
782
|
+
```grain
|
|
783
|
+
use Int16.{ (^) }
|
|
784
|
+
assert (3S ^ 5S) == 6S
|
|
785
|
+
```
|
|
786
|
+
|
package/int8.gr
CHANGED
package/int8.md
CHANGED
package/package.json
CHANGED
package/runtime/malloc.gr
CHANGED
|
@@ -3,8 +3,6 @@ module Malloc
|
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* This module implements a generic memory allocator.
|
|
6
|
-
* The algorithm is quite simple, being based on the memory allocator
|
|
7
|
-
* from pages 185-188 of K&R C (2nd edition).
|
|
8
6
|
*/
|
|
9
7
|
|
|
10
8
|
from "runtime/unsafe/wasmi32" include WasmI32
|
|
@@ -20,6 +18,8 @@ use WasmI32.{
|
|
|
20
18
|
(>>>),
|
|
21
19
|
(==),
|
|
22
20
|
(!=),
|
|
21
|
+
(&),
|
|
22
|
+
(^),
|
|
23
23
|
}
|
|
24
24
|
from "runtime/exception" include Exception
|
|
25
25
|
|
|
@@ -32,44 +32,64 @@ primitive (||) = "@or"
|
|
|
32
32
|
|
|
33
33
|
primitive heapStart = "@heap.start"
|
|
34
34
|
|
|
35
|
-
/* UNDERSTANDING THE STRUCTURE OF THE FREE
|
|
36
|
-
* The original K&R definition for the free list entry type was the following:
|
|
35
|
+
/* UNDERSTANDING THE STRUCTURE OF THE FREE LISTS
|
|
37
36
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
37
|
+
* `malloc` allocates memory and `free` releases this memory. Two separate free
|
|
38
|
+
* lists are maintained, one for small blocks of 64 bytes, and one for larger
|
|
39
|
+
* blocks of multiples of 64 bytes. Each block has an 8-byte header and 8-byte
|
|
40
|
+
* footer to keep track of block sizes and maintain the free list.
|
|
41
|
+
*
|
|
42
|
+
* Most allocations in programs are small, so the separate free lists allow us
|
|
43
|
+
* to implement `malloc` and `free` in O(1) for small allocations and O(n)
|
|
44
|
+
* `malloc` and O(1) `free` for large allocations, where `n` is the size of the
|
|
45
|
+
* free list for large blocks.
|
|
46
|
+
*
|
|
47
|
+
* The small blocks are able to service:
|
|
48
|
+
* - Numbers (with the exception of large BigInts/Rationals)
|
|
49
|
+
* - Tuples/Arrays up to 8 elements
|
|
50
|
+
* - Records up to 6 elements
|
|
51
|
+
* - Variants up to 5 elements
|
|
52
|
+
* - Closures up to 6 elements
|
|
53
|
+
* - Bytes/Strings up to length 32
|
|
54
|
+
*
|
|
55
|
+
* Blocks in memory look like this:
|
|
45
56
|
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
57
|
+
* 8 bytes 8 bytes 64n - 16 bytes 8 bytes 8 bytes
|
|
58
|
+
* ┌─────────────────────┬────────────────┬─────────────────┬────────────────┬─────────────────────┐
|
|
59
|
+
* │ <prev block footer> │ <block header> │ <block content> │ <block footer> │ <next block header> │
|
|
60
|
+
* └─────────────────────┴────────────────┴─────────────────┴────────────────┴─────────────────────┘
|
|
49
61
|
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
62
|
+
* Block headers look like this:
|
|
63
|
+
* ┌───────────────────────┬──────────────┐
|
|
64
|
+
* │ <prev free block ptr> │ <block size> │
|
|
65
|
+
* └───────────────────────┴──────────────┘
|
|
66
|
+
*
|
|
67
|
+
* Block footers look like this:
|
|
68
|
+
* ┌───────────────────────┬──────────────┐
|
|
69
|
+
* │ <next free block ptr> │ <block size> │
|
|
70
|
+
* └───────────────────────┴──────────────┘
|
|
71
|
+
*
|
|
72
|
+
* The size is kept in the header and footer to allow us to quickly combine
|
|
73
|
+
* free blocks when blocks are freed.
|
|
74
|
+
*
|
|
75
|
+
* Pointers to the previous/next free blocks give us doubly-linked free lists,
|
|
76
|
+
* which makes it possible to remove blocks from the free list in constant
|
|
77
|
+
* time.
|
|
78
|
+
*
|
|
79
|
+
* A block is considered in use when the previous/next pointers are both zero.
|
|
55
80
|
*/
|
|
56
81
|
|
|
57
82
|
/**
|
|
58
|
-
*
|
|
83
|
+
* Pointers to the start of the free lists. This is always a multiple of
|
|
59
84
|
* 8, with the exception of its initial value (used as a sentinel).
|
|
60
85
|
*/
|
|
61
|
-
let mut
|
|
86
|
+
let mut smallBlockFreePtr = 1n
|
|
87
|
+
let mut largeBlockFreePtr = 1n
|
|
62
88
|
|
|
63
89
|
/**
|
|
64
90
|
* Size (in bytes) of entries in the free list.
|
|
65
91
|
*/
|
|
66
|
-
let
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* log_2(mallocHeaderSize) (multiplication by the header
|
|
70
|
-
* size is equivalent to left-shifting by this amount)
|
|
71
|
-
*/
|
|
72
|
-
let logMallocHeaderSize = 3n
|
|
92
|
+
let _HEADER_FOOTER_SIZE = 8n
|
|
73
93
|
|
|
74
94
|
/**
|
|
75
95
|
* The current size (in bytes) of the heap.
|
|
@@ -87,9 +107,9 @@ let _BASE = heapStart() + _RESERVED_RUNTIME_SPACE
|
|
|
87
107
|
/**
|
|
88
108
|
* The start pointer of the heap.
|
|
89
109
|
*/
|
|
90
|
-
let _HEAP_START = _BASE +
|
|
110
|
+
let _HEAP_START = _BASE + _HEADER_FOOTER_SIZE
|
|
91
111
|
|
|
92
|
-
let
|
|
112
|
+
let _PREV_NEXT_OFFSET = 0n
|
|
93
113
|
let _SIZE_OFFSET = 4n
|
|
94
114
|
|
|
95
115
|
/**
|
|
@@ -97,33 +117,65 @@ let _SIZE_OFFSET = 4n
|
|
|
97
117
|
*/
|
|
98
118
|
let _PAGE_SIZE = 65536n
|
|
99
119
|
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
/**
|
|
121
|
+
* Size (in bytes) of blocks allocated by the allocator
|
|
122
|
+
*/
|
|
123
|
+
let _UNIT_SIZE = 64n
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* log_2(_UNIT_SIZE) (multiplication by the header
|
|
127
|
+
* size is equivalent to left-shifting by this amount)
|
|
128
|
+
*/
|
|
129
|
+
let logUnitSize = 6n
|
|
130
|
+
|
|
131
|
+
let headerGetPrevious = (headerPtr: WasmI32) => {
|
|
132
|
+
WasmI32.load(headerPtr, _PREV_NEXT_OFFSET)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let headerSetPrevious = (headerPtr: WasmI32, val: WasmI32) => {
|
|
136
|
+
WasmI32.store(headerPtr, val, _PREV_NEXT_OFFSET)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
let headerGetSize = (headerPtr: WasmI32) => {
|
|
140
|
+
WasmI32.load(headerPtr, _SIZE_OFFSET)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let headerSetSize = (headerPtr: WasmI32, val: WasmI32) => {
|
|
144
|
+
WasmI32.store(headerPtr, val, _SIZE_OFFSET)
|
|
102
145
|
}
|
|
103
146
|
|
|
104
|
-
|
|
105
|
-
|
|
147
|
+
// These functions are no different than the ones above, but exist to make the
|
|
148
|
+
// code much easier to follow
|
|
149
|
+
|
|
150
|
+
let footerGetNext = (footerPtr: WasmI32) => {
|
|
151
|
+
WasmI32.load(footerPtr, _PREV_NEXT_OFFSET)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let footerSetNext = (footerPtr: WasmI32, val: WasmI32) => {
|
|
155
|
+
WasmI32.store(footerPtr, val, _PREV_NEXT_OFFSET)
|
|
106
156
|
}
|
|
107
157
|
|
|
108
|
-
let
|
|
109
|
-
WasmI32.load(
|
|
158
|
+
let footerGetSize = (footerPtr: WasmI32) => {
|
|
159
|
+
WasmI32.load(footerPtr, _SIZE_OFFSET)
|
|
110
160
|
}
|
|
111
161
|
|
|
112
|
-
let
|
|
113
|
-
WasmI32.store(
|
|
162
|
+
let footerSetSize = (footerPtr: WasmI32, val: WasmI32) => {
|
|
163
|
+
WasmI32.store(footerPtr, val, _SIZE_OFFSET)
|
|
114
164
|
}
|
|
115
165
|
|
|
116
166
|
/**
|
|
117
|
-
* Requests that the heap be grown by the given number of
|
|
167
|
+
* Requests that the heap be grown by the given number of units.
|
|
118
168
|
*
|
|
119
|
-
* @param
|
|
169
|
+
* @param nunits: The number of units requested
|
|
120
170
|
* @returns The pointer to the beginning of the extended region if successful or -1 otherwise
|
|
121
171
|
*/
|
|
122
|
-
let growHeap = (
|
|
172
|
+
let growHeap = (nunits: WasmI32) => {
|
|
123
173
|
let mut reqSize = 0n
|
|
124
174
|
let mut reqResult = 0n
|
|
125
175
|
let mut origSize = heapSize
|
|
126
176
|
|
|
177
|
+
let nbytes = nunits << logUnitSize
|
|
178
|
+
|
|
127
179
|
// If the size has not been initialized, do so.
|
|
128
180
|
if (heapSize == 0n) {
|
|
129
181
|
heapSize = memorySize() * _PAGE_SIZE - _HEAP_START
|
|
@@ -131,8 +183,7 @@ let growHeap = (nbytes: WasmI32) => {
|
|
|
131
183
|
// More bytes requested than the initial heap size,
|
|
132
184
|
// so we need to request more anyway.
|
|
133
185
|
reqSize = nbytes - heapSize
|
|
134
|
-
reqSize = reqSize >>> 16n
|
|
135
|
-
reqSize += 1n
|
|
186
|
+
reqSize = (reqSize + _PAGE_SIZE - 1n) >>> 16n
|
|
136
187
|
reqResult = memoryGrow(reqSize)
|
|
137
188
|
if (reqResult == -1n) {
|
|
138
189
|
-1n
|
|
@@ -161,49 +212,105 @@ let growHeap = (nbytes: WasmI32) => {
|
|
|
161
212
|
}
|
|
162
213
|
}
|
|
163
214
|
|
|
215
|
+
let removeFromFreeList = (blockPtr: WasmI32) => {
|
|
216
|
+
let blockSize = headerGetSize(blockPtr)
|
|
217
|
+
let blockFooterPtr = blockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
218
|
+
let nextPtr = footerGetNext(blockFooterPtr)
|
|
219
|
+
|
|
220
|
+
let prevPtr = headerGetPrevious(blockPtr)
|
|
221
|
+
if (prevPtr == 1n) {
|
|
222
|
+
// this block was the start of the free list
|
|
223
|
+
if (blockSize == 1n) {
|
|
224
|
+
smallBlockFreePtr = nextPtr
|
|
225
|
+
} else {
|
|
226
|
+
largeBlockFreePtr = nextPtr
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
headerSetPrevious(nextPtr, prevPtr)
|
|
230
|
+
} else {
|
|
231
|
+
let prevSize = headerGetSize(prevPtr)
|
|
232
|
+
let prevFooterPtr = prevPtr + prevSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
233
|
+
footerSetNext(prevFooterPtr, nextPtr)
|
|
234
|
+
headerSetPrevious(nextPtr, prevPtr)
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
164
238
|
/**
|
|
165
239
|
* Frees the given allocated pointer.
|
|
166
240
|
*
|
|
167
241
|
* @param ap: The pointer to free
|
|
168
242
|
*/
|
|
169
243
|
provide let free = (ap: WasmI32) => {
|
|
170
|
-
let mut blockPtr = ap -
|
|
171
|
-
let mut
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
244
|
+
let mut blockPtr = ap - _HEADER_FOOTER_SIZE
|
|
245
|
+
let mut blockSize = headerGetSize(blockPtr)
|
|
246
|
+
|
|
247
|
+
let nextBlockPtr = blockPtr + blockSize * _UNIT_SIZE
|
|
248
|
+
if (headerGetPrevious(nextBlockPtr) > 0n) {
|
|
249
|
+
// adjacent block is free, so merge
|
|
250
|
+
removeFromFreeList(nextBlockPtr)
|
|
251
|
+
|
|
252
|
+
let nextBlockSize = headerGetSize(nextBlockPtr)
|
|
253
|
+
blockSize += nextBlockSize
|
|
254
|
+
headerSetSize(blockPtr, blockSize)
|
|
255
|
+
|
|
256
|
+
let footerPtr = blockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
257
|
+
footerSetSize(footerPtr, blockSize)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
let prevBlockFooterPtr = blockPtr - _HEADER_FOOTER_SIZE
|
|
261
|
+
if (footerGetNext(prevBlockFooterPtr) > 0n) {
|
|
262
|
+
// (prev) adjacent block is free, so merge
|
|
263
|
+
let prevBlockSize = footerGetSize(prevBlockFooterPtr)
|
|
264
|
+
let prevBlockPtr = blockPtr - prevBlockSize * _UNIT_SIZE
|
|
265
|
+
|
|
266
|
+
if (prevBlockSize == 1n) {
|
|
267
|
+
// Since we merged, this block is already a part of the free list. If
|
|
268
|
+
// the old block was size 1, it needs to be switched to the large list.
|
|
269
|
+
removeFromFreeList(prevBlockPtr)
|
|
186
270
|
}
|
|
187
271
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
272
|
+
blockPtr = prevBlockPtr
|
|
273
|
+
|
|
274
|
+
blockSize += prevBlockSize
|
|
275
|
+
headerSetSize(blockPtr, blockSize)
|
|
276
|
+
|
|
277
|
+
let footerPtr = blockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
278
|
+
footerSetSize(footerPtr, blockSize)
|
|
279
|
+
footerSetNext(footerPtr, footerGetNext(prevBlockFooterPtr))
|
|
280
|
+
|
|
281
|
+
if (prevBlockSize == 1n) {
|
|
282
|
+
if (largeBlockFreePtr != 1n) {
|
|
283
|
+
headerSetPrevious(largeBlockFreePtr, blockPtr)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
let footerPtr = blockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
287
|
+
footerSetNext(footerPtr, largeBlockFreePtr)
|
|
288
|
+
headerSetPrevious(blockPtr, 1n)
|
|
289
|
+
|
|
290
|
+
largeBlockFreePtr = blockPtr
|
|
196
291
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
292
|
+
} else {
|
|
293
|
+
if (blockSize == 1n) {
|
|
294
|
+
if (smallBlockFreePtr != 1n) {
|
|
295
|
+
headerSetPrevious(smallBlockFreePtr, blockPtr)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
let footerPtr = blockPtr + _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
299
|
+
footerSetNext(footerPtr, smallBlockFreePtr)
|
|
300
|
+
headerSetPrevious(blockPtr, 1n)
|
|
301
|
+
|
|
302
|
+
smallBlockFreePtr = blockPtr
|
|
202
303
|
} else {
|
|
203
|
-
|
|
304
|
+
if (largeBlockFreePtr != 1n) {
|
|
305
|
+
headerSetPrevious(largeBlockFreePtr, blockPtr)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
let footerPtr = blockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
309
|
+
footerSetNext(footerPtr, largeBlockFreePtr)
|
|
310
|
+
headerSetPrevious(blockPtr, 1n)
|
|
311
|
+
|
|
312
|
+
largeBlockFreePtr = blockPtr
|
|
204
313
|
}
|
|
205
|
-
// Set the free list head to this block
|
|
206
|
-
freePtr = p
|
|
207
314
|
}
|
|
208
315
|
}
|
|
209
316
|
|
|
@@ -215,25 +322,48 @@ provide let free = (ap: WasmI32) => {
|
|
|
215
322
|
* @param nbytes: The number of bytes to try to grow the heap by
|
|
216
323
|
* @returns A pointer to the start of the free list if successful or -1 otherwise
|
|
217
324
|
*/
|
|
218
|
-
let morecore = (
|
|
325
|
+
let morecore = (nunits: WasmI32) => {
|
|
219
326
|
let origSize = heapSize
|
|
220
|
-
|
|
327
|
+
|
|
328
|
+
let cp = growHeap(nunits + 1n) // include an extra unit for 4 headers/footers
|
|
221
329
|
|
|
222
330
|
// If there was an error, fail
|
|
223
331
|
if (cp == -1n) {
|
|
224
332
|
Exception.panic("OutOfMemory: Maximum memory size exceeded")
|
|
225
333
|
} else {
|
|
226
|
-
// Set the
|
|
227
|
-
//
|
|
334
|
+
// Set up the block. We'll add dummy headers/footers before and after the
|
|
335
|
+
// block to avoid unnecessary bounds checks elsewhere in the code.
|
|
228
336
|
let grownAmount = heapSize - origSize
|
|
229
|
-
|
|
337
|
+
let units = (grownAmount >>> logUnitSize) - 1n
|
|
338
|
+
|
|
339
|
+
let dummyFooter = cp
|
|
340
|
+
footerSetSize(dummyFooter, 0n)
|
|
341
|
+
footerSetNext(dummyFooter, 0n)
|
|
342
|
+
|
|
343
|
+
let blockHeader = dummyFooter + _HEADER_FOOTER_SIZE
|
|
344
|
+
headerSetSize(blockHeader, units)
|
|
345
|
+
headerSetPrevious(blockHeader, 0n)
|
|
346
|
+
|
|
347
|
+
let blockFooter = blockHeader + units * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
348
|
+
footerSetSize(blockFooter, units)
|
|
349
|
+
footerSetNext(blockFooter, 0n)
|
|
350
|
+
|
|
351
|
+
let dummyHeader = blockFooter + _HEADER_FOOTER_SIZE
|
|
352
|
+
headerSetSize(dummyHeader, 0n)
|
|
353
|
+
headerSetPrevious(dummyHeader, 0n)
|
|
354
|
+
|
|
230
355
|
// Call free() with the new block to add it to the free list.
|
|
231
|
-
free(
|
|
356
|
+
free(blockHeader + _HEADER_FOOTER_SIZE)
|
|
357
|
+
|
|
232
358
|
// Return the free list pointer.
|
|
233
|
-
|
|
359
|
+
largeBlockFreePtr
|
|
234
360
|
}
|
|
235
361
|
}
|
|
236
362
|
|
|
363
|
+
let roundBytesToUnits = bytes => {
|
|
364
|
+
(bytes + _UNIT_SIZE - 1n) >>> logUnitSize
|
|
365
|
+
}
|
|
366
|
+
|
|
237
367
|
/**
|
|
238
368
|
* Allocates the requested number of bytes, returning a pointer.
|
|
239
369
|
*
|
|
@@ -241,70 +371,74 @@ let morecore = (nbytes: WasmI32) => {
|
|
|
241
371
|
* @returns The pointer to the allocated region (8-byte aligned) or -1 if the allocation failed
|
|
242
372
|
*/
|
|
243
373
|
provide let malloc = (nbytes: WasmI32) => {
|
|
244
|
-
let mut
|
|
245
|
-
let mut prevp = freePtr
|
|
374
|
+
let mut nunits = roundBytesToUnits(nbytes + _HEADER_FOOTER_SIZE * 2n)
|
|
246
375
|
|
|
247
|
-
//
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
376
|
+
// Fast path for small blocks
|
|
377
|
+
if (nunits == 1n && smallBlockFreePtr != 1n) {
|
|
378
|
+
let blockPtr = smallBlockFreePtr
|
|
379
|
+
headerSetPrevious(blockPtr, 0n)
|
|
380
|
+
let footer = blockPtr + _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
381
|
+
let next = footerGetNext(footer)
|
|
382
|
+
footerSetNext(footer, 0n)
|
|
251
383
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
prevp = _BASE
|
|
257
|
-
WasmI32.store(_BASE, 0n, _SIZE_OFFSET)
|
|
384
|
+
headerSetPrevious(next, 1n)
|
|
385
|
+
smallBlockFreePtr = next
|
|
386
|
+
|
|
387
|
+
return blockPtr + _HEADER_FOOTER_SIZE
|
|
258
388
|
}
|
|
259
389
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (size == nbytes) {
|
|
271
|
-
// It's exactly the right size!
|
|
272
|
-
setNext(prevp, getNext(p))
|
|
273
|
-
} else {
|
|
274
|
-
// Shrink it as needed
|
|
275
|
-
let newSize = size - nbytes
|
|
276
|
-
setSize(p, newSize)
|
|
277
|
-
p += newSize
|
|
278
|
-
setSize(p, nbytes)
|
|
279
|
-
}
|
|
280
|
-
// Update the pointer to the free list.
|
|
281
|
-
freePtr = prevp
|
|
390
|
+
// Find a large enough block
|
|
391
|
+
let mut freeBlockPtr = largeBlockFreePtr
|
|
392
|
+
while (true) {
|
|
393
|
+
// Free list is empty; grow the heap
|
|
394
|
+
if (freeBlockPtr == 1n) {
|
|
395
|
+
freeBlockPtr = morecore(nunits)
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
let blockSize = headerGetSize(freeBlockPtr)
|
|
399
|
+
let footerPtr = freeBlockPtr + blockSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
282
400
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
401
|
+
// Perfectly sized block, or one unit larger to avoid leaving size 1 blocks
|
|
402
|
+
// in the large block free list
|
|
403
|
+
if (blockSize == nunits || blockSize == nunits + 1n) {
|
|
404
|
+
let blockPtr = freeBlockPtr
|
|
405
|
+
|
|
406
|
+
removeFromFreeList(blockPtr)
|
|
407
|
+
headerSetPrevious(blockPtr, 0n)
|
|
408
|
+
footerSetNext(footerPtr, 0n)
|
|
409
|
+
|
|
410
|
+
return blockPtr + _HEADER_FOOTER_SIZE
|
|
286
411
|
}
|
|
287
412
|
|
|
288
|
-
//
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
413
|
+
// Take a chunk of this larger block
|
|
414
|
+
if (blockSize > nunits) {
|
|
415
|
+
let blockPtr = freeBlockPtr
|
|
416
|
+
|
|
417
|
+
let newSize = blockSize - nunits
|
|
418
|
+
headerSetSize(blockPtr, newSize)
|
|
419
|
+
let newFooterPtr = blockPtr + newSize * _UNIT_SIZE - _HEADER_FOOTER_SIZE
|
|
420
|
+
footerSetSize(newFooterPtr, newSize)
|
|
421
|
+
footerSetNext(newFooterPtr, footerGetNext(footerPtr))
|
|
422
|
+
|
|
423
|
+
let newBlockPtr = newFooterPtr + _HEADER_FOOTER_SIZE
|
|
424
|
+
headerSetSize(newBlockPtr, nunits)
|
|
425
|
+
headerSetPrevious(newBlockPtr, 0n)
|
|
426
|
+
footerSetSize(footerPtr, nunits)
|
|
427
|
+
footerSetNext(footerPtr, 0n)
|
|
428
|
+
|
|
429
|
+
return newBlockPtr + _HEADER_FOOTER_SIZE
|
|
297
430
|
}
|
|
431
|
+
|
|
432
|
+
freeBlockPtr = footerGetNext(footerPtr)
|
|
298
433
|
}
|
|
299
|
-
|
|
434
|
+
|
|
435
|
+
return -1n
|
|
300
436
|
}
|
|
301
437
|
|
|
302
438
|
/**
|
|
303
|
-
*
|
|
304
|
-
* Used for debugging.
|
|
305
|
-
*
|
|
306
|
-
* @returns The free list pointer
|
|
439
|
+
* Leaks all memory in all free lists; used for testing.
|
|
307
440
|
*/
|
|
308
|
-
provide let
|
|
309
|
-
|
|
441
|
+
provide let leakAll = () => {
|
|
442
|
+
smallBlockFreePtr = 1n
|
|
443
|
+
largeBlockFreePtr = 1n
|
|
310
444
|
}
|
package/runtime/malloc.md
CHANGED
|
@@ -46,18 +46,11 @@ Returns:
|
|
|
46
46
|
|----|-----------|
|
|
47
47
|
|`WasmI32`|The pointer to the allocated region (8-byte aligned) or -1 if the allocation failed|
|
|
48
48
|
|
|
49
|
-
### Malloc.**
|
|
49
|
+
### Malloc.**leakAll**
|
|
50
50
|
|
|
51
51
|
```grain
|
|
52
|
-
|
|
52
|
+
leakAll : () => Void
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
Used for debugging.
|
|
57
|
-
|
|
58
|
-
Returns:
|
|
59
|
-
|
|
60
|
-
|type|description|
|
|
61
|
-
|----|-----------|
|
|
62
|
-
|`WasmI32`|The free list pointer|
|
|
55
|
+
Leaks all memory in all free lists; used for testing.
|
|
63
56
|
|
package/set.gr
CHANGED
package/wasi/process.gr
CHANGED
|
@@ -145,16 +145,17 @@ provide let argv = () => {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
let argc = WasmI32.load(argcPtr, 0n)
|
|
148
|
-
Memory.free(argcPtr)
|
|
149
148
|
|
|
150
149
|
let argsLength = argc * 4n
|
|
151
150
|
let arr = allocateArray(argc)
|
|
152
151
|
|
|
153
152
|
if (WasmI32.eqz(argsLength)) {
|
|
153
|
+
Memory.free(argcPtr)
|
|
154
154
|
return Ok(WasmI32.toGrain(arr): Array<String>)
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
let argvBufSize = WasmI32.load(argvBufSizePtr, 0n)
|
|
158
|
+
Memory.free(argcPtr)
|
|
158
159
|
|
|
159
160
|
let argvPtr = Memory.malloc(argc * 4n)
|
|
160
161
|
let argvBufPtr = Memory.malloc(argvBufSize)
|