1
- import { AL_MASK } from "../internal/allocator" ;
1
+ import { AL_MASK , MAX_SIZE_32 } from "../internal/allocator" ;
2
2
import { __rt_classid } from "../builtins" ;
3
3
4
4
/** Common runtime header of all objects. */
@@ -8,18 +8,22 @@ import { __rt_classid } from "../builtins";
8
8
/** Size of the allocated payload. */
9
9
payloadSize : u32 ;
10
10
/** Reserved field for use by GC. Only present if GC is. */
11
- reserved1 : usize ; // itcm: tagged next
11
+ gc1 : usize ; // itcm: tagged next
12
12
/** Reserved field for use by GC. Only present if GC is. */
13
- reserved2 : usize ; // itcm: prev
13
+ gc2 : usize ; // itcm: prev
14
14
}
15
15
16
+ // Note that header data and layout isn't quite optimal depending on which allocator one
17
+ // decides to use, but it's done this way for maximum flexibility. Also remember that the
18
+ // runtime will most likely change significantly once reftypes and WASM GC are a thing.
19
+
16
20
/** Whether a GC is present or not. */
17
- @inline export const GC = isDefined ( __REGISTER_IMPL ) ;
21
+ @inline export const GC = isDefined ( gc ) ;
18
22
19
23
/** Size of the common runtime header. */
20
24
@inline export const HEADER_SIZE : usize = GC
21
- ? ( offsetof < HEADER > ( ) + AL_MASK ) & ~ AL_MASK // full header if GC is present
22
- : ( offsetof < HEADER > ( "reserved1 " ) + AL_MASK ) & ~ AL_MASK ; // half header if GC is absent
25
+ ? ( offsetof < HEADER > ( ) + AL_MASK ) & ~ AL_MASK // full header if GC is present
26
+ : ( offsetof < HEADER > ( "gc1 " ) + AL_MASK ) & ~ AL_MASK ; // half header if GC is absent
23
27
24
28
/** Magic value used to validate common runtime headers. */
25
29
@inline export const HEADER_MAGIC : u32 = 0xA55E4B17 ;
@@ -41,8 +45,8 @@ export function ALLOC(payloadSize: u32): usize {
41
45
header . classId = HEADER_MAGIC ;
42
46
header . payloadSize = payloadSize ;
43
47
if ( GC ) {
44
- header . reserved1 = 0 ;
45
- header . reserved2 = 0 ;
48
+ header . gc1 = 0 ;
49
+ header . gc2 = 0 ;
46
50
}
47
51
var ref = changetype < usize > ( header ) + HEADER_SIZE ;
48
52
memory . fill ( ref , 0 , payloadSize ) ;
@@ -60,8 +64,8 @@ export function REALLOC(ref: usize, newPayloadSize: u32): usize {
60
64
let newHeader = changetype < HEADER > ( memory . allocate ( newAlignedSize ) ) ;
61
65
newHeader . classId = HEADER_MAGIC ;
62
66
if ( GC ) {
63
- newHeader . reserved1 = 0 ;
64
- newHeader . reserved2 = 0 ;
67
+ newHeader . gc1 = 0 ;
68
+ newHeader . gc2 = 0 ;
65
69
}
66
70
let newRef = changetype < usize > ( newHeader ) + HEADER_SIZE ;
67
71
memory . copy ( newRef , ref , payloadSize ) ;
@@ -85,7 +89,7 @@ export function REALLOC(ref: usize, newPayloadSize: u32): usize {
85
89
return ref ;
86
90
}
87
91
88
- function ensureUnregistered ( ref : usize ) : HEADER {
92
+ function unref ( ref : usize ) : HEADER {
89
93
assert ( ref >= HEAP_BASE + HEADER_SIZE ) ; // must be a heap object
90
94
var header = changetype < HEADER > ( ref - HEADER_SIZE ) ;
91
95
assert ( header . classId == HEADER_MAGIC ) ; // must be unregistered
@@ -94,24 +98,36 @@ function ensureUnregistered(ref: usize): HEADER {
94
98
95
99
/** Frees an object. Must not have been registered with GC yet. */
96
100
export function FREE ( ref : usize ) : void {
97
- memory . free ( changetype < usize > ( ensureUnregistered ( ref ) ) ) ;
101
+ memory . free ( changetype < usize > ( unref ( ref ) ) ) ;
102
+ }
103
+
104
+ /** Registers a managed object. Cannot be free'd anymore afterwards. */
105
+ @inline export function REGISTER < T > ( ref : usize ) : T {
106
+ // inline this because it's generic so we don't get a bunch of functions
107
+ unref ( ref ) . classId = __rt_classid < T > ( ) ;
108
+ if ( GC ) gc . register ( ref ) ;
109
+ return changetype < T > ( ref ) ;
98
110
}
99
111
100
- /** Registers a managed object with GC. Cannot be free'd anymore afterwards. */
101
- @inline export function REGISTER < T > ( ref : usize , parentRef : usize ) : void {
102
- ensureUnregistered ( ref ) . classId = __rt_classid < T > ( ) ;
103
- if ( GC ) __REGISTER_IMPL ( ref , parentRef ) ; // tslint:disable-line
112
+ /** Links a managed object with its managed parent. */
113
+ export function LINK ( ref : usize , parentRef : usize ) : void {
114
+ assert ( ref >= HEAP_BASE + HEADER_SIZE ) ; // must be a heap object
115
+ var header = changetype < HEADER > ( ref - HEADER_SIZE ) ;
116
+ assert ( header . classId != HEADER_MAGIC && header . gc1 != 0 && header . gc2 != 0 ) ; // must be registered
117
+ if ( GC ) gc . link ( ref , parentRef ) ; // tslint:disable-line
104
118
}
105
119
106
120
/** ArrayBuffer base class. */
107
121
export abstract class ArrayBufferBase {
122
+ static readonly MAX_BYTELENGTH : i32 = MAX_SIZE_32 - HEADER_SIZE ;
108
123
get byteLength ( ) : i32 {
109
124
return changetype < HEADER > ( changetype < usize > ( this ) - HEADER_SIZE ) . payloadSize ;
110
125
}
111
126
}
112
127
113
128
/** String base class. */
114
129
export abstract class StringBase {
130
+ static readonly MAX_LENGTH : i32 = ( MAX_SIZE_32 - HEADER_SIZE ) >> 1 ;
115
131
get length ( ) : i32 {
116
132
return changetype < HEADER > ( changetype < usize > ( this ) - HEADER_SIZE ) . payloadSize >> 1 ;
117
133
}
0 commit comments