@@ -25,6 +25,7 @@ from "runtime/unsafe/panic" include Panic
2525from "runtime/unsafe/wasmi32" include WasmI32
2626use WasmI32.{ (+), (-), (*), (&), (==), (!=) }
2727
28+ primitive (!) = "@not"
2829primitive (&&) = "@and"
2930primitive (||) = "@or"
3031primitive ignore = "@ignore"
@@ -84,24 +85,37 @@ let rec decRef = (userPtr: WasmI32, ignoreZeros: Bool) => {
8485 // }
8586
8687 if (WasmI32.eqz(refCount)) {
87- if (ignoreZeros) {
88- userPtr
89- } else {
88+ if (!ignoreZeros) {
9089 throwDecRefError()
9190 }
9291 } else {
9392 let refCount = refCount - 1n
9493 setRefCount(userPtr, refCount)
9594
9695 if (WasmI32.eqz(refCount)) {
97- decRefChildren(userPtr)
96+ /*
97+ * Note: We call free before decRefChildren to allow for a tail call.
98+ * This is okay because no allocations occur while we traverse the
99+ * structure and free does not mangle the data.
100+ */
98101 free(userPtr)
102+ decRefChildren(userPtr)
99103 }
100-
101- userPtr
102104 }
103- } else {
104- userPtr
105+ }
106+ }
107+ and decRefChildrenHelp = (
108+ userPtr: WasmI32,
109+ arityOffset: WasmI32,
110+ offset: WasmI32,
111+ ) => {
112+ let arity = WasmI32.load(userPtr, arityOffset)
113+ if (arity != 0n) {
114+ let maxOffset = (arity - 1n) * 4n
115+ for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
116+ decRef(WasmI32.load(userPtr + i, offset), false)
117+ }
118+ decRef(WasmI32.load(userPtr + maxOffset, offset), false)
105119 }
106120}
107121and decRefChildren = (userPtr: WasmI32) => {
@@ -110,43 +124,25 @@ and decRefChildren = (userPtr: WasmI32) => {
110124 let tag = WasmI32.load(userPtr, 4n)
111125 if (userPtr == Tags._GRAIN_RATIONAL_BOXED_NUM_TAG) {
112126 // decRef underlying BigInts
113- ignore( decRef(WasmI32.load(userPtr, 8n), false) )
114- ignore( decRef(WasmI32.load(userPtr, 12n), false) )
127+ decRef(WasmI32.load(userPtr, 8n), false)
128+ decRef(WasmI32.load(userPtr, 12n), false)
115129 }
116130 },
117131 t when t == Tags._GRAIN_ADT_HEAP_TAG => {
118- let arity = WasmI32.load(userPtr, 16n)
119- let maxOffset = arity * 4n
120- for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
121- ignore(decRef(WasmI32.load(userPtr + i, 20n), false))
122- }
132+ decRefChildrenHelp(userPtr, 16n, 20n)
123133 },
124- t when t == Tags._GRAIN_RECORD_HEAP_TAG => {
125- let arity = WasmI32.load(userPtr, 12n)
126- let maxOffset = arity * 4n
127- for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
128- ignore(decRef(WasmI32.load(userPtr + i, 16n), false))
129- }
134+ t when t == Tags._GRAIN_RECORD_HEAP_TAG || t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
135+ decRefChildrenHelp(userPtr, 12n, 16n)
130136 },
131137 t when t == Tags._GRAIN_ARRAY_HEAP_TAG || t == Tags._GRAIN_TUPLE_HEAP_TAG => {
132- let arity = WasmI32.load(userPtr, 4n)
133- let maxOffset = arity * 4n
134- for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
135- ignore(decRef(WasmI32.load(userPtr + i, 8n), false))
136- }
137- },
138- t when t == Tags._GRAIN_LAMBDA_HEAP_TAG => {
139- let arity = WasmI32.load(userPtr, 12n)
140- let maxOffset = arity * 4n
141- for (let mut i = 0n; WasmI32.ltU(i, maxOffset); i += 4n) {
142- ignore(decRef(WasmI32.load(userPtr + i, 16n), false))
143- }
144- },
145- _ => {
146- // No travelsal necessary for other tags
147- void
138+ decRefChildrenHelp(userPtr, 4n, 8n)
148139 },
140+ // No traversal necessary for other tags
141+ _ => void,
149142 }
150143}
151144
152- provide let decRef = userPtr => decRef(userPtr, false)
145+ provide let decRef = userPtr => {
146+ decRef(userPtr, false)
147+ userPtr
148+ }
0 commit comments