/src/moddable/xs/sources/xsMemory.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2016-2025 Moddable Tech, Inc. |
3 | | * |
4 | | * This file is part of the Moddable SDK Runtime. |
5 | | * |
6 | | * The Moddable SDK Runtime is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * The Moddable SDK Runtime is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with the Moddable SDK Runtime. If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * This file incorporates work covered by the following copyright and |
20 | | * permission notice: |
21 | | * |
22 | | * Copyright (C) 2010-2016 Marvell International Ltd. |
23 | | * Copyright (C) 2002-2010 Kinoma, Inc. |
24 | | * |
25 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
26 | | * you may not use this file except in compliance with the License. |
27 | | * You may obtain a copy of the License at |
28 | | * |
29 | | * http://www.apache.org/licenses/LICENSE-2.0 |
30 | | * |
31 | | * Unless required by applicable law or agreed to in writing, software |
32 | | * distributed under the License is distributed on an "AS IS" BASIS, |
33 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
34 | | * See the License for the specific language governing permissions and |
35 | | * limitations under the License. |
36 | | */ |
37 | | |
38 | | #include "xsAll.h" |
39 | | |
40 | | #ifndef mxReport |
41 | | #define mxReport 0 |
42 | | #endif |
43 | | #ifndef mxStress |
44 | | #define mxStress 0 |
45 | | #endif |
46 | | #ifndef mxNoChunks |
47 | | #define mxNoChunks 0 |
48 | | #endif |
49 | | #ifndef mxPoisonSlots |
50 | | #define mxPoisonSlots 0 |
51 | | #endif |
52 | | |
53 | | #if mxPoisonSlots |
54 | | #include <sanitizer/asan_interface.h> |
55 | | #endif |
56 | | |
57 | | #if mxStress |
58 | | int gxStress = 0; |
59 | | |
60 | | static int fxShouldStress() |
61 | 771M | { |
62 | 771M | if (!gxStress) |
63 | 771M | return 0; |
64 | | |
65 | 418k | if (gxStress > 0) |
66 | 0 | return 1; |
67 | | |
68 | 418k | gxStress += 1; |
69 | 418k | return 0 == gxStress; |
70 | 418k | } |
71 | | #endif |
72 | | |
73 | | #if mxNoChunks |
74 | | #if FUZZING |
75 | | extern void *fxMemMalloc_noforcefail(size_t size); |
76 | | #define c_malloc_noforcefail(size) fxMemMalloc_noforcefail(size) |
77 | | #else |
78 | | #define c_malloc_noforcefail c_malloc |
79 | | #endif |
80 | | #endif |
81 | | |
82 | 1.08G | #define mxChunkFlag 0x80000000 |
83 | | |
84 | | static txSize fxAdjustChunkSize(txMachine* the, txSize size); |
85 | | static void* fxCheckChunk(txMachine* the, txChunk* chunk, txSize size, txSize offset); |
86 | | static void* fxFindChunk(txMachine* the, txSize size, txBoolean *once); |
87 | | static void* fxGrowChunk(txMachine* the, txSize size); |
88 | | static void* fxGrowChunks(txMachine* the, txSize theSize); |
89 | | /* static */ void fxGrowSlots(txMachine* the, txSize theCount); |
90 | | static void fxMark(txMachine* the, void (*theMarker)(txMachine*, txSlot*)); |
91 | | #if mxKeysGarbageCollection |
92 | | static void fxMarkID(txMachine* the, txID id); |
93 | | #endif |
94 | | static void fxMarkFinalizationRegistry(txMachine* the, txSlot* registry); |
95 | | static void fxMarkInstance(txMachine* the, txSlot* theCurrent, void (*theMarker)(txMachine*, txSlot*)); |
96 | | static void fxMarkReference(txMachine* the, txSlot* theSlot); |
97 | | static void fxMarkValue(txMachine* the, txSlot* theSlot); |
98 | | static void fxMarkWeakStuff(txMachine* the); |
99 | | static void fxSweep(txMachine* the); |
100 | | static void fxSweepValue(txMachine* the, txSlot* theSlot); |
101 | | |
102 | | #ifdef mxNever |
103 | | |
104 | | typedef struct sxSample txSample; |
105 | | struct sxSample { |
106 | | struct timespec time; |
107 | | txNumber duration; |
108 | | long count; |
109 | | char* label; |
110 | | }; |
111 | | |
112 | | void reportTime(txSample* theSample) |
113 | | { |
114 | | fprintf(stderr, " %s %ld %f", theSample->label, theSample->count, theSample->duration); |
115 | | } |
116 | | |
117 | | void startTime(txSample* theSample) |
118 | | { |
119 | | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(theSample->time)); |
120 | | } |
121 | | |
122 | | void stopTime(txSample* theSample) |
123 | | { |
124 | | struct timespec time; |
125 | | clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time); |
126 | | theSample->duration += ((double)(time.tv_sec) - (double)(theSample->time.tv_sec)) |
127 | | + (((double)(time.tv_nsec) - (double)(theSample->time.tv_nsec)) / 1000000000.0); |
128 | | theSample->count++; |
129 | | } |
130 | | |
131 | | txSample gxLifeTime = { { 0, 0 }, 0, 0, "life" }; |
132 | | txSample gxMarkTime = { { 0, 0 }, 0, 0, "mark" }; |
133 | | txSample gxSweepChunkTime = { { 0, 0 }, 0, 0, "sweep chunk" }; |
134 | | txSample gxSweepSlotTime = { { 0, 0 }, 0, 0, "sweep slot" }; |
135 | | txSample gxCompactChunkTime = { { 0, 0 }, 0, 0, "compact" }; |
136 | | txSample gxChunksGarbageCollectionTime = { { 0, 0 }, 0, 0, "chunks" }; |
137 | | txSample gxKeysGarbageCollectionTime = { { 0, 0 }, 0, 0, "keys" }; |
138 | | txSample gxSlotsGarbageCollectionTime = { { 0, 0 }, 0, 0, "slots" }; |
139 | | txSample gxForcedGarbageCollectionTime = { { 0, 0 }, 0, 0, "forced" }; |
140 | | #endif |
141 | | |
142 | | txSize fxAddChunkSizes(txMachine* the, txSize a, txSize b) |
143 | 354M | { |
144 | 354M | txSize c; |
145 | 354M | #if __has_builtin(__builtin_add_overflow) |
146 | 354M | if (__builtin_add_overflow(a, b, &c)) { |
147 | | #else |
148 | | c = a + b; |
149 | | if (((a ^ c) & (b ^ c)) < 0) { |
150 | | #endif |
151 | 7 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
152 | 7 | } |
153 | 354M | return c; |
154 | 354M | } |
155 | | |
156 | | txSize fxAdjustChunkSize(txMachine* the, txSize size) |
157 | 254M | { |
158 | 254M | txSize adjust = sizeof(txChunk); |
159 | 254M | txSize modulo = size & (sizeof(size_t) - 1); |
160 | 254M | if (modulo) |
161 | 193M | adjust += sizeof(size_t) - modulo; |
162 | 254M | return fxAddChunkSizes(the, size, adjust); |
163 | 254M | } |
164 | | |
165 | | void fxAllocate(txMachine* the, txCreation* theCreation) |
166 | 27.8k | { |
167 | | #ifdef mxNever |
168 | | startTime(&gxLifeTime); |
169 | | #endif |
170 | 27.8k | #if mxStress |
171 | 27.8k | gxStress = 0; |
172 | 27.8k | #endif |
173 | | |
174 | 27.8k | the->currentChunksSize = 0; |
175 | 27.8k | the->peakChunksSize = 0; |
176 | 27.8k | the->maximumChunksSize = 0; |
177 | 27.8k | the->minimumChunksSize = theCreation->incrementalChunkSize; |
178 | | |
179 | 27.8k | the->currentHeapCount = 0; |
180 | 27.8k | the->peakHeapCount = 0; |
181 | 27.8k | the->maximumHeapCount = 0; |
182 | 27.8k | the->minimumHeapCount = theCreation->incrementalHeapCount; |
183 | | |
184 | 27.8k | the->firstBlock = C_NULL; |
185 | 27.8k | the->firstHeap = C_NULL; |
186 | | |
187 | | #if mxNoChunks |
188 | | the->maximumChunksSize = theCreation->initialChunkSize; |
189 | | #else |
190 | 27.8k | fxGrowChunks(the, theCreation->initialChunkSize); |
191 | 27.8k | #endif |
192 | | |
193 | 27.8k | the->stackBottom = fxAllocateSlots(the, theCreation->stackCount); |
194 | 27.8k | the->stackTop = the->stackBottom + theCreation->stackCount; |
195 | 27.8k | the->stackIntrinsics = the->stackTop; |
196 | 27.8k | the->stackPrototypes = the->stackTop - XS_INTRINSICS_COUNT; |
197 | 27.8k | the->stack = the->stackTop; |
198 | | #ifdef mxInstrument |
199 | | the->stackPeak = the->stackTop; |
200 | | #endif |
201 | | |
202 | 27.8k | fxGrowSlots(the, theCreation->initialHeapCount); |
203 | | |
204 | 27.8k | the->keyCount = (txID)theCreation->initialKeyCount; |
205 | 27.8k | the->keyDelta = (txID)theCreation->incrementalKeyCount; |
206 | 27.8k | the->keyIndex = 0; |
207 | 27.8k | the->keyArray = (txSlot **)c_malloc_uint32(theCreation->initialKeyCount * sizeof(txSlot*)); |
208 | 27.8k | if (!the->keyArray) |
209 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
210 | | |
211 | 27.8k | the->nameModulo = theCreation->nameModulo; |
212 | 27.8k | the->nameTable = (txSlot **)c_malloc_uint32(theCreation->nameModulo * sizeof(txSlot*)); |
213 | 27.8k | if (!the->nameTable) |
214 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
215 | | |
216 | 27.8k | the->symbolModulo = theCreation->symbolModulo; |
217 | 27.8k | the->symbolTable = (txSlot **)c_malloc_uint32(theCreation->symbolModulo * sizeof(txSlot*)); |
218 | 27.8k | if (!the->symbolTable) |
219 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
220 | | |
221 | 27.8k | fxAllocateStringInfoCache(the); |
222 | | |
223 | 27.8k | the->stackLimit = fxCStackLimit(); |
224 | | |
225 | 27.8k | the->cRoot = C_NULL; |
226 | 27.8k | the->parserBufferSize = theCreation->parserBufferSize; |
227 | 27.8k | the->parserTableModulo = theCreation->parserTableModulo; |
228 | | |
229 | 27.8k | #ifdef mxDebug |
230 | 27.8k | the->pathCount = 256; |
231 | 27.8k | the->pathValue = c_malloc(the->pathCount); |
232 | 27.8k | if (!the->pathValue) |
233 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
234 | 27.8k | #endif |
235 | 27.8k | } |
236 | | |
237 | | void* fxCheckChunk(txMachine* the, txChunk* chunk, txSize size, txSize offset) |
238 | 230M | { |
239 | 230M | if (chunk) { |
240 | 230M | txByte* data = (txByte*)chunk; |
241 | | #if mxNoChunks |
242 | | chunk->size = size; |
243 | | the->currentChunksSize += size; |
244 | | #else |
245 | 230M | txSize capacity = (txSize)(chunk->temporary - data); |
246 | 230M | #ifdef mxSnapshot |
247 | 230M | #if INTPTR_MAX == INT64_MAX |
248 | 230M | chunk->dummy = 0; |
249 | 230M | #endif |
250 | | #ifdef mxSnapshotRandomInit |
251 | | arc4random_buf(data + sizeof(txChunk), offset); |
252 | | #endif |
253 | 230M | #endif |
254 | 230M | offset += sizeof(txChunk); |
255 | 230M | c_memset(data + offset, 0, capacity - offset); |
256 | 230M | chunk->size = size; |
257 | 230M | the->currentChunksSize += capacity; |
258 | 230M | #endif |
259 | 230M | if (the->peakChunksSize < the->currentChunksSize) |
260 | 68.2M | the->peakChunksSize = the->currentChunksSize; |
261 | 230M | return data + sizeof(txChunk); |
262 | 230M | } |
263 | 7 | fxReport(the, "# Chunk allocation: failed for %ld bytes\n", (long)size); |
264 | 7 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
265 | 7 | return C_NULL; |
266 | 230M | } |
267 | | |
268 | | #if defined(__clang__) || defined (__GNUC__) |
269 | | __attribute__((no_sanitize_address)) |
270 | | #endif |
271 | | void fxCheckCStack(txMachine* the) |
272 | 401M | { |
273 | 401M | char x; |
274 | 401M | char *stack = &x; |
275 | 401M | if (stack <= the->stackLimit) { |
276 | 42 | fxAbort(the, XS_NATIVE_STACK_OVERFLOW_EXIT); |
277 | 42 | } |
278 | 401M | } |
279 | | |
280 | | void fxCollect(txMachine* the, txFlag theFlag) |
281 | 56.5k | { |
282 | 56.5k | txSize aCount; |
283 | 56.5k | txSlot* freeSlot; |
284 | 56.5k | txSlot* aSlot; |
285 | 56.5k | txSlot* bSlot; |
286 | 56.5k | txSlot* cSlot; |
287 | | |
288 | 56.5k | if ((the->collectFlag & XS_COLLECTING_FLAG) == 0) { |
289 | 0 | the->collectFlag |= XS_SKIPPED_COLLECT_FLAG; |
290 | 0 | return; |
291 | 0 | } |
292 | 56.5k | the->collectFlag |= theFlag & (XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
293 | | |
294 | | #ifdef mxNever |
295 | | if (theFlag & XS_ORGANIC_FLAG) { |
296 | | if (theFlag & XS_COMPACT_FLAG) |
297 | | startTime(&gxChunksGarbageCollectionTime); |
298 | | else if (theFlag & XS_COLLECT_KEYS_FLAG) |
299 | | startTime(&gxKeysGarbageCollectionTime); |
300 | | else |
301 | | startTime(&gxSlotsGarbageCollectionTime); |
302 | | } |
303 | | else |
304 | | startTime(&gxForcedGarbageCollectionTime); |
305 | | startTime(&gxMarkTime); |
306 | | #endif |
307 | 56.5k | if (theFlag & XS_COMPACT_FLAG) { |
308 | 39.8k | fxInvalidateStringInfoCache(the); |
309 | 39.8k | fxMark(the, fxMarkValue); |
310 | 39.8k | fxMarkWeakStuff(the); |
311 | | #ifdef mxNever |
312 | | stopTime(&gxMarkTime); |
313 | | #endif |
314 | 39.8k | fxSweep(the); |
315 | 39.8k | } |
316 | 16.7k | else { |
317 | 16.7k | fxMark(the, fxMarkReference); |
318 | 16.7k | fxMarkWeakStuff(the); |
319 | | #ifdef mxNever |
320 | | stopTime(&gxMarkTime); |
321 | | startTime(&gxSweepSlotTime); |
322 | | #endif |
323 | 16.7k | aCount = 0; |
324 | 16.7k | freeSlot = C_NULL; |
325 | 16.7k | aSlot = the->firstHeap; |
326 | 69.2k | while (aSlot) { |
327 | 52.5k | bSlot = aSlot + 1; |
328 | 52.5k | cSlot = aSlot->value.reference; |
329 | 1.72G | while (bSlot < cSlot) { |
330 | 1.72G | if (bSlot->flag & XS_MARK_FLAG) { |
331 | 1.28G | bSlot->flag &= ~XS_MARK_FLAG; |
332 | | |
333 | 1.28G | if (bSlot->kind == XS_REFERENCE_KIND) |
334 | 148M | mxCheck(the, bSlot->value.reference->kind == XS_INSTANCE_KIND); |
335 | | |
336 | 1.28G | aCount++; |
337 | 1.28G | } |
338 | 434M | else { |
339 | 434M | if (bSlot->kind == XS_HOST_KIND) { |
340 | 1.19k | if (bSlot->flag & XS_HOST_HOOKS_FLAG) { |
341 | 0 | if (bSlot->value.host.variant.hooks->destructor) |
342 | 0 | (*(bSlot->value.host.variant.hooks->destructor))(bSlot->value.host.data); |
343 | 0 | } |
344 | 1.19k | else if (bSlot->value.host.variant.destructor) |
345 | 0 | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
346 | 1.19k | } |
347 | | #if mxInstrument |
348 | | if ((bSlot->kind == XS_MODULE_KIND) && (bSlot->ID == XS_MODULE_BEHAVIOR)) |
349 | | the->loadedModulesCount--; |
350 | | #endif |
351 | 434M | bSlot->kind = XS_UNDEFINED_KIND; |
352 | 434M | bSlot->next = freeSlot; |
353 | | #if mxPoisonSlots |
354 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
355 | | #endif |
356 | 434M | freeSlot = bSlot; |
357 | 434M | } |
358 | 1.72G | bSlot++; |
359 | 1.72G | } |
360 | 52.5k | aSlot = aSlot->next; |
361 | 52.5k | } |
362 | 16.7k | the->currentHeapCount = aCount; |
363 | 16.7k | the->freeHeap = freeSlot; |
364 | | #ifdef mxNever |
365 | | stopTime(&gxSweepSlotTime); |
366 | | #endif |
367 | 16.7k | } |
368 | | |
369 | 56.5k | aSlot = the->stack; |
370 | 170M | while (aSlot < the->stackTop) { |
371 | 170M | aSlot->flag &= ~XS_MARK_FLAG; |
372 | 170M | aSlot++; |
373 | 170M | } |
374 | | |
375 | 56.5k | the->collectFlag &= ~(XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
376 | | |
377 | 56.5k | if (theFlag & XS_COMPACT_FLAG) { |
378 | 39.8k | if ((the->maximumChunksSize - the->currentChunksSize) < the->minimumChunksSize) |
379 | 15.3k | the->collectFlag |= XS_TRASHING_CHUNKS_FLAG; |
380 | 24.5k | else |
381 | 24.5k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
382 | 39.8k | } |
383 | | |
384 | 56.5k | if ((the->maximumHeapCount - the->currentHeapCount) < the->minimumHeapCount) |
385 | 48.2k | the->collectFlag |= XS_TRASHING_SLOTS_FLAG; |
386 | 8.30k | else |
387 | 8.30k | the->collectFlag &= ~XS_TRASHING_SLOTS_FLAG; |
388 | | |
389 | | #ifdef mxNever |
390 | | if (theFlag & XS_ORGANIC_FLAG) { |
391 | | if (theFlag & XS_COMPACT_FLAG) |
392 | | stopTime(&gxChunksGarbageCollectionTime); |
393 | | else if (theFlag & XS_COLLECT_KEYS_FLAG) |
394 | | stopTime(&gxKeysGarbageCollectionTime); |
395 | | else |
396 | | stopTime(&gxSlotsGarbageCollectionTime); |
397 | | } |
398 | | else |
399 | | stopTime(&gxForcedGarbageCollectionTime); |
400 | | #endif |
401 | | |
402 | | #if mxReport |
403 | | if (theFlag) |
404 | | fxReport(the, "# Chunk collection: reserved %ld used %ld peak %ld bytes\n", |
405 | | (long)the->maximumChunksSize, (long)the->currentChunksSize, (long)the->peakChunksSize); |
406 | | aCount = 0; |
407 | | aSlot = the->firstHeap; |
408 | | while (aSlot) { |
409 | | aCount++; |
410 | | aSlot = aSlot->next; |
411 | | } |
412 | | fxReport(the, "# Slot collection: reserved %ld used %ld peak %ld bytes %d\n", |
413 | | (long)((the->maximumHeapCount - aCount) * sizeof(txSlot)), |
414 | | (long)(the->currentHeapCount * sizeof(txSlot)), |
415 | | (long)(the->peakHeapCount * sizeof(txSlot)), |
416 | | the->collectFlag & XS_TRASHING_SLOTS_FLAG); |
417 | | #endif |
418 | | #ifdef mxInstrument |
419 | | the->garbageCollectionCount++; |
420 | | #endif |
421 | 56.5k | #if defined(mxInstrument) || defined(mxProfile) |
422 | 56.5k | fxCheckProfiler(the, C_NULL); |
423 | 56.5k | #endif |
424 | 56.5k | } |
425 | | |
426 | | txSlot* fxDuplicateSlot(txMachine* the, txSlot* theSlot) |
427 | 12.0k | { |
428 | 12.0k | txSlot* result; |
429 | | |
430 | 12.0k | result = fxNewSlot(the); |
431 | 12.0k | result->ID = theSlot->ID; |
432 | 12.0k | result->kind = theSlot->kind; |
433 | 12.0k | result->flag = theSlot->flag & ~XS_MARK_FLAG; |
434 | 12.0k | result->value = theSlot->value; |
435 | 12.0k | return result; |
436 | 12.0k | } |
437 | | |
438 | | void* fxFindChunk(txMachine* the, txSize size, txBoolean *once) |
439 | 230M | { |
440 | 230M | txBlock* block; |
441 | 230M | txChunk* chunk; |
442 | 230M | #if mxStress |
443 | 230M | if (fxShouldStress()) { |
444 | 14 | if (*once) { |
445 | 14 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
446 | 14 | *once = 0; |
447 | 14 | } |
448 | 14 | } |
449 | 230M | #endif |
450 | | #if mxNoChunks |
451 | | if ((the->currentChunksSize + size > the->maximumChunksSize)) { |
452 | | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
453 | | if (the->collectFlag & XS_TRASHING_CHUNKS_FLAG) |
454 | | the->maximumChunksSize += the->minimumChunksSize; |
455 | | } |
456 | | chunk = c_malloc_noforcefail(size); |
457 | | if (!chunk) |
458 | | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
459 | | chunk->size = size; |
460 | | chunk->temporary = (txByte*)the->firstBlock; |
461 | | the->firstBlock = (txBlock*)chunk; |
462 | | return chunk; |
463 | | #endif |
464 | 230M | again: |
465 | 230M | block = the->firstBlock; |
466 | 321M | while (block) { |
467 | 321M | if ((block->current + size) <= block->limit) { |
468 | 230M | chunk = (txChunk*)(block->current); |
469 | 230M | block->current += size; |
470 | 230M | chunk->temporary = block->current; |
471 | 230M | return chunk; |
472 | 230M | } |
473 | 90.9M | block = block->nextBlock; |
474 | 90.9M | } |
475 | 30.4k | if (*once) { |
476 | 28.8k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0), isThrashing; |
477 | 28.8k | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
478 | 28.8k | isThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0); |
479 | 28.8k | *once = 0; |
480 | 28.8k | if (wasThrashing && isThrashing) |
481 | 1.25k | return C_NULL; |
482 | 27.5k | goto again; |
483 | 28.8k | } |
484 | 1.60k | return C_NULL; |
485 | 30.4k | } |
486 | | |
487 | | txSlot* fxFindKey(txMachine* the) |
488 | 17.1M | { |
489 | 17.1M | #if mxKeysGarbageCollection |
490 | 17.1M | txBoolean once = 1; |
491 | 17.1M | #endif |
492 | 17.1M | txID id; |
493 | 17.1M | txSlot* result; |
494 | 17.1M | more: |
495 | 17.1M | id = the->keyIndex; |
496 | 17.1M | if (id < the->keyCount) { |
497 | 16.0M | result = fxNewSlot(the); |
498 | 16.0M | result->ID = id; |
499 | 16.0M | the->keyArray[id - the->keyOffset] = result; |
500 | 16.0M | the->keyIndex++; |
501 | 16.0M | return result; |
502 | 16.0M | } |
503 | 1.02M | #if mxKeysGarbageCollection |
504 | 1.03M | again: |
505 | 1.03M | result = the->keyholeList; |
506 | 1.03M | if (result) { |
507 | 1.02M | the->keyholeCount--; |
508 | 1.02M | the->keyholeList = result->next; |
509 | 1.02M | result->next = C_NULL; |
510 | 1.02M | return result; |
511 | 1.02M | } |
512 | 11.3k | if (once) { |
513 | 10.5k | fxCollect(the, XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
514 | 10.5k | once = 0; |
515 | 10.5k | goto again; |
516 | 10.5k | } |
517 | 834 | #endif |
518 | 834 | else { |
519 | 834 | fxGrowKeys(the, 1); |
520 | 834 | goto more; |
521 | 834 | } |
522 | 0 | return C_NULL; |
523 | 11.3k | } |
524 | | |
525 | | void fxFree(txMachine* the) |
526 | 27.8k | { |
527 | 27.8k | txSlot* aHeap; |
528 | | |
529 | | #if mxAliasInstance |
530 | | if (the->aliasArray) |
531 | | c_free_uint32(the->aliasArray); |
532 | | the->aliasArray = C_NULL; |
533 | | #endif |
534 | | |
535 | 27.8k | fxFreeStringInfoCache(the); |
536 | | |
537 | 27.8k | if (the->symbolTable) |
538 | 27.8k | c_free_uint32(the->symbolTable); |
539 | 27.8k | the->symbolTable = C_NULL; |
540 | 27.8k | if (the->nameTable) |
541 | 27.8k | c_free_uint32(the->nameTable); |
542 | 27.8k | the->nameTable = C_NULL; |
543 | 27.8k | if (the->keyArray) |
544 | 27.8k | c_free_uint32(the->keyArray); |
545 | 27.8k | the->keyArray = C_NULL; |
546 | | |
547 | 58.2k | while (the->firstHeap) { |
548 | 30.4k | aHeap = the->firstHeap; |
549 | 30.4k | the->firstHeap = aHeap->next; |
550 | 30.4k | fxFreeSlots(the, aHeap); |
551 | 30.4k | } |
552 | 27.8k | the->firstHeap = C_NULL; |
553 | | |
554 | 27.8k | if (the->stackBottom) |
555 | 27.8k | fxFreeSlots(the, the->stackBottom); |
556 | 27.8k | the->stackBottom = C_NULL; |
557 | 27.8k | the->stackTop = C_NULL; |
558 | 27.8k | the->stackIntrinsics = C_NULL; |
559 | 27.8k | the->stackPrototypes = C_NULL; |
560 | 27.8k | the->stack = C_NULL; |
561 | | |
562 | | #if mxNoChunks |
563 | | { |
564 | | txChunk** address; |
565 | | txChunk* chunk; |
566 | | address = (txChunk**)&(the->firstBlock); |
567 | | while ((chunk = *address)) { |
568 | | *address = (txChunk*)(chunk->temporary); |
569 | | c_free(chunk); |
570 | | } |
571 | | } |
572 | | #else |
573 | 27.8k | { |
574 | 27.8k | txBlock* aBlock; |
575 | 58.5k | while (the->firstBlock) { |
576 | 30.7k | aBlock = the->firstBlock; |
577 | 30.7k | the->firstBlock = aBlock->nextBlock; |
578 | 30.7k | fxFreeChunks(the, aBlock); |
579 | 30.7k | } |
580 | 27.8k | the->firstBlock = C_NULL; |
581 | 27.8k | } |
582 | 27.8k | #endif |
583 | | |
584 | 27.8k | #ifdef mxDebug |
585 | 27.8k | if (the->pathValue) |
586 | 27.8k | c_free(the->pathValue); |
587 | 27.8k | the->pathValue = C_NULL; |
588 | 27.8k | #endif |
589 | | |
590 | | #ifdef mxNever |
591 | | stopTime(&gxLifeTime); |
592 | | // fprintf(stderr, "###"); |
593 | | // reportTime(&gxLifeTime); |
594 | | // reportTime(&gxForcedGarbageCollectionTime); |
595 | | // reportTime(&gxChunksGarbageCollectionTime); |
596 | | // reportTime(&gxKeysGarbageCollectionTime); |
597 | | // reportTime(&gxSlotsGarbageCollectionTime); |
598 | | // reportTime(&gxMarkTime); |
599 | | // reportTime(&gxSweepChunkTime); |
600 | | // reportTime(&gxSweepSlotTime); |
601 | | // reportTime(&gxCompactChunkTime); |
602 | | // fprintf(stderr, "\n"); |
603 | | #endif |
604 | 27.8k | } |
605 | | |
606 | | void* fxGrowChunk(txMachine* the, txSize size) |
607 | 2.86k | { |
608 | 2.86k | txBlock* block = fxGrowChunks(the, size); |
609 | 2.86k | txChunk* chunk = C_NULL; |
610 | 2.86k | if (block) { |
611 | 2.85k | chunk = (txChunk*)(block->current); |
612 | 2.85k | block->current += size; |
613 | 2.85k | chunk->temporary = block->current; |
614 | 2.85k | } |
615 | 2.86k | return chunk; |
616 | 2.86k | } |
617 | | |
618 | | void* fxGrowChunks(txMachine* the, txSize size) |
619 | 30.7k | { |
620 | 30.7k | txByte* buffer; |
621 | 30.7k | txBlock* block = C_NULL; |
622 | | |
623 | 30.7k | if (!the->minimumChunksSize && the->firstBlock) { |
624 | 0 | fxReport(the, "# Chunk allocation: %d bytes failed in fixed size heap\n", size); |
625 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
626 | 0 | } |
627 | | |
628 | 30.7k | if ((the->firstBlock != C_NULL) && (!(the->collectFlag & XS_SKIPPED_COLLECT_FLAG))) { |
629 | 2.86k | txSize modulo = size % (the->minimumChunksSize ? the->minimumChunksSize : 16); |
630 | 2.86k | if (modulo) |
631 | 2.85k | size = fxAddChunkSizes(the, size, the->minimumChunksSize - modulo); |
632 | 2.86k | } |
633 | 30.7k | size = fxAddChunkSizes(the, size, sizeof(txBlock)); |
634 | 30.7k | buffer = fxAllocateChunks(the, size); |
635 | 30.7k | if (buffer) { |
636 | 30.7k | #ifdef mxSnapshot |
637 | 30.7k | c_memset(buffer, 0, size); |
638 | 30.7k | #endif |
639 | 30.7k | if ((the->firstBlock != C_NULL) && (the->firstBlock->limit == buffer)) { |
640 | 0 | the->firstBlock->limit += size; |
641 | 0 | block = the->firstBlock; |
642 | 0 | } |
643 | 30.7k | else { |
644 | 30.7k | block = (txBlock*)buffer; |
645 | 30.7k | block->nextBlock = the->firstBlock; |
646 | 30.7k | block->current = buffer + sizeof(txBlock); |
647 | 30.7k | block->limit = buffer + size; |
648 | 30.7k | block->temporary = C_NULL; |
649 | 30.7k | the->firstBlock = block; |
650 | 30.7k | size -= sizeof(txBlock); |
651 | 30.7k | } |
652 | 30.7k | the->maximumChunksSize = fxAddChunkSizes(the, the->maximumChunksSize, size); |
653 | | #if mxReport |
654 | | fxReport(the, "# Chunk allocation: reserved %ld used %ld peak %ld bytes\n", |
655 | | (long)the->maximumChunksSize, (long)the->currentChunksSize, (long)the->peakChunksSize); |
656 | | #endif |
657 | 30.7k | } |
658 | 30.7k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
659 | 30.7k | return block; |
660 | 30.7k | } |
661 | | |
662 | | void fxGrowKeys(txMachine* the, txID theCount) |
663 | 834 | { |
664 | 834 | if (the->keyDelta > 0) { |
665 | 834 | txID keyDelta = (theCount > the->keyDelta) ? theCount : the->keyDelta; |
666 | 834 | txID keyCount = (the->keyCount + keyDelta) - the->keyOffset; |
667 | 834 | txSlot** keyArray = c_realloc(the->keyArray, keyCount * sizeof(txSlot*)); |
668 | 834 | if (keyArray == C_NULL) |
669 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
670 | 834 | the->keyArray = keyArray; |
671 | 834 | the->keyCount = keyCount + the->keyOffset; |
672 | 834 | } |
673 | 0 | else |
674 | 0 | fxAbort(the, XS_NO_MORE_KEYS_EXIT); |
675 | 834 | } |
676 | | |
677 | | void fxGrowSlots(txMachine* the, txSize theCount) |
678 | 30.4k | { |
679 | 30.4k | txSlot* aHeap; |
680 | 30.4k | txSlot* aSlot; |
681 | | |
682 | 30.4k | aHeap = fxAllocateSlots(the, theCount); |
683 | 30.4k | if (!aHeap) { |
684 | 0 | fxReport(the, "# Slot allocation: failed for %ld bytes\n", theCount * sizeof(txSlot)); |
685 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
686 | 0 | } |
687 | 30.4k | if ((void *)-1 == aHeap) |
688 | 0 | return; |
689 | | |
690 | 30.4k | if (the->firstHeap && the->growHeapDirection) { |
691 | 0 | if (the->growHeapDirection > 0) { |
692 | 0 | the->firstHeap->value.reference = aHeap + theCount; |
693 | 0 | the->maximumHeapCount += theCount; |
694 | 0 | theCount -= 1; |
695 | 0 | aSlot = aHeap; |
696 | 0 | } |
697 | 0 | else { |
698 | 0 | *aHeap = *(the->firstHeap); |
699 | 0 | the->maximumHeapCount += theCount; |
700 | 0 | theCount -= 1; |
701 | 0 | the->firstHeap = aHeap; |
702 | 0 | aSlot = aHeap + 1; |
703 | 0 | } |
704 | 0 | } |
705 | 30.4k | else { |
706 | 30.4k | the->maximumHeapCount += theCount - 1; |
707 | 30.4k | aHeap->next = the->firstHeap; |
708 | 30.4k | aHeap->ID = 0; |
709 | 30.4k | aHeap->flag = 0; |
710 | 30.4k | aHeap->kind = 0; |
711 | 30.4k | aHeap->value.reference = aHeap + theCount; |
712 | 30.4k | theCount -= 2; |
713 | 30.4k | the->firstHeap = aHeap; |
714 | 30.4k | aSlot = aHeap + 1; |
715 | 30.4k | } |
716 | 997M | while (theCount--) { |
717 | 997M | txSlot* next = aSlot + 1; |
718 | 997M | aSlot->next = next; |
719 | 997M | aSlot->flag = XS_NO_FLAG; |
720 | 997M | aSlot->kind = XS_UNDEFINED_KIND; |
721 | | #if mxPoisonSlots |
722 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
723 | | #endif |
724 | 997M | aSlot = next; |
725 | 997M | } |
726 | 30.4k | aSlot->next = the->freeHeap; |
727 | 30.4k | aSlot->flag = XS_NO_FLAG; |
728 | 30.4k | aSlot->kind = XS_UNDEFINED_KIND; |
729 | | #if mxPoisonSlots |
730 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
731 | | #endif |
732 | 30.4k | the->freeHeap = aHeap + 1; |
733 | 30.4k | the->collectFlag &= ~XS_TRASHING_SLOTS_FLAG; |
734 | | #if mxReport |
735 | | fxReport(the, "# Slot allocation: reserved %ld used %ld peak %ld bytes\n", |
736 | | (long)(the->maximumHeapCount * sizeof(txSlot)), |
737 | | (long)(the->currentHeapCount * sizeof(txSlot)), |
738 | | (long)(the->peakHeapCount * sizeof(txSlot))); |
739 | | #endif |
740 | 30.4k | } |
741 | | |
742 | | void fxMark(txMachine* the, void (*theMarker)(txMachine*, txSlot*)) |
743 | 56.5k | { |
744 | 56.5k | txSlot** p; |
745 | 56.5k | txSlot** q; |
746 | 56.5k | txSlot* slot; |
747 | | |
748 | | #if mxAliasInstance |
749 | | p = the->aliasArray; |
750 | | q = p + the->aliasCount; |
751 | | while (p < q) { |
752 | | if ((slot = *p)) { |
753 | | (*theMarker)(the, slot); |
754 | | slot->flag |= XS_MARK_FLAG; |
755 | | } |
756 | | p++; |
757 | | } |
758 | | #endif |
759 | | |
760 | 56.5k | slot = the->stackTop; |
761 | 170M | while (slot > the->stack) { |
762 | 170M | slot--; |
763 | 170M | (*theMarker)(the, slot); |
764 | 170M | } |
765 | 56.5k | slot = the->cRoot; |
766 | 56.5k | while (slot) { |
767 | 0 | (*theMarker)(the, slot); |
768 | 0 | slot = slot->next; |
769 | 0 | } |
770 | | |
771 | 56.5k | #if mxKeysGarbageCollection |
772 | 56.5k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
773 | 21.5k | txInteger deletions = 0; |
774 | 21.5k | p = the->keyArray; |
775 | 21.5k | q = p + the->keyIndex - the->keyOffset; |
776 | 25.1M | while (p < q) { |
777 | 25.0M | slot = *p++; |
778 | 25.0M | if (!(slot->flag & XS_MARK_FLAG)) { |
779 | 11.2M | if (slot->flag & XS_DONT_DELETE_FLAG) |
780 | 7.36M | slot->flag |= XS_MARK_FLAG; |
781 | 3.87M | else if (slot->flag & XS_DONT_ENUM_FLAG) |
782 | 452k | deletions++; |
783 | 11.2M | } |
784 | 25.0M | } |
785 | | |
786 | | // fprintf(stderr, "\n### KEYS GC %d", deletions); |
787 | 21.5k | p = the->nameTable; |
788 | 21.5k | q = the->nameTable + the->nameModulo; |
789 | 26.2M | while ((p < q) && deletions) { |
790 | 26.2M | txSlot** address = p; |
791 | 36.9M | while (((slot = *address)) && deletions) { |
792 | 10.6M | if (slot->flag & XS_MARK_FLAG) |
793 | 10.2M | address = &(slot->next); |
794 | 452k | else { |
795 | 452k | *address = slot->next; |
796 | 452k | deletions--; |
797 | 452k | } |
798 | 10.6M | } |
799 | 26.2M | p++; |
800 | 26.2M | } |
801 | | // fprintf(stderr, " => %d", deletions); |
802 | | |
803 | 21.5k | the->keyholeCount = 0; |
804 | 21.5k | the->keyholeList = C_NULL; |
805 | 21.5k | p = the->keyArray; |
806 | 21.5k | q = p + the->keyIndex - the->keyOffset; |
807 | 25.1M | while (p < q) { |
808 | 25.0M | slot = *p; |
809 | 25.0M | if (slot->flag & XS_MARK_FLAG) |
810 | 21.2M | (*theMarker)(the, slot); |
811 | 3.87M | else { |
812 | | // if (slot->kind != XS_UNDEFINED_KIND) { |
813 | | // fxIDToString(the, slot->ID, the->nameBuffer, sizeof(the->nameBuffer)); |
814 | | // fprintf(stderr, "\n%p %d %s", slot, slot->ID, the->nameBuffer); |
815 | | // } |
816 | 3.87M | slot->flag = XS_INTERNAL_FLAG | XS_MARK_FLAG; |
817 | 3.87M | slot->next = the->keyholeList; |
818 | 3.87M | slot->kind = XS_UNDEFINED_KIND; |
819 | 3.87M | the->keyholeCount++; |
820 | 3.87M | the->keyholeList = slot; |
821 | 3.87M | } |
822 | 25.0M | p++; |
823 | 25.0M | } |
824 | | // fprintf(stderr, "\n"); |
825 | 21.5k | } |
826 | 35.0k | else |
827 | 35.0k | #endif |
828 | 35.0k | { |
829 | 35.0k | p = the->keyArray; |
830 | 35.0k | q = p + the->keyIndex - the->keyOffset; |
831 | 20.5M | while (p < q) { |
832 | 20.5M | slot = *p++; |
833 | 20.5M | slot->flag |= XS_MARK_FLAG; |
834 | 20.5M | (*theMarker)(the, slot); |
835 | 20.5M | } |
836 | 35.0k | } |
837 | 56.5k | } |
838 | | |
839 | | #if mxKeysGarbageCollection |
840 | | void fxMarkID(txMachine* the, txID id) |
841 | 139M | { |
842 | 139M | txSlot* slot; |
843 | 139M | if (id == XS_NO_ID) |
844 | 56.1M | return; |
845 | 82.9M | if (id < the->keyOffset) |
846 | 0 | return; |
847 | 82.9M | id -= the->keyOffset; |
848 | 82.9M | slot = the->keyArray[id]; |
849 | 82.9M | slot->flag |= XS_MARK_FLAG; |
850 | 82.9M | } |
851 | | #endif |
852 | | |
853 | | void fxMarkFinalizationRegistry(txMachine* the, txSlot* registry) |
854 | 168k | { |
855 | 168k | txSlot* slot = registry->value.finalizationRegistry.callback->next; |
856 | 168k | txSlot* instance; |
857 | 533k | while (slot) { |
858 | 364k | slot = slot->next; |
859 | 364k | if (slot) { |
860 | 364k | instance = slot->value.finalizationCell.target; |
861 | 364k | if (instance && !(instance->flag & XS_MARK_FLAG)) { |
862 | 42.2k | slot->value.finalizationCell.target = C_NULL; |
863 | 42.2k | registry->value.finalizationRegistry.flags |= XS_FINALIZATION_REGISTRY_CHANGED; |
864 | 42.2k | } |
865 | 364k | instance = slot->value.finalizationCell.token; |
866 | 364k | if (instance && !(instance->flag & XS_MARK_FLAG)) |
867 | 9.00k | slot->value.finalizationCell.token = C_NULL; |
868 | 364k | slot = slot->next; |
869 | 364k | } |
870 | 364k | } |
871 | 168k | } |
872 | | |
873 | | void fxMarkInstance(txMachine* the, txSlot* theCurrent, void (*theMarker)(txMachine*, txSlot*)) |
874 | 180M | { |
875 | 180M | txSlot* aProperty; |
876 | 180M | txSlot* aTemporary; |
877 | | |
878 | 180M | mxCheck(the, theCurrent->kind == XS_INSTANCE_KIND); |
879 | 180M | aProperty = theCurrent; |
880 | 180M | theCurrent->value.instance.garbage = C_NULL; |
881 | 2.27G | for (;;) { |
882 | 2.27G | if (aProperty) { |
883 | 1.90G | if (!(aProperty->flag & XS_MARK_FLAG)) { |
884 | 1.90G | aProperty->flag |= XS_MARK_FLAG; |
885 | 1.90G | switch (aProperty->kind) { |
886 | 361M | case XS_INSTANCE_KIND: |
887 | 361M | aTemporary = aProperty->value.instance.prototype; |
888 | 361M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
889 | 12.1M | aProperty->value.instance.prototype = theCurrent; |
890 | 12.1M | theCurrent = aTemporary; |
891 | 12.1M | theCurrent->value.instance.garbage = aProperty; |
892 | 12.1M | aProperty = theCurrent; |
893 | 12.1M | } |
894 | 349M | else |
895 | 349M | aProperty = aProperty->next; |
896 | 361M | break; |
897 | 193M | case XS_REFERENCE_KIND: |
898 | 193M | #if mxKeysGarbageCollection |
899 | 193M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
900 | 25.7M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
901 | 25.3M | fxMarkID(the, aProperty->ID); |
902 | 25.7M | } |
903 | 193M | #endif |
904 | 193M | aTemporary = aProperty->value.reference; |
905 | 193M | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
906 | 164M | aProperty->value.reference = theCurrent; |
907 | 164M | theCurrent = aTemporary; |
908 | 164M | theCurrent->value.instance.garbage = aProperty; |
909 | 164M | aProperty = theCurrent; |
910 | 164M | } |
911 | 29.1M | else |
912 | 29.1M | aProperty = aProperty->next; |
913 | 193M | break; |
914 | | |
915 | 1.08M | case XS_PROXY_KIND: |
916 | 1.08M | aTemporary = aProperty->value.proxy.handler; |
917 | 1.08M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
918 | 1.08M | aProperty->flag |= XS_INSPECTOR_FLAG; |
919 | 1.08M | aProperty->value.proxy.handler = theCurrent; |
920 | 1.08M | theCurrent = aTemporary; |
921 | 1.08M | theCurrent->value.instance.garbage = aProperty; |
922 | 1.08M | aProperty = theCurrent; |
923 | 1.08M | } |
924 | 2.33k | else { |
925 | 2.33k | aTemporary = aProperty->value.proxy.target; |
926 | 2.33k | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
927 | 1 | aProperty->value.proxy.target = theCurrent; |
928 | 1 | theCurrent = aTemporary; |
929 | 1 | theCurrent->value.instance.garbage = aProperty; |
930 | 1 | aProperty = theCurrent; |
931 | 1 | } |
932 | 2.33k | else |
933 | 2.33k | aProperty = aProperty->next; |
934 | 2.33k | } |
935 | 1.08M | break; |
936 | | |
937 | 17.5M | case XS_CLOSURE_KIND: |
938 | 17.5M | #if mxKeysGarbageCollection |
939 | 17.5M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
940 | 150k | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
941 | 98.1k | fxMarkID(the, aProperty->ID); |
942 | 150k | } |
943 | 17.5M | #endif |
944 | 17.5M | aTemporary = aProperty->value.closure; |
945 | 17.5M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
946 | 15.7M | aTemporary->flag |= XS_MARK_FLAG; |
947 | 15.7M | if (aTemporary->kind == XS_REFERENCE_KIND) { |
948 | 2.67M | aTemporary = aTemporary->value.reference; |
949 | 2.67M | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
950 | 2.63M | aProperty->value.closure->value.reference = theCurrent; |
951 | 2.63M | theCurrent = aTemporary; |
952 | 2.63M | theCurrent->value.instance.garbage = aProperty; |
953 | 2.63M | aProperty = theCurrent; |
954 | | |
955 | 2.63M | } |
956 | 2.67M | } |
957 | 13.1M | else { |
958 | 13.1M | (*theMarker)(the, aTemporary); |
959 | 13.1M | aProperty = aProperty->next; |
960 | 13.1M | } |
961 | 15.7M | } |
962 | 1.81M | else |
963 | 1.81M | aProperty = aProperty->next; |
964 | 17.5M | break; |
965 | | |
966 | 53.6M | case XS_CALLBACK_KIND: |
967 | 56.6M | case XS_CODE_KIND: |
968 | 56.6M | #if mxKeysGarbageCollection |
969 | 56.6M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
970 | 12.9M | fxMarkID(the, aProperty->ID); |
971 | 56.6M | #endif |
972 | 56.6M | (*theMarker)(the, aProperty); |
973 | 56.6M | aProperty = aProperty->next; |
974 | 56.6M | break; |
975 | | |
976 | 1.27G | default: |
977 | 1.27G | #if mxKeysGarbageCollection |
978 | 1.27G | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
979 | 99.0M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
980 | 61.9M | fxMarkID(the, aProperty->ID); |
981 | 99.0M | } |
982 | 1.27G | #endif |
983 | 1.27G | (*theMarker)(the, aProperty); |
984 | 1.27G | aProperty = aProperty->next; |
985 | 1.27G | break; |
986 | 1.90G | } |
987 | 1.90G | } |
988 | 35.0k | else |
989 | 35.0k | aProperty = aProperty->next; |
990 | 1.90G | } |
991 | 361M | else if (theCurrent->value.instance.garbage) { |
992 | 181M | aProperty = theCurrent->value.instance.garbage; |
993 | 181M | theCurrent->value.instance.garbage = C_NULL; |
994 | 181M | switch (aProperty->kind) { |
995 | 12.1M | case XS_INSTANCE_KIND: |
996 | 12.1M | aTemporary = aProperty->value.instance.prototype; |
997 | 12.1M | aProperty->value.instance.prototype = theCurrent; |
998 | 12.1M | theCurrent = aTemporary; |
999 | 12.1M | aProperty = aProperty->next; |
1000 | 12.1M | break; |
1001 | 164M | case XS_REFERENCE_KIND: |
1002 | 164M | aTemporary = aProperty->value.reference; |
1003 | 164M | aProperty->value.reference = theCurrent; |
1004 | 164M | theCurrent = aTemporary; |
1005 | 164M | aProperty = aProperty->next; |
1006 | 164M | break; |
1007 | 2.16M | case XS_PROXY_KIND: |
1008 | 2.16M | if (aProperty->flag & XS_INSPECTOR_FLAG) { |
1009 | 1.08M | aProperty->flag &= ~XS_INSPECTOR_FLAG; |
1010 | 1.08M | aTemporary = aProperty->value.proxy.handler; |
1011 | 1.08M | aProperty->value.proxy.handler = theCurrent; |
1012 | 1.08M | theCurrent = aTemporary; |
1013 | | |
1014 | 1.08M | aTemporary = aProperty->value.proxy.target; |
1015 | 1.08M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
1016 | 1.08M | aProperty->value.proxy.target = theCurrent; |
1017 | 1.08M | theCurrent = aTemporary; |
1018 | 1.08M | theCurrent->value.instance.garbage = aProperty; |
1019 | 1.08M | aProperty = theCurrent; |
1020 | 1.08M | } |
1021 | 165 | else { |
1022 | 165 | aProperty = aProperty->next; |
1023 | 165 | } |
1024 | 1.08M | } |
1025 | 1.08M | else { |
1026 | 1.08M | aTemporary = aProperty->value.proxy.target; |
1027 | 1.08M | aProperty->value.proxy.target = theCurrent; |
1028 | 1.08M | theCurrent = aTemporary; |
1029 | 1.08M | aProperty = aProperty->next; |
1030 | 1.08M | } |
1031 | 2.16M | break; |
1032 | 2.63M | case XS_CLOSURE_KIND: |
1033 | 2.63M | aTemporary = aProperty->value.closure->value.reference; |
1034 | 2.63M | aProperty->value.closure->value.reference = theCurrent; |
1035 | 2.63M | theCurrent = aTemporary; |
1036 | 2.63M | aProperty = aProperty->next; |
1037 | 2.63M | break; |
1038 | 181M | } |
1039 | 181M | } |
1040 | 180M | else |
1041 | 180M | break; |
1042 | 2.27G | } |
1043 | 180M | } |
1044 | | |
1045 | | void fxMarkReference(txMachine* the, txSlot* theSlot) |
1046 | 1.25G | { |
1047 | 1.25G | txSlot* aSlot; |
1048 | 1.25G | switch (theSlot->kind) { |
1049 | 94.0M | case XS_REFERENCE_KIND: |
1050 | 94.0M | aSlot = theSlot->value.reference; |
1051 | 94.0M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1052 | 83.4M | fxMarkInstance(the, aSlot, fxMarkReference); |
1053 | 94.0M | break; |
1054 | 1.19M | case XS_CLOSURE_KIND: |
1055 | 1.19M | aSlot = theSlot->value.closure; |
1056 | 1.19M | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1057 | 266k | aSlot->flag |= XS_MARK_FLAG; |
1058 | 266k | fxMarkReference(the, aSlot); |
1059 | 266k | } |
1060 | 1.19M | break; |
1061 | 188k | case XS_INSTANCE_KIND: |
1062 | 188k | if (!(theSlot->flag & XS_MARK_FLAG)) |
1063 | 188k | fxMarkInstance(the, theSlot, fxMarkReference); |
1064 | 188k | break; |
1065 | 1.75M | case XS_ACCESSOR_KIND: |
1066 | 1.75M | aSlot = theSlot->value.accessor.getter; |
1067 | 1.75M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1068 | 1.74M | fxCheckCStack(the); |
1069 | 1.74M | fxMarkInstance(the, aSlot, fxMarkReference); |
1070 | 1.74M | } |
1071 | 1.75M | aSlot = theSlot->value.accessor.setter; |
1072 | 1.75M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1073 | 921k | fxCheckCStack(the); |
1074 | 921k | fxMarkInstance(the, aSlot, fxMarkReference); |
1075 | 921k | } |
1076 | 1.75M | break; |
1077 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1078 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1079 | 144M | case XS_ARRAY_KIND: |
1080 | 145M | case XS_STACK_KIND: |
1081 | 145M | fxCheckCStack(the); |
1082 | 145M | if ((aSlot = theSlot->value.array.address)) { |
1083 | 48.0M | txIndex aLength = (((txChunk*)(((txByte*)aSlot) - sizeof(txChunk)))->size) / sizeof(txSlot); |
1084 | 48.0M | if (aLength > theSlot->value.array.length) |
1085 | 15.1k | aLength = theSlot->value.array.length; |
1086 | 335M | while (aLength) { |
1087 | 287M | fxMarkReference(the, aSlot); |
1088 | 287M | aSlot++; |
1089 | 287M | aLength--; |
1090 | 287M | } |
1091 | 48.0M | } |
1092 | 145M | break; |
1093 | 27.6M | case XS_CALLBACK_KIND: |
1094 | 27.6M | aSlot = theSlot->value.callback.closures; |
1095 | 27.6M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1096 | 0 | fxCheckCStack(the); |
1097 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1098 | 0 | } |
1099 | 27.6M | break; |
1100 | 2.21M | case XS_CODE_KIND: |
1101 | | // continue |
1102 | 2.25M | case XS_CODE_X_KIND: |
1103 | 2.25M | aSlot = theSlot->value.code.closures; |
1104 | 2.25M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1105 | 1.82M | fxCheckCStack(the); |
1106 | 1.82M | fxMarkInstance(the, aSlot, fxMarkReference); |
1107 | 1.82M | } |
1108 | 2.25M | break; |
1109 | 29.8M | case XS_HOME_KIND: |
1110 | 29.8M | aSlot = theSlot->value.home.object; |
1111 | 29.8M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1112 | 13.4M | fxCheckCStack(the); |
1113 | 13.4M | fxMarkInstance(the, aSlot, fxMarkReference); |
1114 | 13.4M | } |
1115 | 29.8M | aSlot = theSlot->value.home.module; |
1116 | 29.8M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1117 | 1.23k | fxCheckCStack(the); |
1118 | 1.23k | fxMarkInstance(the, aSlot, fxMarkReference); |
1119 | 1.23k | } |
1120 | 29.8M | break; |
1121 | 51 | case XS_MODULE_KIND: |
1122 | 16.7k | case XS_PROGRAM_KIND: |
1123 | 16.7k | #if mxKeysGarbageCollection |
1124 | 16.7k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1125 | 10.5k | fxMarkID(the, theSlot->value.module.id); |
1126 | 16.7k | #endif |
1127 | 16.7k | aSlot = theSlot->value.module.realm; |
1128 | 16.7k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1129 | 16.7k | fxCheckCStack(the); |
1130 | 16.7k | fxMarkInstance(the, aSlot, fxMarkReference); |
1131 | 16.7k | } |
1132 | 16.7k | break; |
1133 | 0 | case XS_EXPORT_KIND: |
1134 | 0 | aSlot = theSlot->value.export.closure; |
1135 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1136 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1137 | 0 | fxMarkReference(the, aSlot); |
1138 | 0 | } |
1139 | 0 | aSlot = theSlot->value.export.module; |
1140 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1141 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1142 | 0 | break; |
1143 | 17.8k | case XS_HOST_KIND: |
1144 | 17.8k | if (theSlot->value.host.data) { |
1145 | 1.16k | if ((theSlot->flag & XS_HOST_HOOKS_FLAG) && (theSlot->value.host.variant.hooks->marker)) |
1146 | 0 | (*theSlot->value.host.variant.hooks->marker)(the, theSlot->value.host.data, fxMarkReference); |
1147 | 1.16k | } |
1148 | 17.8k | break; |
1149 | 0 | case XS_PROXY_KIND: |
1150 | 0 | aSlot = theSlot->value.proxy.handler; |
1151 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1152 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1153 | 0 | aSlot = theSlot->value.proxy.target; |
1154 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1155 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1156 | 0 | break; |
1157 | | |
1158 | 0 | case XS_BREAKPOINT_KIND: |
1159 | 0 | aSlot = theSlot->value.breakpoint.info; |
1160 | 0 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1161 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1162 | 0 | break; |
1163 | 145k | case XS_ERROR_KIND: |
1164 | 145k | aSlot = theSlot->value.error.info; |
1165 | 145k | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1166 | 145k | fxMarkInstance(the, aSlot, fxMarkReference); |
1167 | 145k | break; |
1168 | 46 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1169 | 72 | case XS_DISPOSABLE_STACK_KIND: |
1170 | 77.7k | case XS_LIST_KIND: |
1171 | 77.7k | fxCheckCStack(the); |
1172 | 77.7k | aSlot = theSlot->value.list.first; |
1173 | 134k | while (aSlot) { |
1174 | 57.1k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1175 | 57.1k | aSlot->flag |= XS_MARK_FLAG; |
1176 | 57.1k | fxMarkReference(the, aSlot); |
1177 | 57.1k | } |
1178 | 57.1k | aSlot = aSlot->next; |
1179 | 57.1k | } |
1180 | 77.7k | break; |
1181 | | |
1182 | 2 | case XS_PRIVATE_KIND: |
1183 | 2 | fxCheckCStack(the); |
1184 | 2 | aSlot = theSlot->value.private.check; |
1185 | 2 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1186 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1187 | 2 | aSlot = theSlot->value.private.first; |
1188 | 4 | while (aSlot) { |
1189 | 2 | aSlot->flag |= XS_MARK_FLAG; |
1190 | 2 | fxMarkReference(the, aSlot); |
1191 | 2 | aSlot = aSlot->next; |
1192 | 2 | } |
1193 | 2 | break; |
1194 | | |
1195 | 57 | case XS_MAP_KIND: |
1196 | 27.5k | case XS_SET_KIND: |
1197 | 27.5k | { |
1198 | 27.5k | txSlot** anAddress = theSlot->value.table.address; |
1199 | 27.5k | txInteger aLength = theSlot->value.table.length; |
1200 | 141k | while (aLength) { |
1201 | 113k | aSlot = *anAddress; |
1202 | 170k | while (aSlot) { |
1203 | 57.1k | aSlot->flag |= XS_MARK_FLAG; |
1204 | 57.1k | aSlot = aSlot->next; |
1205 | 57.1k | } |
1206 | 113k | anAddress++; |
1207 | 113k | aLength--; |
1208 | 113k | } |
1209 | 27.5k | } |
1210 | 27.5k | break; |
1211 | 117k | case XS_WEAK_MAP_KIND: |
1212 | 117k | case XS_WEAK_SET_KIND: |
1213 | 117k | aSlot = theSlot->value.weakList.first; |
1214 | 167k | while (aSlot) { |
1215 | 50.0k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1216 | 50.0k | aSlot->flag |= XS_MARK_FLAG; |
1217 | 50.0k | fxMarkReference(the, aSlot); |
1218 | 50.0k | } |
1219 | 50.0k | aSlot = aSlot->next; |
1220 | 50.0k | } |
1221 | 117k | break; |
1222 | 132k | case XS_WEAK_ENTRY_KIND: |
1223 | 132k | aSlot = theSlot->value.weakEntry.check; |
1224 | 132k | if (aSlot->flag & XS_MARK_FLAG) { |
1225 | 33.4k | aSlot = theSlot->value.weakEntry.value; |
1226 | 33.4k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1227 | 33.4k | aSlot->flag |= XS_MARK_FLAG; |
1228 | 33.4k | fxMarkReference(the, aSlot); |
1229 | 33.4k | } |
1230 | 33.4k | } |
1231 | 132k | break; |
1232 | 188k | case XS_WEAK_REF_KIND: |
1233 | 188k | aSlot = theSlot->value.weakRef.target; |
1234 | 188k | if (aSlot) { |
1235 | 188k | #ifdef mxSnapshot |
1236 | 188k | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1237 | 188k | fxMarkReference(the, aSlot); |
1238 | 188k | } |
1239 | 0 | else { |
1240 | 0 | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1241 | 0 | the->firstWeakRefLink = theSlot; |
1242 | 0 | } |
1243 | | #else |
1244 | | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1245 | | the->firstWeakRefLink = theSlot; |
1246 | | #endif |
1247 | 188k | } |
1248 | 188k | break; |
1249 | 122k | case XS_FINALIZATION_REGISTRY_KIND: |
1250 | 122k | aSlot = theSlot->value.finalizationRegistry.callback; |
1251 | 122k | if (aSlot) { |
1252 | 122k | fxCheckCStack(the); |
1253 | 122k | aSlot->flag |= XS_MARK_FLAG; |
1254 | 122k | fxMarkReference(the, aSlot); |
1255 | 122k | aSlot = aSlot->next; |
1256 | 357k | while (aSlot) { |
1257 | 235k | aSlot->flag |= XS_MARK_FLAG; |
1258 | 235k | fxMarkReference(the, aSlot); // holdings |
1259 | 235k | aSlot = aSlot->next; |
1260 | 235k | if (aSlot) { |
1261 | 235k | aSlot->flag |= XS_MARK_FLAG; |
1262 | | // weak target and token |
1263 | 235k | aSlot = aSlot->next; |
1264 | 235k | } |
1265 | 235k | } |
1266 | 122k | } |
1267 | 122k | break; |
1268 | | |
1269 | 0 | case XS_HOST_INSPECTOR_KIND: |
1270 | 0 | aSlot = theSlot->value.hostInspector.cache; |
1271 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1272 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1273 | 0 | break; |
1274 | 0 | #if mxKeysGarbageCollection |
1275 | 547k | case XS_SYMBOL_KIND: |
1276 | 547k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1277 | 326k | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1278 | 160k | fxMarkID(the, theSlot->value.symbol); |
1279 | 326k | } |
1280 | 547k | break; |
1281 | 21.1M | case XS_AT_KIND: |
1282 | 21.1M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1283 | 17.2M | fxMarkID(the, theSlot->value.at.id); |
1284 | 21.1M | break; |
1285 | 1.25G | #endif |
1286 | 1.25G | } |
1287 | 1.25G | } |
1288 | | |
1289 | | void fxMarkValue(txMachine* the, txSlot* theSlot) |
1290 | 965M | { |
1291 | 965M | #define mxMarkChunk(_THE_DATA) \ |
1292 | 965M | ((txChunk*)(((txByte*)_THE_DATA) - sizeof(txChunk)))->size |= mxChunkFlag |
1293 | | |
1294 | 965M | txSlot* aSlot; |
1295 | 965M | switch (theSlot->kind) { |
1296 | 192M | case XS_STRING_KIND: |
1297 | 192M | mxMarkChunk(theSlot->value.string); |
1298 | 192M | break; |
1299 | 1.59k | case XS_BIGINT_KIND: |
1300 | 1.59k | mxMarkChunk(theSlot->value.bigint.data); |
1301 | 1.59k | break; |
1302 | 127M | case XS_REFERENCE_KIND: |
1303 | 127M | aSlot = theSlot->value.reference; |
1304 | 127M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1305 | 73.0M | fxMarkInstance(the, aSlot, fxMarkValue); |
1306 | 127M | break; |
1307 | 15.0M | case XS_CLOSURE_KIND: |
1308 | 15.0M | aSlot = theSlot->value.closure; |
1309 | 15.0M | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1310 | 2.52M | aSlot->flag |= XS_MARK_FLAG; |
1311 | 2.52M | fxMarkValue(the, aSlot); |
1312 | 2.52M | } |
1313 | 15.0M | break; |
1314 | 418k | case XS_INSTANCE_KIND: |
1315 | 418k | if (!(theSlot->flag & XS_MARK_FLAG)) |
1316 | 418k | fxMarkInstance(the, theSlot, fxMarkValue); |
1317 | 418k | break; |
1318 | | |
1319 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1320 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1321 | 62.2M | case XS_ARRAY_KIND: |
1322 | 68.6M | case XS_STACK_KIND: |
1323 | 68.6M | fxCheckCStack(the); |
1324 | 68.6M | if ((aSlot = theSlot->value.array.address)) { |
1325 | 57.9M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
1326 | 57.9M | if (!(chunk->size & mxChunkFlag)) { |
1327 | 57.9M | txIndex aLength = chunk->size / sizeof(txSlot); |
1328 | 57.9M | if (aLength > theSlot->value.array.length) |
1329 | 6.45k | aLength = theSlot->value.array.length; |
1330 | 420M | while (aLength) { |
1331 | 362M | fxMarkValue(the, aSlot); |
1332 | 362M | aSlot++; |
1333 | 362M | aLength--; |
1334 | 362M | } |
1335 | 57.9M | mxMarkChunk(theSlot->value.array.address); |
1336 | 57.9M | } |
1337 | 57.9M | } |
1338 | 68.6M | break; |
1339 | 944k | case XS_ARRAY_BUFFER_KIND: |
1340 | 944k | if (theSlot->value.arrayBuffer.address) |
1341 | 941k | mxMarkChunk(theSlot->value.arrayBuffer.address); |
1342 | 944k | break; |
1343 | 26.0M | case XS_CALLBACK_KIND: |
1344 | 26.0M | aSlot = theSlot->value.callback.closures; |
1345 | 26.0M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1346 | 0 | fxCheckCStack(the); |
1347 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1348 | 0 | } |
1349 | 26.0M | break; |
1350 | 792k | case XS_CODE_KIND: |
1351 | 792k | mxMarkChunk(theSlot->value.code.address); |
1352 | | /* continue */ |
1353 | 909k | case XS_CODE_X_KIND: |
1354 | 909k | aSlot = theSlot->value.code.closures; |
1355 | 909k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1356 | 420k | fxCheckCStack(the); |
1357 | 420k | fxMarkInstance(the, aSlot, fxMarkValue); |
1358 | 420k | } |
1359 | 909k | break; |
1360 | 39.8k | case XS_GLOBAL_KIND: |
1361 | 39.8k | mxMarkChunk(theSlot->value.table.address); |
1362 | 39.8k | break; |
1363 | 41.4k | case XS_HOST_KIND: |
1364 | 41.4k | if (theSlot->value.host.data) { |
1365 | 1.55k | if ((theSlot->flag & XS_HOST_HOOKS_FLAG) && (theSlot->value.host.variant.hooks->marker)) |
1366 | 0 | (*theSlot->value.host.variant.hooks->marker)(the, theSlot->value.host.data, fxMarkValue); |
1367 | 1.55k | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
1368 | 123 | mxMarkChunk(theSlot->value.host.data); |
1369 | 1.55k | } |
1370 | 41.4k | break; |
1371 | 9 | case XS_IDS_KIND: |
1372 | 9 | if (theSlot->value.IDs) |
1373 | 9 | mxMarkChunk(theSlot->value.IDs); |
1374 | 9 | break; |
1375 | 0 | case XS_PROXY_KIND: |
1376 | 0 | aSlot = theSlot->value.proxy.handler; |
1377 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1378 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1379 | 0 | aSlot = theSlot->value.proxy.target; |
1380 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1381 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1382 | 0 | break; |
1383 | 6.78k | case XS_REGEXP_KIND: |
1384 | 6.78k | if (theSlot->value.regexp.code) |
1385 | 6.42k | mxMarkChunk(theSlot->value.regexp.code); |
1386 | 6.78k | if (theSlot->value.regexp.data) |
1387 | 6.74k | mxMarkChunk(theSlot->value.regexp.data); |
1388 | 6.78k | break; |
1389 | | |
1390 | 2.48M | case XS_ACCESSOR_KIND: |
1391 | 2.48M | aSlot = theSlot->value.accessor.getter; |
1392 | 2.48M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1393 | 2.44M | fxCheckCStack(the); |
1394 | 2.44M | fxMarkInstance(the, aSlot, fxMarkValue); |
1395 | 2.44M | } |
1396 | 2.48M | aSlot = theSlot->value.accessor.setter; |
1397 | 2.48M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1398 | 487k | fxCheckCStack(the); |
1399 | 487k | fxMarkInstance(the, aSlot, fxMarkValue); |
1400 | 487k | } |
1401 | 2.48M | break; |
1402 | 26.8M | case XS_HOME_KIND: |
1403 | 26.8M | aSlot = theSlot->value.home.object; |
1404 | 26.8M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1405 | 1.63M | fxCheckCStack(the); |
1406 | 1.63M | fxMarkInstance(the, aSlot, fxMarkValue); |
1407 | 1.63M | } |
1408 | 26.8M | aSlot = theSlot->value.home.module; |
1409 | 26.8M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1410 | 9.28k | fxCheckCStack(the); |
1411 | 9.28k | fxMarkInstance(the, aSlot, fxMarkValue); |
1412 | 9.28k | } |
1413 | 26.8M | break; |
1414 | 178 | case XS_MODULE_KIND: |
1415 | 40.0k | case XS_PROGRAM_KIND: |
1416 | 40.0k | #if mxKeysGarbageCollection |
1417 | 40.0k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1418 | 11.1k | fxMarkID(the, theSlot->value.module.id); |
1419 | 40.0k | #endif |
1420 | 40.0k | aSlot = theSlot->value.module.realm; |
1421 | 40.0k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1422 | 39.8k | fxCheckCStack(the); |
1423 | 39.8k | fxMarkInstance(the, aSlot, fxMarkValue); |
1424 | 39.8k | } |
1425 | 40.0k | break; |
1426 | 0 | case XS_EXPORT_KIND: |
1427 | 0 | aSlot = theSlot->value.export.closure; |
1428 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1429 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1430 | 0 | fxMarkValue(the, aSlot); |
1431 | 0 | } |
1432 | 0 | aSlot = theSlot->value.export.module; |
1433 | 0 | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) |
1434 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1435 | 0 | break; |
1436 | 74.8M | case XS_KEY_KIND: |
1437 | 74.8M | if (theSlot->value.key.string) |
1438 | 74.8M | mxMarkChunk(theSlot->value.key.string); |
1439 | 74.8M | break; |
1440 | | |
1441 | 0 | case XS_BREAKPOINT_KIND: |
1442 | 0 | aSlot = theSlot->value.breakpoint.info; |
1443 | 0 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1444 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1445 | 0 | break; |
1446 | 412k | case XS_ERROR_KIND: |
1447 | 412k | aSlot = theSlot->value.error.info; |
1448 | 412k | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1449 | 412k | fxMarkInstance(the, aSlot, fxMarkValue); |
1450 | 412k | break; |
1451 | 11 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1452 | 43 | case XS_DISPOSABLE_STACK_KIND: |
1453 | 128k | case XS_LIST_KIND: |
1454 | 128k | aSlot = theSlot->value.list.first; |
1455 | 148k | while (aSlot) { |
1456 | 20.2k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1457 | 20.1k | aSlot->flag |= XS_MARK_FLAG; |
1458 | 20.1k | fxMarkValue(the, aSlot); |
1459 | 20.1k | } |
1460 | 20.2k | aSlot = aSlot->next; |
1461 | 20.2k | } |
1462 | 128k | break; |
1463 | | |
1464 | 0 | case XS_PRIVATE_KIND: |
1465 | 0 | fxCheckCStack(the); |
1466 | 0 | aSlot = theSlot->value.private.check; |
1467 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1468 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1469 | 0 | aSlot = theSlot->value.private.first; |
1470 | 0 | while (aSlot) { |
1471 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1472 | 0 | fxMarkValue(the, aSlot); |
1473 | 0 | aSlot = aSlot->next; |
1474 | 0 | } |
1475 | 0 | break; |
1476 | | |
1477 | 35 | case XS_MAP_KIND: |
1478 | 8.55k | case XS_SET_KIND: |
1479 | 8.55k | { |
1480 | 8.55k | txSlot** anAddress = theSlot->value.table.address; |
1481 | 8.55k | txInteger aLength = theSlot->value.table.length; |
1482 | 47.2k | while (aLength) { |
1483 | 38.7k | aSlot = *anAddress; |
1484 | 58.8k | while (aSlot) { |
1485 | 20.0k | aSlot->flag |= XS_MARK_FLAG; |
1486 | 20.0k | aSlot = aSlot->next; |
1487 | 20.0k | } |
1488 | 38.7k | anAddress++; |
1489 | 38.7k | aLength--; |
1490 | 38.7k | } |
1491 | 8.55k | } |
1492 | 8.55k | mxMarkChunk(theSlot->value.table.address); |
1493 | 8.55k | break; |
1494 | | |
1495 | 59.5k | case XS_WEAK_MAP_KIND: |
1496 | 59.6k | case XS_WEAK_SET_KIND: |
1497 | 59.6k | aSlot = theSlot->value.weakList.first; |
1498 | 73.8k | while (aSlot) { |
1499 | 14.1k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1500 | 14.1k | aSlot->flag |= XS_MARK_FLAG; |
1501 | 14.1k | fxMarkValue(the, aSlot); |
1502 | 14.1k | } |
1503 | 14.1k | aSlot = aSlot->next; |
1504 | 14.1k | } |
1505 | 59.6k | break; |
1506 | 38.6k | case XS_WEAK_ENTRY_KIND: |
1507 | 38.6k | aSlot = theSlot->value.weakEntry.check; |
1508 | 38.6k | if (aSlot->flag & XS_MARK_FLAG) { |
1509 | 14.1k | aSlot = theSlot->value.weakEntry.value; |
1510 | 14.1k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1511 | 14.1k | aSlot->flag |= XS_MARK_FLAG; |
1512 | 14.1k | fxMarkValue(the, aSlot); |
1513 | 14.1k | } |
1514 | 14.1k | } |
1515 | 38.6k | break; |
1516 | 421k | case XS_WEAK_REF_KIND: |
1517 | 421k | aSlot = theSlot->value.weakRef.target; |
1518 | 421k | if (aSlot) { |
1519 | 419k | #ifdef mxSnapshot |
1520 | 419k | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1521 | 418k | fxMarkValue(the, aSlot); |
1522 | 418k | } |
1523 | 927 | else { |
1524 | 927 | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1525 | 927 | the->firstWeakRefLink = theSlot; |
1526 | 927 | } |
1527 | | #else |
1528 | | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1529 | | the->firstWeakRefLink = theSlot; |
1530 | | #endif |
1531 | 419k | } |
1532 | 421k | break; |
1533 | 63.4k | case XS_FINALIZATION_REGISTRY_KIND: |
1534 | 63.4k | aSlot = theSlot->value.finalizationRegistry.callback; |
1535 | 63.4k | if (aSlot) { |
1536 | 63.4k | aSlot->flag |= XS_MARK_FLAG; |
1537 | 63.4k | fxMarkValue(the, aSlot); |
1538 | 63.4k | aSlot = aSlot->next; |
1539 | 192k | while (aSlot) { |
1540 | 129k | aSlot->flag |= XS_MARK_FLAG; |
1541 | 129k | fxCheckCStack(the); |
1542 | 129k | fxMarkValue(the, aSlot); // holdings |
1543 | 129k | aSlot = aSlot->next; |
1544 | 129k | if (aSlot) { |
1545 | 129k | aSlot->flag |= XS_MARK_FLAG; |
1546 | | // weak target and token |
1547 | 129k | aSlot = aSlot->next; |
1548 | 129k | } |
1549 | 129k | } |
1550 | 63.4k | } |
1551 | 63.4k | break; |
1552 | | |
1553 | 0 | case XS_HOST_INSPECTOR_KIND: |
1554 | 0 | aSlot = theSlot->value.hostInspector.cache; |
1555 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1556 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1557 | 0 | break; |
1558 | | |
1559 | 0 | #if mxKeysGarbageCollection |
1560 | 1.28M | case XS_SYMBOL_KIND: |
1561 | 1.28M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1562 | 329k | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1563 | 164k | fxMarkID(the, theSlot->value.symbol); |
1564 | 329k | } |
1565 | 1.28M | break; |
1566 | 88.2M | case XS_AT_KIND: |
1567 | 88.2M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1568 | 21.1M | fxMarkID(the, theSlot->value.at.id); |
1569 | 88.2M | break; |
1570 | 965M | #endif |
1571 | 965M | } |
1572 | 965M | } |
1573 | | |
1574 | | void fxMarkWeakStuff(txMachine* the) |
1575 | 56.5k | { |
1576 | 56.5k | txSlot* slot; |
1577 | 56.5k | txSlot** address; |
1578 | | |
1579 | 56.5k | { |
1580 | 56.5k | txSlot* list; |
1581 | 56.5k | txSlot** listAddress = &the->firstWeakListLink; |
1582 | 720k | while ((list = *listAddress)) { |
1583 | 663k | if (list->flag & XS_MARK_FLAG) { |
1584 | 177k | txSlot* listEntry; |
1585 | 177k | txSlot** listEntryAddress = &list->value.weakList.first; |
1586 | 241k | while ((listEntry = *listEntryAddress)) { |
1587 | 64.2k | txSlot* value = listEntry->value.weakEntry.value; |
1588 | 64.2k | if ((value->flag & XS_MARK_FLAG) && (value->kind != XS_UNINITIALIZED_KIND)) { |
1589 | 47.5k | listEntryAddress = &listEntry->next; |
1590 | 47.5k | } |
1591 | 16.6k | else { |
1592 | 16.6k | listEntry->flag &= ~XS_MARK_FLAG; |
1593 | 16.6k | *listEntryAddress = listEntry->next; |
1594 | 16.6k | } |
1595 | 64.2k | } |
1596 | 177k | listAddress = &list->value.weakList.link; |
1597 | 177k | } |
1598 | 486k | else { |
1599 | 486k | txSlot* listEntry = list->value.weakList.first; |
1600 | 546k | while (listEntry) { |
1601 | 59.7k | txSlot* key = listEntry->value.weakEntry.check; |
1602 | 59.7k | if (key->flag & XS_MARK_FLAG) { |
1603 | 59.7k | txSlot* keyEntry; |
1604 | 59.7k | txSlot** keyEntryAddress = &key->next; |
1605 | 86.7M | while ((keyEntry = *keyEntryAddress)) { |
1606 | 86.7M | if (!(keyEntry->flag & XS_INTERNAL_FLAG)) |
1607 | 46 | break; |
1608 | 86.7M | if ((keyEntry->kind == XS_WEAK_ENTRY_KIND) && (keyEntry->value.weakEntry.check == list)) { |
1609 | 59.6k | keyEntry->flag &= ~XS_MARK_FLAG; |
1610 | 59.6k | *keyEntryAddress = keyEntry->next; |
1611 | 59.6k | break; |
1612 | 59.6k | } |
1613 | 86.7M | keyEntryAddress = &keyEntry->next; |
1614 | 86.7M | } |
1615 | 59.7k | } |
1616 | 59.7k | listEntry = listEntry->next; |
1617 | 59.7k | } |
1618 | 486k | *listAddress = list->value.weakList.link; |
1619 | 486k | } |
1620 | 663k | } |
1621 | 56.5k | } |
1622 | 56.5k | address = &the->firstWeakRefLink; |
1623 | 57.5k | while ((slot = *address)) { |
1624 | 927 | if (!(slot->value.weakRef.target->flag & XS_MARK_FLAG)) |
1625 | 845 | slot->value.weakRef.target = C_NULL; |
1626 | 927 | *address = C_NULL; |
1627 | 927 | address = &(slot->value.weakRef.link); |
1628 | 927 | } |
1629 | | |
1630 | 56.5k | if (mxFinalizationRegistries.kind == XS_REFERENCE_KIND) { |
1631 | 56.5k | slot = mxFinalizationRegistries.value.reference->next; |
1632 | 225k | while (slot) { |
1633 | 168k | fxMarkFinalizationRegistry(the, slot->value.closure); |
1634 | 168k | slot = slot->next; |
1635 | 168k | } |
1636 | 56.5k | } |
1637 | 56.5k | } |
1638 | | |
1639 | | txSize fxMultiplyChunkSizes(txMachine* the, txSize a, txSize b) |
1640 | 47.1M | { |
1641 | 47.1M | txSize c; |
1642 | 47.1M | #if __has_builtin(__builtin_mul_overflow) |
1643 | 47.1M | if (__builtin_mul_overflow(a, b, &c) || (c < 0)) { |
1644 | | #else |
1645 | | txNumber C = (txNumber)a * (txNumber)b; |
1646 | | c = (txSize)C; |
1647 | | if ((C > (txNumber)0x7FFFFFFF) || (C < (txNumber)0)) { |
1648 | | #endif |
1649 | 1 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
1650 | 1 | } |
1651 | 47.1M | return c; |
1652 | 47.1M | } |
1653 | | |
1654 | | void* fxNewChunk(txMachine* the, txSize size) |
1655 | 228M | { |
1656 | 228M | txSize offset = size; |
1657 | 228M | txChunk* chunk; |
1658 | 228M | txBoolean once = 1; |
1659 | 228M | size = fxAdjustChunkSize(the, size); |
1660 | 228M | chunk = fxFindChunk(the, size, &once); |
1661 | 228M | if (!chunk) { |
1662 | 2.81k | chunk = fxGrowChunk(the, size); |
1663 | 2.81k | } |
1664 | 228M | #ifdef mxMetering |
1665 | 228M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1666 | 228M | #endif |
1667 | 228M | return fxCheckChunk(the, chunk, size, offset); |
1668 | 228M | } |
1669 | | |
1670 | | void* fxNewGrowableChunk(txMachine* the, txSize size, txSize capacity) |
1671 | 2.38M | { |
1672 | | #if mxNoChunks |
1673 | | return fxNewChunk(the, size); |
1674 | | #else |
1675 | 2.38M | txSize offset = size; |
1676 | 2.38M | txChunk* chunk; |
1677 | 2.38M | txBoolean once = 1; |
1678 | 2.38M | size = fxAdjustChunkSize(the, size); |
1679 | 2.38M | capacity = fxAdjustChunkSize(the, capacity); |
1680 | 2.38M | chunk = fxFindChunk(the, capacity, &once); |
1681 | 2.38M | if (!chunk) { |
1682 | 48 | chunk = fxGrowChunk(the, capacity); |
1683 | 48 | if (!chunk) { |
1684 | 0 | chunk = fxFindChunk(the, size, &once); |
1685 | 0 | if (!chunk) { |
1686 | 0 | chunk = fxGrowChunk(the, size); |
1687 | 0 | } |
1688 | 0 | } |
1689 | 48 | } |
1690 | 2.38M | #ifdef mxMetering |
1691 | 2.38M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1692 | 2.38M | #endif |
1693 | 2.38M | return fxCheckChunk(the, chunk, size, offset); |
1694 | 2.38M | #endif |
1695 | 2.38M | } |
1696 | | |
1697 | | txSlot* fxNewSlot(txMachine* the) |
1698 | 540M | { |
1699 | 540M | txSlot* aSlot; |
1700 | 540M | txBoolean once = 1, allocate; |
1701 | | |
1702 | 540M | #if mxStress |
1703 | 540M | if (fxShouldStress()) { |
1704 | 30 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
1705 | 30 | once = 0; |
1706 | 30 | } |
1707 | 540M | #endif |
1708 | 541M | again: |
1709 | 541M | aSlot = the->freeHeap; |
1710 | 541M | if (aSlot) { |
1711 | 540M | the->freeHeap = aSlot->next; |
1712 | 540M | aSlot->next = C_NULL; |
1713 | 540M | aSlot->ID = XS_NO_ID; |
1714 | 540M | aSlot->flag = XS_NO_FLAG; |
1715 | 540M | #ifdef mxSnapshot |
1716 | 540M | #if mx32bitID |
1717 | 540M | aSlot->dummy = 0; |
1718 | | #elif INTPTR_MAX == INT64_MAX |
1719 | | aSlot->dummy = 0; |
1720 | | #endif |
1721 | 540M | #endif |
1722 | | #if mxPoisonSlots |
1723 | | ASAN_UNPOISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
1724 | | #endif |
1725 | 540M | the->currentHeapCount++; |
1726 | 540M | if (the->peakHeapCount < the->currentHeapCount) |
1727 | 241M | the->peakHeapCount = the->currentHeapCount; |
1728 | 540M | #ifdef mxMetering |
1729 | 540M | the->meterIndex += XS_SLOT_ALLOCATION_METERING; |
1730 | 540M | #endif |
1731 | 540M | return aSlot; |
1732 | 540M | } |
1733 | 6.86k | if (once) { |
1734 | 6.21k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0), isThrashing; |
1735 | | |
1736 | 6.21k | fxCollect(the, XS_ORGANIC_FLAG); |
1737 | | |
1738 | 6.21k | isThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0); |
1739 | 6.21k | allocate = wasThrashing && isThrashing; |
1740 | | |
1741 | 6.21k | once = 0; |
1742 | 6.21k | } |
1743 | 658 | else |
1744 | 658 | allocate = 1; |
1745 | 6.86k | if (allocate) { |
1746 | 2.57k | if (!the->minimumHeapCount) { |
1747 | 0 | fxReport(the, "# Slot allocation: failed in fixed size heap\n"); |
1748 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
1749 | 0 | } |
1750 | 2.57k | fxGrowSlots(the, !(the->collectFlag & XS_SKIPPED_COLLECT_FLAG) ? the->minimumHeapCount : 64); |
1751 | 2.57k | } |
1752 | 6.86k | goto again; |
1753 | 0 | return C_NULL; |
1754 | 541M | } |
1755 | | |
1756 | | void* fxRenewChunk(txMachine* the, void* theData, txSize size) |
1757 | 21.5M | { |
1758 | | #if mxNoChunks |
1759 | | txByte* aData = ((txByte*)theData) - sizeof(txChunk); |
1760 | | txChunk* aChunk = (txChunk*)aData; |
1761 | | size = fxAdjustChunkSize(the, size); |
1762 | | if (size <= aChunk->size) { |
1763 | | aChunk->size = size; |
1764 | | return theData; |
1765 | | } |
1766 | | return C_NULL; |
1767 | | #else |
1768 | 21.5M | txByte* aData = ((txByte*)theData) - sizeof(txChunk); |
1769 | 21.5M | txChunk* aChunk = (txChunk*)aData; |
1770 | 21.5M | txSize capacity = (txSize)(aChunk->temporary - aData); |
1771 | 21.5M | txBlock* aBlock = the->firstBlock; |
1772 | 21.5M | size = fxAdjustChunkSize(the, size); |
1773 | 21.5M | if (size <= capacity) { |
1774 | 6.81M | the->currentChunksSize += size - aChunk->size; |
1775 | 6.81M | if (the->peakChunksSize < the->currentChunksSize) |
1776 | 428k | the->peakChunksSize = the->currentChunksSize; |
1777 | 6.81M | aChunk->size = size; |
1778 | 6.81M | #ifdef mxMetering |
1779 | 6.81M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1780 | 6.81M | #endif |
1781 | 6.81M | return theData; |
1782 | 6.81M | } |
1783 | 40.8M | while (aBlock) { |
1784 | 37.2M | if (aChunk->temporary == aBlock->current) { |
1785 | 11.1M | txSize delta = size - capacity; |
1786 | 11.1M | if (aBlock->current + delta <= aBlock->limit) { |
1787 | 11.1M | the->currentChunksSize += size - aChunk->size; |
1788 | 11.1M | if (the->peakChunksSize < the->currentChunksSize) |
1789 | 855k | the->peakChunksSize = the->currentChunksSize; |
1790 | 11.1M | aBlock->current += delta; |
1791 | 11.1M | aChunk->temporary = aBlock->current; |
1792 | 11.1M | aChunk->size = size; |
1793 | 11.1M | #ifdef mxSnapshot |
1794 | 11.1M | c_memset(aData + capacity, 0, delta); |
1795 | 11.1M | #endif |
1796 | 11.1M | #ifdef mxMetering |
1797 | 11.1M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1798 | 11.1M | #endif |
1799 | 11.1M | return theData; |
1800 | 11.1M | } |
1801 | 753 | else { |
1802 | 753 | return C_NULL; |
1803 | 753 | } |
1804 | 11.1M | } |
1805 | 26.1M | aBlock = aBlock->nextBlock; |
1806 | 26.1M | } |
1807 | 3.61M | return C_NULL; |
1808 | 14.7M | #endif |
1809 | 14.7M | } |
1810 | | |
1811 | | #if mxAliasInstance |
1812 | | void fxShare(txMachine* the) |
1813 | | { |
1814 | | txID aliasCount = 0; |
1815 | | txSlot *heap, *slot, *limit; |
1816 | | |
1817 | | heap = the->firstHeap; |
1818 | | while (heap) { |
1819 | | slot = heap + 1; |
1820 | | limit = heap->value.reference; |
1821 | | while (slot < limit) { |
1822 | | if (slot->kind == XS_INSTANCE_KIND) { |
1823 | | txBoolean frozen = (slot->flag & XS_DONT_PATCH_FLAG) ? 1 : 0; |
1824 | | if (frozen) { |
1825 | | txSlot *property = slot->next; |
1826 | | while (property) { |
1827 | | if (property->kind == XS_ARRAY_KIND) { |
1828 | | txSlot* item = property->value.array.address; |
1829 | | txInteger length = (txInteger)fxGetIndexSize(the, property); |
1830 | | while (length > 0) { |
1831 | | if (item->kind != XS_ACCESSOR_KIND) |
1832 | | if (!(item->flag & XS_DONT_SET_FLAG)) |
1833 | | frozen = 0; |
1834 | | if (!(item->flag & XS_DONT_DELETE_FLAG)) |
1835 | | frozen = 0; |
1836 | | item++; |
1837 | | length--; |
1838 | | } |
1839 | | } |
1840 | | else { |
1841 | | if (property->kind != XS_ACCESSOR_KIND) |
1842 | | if (!(property->flag & XS_DONT_SET_FLAG)) |
1843 | | frozen = 0; |
1844 | | if (!(property->flag & XS_DONT_DELETE_FLAG)) |
1845 | | frozen = 0; |
1846 | | } |
1847 | | property = property->next; |
1848 | | } |
1849 | | } |
1850 | | if (frozen) |
1851 | | slot->ID = XS_NO_ID; |
1852 | | else |
1853 | | slot->ID = aliasCount++; |
1854 | | } |
1855 | | else if (slot->kind == XS_CLOSURE_KIND) { |
1856 | | txSlot* closure = slot->value.closure; |
1857 | | if (closure->flag & XS_DONT_SET_FLAG) |
1858 | | closure->flag |= XS_DONT_DELETE_FLAG; |
1859 | | else { |
1860 | | if (closure->ID == XS_NO_ID) |
1861 | | closure->ID = aliasCount++; |
1862 | | slot->flag &= ~XS_DONT_SET_FLAG; |
1863 | | } |
1864 | | } |
1865 | | slot->flag |= XS_MARK_FLAG; |
1866 | | slot++; |
1867 | | } |
1868 | | heap = heap->next; |
1869 | | } |
1870 | | the->aliasCount = aliasCount; |
1871 | | /* |
1872 | | fxReport(the, "# Share\n"); |
1873 | | fxReport(the, "# \tSlots: %ld\n", the->currentHeapCount); |
1874 | | fxReport(the, "# \t\tSymbols: %ld\n", the->keyIndex); |
1875 | | fxReport(the, "# \t\tInstances: %ld\n", aliasCount); |
1876 | | fxReport(the, "# \tChunks: %ld bytes\n", the->currentChunksSize); |
1877 | | */ |
1878 | | } |
1879 | | #endif |
1880 | | |
1881 | | void fxSweep(txMachine* the) |
1882 | 39.8k | { |
1883 | 39.8k | txSize aTotal; |
1884 | | #if mxNoChunks |
1885 | | txChunk** address; |
1886 | | txChunk* chunk; |
1887 | | #else |
1888 | 39.8k | txBlock* aBlock; |
1889 | 39.8k | txByte* limit; |
1890 | 39.8k | txByte* next; |
1891 | 39.8k | #endif |
1892 | 39.8k | txByte* current; |
1893 | 39.8k | txByte* temporary; |
1894 | 39.8k | txSize aSize; |
1895 | 39.8k | txByte** aCodeAddress; |
1896 | 39.8k | txSlot* aSlot; |
1897 | 39.8k | txSlot* bSlot; |
1898 | 39.8k | txSlot* cSlot; |
1899 | 39.8k | txSlot* freeSlot; |
1900 | 39.8k | txJump* jump; |
1901 | | |
1902 | | #ifdef mxNever |
1903 | | startTime(&gxSweepChunkTime); |
1904 | | #endif |
1905 | | |
1906 | 39.8k | aTotal = 0; |
1907 | | #if mxNoChunks |
1908 | | address = (txChunk**)&(the->firstBlock); |
1909 | | while ((chunk = *address)) { |
1910 | | aSize = chunk->size; |
1911 | | if (aSize & mxChunkFlag) { |
1912 | | aSize &= ~mxChunkFlag; |
1913 | | temporary = c_malloc_noforcefail(aSize); |
1914 | | if (!temporary) |
1915 | | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); // should never happen |
1916 | | c_memcpy(temporary, chunk, aSize); |
1917 | | ((txChunk*)temporary)->size = aSize; |
1918 | | chunk->temporary = temporary; |
1919 | | address = (txChunk**)&(((txChunk*)temporary)->temporary); |
1920 | | aTotal += aSize; |
1921 | | } |
1922 | | else { |
1923 | | *address = (txChunk*)(chunk->temporary); |
1924 | | c_free(chunk); |
1925 | | } |
1926 | | } |
1927 | | #else |
1928 | 39.8k | aBlock = the->firstBlock; |
1929 | 153k | while (aBlock) { |
1930 | 113k | current = ((txByte*)aBlock) + sizeof(txBlock); |
1931 | 113k | limit = aBlock->current; |
1932 | 113k | temporary = current; |
1933 | 439M | while (current < limit) { |
1934 | 439M | aSize = ((txChunk*)current)->size; |
1935 | 439M | next = ((txChunk*)current)->temporary; |
1936 | 439M | if (aSize & mxChunkFlag) { |
1937 | 264M | aSize &= ~mxChunkFlag; |
1938 | 264M | ((txChunk*)current)->temporary = temporary; |
1939 | 264M | temporary += aSize; |
1940 | 264M | aTotal += aSize; |
1941 | 264M | } |
1942 | 174M | else { |
1943 | 174M | ((txChunk*)current)->temporary = C_NULL; |
1944 | 174M | } |
1945 | 439M | ((txChunk*)current)->size = (txSize)(next - current); |
1946 | 439M | current = next; |
1947 | 439M | } |
1948 | 113k | aBlock->temporary = temporary; |
1949 | 113k | aBlock = aBlock->nextBlock; |
1950 | 113k | } |
1951 | 39.8k | #endif |
1952 | 39.8k | the->currentChunksSize = aTotal; |
1953 | | |
1954 | 39.8k | aCodeAddress = &(the->code); |
1955 | 39.8k | aSlot = the->frame; |
1956 | 4.09M | while (aSlot) { |
1957 | 4.05M | mxCheck(the, aSlot->kind == XS_FRAME_KIND); |
1958 | 4.05M | if ((aSlot->flag & XS_C_FLAG) == 0) { |
1959 | 3.86M | bSlot = (aSlot + 3)->value.reference->next; |
1960 | 3.86M | if (bSlot->kind == XS_CODE_KIND) { |
1961 | 3.83M | current = bSlot->value.code.address; |
1962 | 3.83M | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1963 | 3.83M | if (temporary) { |
1964 | 3.83M | temporary += sizeof(txChunk); |
1965 | 3.83M | *aCodeAddress += temporary - current; |
1966 | 3.83M | } |
1967 | 3.83M | } |
1968 | 3.86M | } |
1969 | 192k | else { |
1970 | 192k | current = *aCodeAddress; |
1971 | 192k | if (current) { |
1972 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1973 | 0 | if (temporary) |
1974 | 0 | *aCodeAddress = temporary + sizeof(txChunk); |
1975 | 0 | } |
1976 | 192k | } |
1977 | 4.05M | aCodeAddress = &(aSlot->value.frame.code); |
1978 | 4.05M | aSlot = aSlot->next; |
1979 | 4.05M | } |
1980 | | |
1981 | 39.8k | jump = the->firstJump; |
1982 | 2.75M | while (jump) { |
1983 | 2.71M | if (jump->flag) { |
1984 | 2.40M | aSlot = jump->frame; |
1985 | 2.40M | bSlot = (aSlot + 3)->value.reference->next; |
1986 | 2.40M | if (bSlot->kind == XS_CODE_KIND) { |
1987 | 2.37M | current = bSlot->value.code.address; |
1988 | 2.37M | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1989 | 2.37M | if (temporary) { |
1990 | 2.37M | temporary += sizeof(txChunk); |
1991 | 2.37M | jump->code += temporary - current; |
1992 | 2.37M | } |
1993 | 2.37M | } |
1994 | 2.40M | } |
1995 | 308k | else { |
1996 | 308k | current = jump->code; |
1997 | 308k | if (current) { |
1998 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1999 | 0 | if (temporary) |
2000 | 0 | jump->code = temporary + sizeof(txChunk); |
2001 | 0 | } |
2002 | 308k | } |
2003 | 2.71M | jump = jump->nextJump; |
2004 | 2.71M | } |
2005 | | |
2006 | 39.8k | aSlot = the->stack; |
2007 | 109M | while (aSlot < the->stackTop) { |
2008 | 109M | fxSweepValue(the, aSlot); |
2009 | 109M | aSlot++; |
2010 | 109M | } |
2011 | 39.8k | aSlot = the->cRoot; |
2012 | 39.8k | while (aSlot) { |
2013 | 0 | fxSweepValue(the, aSlot); |
2014 | 0 | aSlot = aSlot->next; |
2015 | 0 | } |
2016 | | |
2017 | | #ifdef mxNever |
2018 | | stopTime(&gxSweepChunkTime); |
2019 | | startTime(&gxSweepSlotTime); |
2020 | | #endif |
2021 | | |
2022 | 39.8k | aTotal = 0; |
2023 | 39.8k | freeSlot = C_NULL; |
2024 | 39.8k | aSlot = the->firstHeap; |
2025 | 96.9k | while (aSlot) { |
2026 | 57.0k | bSlot = aSlot + 1; |
2027 | 57.0k | cSlot = aSlot->value.reference; |
2028 | 1.86G | while (bSlot < cSlot) { |
2029 | 1.86G | if (bSlot->flag & XS_MARK_FLAG) { |
2030 | 687M | bSlot->flag &= ~XS_MARK_FLAG; |
2031 | 687M | fxSweepValue(the, bSlot); |
2032 | 687M | aTotal++; |
2033 | 687M | } |
2034 | 1.18G | else { |
2035 | 1.18G | #ifndef mxLink |
2036 | 1.18G | if (bSlot->kind == XS_HOST_KIND) { |
2037 | 2.26k | if (bSlot->flag & XS_HOST_HOOKS_FLAG) { |
2038 | 0 | if (bSlot->value.host.variant.hooks->destructor) |
2039 | 0 | (*(bSlot->value.host.variant.hooks->destructor))(bSlot->value.host.data); |
2040 | 0 | } |
2041 | 2.26k | else if (bSlot->value.host.variant.destructor) |
2042 | 1.08k | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
2043 | 2.26k | } |
2044 | 1.18G | #endif |
2045 | | // if (bSlot->kind == XS_MODULE_KIND) { |
2046 | | // char* name = fxGetKeyName(the, bSlot->value.module.id); |
2047 | | // fprintf(stderr, "gc module %d %s\n", bSlot->value.module.id, name); |
2048 | | // } |
2049 | | #if mxInstrument |
2050 | | if ((bSlot->kind == XS_MODULE_KIND) && (bSlot->ID == XS_MODULE_BEHAVIOR)) |
2051 | | the->loadedModulesCount--; |
2052 | | #endif |
2053 | 1.18G | bSlot->kind = XS_UNDEFINED_KIND; |
2054 | 1.18G | bSlot->next = freeSlot; |
2055 | | #if mxPoisonSlots |
2056 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
2057 | | #endif |
2058 | 1.18G | freeSlot = bSlot; |
2059 | 1.18G | } |
2060 | 1.86G | bSlot++; |
2061 | 1.86G | } |
2062 | 57.0k | aSlot = aSlot->next; |
2063 | 57.0k | } |
2064 | 39.8k | the->currentHeapCount = aTotal; |
2065 | 39.8k | the->freeHeap = freeSlot; |
2066 | | |
2067 | | #ifdef mxNever |
2068 | | stopTime(&gxSweepSlotTime); |
2069 | | startTime(&gxCompactChunkTime); |
2070 | | #endif |
2071 | | |
2072 | | #if mxNoChunks |
2073 | | address = (txChunk**)&(the->firstBlock); |
2074 | | while ((chunk = *address)) { |
2075 | | aSize = chunk->size; |
2076 | | if (aSize & mxChunkFlag) { |
2077 | | *address = (txChunk*)(chunk->temporary); |
2078 | | c_free(chunk); |
2079 | | } |
2080 | | else { |
2081 | | address = (txChunk**)&(chunk->temporary); |
2082 | | } |
2083 | | } |
2084 | | #else |
2085 | 39.8k | aBlock = the->firstBlock; |
2086 | 153k | while (aBlock) { |
2087 | 113k | txByte* former = C_NULL; |
2088 | 113k | current = ((txByte*)aBlock) + sizeof(txBlock); |
2089 | 113k | limit = aBlock->current; |
2090 | 439M | while (current < limit) { |
2091 | 439M | aSize = ((txChunk*)current)->size; |
2092 | 439M | next = current + aSize; |
2093 | 439M | if ((temporary = ((txChunk*)current)->temporary)) { |
2094 | 264M | if (former) { |
2095 | 264M | ((txChunk*)former)->temporary = temporary; |
2096 | 264M | ((txChunk*)former)->size = (txSize)(temporary - former); |
2097 | 264M | } |
2098 | 264M | if (temporary != current) |
2099 | 20.6M | c_memmove(temporary, current, aSize); |
2100 | 264M | former = temporary; |
2101 | 264M | } |
2102 | 439M | current = next; |
2103 | 439M | } |
2104 | 113k | if (former) { |
2105 | 104k | ((txChunk*)former)->temporary = aBlock->temporary; |
2106 | 104k | ((txChunk*)former)->size = (txSize)(aBlock->temporary - former); |
2107 | 104k | } |
2108 | 113k | aBlock->current = aBlock->temporary; |
2109 | 113k | aBlock->temporary = C_NULL; |
2110 | 113k | aBlock = aBlock->nextBlock; |
2111 | 113k | } |
2112 | 39.8k | #endif |
2113 | | |
2114 | | #ifdef mxNever |
2115 | | stopTime(&gxCompactChunkTime); |
2116 | | #endif |
2117 | 39.8k | } |
2118 | | |
2119 | | void fxSweepValue(txMachine* the, txSlot* theSlot) |
2120 | 1.15G | { |
2121 | 1.15G | txSlot* aSlot; |
2122 | 1.15G | txByte* data; |
2123 | | |
2124 | 1.15G | #define mxSweepChunk(_THE_DATA, _THE_DATA_TYPE) \ |
2125 | 1.15G | if ((data = (txByte*)(((txChunk*)(((txByte*)(_THE_DATA)) - sizeof(txChunk)))->temporary))) \ |
2126 | 327M | ((_THE_DATA)) = (_THE_DATA_TYPE)(data + sizeof(txChunk)) |
2127 | | |
2128 | 1.15G | switch (theSlot->kind) { |
2129 | 192M | case XS_STRING_KIND: |
2130 | 192M | mxSweepChunk(theSlot->value.string, txString); |
2131 | 192M | break; |
2132 | 1.59k | case XS_BIGINT_KIND: |
2133 | 1.59k | mxSweepChunk(theSlot->value.bigint.data, txU4*); |
2134 | 1.59k | break; |
2135 | | |
2136 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
2137 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
2138 | 62.2M | case XS_ARRAY_KIND: |
2139 | 68.6M | case XS_STACK_KIND: |
2140 | 68.6M | if ((aSlot = theSlot->value.array.address)) { |
2141 | | #if mxNoChunks |
2142 | | mxSweepChunk(theSlot->value.array.address, txSlot*); |
2143 | | aSlot = theSlot->value.array.address; |
2144 | | #endif |
2145 | 57.9M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
2146 | 57.9M | txIndex aLength = chunk->size / sizeof(txSlot); |
2147 | 57.9M | if (aLength > theSlot->value.array.length) |
2148 | 7.92k | aLength = theSlot->value.array.length; |
2149 | 420M | while (aLength) { |
2150 | 362M | fxSweepValue(the, aSlot); |
2151 | 362M | aSlot++; |
2152 | 362M | aLength--; |
2153 | 362M | } |
2154 | | #if mxNoChunks |
2155 | | #else |
2156 | 57.9M | mxSweepChunk(theSlot->value.array.address, txSlot*); |
2157 | 57.9M | #endif |
2158 | 57.9M | } |
2159 | 68.6M | break; |
2160 | 944k | case XS_ARRAY_BUFFER_KIND: |
2161 | 944k | if (theSlot->value.arrayBuffer.address) |
2162 | 941k | mxSweepChunk(theSlot->value.arrayBuffer.address, txByte*); |
2163 | 944k | break; |
2164 | 792k | case XS_CODE_KIND: |
2165 | 792k | mxSweepChunk(theSlot->value.code.address, txByte*); |
2166 | 792k | break; |
2167 | 39.8k | case XS_GLOBAL_KIND: |
2168 | 39.8k | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2169 | 39.8k | break; |
2170 | 41.4k | case XS_HOST_KIND: |
2171 | 41.4k | if (theSlot->value.host.data) { |
2172 | 1.55k | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
2173 | 123 | mxSweepChunk(theSlot->value.host.data, void*); |
2174 | 1.55k | } |
2175 | 41.4k | break; |
2176 | 9 | case XS_IDS_KIND: |
2177 | 9 | if (theSlot->value.IDs) |
2178 | 9 | mxSweepChunk(theSlot->value.IDs, txID*); |
2179 | 9 | break; |
2180 | 6.78k | case XS_REGEXP_KIND: |
2181 | 6.78k | if (theSlot->value.regexp.code) |
2182 | 6.42k | mxSweepChunk(theSlot->value.regexp.code, void*); |
2183 | 6.78k | if (theSlot->value.regexp.data) |
2184 | 6.74k | mxSweepChunk(theSlot->value.regexp.data, void*); |
2185 | 6.78k | break; |
2186 | 74.8M | case XS_KEY_KIND: |
2187 | 74.8M | if (theSlot->value.key.string) |
2188 | 74.8M | mxSweepChunk(theSlot->value.key.string, txString); |
2189 | 74.8M | break; |
2190 | 35 | case XS_MAP_KIND: |
2191 | 8.55k | case XS_SET_KIND: |
2192 | 8.55k | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2193 | 8.55k | break; |
2194 | 1.15G | } |
2195 | 1.15G | } |