/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 | 1.10G | { |
62 | 1.10G | if (!gxStress) |
63 | 1.10G | return 0; |
64 | | |
65 | 491k | if (gxStress > 0) |
66 | 0 | return 1; |
67 | | |
68 | 491k | gxStress += 1; |
69 | 491k | return 0 == gxStress; |
70 | 491k | } |
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.36G | #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 | 548M | { |
144 | 548M | txSize c; |
145 | 548M | #if __has_builtin(__builtin_add_overflow) |
146 | 548M | 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 | 548M | return c; |
154 | 548M | } |
155 | | |
156 | | txSize fxAdjustChunkSize(txMachine* the, txSize size) |
157 | 373M | { |
158 | 373M | txSize adjust = sizeof(txChunk); |
159 | 373M | txSize modulo = size & (sizeof(size_t) - 1); |
160 | 373M | if (modulo) |
161 | 272M | adjust += sizeof(size_t) - modulo; |
162 | 373M | return fxAddChunkSizes(the, size, adjust); |
163 | 373M | } |
164 | | |
165 | | void fxAllocate(txMachine* the, txCreation* theCreation) |
166 | 33.3k | { |
167 | | #ifdef mxNever |
168 | | startTime(&gxLifeTime); |
169 | | #endif |
170 | 33.3k | #if mxStress |
171 | 33.3k | gxStress = 0; |
172 | 33.3k | #endif |
173 | | |
174 | 33.3k | the->currentChunksSize = 0; |
175 | 33.3k | the->peakChunksSize = 0; |
176 | 33.3k | the->maximumChunksSize = 0; |
177 | 33.3k | the->minimumChunksSize = theCreation->incrementalChunkSize; |
178 | | |
179 | 33.3k | the->currentHeapCount = 0; |
180 | 33.3k | the->peakHeapCount = 0; |
181 | 33.3k | the->maximumHeapCount = 0; |
182 | 33.3k | the->minimumHeapCount = theCreation->incrementalHeapCount; |
183 | | |
184 | 33.3k | the->firstBlock = C_NULL; |
185 | 33.3k | the->firstHeap = C_NULL; |
186 | | |
187 | | #if mxNoChunks |
188 | | the->maximumChunksSize = theCreation->initialChunkSize; |
189 | | #else |
190 | 33.3k | fxGrowChunks(the, theCreation->initialChunkSize); |
191 | 33.3k | #endif |
192 | | |
193 | 33.3k | the->stackBottom = fxAllocateSlots(the, theCreation->stackCount); |
194 | 33.3k | the->stackTop = the->stackBottom + theCreation->stackCount; |
195 | 33.3k | the->stackIntrinsics = the->stackTop; |
196 | 33.3k | the->stackPrototypes = the->stackTop - XS_INTRINSICS_COUNT; |
197 | 33.3k | the->stack = the->stackTop; |
198 | | #ifdef mxInstrument |
199 | | the->stackPeak = the->stackTop; |
200 | | #endif |
201 | | |
202 | 33.3k | fxGrowSlots(the, theCreation->initialHeapCount); |
203 | | |
204 | 33.3k | the->keyCount = (txID)theCreation->initialKeyCount; |
205 | 33.3k | the->keyDelta = (txID)theCreation->incrementalKeyCount; |
206 | 33.3k | the->keyIndex = 0; |
207 | 33.3k | the->keyArray = (txSlot **)c_malloc_uint32(theCreation->initialKeyCount * sizeof(txSlot*)); |
208 | 33.3k | if (!the->keyArray) |
209 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
210 | | |
211 | 33.3k | the->nameModulo = theCreation->nameModulo; |
212 | 33.3k | the->nameTable = (txSlot **)c_malloc_uint32(theCreation->nameModulo * sizeof(txSlot*)); |
213 | 33.3k | if (!the->nameTable) |
214 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
215 | | |
216 | 33.3k | the->symbolModulo = theCreation->symbolModulo; |
217 | 33.3k | the->symbolTable = (txSlot **)c_malloc_uint32(theCreation->symbolModulo * sizeof(txSlot*)); |
218 | 33.3k | if (!the->symbolTable) |
219 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
220 | | |
221 | 33.3k | fxAllocateStringInfoCache(the); |
222 | | |
223 | 33.3k | the->stackLimit = fxCStackLimit(); |
224 | | |
225 | 33.3k | the->cRoot = C_NULL; |
226 | 33.3k | the->parserBufferSize = theCreation->parserBufferSize; |
227 | 33.3k | the->parserTableModulo = theCreation->parserTableModulo; |
228 | | |
229 | 33.3k | #ifdef mxDebug |
230 | 33.3k | the->pathCount = 256; |
231 | 33.3k | the->pathValue = c_malloc(the->pathCount); |
232 | 33.3k | if (!the->pathValue) |
233 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
234 | 33.3k | #endif |
235 | 33.3k | } |
236 | | |
237 | | void* fxCheckChunk(txMachine* the, txChunk* chunk, txSize size, txSize offset) |
238 | 330M | { |
239 | 330M | if (chunk) { |
240 | 330M | txByte* data = (txByte*)chunk; |
241 | | #if mxNoChunks |
242 | | chunk->size = size; |
243 | | the->currentChunksSize += size; |
244 | | #else |
245 | 330M | txSize capacity = (txSize)(chunk->temporary - data); |
246 | 330M | #ifdef mxSnapshot |
247 | 330M | #if INTPTR_MAX == INT64_MAX |
248 | 330M | chunk->dummy = 0; |
249 | 330M | #endif |
250 | | #ifdef mxSnapshotRandomInit |
251 | | arc4random_buf(data + sizeof(txChunk), offset); |
252 | | #endif |
253 | 330M | #endif |
254 | 330M | offset += sizeof(txChunk); |
255 | 330M | c_memset(data + offset, 0, capacity - offset); |
256 | 330M | chunk->size = size; |
257 | 330M | the->currentChunksSize += capacity; |
258 | 330M | #endif |
259 | 330M | if (the->peakChunksSize < the->currentChunksSize) |
260 | 90.8M | the->peakChunksSize = the->currentChunksSize; |
261 | 330M | return data + sizeof(txChunk); |
262 | 330M | } |
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 | 330M | } |
267 | | |
268 | | #if defined(__clang__) || defined (__GNUC__) |
269 | | __attribute__((no_sanitize_address)) |
270 | | #endif |
271 | | void fxCheckCStack(txMachine* the) |
272 | 397M | { |
273 | 397M | char x; |
274 | 397M | char *stack = &x; |
275 | 397M | if (stack <= the->stackLimit) { |
276 | 58 | fxAbort(the, XS_NATIVE_STACK_OVERFLOW_EXIT); |
277 | 58 | } |
278 | 397M | } |
279 | | |
280 | | void fxCollect(txMachine* the, txFlag theFlag) |
281 | 83.6k | { |
282 | 83.6k | txSize aCount; |
283 | 83.6k | txSlot* freeSlot; |
284 | 83.6k | txSlot* aSlot; |
285 | 83.6k | txSlot* bSlot; |
286 | 83.6k | txSlot* cSlot; |
287 | | |
288 | 83.6k | if ((the->collectFlag & XS_COLLECTING_FLAG) == 0) { |
289 | 0 | the->collectFlag |= XS_SKIPPED_COLLECT_FLAG; |
290 | 0 | return; |
291 | 0 | } |
292 | 83.6k | 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 | 83.6k | if (theFlag & XS_COMPACT_FLAG) { |
308 | 59.1k | fxInvalidateStringInfoCache(the); |
309 | 59.1k | fxMark(the, fxMarkValue); |
310 | 59.1k | fxMarkWeakStuff(the); |
311 | | #ifdef mxNever |
312 | | stopTime(&gxMarkTime); |
313 | | #endif |
314 | 59.1k | fxSweep(the); |
315 | 59.1k | } |
316 | 24.5k | else { |
317 | 24.5k | fxMark(the, fxMarkReference); |
318 | 24.5k | fxMarkWeakStuff(the); |
319 | | #ifdef mxNever |
320 | | stopTime(&gxMarkTime); |
321 | | startTime(&gxSweepSlotTime); |
322 | | #endif |
323 | 24.5k | aCount = 0; |
324 | 24.5k | freeSlot = C_NULL; |
325 | 24.5k | aSlot = the->firstHeap; |
326 | 86.3k | while (aSlot) { |
327 | 61.8k | bSlot = aSlot + 1; |
328 | 61.8k | cSlot = aSlot->value.reference; |
329 | 2.02G | while (bSlot < cSlot) { |
330 | 2.02G | if (bSlot->flag & XS_MARK_FLAG) { |
331 | 1.33G | bSlot->flag &= ~XS_MARK_FLAG; |
332 | | |
333 | 1.33G | if (bSlot->kind == XS_REFERENCE_KIND) |
334 | 132M | mxCheck(the, bSlot->value.reference->kind == XS_INSTANCE_KIND); |
335 | | |
336 | 1.33G | aCount++; |
337 | 1.33G | } |
338 | 694M | else { |
339 | 694M | if (bSlot->kind == XS_HOST_KIND) { |
340 | 1.59k | 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.59k | else if (bSlot->value.host.variant.destructor) |
345 | 0 | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
346 | 1.59k | } |
347 | | #if mxInstrument |
348 | | if ((bSlot->kind == XS_MODULE_KIND) && (bSlot->ID == XS_MODULE_BEHAVIOR)) |
349 | | the->loadedModulesCount--; |
350 | | #endif |
351 | 694M | bSlot->kind = XS_UNDEFINED_KIND; |
352 | 694M | bSlot->next = freeSlot; |
353 | | #if mxPoisonSlots |
354 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
355 | | #endif |
356 | 694M | freeSlot = bSlot; |
357 | 694M | } |
358 | 2.02G | bSlot++; |
359 | 2.02G | } |
360 | 61.8k | aSlot = aSlot->next; |
361 | 61.8k | } |
362 | 24.5k | the->currentHeapCount = aCount; |
363 | 24.5k | the->freeHeap = freeSlot; |
364 | | #ifdef mxNever |
365 | | stopTime(&gxSweepSlotTime); |
366 | | #endif |
367 | 24.5k | } |
368 | | |
369 | 83.6k | aSlot = the->stack; |
370 | 112M | while (aSlot < the->stackTop) { |
371 | 112M | aSlot->flag &= ~XS_MARK_FLAG; |
372 | 112M | aSlot++; |
373 | 112M | } |
374 | | |
375 | 83.6k | the->collectFlag &= ~(XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
376 | | |
377 | 83.6k | if (theFlag & XS_COMPACT_FLAG) { |
378 | 59.1k | if ((the->maximumChunksSize - the->currentChunksSize) < the->minimumChunksSize) |
379 | 17.2k | the->collectFlag |= XS_TRASHING_CHUNKS_FLAG; |
380 | 41.8k | else |
381 | 41.8k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
382 | 59.1k | } |
383 | | |
384 | 83.6k | if ((the->maximumHeapCount - the->currentHeapCount) < the->minimumHeapCount) |
385 | 73.0k | the->collectFlag |= XS_TRASHING_SLOTS_FLAG; |
386 | 10.5k | else |
387 | 10.5k | 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 | 83.6k | #if defined(mxInstrument) || defined(mxProfile) |
422 | 83.6k | fxCheckProfiler(the, C_NULL); |
423 | 83.6k | #endif |
424 | 83.6k | } |
425 | | |
426 | | txSlot* fxDuplicateSlot(txMachine* the, txSlot* theSlot) |
427 | 8.03k | { |
428 | 8.03k | txSlot* result; |
429 | | |
430 | 8.03k | result = fxNewSlot(the); |
431 | 8.03k | result->ID = theSlot->ID; |
432 | 8.03k | result->kind = theSlot->kind; |
433 | 8.03k | result->flag = theSlot->flag & ~XS_MARK_FLAG; |
434 | 8.03k | result->value = theSlot->value; |
435 | 8.03k | return result; |
436 | 8.03k | } |
437 | | |
438 | | void* fxFindChunk(txMachine* the, txSize size, txBoolean *once) |
439 | 330M | { |
440 | 330M | txBlock* block; |
441 | 330M | txChunk* chunk; |
442 | 330M | #if mxStress |
443 | 330M | if (fxShouldStress()) { |
444 | 266 | if (*once) { |
445 | 266 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
446 | 266 | *once = 0; |
447 | 266 | } |
448 | 266 | } |
449 | 330M | #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 | 330M | again: |
465 | 330M | block = the->firstBlock; |
466 | 463M | while (block) { |
467 | 463M | if ((block->current + size) <= block->limit) { |
468 | 330M | chunk = (txChunk*)(block->current); |
469 | 330M | block->current += size; |
470 | 330M | chunk->temporary = block->current; |
471 | 330M | return chunk; |
472 | 330M | } |
473 | 132M | block = block->nextBlock; |
474 | 132M | } |
475 | 49.1k | if (*once) { |
476 | 47.3k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0), isThrashing; |
477 | 47.3k | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
478 | 47.3k | isThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0); |
479 | 47.3k | *once = 0; |
480 | 47.3k | if (wasThrashing && isThrashing) |
481 | 1.65k | return C_NULL; |
482 | 45.7k | goto again; |
483 | 47.3k | } |
484 | 1.76k | return C_NULL; |
485 | 49.1k | } |
486 | | |
487 | | txSlot* fxFindKey(txMachine* the) |
488 | 22.6M | { |
489 | 22.6M | #if mxKeysGarbageCollection |
490 | 22.6M | txBoolean once = 1; |
491 | 22.6M | #endif |
492 | 22.6M | txID id; |
493 | 22.6M | txSlot* result; |
494 | 22.6M | more: |
495 | 22.6M | id = the->keyIndex; |
496 | 22.6M | if (id < the->keyCount) { |
497 | 19.1M | result = fxNewSlot(the); |
498 | 19.1M | result->ID = id; |
499 | 19.1M | the->keyArray[id - the->keyOffset] = result; |
500 | 19.1M | the->keyIndex++; |
501 | 19.1M | return result; |
502 | 19.1M | } |
503 | 3.48M | #if mxKeysGarbageCollection |
504 | 3.50M | again: |
505 | 3.50M | result = the->keyholeList; |
506 | 3.50M | if (result) { |
507 | 3.48M | the->keyholeCount--; |
508 | 3.48M | the->keyholeList = result->next; |
509 | 3.48M | result->next = C_NULL; |
510 | 3.48M | return result; |
511 | 3.48M | } |
512 | 17.0k | if (once) { |
513 | 16.2k | fxCollect(the, XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
514 | 16.2k | once = 0; |
515 | 16.2k | goto again; |
516 | 16.2k | } |
517 | 845 | #endif |
518 | 845 | else { |
519 | 845 | fxGrowKeys(the, 1); |
520 | 845 | goto more; |
521 | 845 | } |
522 | 0 | return C_NULL; |
523 | 17.0k | } |
524 | | |
525 | | void fxFree(txMachine* the) |
526 | 33.3k | { |
527 | 33.3k | 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 | 33.3k | fxFreeStringInfoCache(the); |
536 | | |
537 | 33.3k | if (the->symbolTable) |
538 | 33.3k | c_free_uint32(the->symbolTable); |
539 | 33.3k | the->symbolTable = C_NULL; |
540 | 33.3k | if (the->nameTable) |
541 | 33.3k | c_free_uint32(the->nameTable); |
542 | 33.3k | the->nameTable = C_NULL; |
543 | 33.3k | if (the->keyArray) |
544 | 33.3k | c_free_uint32(the->keyArray); |
545 | 33.3k | the->keyArray = C_NULL; |
546 | | |
547 | 69.5k | while (the->firstHeap) { |
548 | 36.2k | aHeap = the->firstHeap; |
549 | 36.2k | the->firstHeap = aHeap->next; |
550 | 36.2k | fxFreeSlots(the, aHeap); |
551 | 36.2k | } |
552 | 33.3k | the->firstHeap = C_NULL; |
553 | | |
554 | 33.3k | if (the->stackBottom) |
555 | 33.3k | fxFreeSlots(the, the->stackBottom); |
556 | 33.3k | the->stackBottom = C_NULL; |
557 | 33.3k | the->stackTop = C_NULL; |
558 | 33.3k | the->stackIntrinsics = C_NULL; |
559 | 33.3k | the->stackPrototypes = C_NULL; |
560 | 33.3k | 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 | 33.3k | { |
574 | 33.3k | txBlock* aBlock; |
575 | 70.0k | while (the->firstBlock) { |
576 | 36.7k | aBlock = the->firstBlock; |
577 | 36.7k | the->firstBlock = aBlock->nextBlock; |
578 | 36.7k | fxFreeChunks(the, aBlock); |
579 | 36.7k | } |
580 | 33.3k | the->firstBlock = C_NULL; |
581 | 33.3k | } |
582 | 33.3k | #endif |
583 | | |
584 | 33.3k | #ifdef mxDebug |
585 | 33.3k | if (the->pathValue) |
586 | 33.3k | c_free(the->pathValue); |
587 | 33.3k | the->pathValue = C_NULL; |
588 | 33.3k | #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 | 33.3k | } |
605 | | |
606 | | void* fxGrowChunk(txMachine* the, txSize size) |
607 | 3.41k | { |
608 | 3.41k | txBlock* block = fxGrowChunks(the, size); |
609 | 3.41k | txChunk* chunk = C_NULL; |
610 | 3.41k | if (block) { |
611 | 3.40k | chunk = (txChunk*)(block->current); |
612 | 3.40k | block->current += size; |
613 | 3.40k | chunk->temporary = block->current; |
614 | 3.40k | } |
615 | 3.41k | return chunk; |
616 | 3.41k | } |
617 | | |
618 | | void* fxGrowChunks(txMachine* the, txSize size) |
619 | 36.7k | { |
620 | 36.7k | txByte* buffer; |
621 | 36.7k | txBlock* block = C_NULL; |
622 | | |
623 | 36.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 | 36.7k | if ((the->firstBlock != C_NULL) && (!(the->collectFlag & XS_SKIPPED_COLLECT_FLAG))) { |
629 | 3.41k | txSize modulo = size % (the->minimumChunksSize ? the->minimumChunksSize : 16); |
630 | 3.41k | if (modulo) |
631 | 3.40k | size = fxAddChunkSizes(the, size, the->minimumChunksSize - modulo); |
632 | 3.41k | } |
633 | 36.7k | size = fxAddChunkSizes(the, size, sizeof(txBlock)); |
634 | 36.7k | buffer = fxAllocateChunks(the, size); |
635 | 36.7k | if (buffer) { |
636 | 36.7k | #ifdef mxSnapshot |
637 | 36.7k | c_memset(buffer, 0, size); |
638 | 36.7k | #endif |
639 | 36.7k | if ((the->firstBlock != C_NULL) && (the->firstBlock->limit == buffer)) { |
640 | 0 | the->firstBlock->limit += size; |
641 | 0 | block = the->firstBlock; |
642 | 0 | } |
643 | 36.7k | else { |
644 | 36.7k | block = (txBlock*)buffer; |
645 | 36.7k | block->nextBlock = the->firstBlock; |
646 | 36.7k | block->current = buffer + sizeof(txBlock); |
647 | 36.7k | block->limit = buffer + size; |
648 | 36.7k | block->temporary = C_NULL; |
649 | 36.7k | the->firstBlock = block; |
650 | 36.7k | size -= sizeof(txBlock); |
651 | 36.7k | } |
652 | 36.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 | 36.7k | } |
658 | 36.7k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
659 | 36.7k | return block; |
660 | 36.7k | } |
661 | | |
662 | | void fxGrowKeys(txMachine* the, txID theCount) |
663 | 845 | { |
664 | 845 | if (the->keyDelta > 0) { |
665 | 845 | txID keyDelta = (theCount > the->keyDelta) ? theCount : the->keyDelta; |
666 | 845 | txID keyCount = (the->keyCount + keyDelta) - the->keyOffset; |
667 | 845 | txSlot** keyArray = c_realloc(the->keyArray, keyCount * sizeof(txSlot*)); |
668 | 845 | if (keyArray == C_NULL) |
669 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
670 | 845 | the->keyArray = keyArray; |
671 | 845 | the->keyCount = keyCount + the->keyOffset; |
672 | 845 | } |
673 | 0 | else |
674 | 0 | fxAbort(the, XS_NO_MORE_KEYS_EXIT); |
675 | 845 | } |
676 | | |
677 | | void fxGrowSlots(txMachine* the, txSize theCount) |
678 | 36.2k | { |
679 | 36.2k | txSlot* aHeap; |
680 | 36.2k | txSlot* aSlot; |
681 | | |
682 | 36.2k | aHeap = fxAllocateSlots(the, theCount); |
683 | 36.2k | 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 | 36.2k | if ((void *)-1 == aHeap) |
688 | 0 | return; |
689 | | |
690 | 36.2k | 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 | 36.2k | else { |
706 | 36.2k | the->maximumHeapCount += theCount - 1; |
707 | 36.2k | aHeap->next = the->firstHeap; |
708 | 36.2k | aHeap->ID = 0; |
709 | 36.2k | aHeap->flag = 0; |
710 | 36.2k | aHeap->kind = 0; |
711 | 36.2k | aHeap->value.reference = aHeap + theCount; |
712 | 36.2k | theCount -= 2; |
713 | 36.2k | the->firstHeap = aHeap; |
714 | 36.2k | aSlot = aHeap + 1; |
715 | 36.2k | } |
716 | 1.18G | while (theCount--) { |
717 | 1.18G | txSlot* next = aSlot + 1; |
718 | 1.18G | aSlot->next = next; |
719 | 1.18G | aSlot->flag = XS_NO_FLAG; |
720 | 1.18G | aSlot->kind = XS_UNDEFINED_KIND; |
721 | | #if mxPoisonSlots |
722 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
723 | | #endif |
724 | 1.18G | aSlot = next; |
725 | 1.18G | } |
726 | 36.2k | aSlot->next = the->freeHeap; |
727 | 36.2k | aSlot->flag = XS_NO_FLAG; |
728 | 36.2k | aSlot->kind = XS_UNDEFINED_KIND; |
729 | | #if mxPoisonSlots |
730 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
731 | | #endif |
732 | 36.2k | the->freeHeap = aHeap + 1; |
733 | 36.2k | 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 | 36.2k | } |
741 | | |
742 | | void fxMark(txMachine* the, void (*theMarker)(txMachine*, txSlot*)) |
743 | 83.6k | { |
744 | 83.6k | txSlot** p; |
745 | 83.6k | txSlot** q; |
746 | 83.6k | 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 | 83.6k | slot = the->stackTop; |
761 | 112M | while (slot > the->stack) { |
762 | 112M | slot--; |
763 | 112M | (*theMarker)(the, slot); |
764 | 112M | } |
765 | 83.6k | slot = the->cRoot; |
766 | 83.6k | while (slot) { |
767 | 0 | (*theMarker)(the, slot); |
768 | 0 | slot = slot->next; |
769 | 0 | } |
770 | | |
771 | 83.6k | #if mxKeysGarbageCollection |
772 | 83.6k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
773 | 27.6k | txInteger deletions = 0; |
774 | 27.6k | p = the->keyArray; |
775 | 27.6k | q = p + the->keyIndex - the->keyOffset; |
776 | 29.9M | while (p < q) { |
777 | 29.9M | slot = *p++; |
778 | 29.9M | if (!(slot->flag & XS_MARK_FLAG)) { |
779 | 12.6M | if (slot->flag & XS_DONT_DELETE_FLAG) |
780 | 6.82M | slot->flag |= XS_MARK_FLAG; |
781 | 5.87M | else if (slot->flag & XS_DONT_ENUM_FLAG) |
782 | 922k | deletions++; |
783 | 12.6M | } |
784 | 29.9M | } |
785 | | |
786 | | // fprintf(stderr, "\n### KEYS GC %d", deletions); |
787 | 27.6k | p = the->nameTable; |
788 | 27.6k | q = the->nameTable + the->nameModulo; |
789 | 28.8M | while ((p < q) && deletions) { |
790 | 28.8M | txSlot** address = p; |
791 | 40.7M | while (((slot = *address)) && deletions) { |
792 | 11.9M | if (slot->flag & XS_MARK_FLAG) |
793 | 11.0M | address = &(slot->next); |
794 | 922k | else { |
795 | 922k | *address = slot->next; |
796 | 922k | deletions--; |
797 | 922k | } |
798 | 11.9M | } |
799 | 28.8M | p++; |
800 | 28.8M | } |
801 | | // fprintf(stderr, " => %d", deletions); |
802 | | |
803 | 27.6k | the->keyholeCount = 0; |
804 | 27.6k | the->keyholeList = C_NULL; |
805 | 27.6k | p = the->keyArray; |
806 | 27.6k | q = p + the->keyIndex - the->keyOffset; |
807 | 29.9M | while (p < q) { |
808 | 29.9M | slot = *p; |
809 | 29.9M | if (slot->flag & XS_MARK_FLAG) |
810 | 24.1M | (*theMarker)(the, slot); |
811 | 5.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 | 5.87M | slot->flag = XS_INTERNAL_FLAG | XS_MARK_FLAG; |
817 | 5.87M | slot->next = the->keyholeList; |
818 | 5.87M | slot->kind = XS_UNDEFINED_KIND; |
819 | 5.87M | the->keyholeCount++; |
820 | 5.87M | the->keyholeList = slot; |
821 | 5.87M | } |
822 | 29.9M | p++; |
823 | 29.9M | } |
824 | | // fprintf(stderr, "\n"); |
825 | 27.6k | } |
826 | 55.9k | else |
827 | 55.9k | #endif |
828 | 55.9k | { |
829 | 55.9k | p = the->keyArray; |
830 | 55.9k | q = p + the->keyIndex - the->keyOffset; |
831 | 39.9M | while (p < q) { |
832 | 39.9M | slot = *p++; |
833 | 39.9M | slot->flag |= XS_MARK_FLAG; |
834 | 39.9M | (*theMarker)(the, slot); |
835 | 39.9M | } |
836 | 55.9k | } |
837 | 83.6k | } |
838 | | |
839 | | #if mxKeysGarbageCollection |
840 | | void fxMarkID(txMachine* the, txID id) |
841 | 135M | { |
842 | 135M | txSlot* slot; |
843 | 135M | if (id == XS_NO_ID) |
844 | 44.7M | return; |
845 | 91.1M | if (id < the->keyOffset) |
846 | 0 | return; |
847 | 91.1M | id -= the->keyOffset; |
848 | 91.1M | slot = the->keyArray[id]; |
849 | 91.1M | slot->flag |= XS_MARK_FLAG; |
850 | 91.1M | } |
851 | | #endif |
852 | | |
853 | | void fxMarkFinalizationRegistry(txMachine* the, txSlot* registry) |
854 | 202k | { |
855 | 202k | txSlot* slot = registry->value.finalizationRegistry.callback->next; |
856 | 202k | txSlot* instance; |
857 | 1.11M | while (slot) { |
858 | 910k | slot = slot->next; |
859 | 910k | if (slot) { |
860 | 910k | instance = slot->value.finalizationCell.target; |
861 | 910k | if (instance && !(instance->flag & XS_MARK_FLAG)) { |
862 | 98.5k | slot->value.finalizationCell.target = C_NULL; |
863 | 98.5k | registry->value.finalizationRegistry.flags |= XS_FINALIZATION_REGISTRY_CHANGED; |
864 | 98.5k | } |
865 | 910k | instance = slot->value.finalizationCell.token; |
866 | 910k | if (instance && !(instance->flag & XS_MARK_FLAG)) |
867 | 62.8k | slot->value.finalizationCell.token = C_NULL; |
868 | 910k | slot = slot->next; |
869 | 910k | } |
870 | 910k | } |
871 | 202k | } |
872 | | |
873 | | void fxMarkInstance(txMachine* the, txSlot* theCurrent, void (*theMarker)(txMachine*, txSlot*)) |
874 | 162M | { |
875 | 162M | txSlot* aProperty; |
876 | 162M | txSlot* aTemporary; |
877 | | |
878 | 162M | mxCheck(the, theCurrent->kind == XS_INSTANCE_KIND); |
879 | 162M | aProperty = theCurrent; |
880 | 162M | theCurrent->value.instance.garbage = C_NULL; |
881 | 2.31G | for (;;) { |
882 | 2.31G | if (aProperty) { |
883 | 1.99G | if (!(aProperty->flag & XS_MARK_FLAG)) { |
884 | 1.99G | aProperty->flag |= XS_MARK_FLAG; |
885 | 1.99G | switch (aProperty->kind) { |
886 | 320M | case XS_INSTANCE_KIND: |
887 | 320M | aTemporary = aProperty->value.instance.prototype; |
888 | 320M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
889 | 530k | aProperty->value.instance.prototype = theCurrent; |
890 | 530k | theCurrent = aTemporary; |
891 | 530k | theCurrent->value.instance.garbage = aProperty; |
892 | 530k | aProperty = theCurrent; |
893 | 530k | } |
894 | 319M | else |
895 | 319M | aProperty = aProperty->next; |
896 | 320M | break; |
897 | 182M | case XS_REFERENCE_KIND: |
898 | 182M | #if mxKeysGarbageCollection |
899 | 182M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
900 | 26.3M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
901 | 25.8M | fxMarkID(the, aProperty->ID); |
902 | 26.3M | } |
903 | 182M | #endif |
904 | 182M | aTemporary = aProperty->value.reference; |
905 | 182M | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
906 | 154M | aProperty->value.reference = theCurrent; |
907 | 154M | theCurrent = aTemporary; |
908 | 154M | theCurrent->value.instance.garbage = aProperty; |
909 | 154M | aProperty = theCurrent; |
910 | 154M | } |
911 | 28.1M | else |
912 | 28.1M | aProperty = aProperty->next; |
913 | 182M | 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.42k | else { |
925 | 2.42k | aTemporary = aProperty->value.proxy.target; |
926 | 2.42k | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
927 | 2 | aProperty->value.proxy.target = theCurrent; |
928 | 2 | theCurrent = aTemporary; |
929 | 2 | theCurrent->value.instance.garbage = aProperty; |
930 | 2 | aProperty = theCurrent; |
931 | 2 | } |
932 | 2.42k | else |
933 | 2.42k | aProperty = aProperty->next; |
934 | 2.42k | } |
935 | 1.08M | break; |
936 | | |
937 | 6.15M | case XS_CLOSURE_KIND: |
938 | 6.15M | #if mxKeysGarbageCollection |
939 | 6.15M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
940 | 204k | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
941 | 138k | fxMarkID(the, aProperty->ID); |
942 | 204k | } |
943 | 6.15M | #endif |
944 | 6.15M | aTemporary = aProperty->value.closure; |
945 | 6.15M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
946 | 1.81M | aTemporary->flag |= XS_MARK_FLAG; |
947 | 1.81M | if (aTemporary->kind == XS_REFERENCE_KIND) { |
948 | 394k | aTemporary = aTemporary->value.reference; |
949 | 394k | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
950 | 320k | aProperty->value.closure->value.reference = theCurrent; |
951 | 320k | theCurrent = aTemporary; |
952 | 320k | theCurrent->value.instance.garbage = aProperty; |
953 | 320k | aProperty = theCurrent; |
954 | | |
955 | 320k | } |
956 | 394k | } |
957 | 1.42M | else { |
958 | 1.42M | (*theMarker)(the, aTemporary); |
959 | 1.42M | aProperty = aProperty->next; |
960 | 1.42M | } |
961 | 1.81M | } |
962 | 4.34M | else |
963 | 4.34M | aProperty = aProperty->next; |
964 | 6.15M | break; |
965 | | |
966 | 66.4M | case XS_CALLBACK_KIND: |
967 | 72.3M | case XS_CODE_KIND: |
968 | 72.3M | #if mxKeysGarbageCollection |
969 | 72.3M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
970 | 16.6M | fxMarkID(the, aProperty->ID); |
971 | 72.3M | #endif |
972 | 72.3M | (*theMarker)(the, aProperty); |
973 | 72.3M | aProperty = aProperty->next; |
974 | 72.3M | break; |
975 | | |
976 | 1.41G | default: |
977 | 1.41G | #if mxKeysGarbageCollection |
978 | 1.41G | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
979 | 97.7M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
980 | 63.8M | fxMarkID(the, aProperty->ID); |
981 | 97.7M | } |
982 | 1.41G | #endif |
983 | 1.41G | (*theMarker)(the, aProperty); |
984 | 1.41G | aProperty = aProperty->next; |
985 | 1.41G | break; |
986 | 1.99G | } |
987 | 1.99G | } |
988 | 103k | else |
989 | 103k | aProperty = aProperty->next; |
990 | 1.99G | } |
991 | 320M | else if (theCurrent->value.instance.garbage) { |
992 | 157M | aProperty = theCurrent->value.instance.garbage; |
993 | 157M | theCurrent->value.instance.garbage = C_NULL; |
994 | 157M | switch (aProperty->kind) { |
995 | 530k | case XS_INSTANCE_KIND: |
996 | 530k | aTemporary = aProperty->value.instance.prototype; |
997 | 530k | aProperty->value.instance.prototype = theCurrent; |
998 | 530k | theCurrent = aTemporary; |
999 | 530k | aProperty = aProperty->next; |
1000 | 530k | break; |
1001 | 154M | case XS_REFERENCE_KIND: |
1002 | 154M | aTemporary = aProperty->value.reference; |
1003 | 154M | aProperty->value.reference = theCurrent; |
1004 | 154M | theCurrent = aTemporary; |
1005 | 154M | aProperty = aProperty->next; |
1006 | 154M | 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 | 313 | else { |
1022 | 313 | aProperty = aProperty->next; |
1023 | 313 | } |
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 | 320k | case XS_CLOSURE_KIND: |
1033 | 320k | aTemporary = aProperty->value.closure->value.reference; |
1034 | 320k | aProperty->value.closure->value.reference = theCurrent; |
1035 | 320k | theCurrent = aTemporary; |
1036 | 320k | aProperty = aProperty->next; |
1037 | 320k | break; |
1038 | 157M | } |
1039 | 157M | } |
1040 | 162M | else |
1041 | 162M | break; |
1042 | 2.31G | } |
1043 | 162M | } |
1044 | | |
1045 | | void fxMarkReference(txMachine* the, txSlot* theSlot) |
1046 | 1.37G | { |
1047 | 1.37G | txSlot* aSlot; |
1048 | 1.37G | switch (theSlot->kind) { |
1049 | 88.3M | case XS_REFERENCE_KIND: |
1050 | 88.3M | aSlot = theSlot->value.reference; |
1051 | 88.3M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1052 | 73.5M | fxMarkInstance(the, aSlot, fxMarkReference); |
1053 | 88.3M | break; |
1054 | 1.50M | case XS_CLOSURE_KIND: |
1055 | 1.50M | aSlot = theSlot->value.closure; |
1056 | 1.50M | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1057 | 338k | aSlot->flag |= XS_MARK_FLAG; |
1058 | 338k | fxMarkReference(the, aSlot); |
1059 | 338k | } |
1060 | 1.50M | break; |
1061 | 206k | case XS_INSTANCE_KIND: |
1062 | 206k | if (!(theSlot->flag & XS_MARK_FLAG)) |
1063 | 206k | fxMarkInstance(the, theSlot, fxMarkReference); |
1064 | 206k | break; |
1065 | 2.20M | case XS_ACCESSOR_KIND: |
1066 | 2.20M | aSlot = theSlot->value.accessor.getter; |
1067 | 2.20M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1068 | 2.18M | fxCheckCStack(the); |
1069 | 2.18M | fxMarkInstance(the, aSlot, fxMarkReference); |
1070 | 2.18M | } |
1071 | 2.20M | aSlot = theSlot->value.accessor.setter; |
1072 | 2.20M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1073 | 984k | fxCheckCStack(the); |
1074 | 984k | fxMarkInstance(the, aSlot, fxMarkReference); |
1075 | 984k | } |
1076 | 2.20M | break; |
1077 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1078 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1079 | 112M | case XS_ARRAY_KIND: |
1080 | 113M | case XS_STACK_KIND: |
1081 | 113M | fxCheckCStack(the); |
1082 | 113M | if ((aSlot = theSlot->value.array.address)) { |
1083 | 44.9M | txIndex aLength = (((txChunk*)(((txByte*)aSlot) - sizeof(txChunk)))->size) / sizeof(txSlot); |
1084 | 44.9M | if (aLength > theSlot->value.array.length) |
1085 | 3.65k | aLength = theSlot->value.array.length; |
1086 | 363M | while (aLength) { |
1087 | 318M | fxMarkReference(the, aSlot); |
1088 | 318M | aSlot++; |
1089 | 318M | aLength--; |
1090 | 318M | } |
1091 | 44.9M | } |
1092 | 113M | break; |
1093 | 30.2M | case XS_CALLBACK_KIND: |
1094 | 30.2M | aSlot = theSlot->value.callback.closures; |
1095 | 30.2M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1096 | 0 | fxCheckCStack(the); |
1097 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1098 | 0 | } |
1099 | 30.2M | break; |
1100 | 5.01M | case XS_CODE_KIND: |
1101 | | // continue |
1102 | 5.08M | case XS_CODE_X_KIND: |
1103 | 5.08M | aSlot = theSlot->value.code.closures; |
1104 | 5.08M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1105 | 1.86M | fxCheckCStack(the); |
1106 | 1.86M | fxMarkInstance(the, aSlot, fxMarkReference); |
1107 | 1.86M | } |
1108 | 5.08M | break; |
1109 | 35.3M | case XS_HOME_KIND: |
1110 | 35.3M | aSlot = theSlot->value.home.object; |
1111 | 35.3M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1112 | 11.1M | fxCheckCStack(the); |
1113 | 11.1M | fxMarkInstance(the, aSlot, fxMarkReference); |
1114 | 11.1M | } |
1115 | 35.3M | aSlot = theSlot->value.home.module; |
1116 | 35.3M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1117 | 1.87k | fxCheckCStack(the); |
1118 | 1.87k | fxMarkInstance(the, aSlot, fxMarkReference); |
1119 | 1.87k | } |
1120 | 35.3M | break; |
1121 | 49 | case XS_MODULE_KIND: |
1122 | 24.5k | case XS_PROGRAM_KIND: |
1123 | 24.5k | #if mxKeysGarbageCollection |
1124 | 24.5k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1125 | 16.2k | fxMarkID(the, theSlot->value.module.id); |
1126 | 24.5k | #endif |
1127 | 24.5k | aSlot = theSlot->value.module.realm; |
1128 | 24.5k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1129 | 24.5k | fxCheckCStack(the); |
1130 | 24.5k | fxMarkInstance(the, aSlot, fxMarkReference); |
1131 | 24.5k | } |
1132 | 24.5k | 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 | 24.5k | case XS_HOST_KIND: |
1144 | 24.5k | if (theSlot->value.host.data) { |
1145 | 66 | 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 | 66 | } |
1148 | 24.5k | 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 | 166k | case XS_ERROR_KIND: |
1164 | 166k | aSlot = theSlot->value.error.info; |
1165 | 166k | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1166 | 166k | fxMarkInstance(the, aSlot, fxMarkReference); |
1167 | 166k | break; |
1168 | 123 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1169 | 162 | case XS_DISPOSABLE_STACK_KIND: |
1170 | 102k | case XS_LIST_KIND: |
1171 | 102k | fxCheckCStack(the); |
1172 | 102k | aSlot = theSlot->value.list.first; |
1173 | 134k | while (aSlot) { |
1174 | 31.8k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1175 | 31.8k | aSlot->flag |= XS_MARK_FLAG; |
1176 | 31.8k | fxMarkReference(the, aSlot); |
1177 | 31.8k | } |
1178 | 31.8k | aSlot = aSlot->next; |
1179 | 31.8k | } |
1180 | 102k | break; |
1181 | | |
1182 | 0 | case XS_PRIVATE_KIND: |
1183 | 0 | fxCheckCStack(the); |
1184 | 0 | aSlot = theSlot->value.private.check; |
1185 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1186 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1187 | 0 | aSlot = theSlot->value.private.first; |
1188 | 0 | while (aSlot) { |
1189 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1190 | 0 | fxMarkReference(the, aSlot); |
1191 | 0 | aSlot = aSlot->next; |
1192 | 0 | } |
1193 | 0 | break; |
1194 | | |
1195 | 215 | case XS_MAP_KIND: |
1196 | 14.2k | case XS_SET_KIND: |
1197 | 14.2k | { |
1198 | 14.2k | txSlot** anAddress = theSlot->value.table.address; |
1199 | 14.2k | txInteger aLength = theSlot->value.table.length; |
1200 | 75.5k | while (aLength) { |
1201 | 61.2k | aSlot = *anAddress; |
1202 | 92.2k | while (aSlot) { |
1203 | 31.0k | aSlot->flag |= XS_MARK_FLAG; |
1204 | 31.0k | aSlot = aSlot->next; |
1205 | 31.0k | } |
1206 | 61.2k | anAddress++; |
1207 | 61.2k | aLength--; |
1208 | 61.2k | } |
1209 | 14.2k | } |
1210 | 14.2k | break; |
1211 | 140k | case XS_WEAK_MAP_KIND: |
1212 | 140k | case XS_WEAK_SET_KIND: |
1213 | 140k | aSlot = theSlot->value.weakList.first; |
1214 | 198k | while (aSlot) { |
1215 | 58.0k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1216 | 58.0k | aSlot->flag |= XS_MARK_FLAG; |
1217 | 58.0k | fxMarkReference(the, aSlot); |
1218 | 58.0k | } |
1219 | 58.0k | aSlot = aSlot->next; |
1220 | 58.0k | } |
1221 | 140k | break; |
1222 | 180k | case XS_WEAK_ENTRY_KIND: |
1223 | 180k | aSlot = theSlot->value.weakEntry.check; |
1224 | 180k | if (aSlot->flag & XS_MARK_FLAG) { |
1225 | 39.1k | aSlot = theSlot->value.weakEntry.value; |
1226 | 39.1k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1227 | 39.1k | aSlot->flag |= XS_MARK_FLAG; |
1228 | 39.1k | fxMarkReference(the, aSlot); |
1229 | 39.1k | } |
1230 | 39.1k | } |
1231 | 180k | break; |
1232 | 206k | case XS_WEAK_REF_KIND: |
1233 | 206k | aSlot = theSlot->value.weakRef.target; |
1234 | 206k | if (aSlot) { |
1235 | 206k | #ifdef mxSnapshot |
1236 | 206k | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1237 | 206k | fxMarkReference(the, aSlot); |
1238 | 206k | } |
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 | 206k | } |
1248 | 206k | break; |
1249 | 145k | case XS_FINALIZATION_REGISTRY_KIND: |
1250 | 145k | aSlot = theSlot->value.finalizationRegistry.callback; |
1251 | 145k | if (aSlot) { |
1252 | 145k | fxCheckCStack(the); |
1253 | 145k | aSlot->flag |= XS_MARK_FLAG; |
1254 | 145k | fxMarkReference(the, aSlot); |
1255 | 145k | aSlot = aSlot->next; |
1256 | 680k | while (aSlot) { |
1257 | 535k | aSlot->flag |= XS_MARK_FLAG; |
1258 | 535k | fxMarkReference(the, aSlot); // holdings |
1259 | 535k | aSlot = aSlot->next; |
1260 | 535k | if (aSlot) { |
1261 | 535k | aSlot->flag |= XS_MARK_FLAG; |
1262 | | // weak target and token |
1263 | 535k | aSlot = aSlot->next; |
1264 | 535k | } |
1265 | 535k | } |
1266 | 145k | } |
1267 | 145k | 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 | 783k | case XS_SYMBOL_KIND: |
1276 | 783k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1277 | 498k | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1278 | 245k | fxMarkID(the, theSlot->value.symbol); |
1279 | 498k | } |
1280 | 783k | break; |
1281 | 24.8M | case XS_AT_KIND: |
1282 | 24.8M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1283 | 18.0M | fxMarkID(the, theSlot->value.at.id); |
1284 | 24.8M | break; |
1285 | 1.37G | #endif |
1286 | 1.37G | } |
1287 | 1.37G | } |
1288 | | |
1289 | | void fxMarkValue(txMachine* the, txSlot* theSlot) |
1290 | 1.01G | { |
1291 | 1.01G | #define mxMarkChunk(_THE_DATA) \ |
1292 | 1.01G | ((txChunk*)(((txByte*)_THE_DATA) - sizeof(txChunk)))->size |= mxChunkFlag |
1293 | | |
1294 | 1.01G | txSlot* aSlot; |
1295 | 1.01G | switch (theSlot->kind) { |
1296 | 249M | case XS_STRING_KIND: |
1297 | 249M | mxMarkChunk(theSlot->value.string); |
1298 | 249M | break; |
1299 | 1.17k | case XS_BIGINT_KIND: |
1300 | 1.17k | mxMarkChunk(theSlot->value.bigint.data); |
1301 | 1.17k | break; |
1302 | 115M | case XS_REFERENCE_KIND: |
1303 | 115M | aSlot = theSlot->value.reference; |
1304 | 115M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1305 | 64.0M | fxMarkInstance(the, aSlot, fxMarkValue); |
1306 | 115M | break; |
1307 | 1.26M | case XS_CLOSURE_KIND: |
1308 | 1.26M | aSlot = theSlot->value.closure; |
1309 | 1.26M | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1310 | 213k | aSlot->flag |= XS_MARK_FLAG; |
1311 | 213k | fxMarkValue(the, aSlot); |
1312 | 213k | } |
1313 | 1.26M | break; |
1314 | 1.64M | case XS_INSTANCE_KIND: |
1315 | 1.64M | if (!(theSlot->flag & XS_MARK_FLAG)) |
1316 | 1.64M | fxMarkInstance(the, theSlot, fxMarkValue); |
1317 | 1.64M | break; |
1318 | | |
1319 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1320 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1321 | 52.8M | case XS_ARRAY_KIND: |
1322 | 59.7M | case XS_STACK_KIND: |
1323 | 59.7M | fxCheckCStack(the); |
1324 | 59.7M | if ((aSlot = theSlot->value.array.address)) { |
1325 | 53.0M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
1326 | 53.0M | if (!(chunk->size & mxChunkFlag)) { |
1327 | 53.0M | txIndex aLength = chunk->size / sizeof(txSlot); |
1328 | 53.0M | if (aLength > theSlot->value.array.length) |
1329 | 1.86k | aLength = theSlot->value.array.length; |
1330 | 455M | while (aLength) { |
1331 | 402M | fxMarkValue(the, aSlot); |
1332 | 402M | aSlot++; |
1333 | 402M | aLength--; |
1334 | 402M | } |
1335 | 53.0M | mxMarkChunk(theSlot->value.array.address); |
1336 | 53.0M | } |
1337 | 53.0M | } |
1338 | 59.7M | break; |
1339 | 1.03M | case XS_ARRAY_BUFFER_KIND: |
1340 | 1.03M | if (theSlot->value.arrayBuffer.address) |
1341 | 1.03M | mxMarkChunk(theSlot->value.arrayBuffer.address); |
1342 | 1.03M | break; |
1343 | 36.2M | case XS_CALLBACK_KIND: |
1344 | 36.2M | aSlot = theSlot->value.callback.closures; |
1345 | 36.2M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1346 | 0 | fxCheckCStack(the); |
1347 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1348 | 0 | } |
1349 | 36.2M | break; |
1350 | 817k | case XS_CODE_KIND: |
1351 | 817k | mxMarkChunk(theSlot->value.code.address); |
1352 | | /* continue */ |
1353 | 993k | case XS_CODE_X_KIND: |
1354 | 993k | aSlot = theSlot->value.code.closures; |
1355 | 993k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1356 | 439k | fxCheckCStack(the); |
1357 | 439k | fxMarkInstance(the, aSlot, fxMarkValue); |
1358 | 439k | } |
1359 | 993k | break; |
1360 | 59.1k | case XS_GLOBAL_KIND: |
1361 | 59.1k | mxMarkChunk(theSlot->value.table.address); |
1362 | 59.1k | break; |
1363 | 59.5k | case XS_HOST_KIND: |
1364 | 59.5k | if (theSlot->value.host.data) { |
1365 | 428 | 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 | 428 | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
1368 | 112 | mxMarkChunk(theSlot->value.host.data); |
1369 | 428 | } |
1370 | 59.5k | break; |
1371 | 7 | case XS_IDS_KIND: |
1372 | 7 | if (theSlot->value.IDs) |
1373 | 7 | mxMarkChunk(theSlot->value.IDs); |
1374 | 7 | 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 | 13.7k | case XS_REGEXP_KIND: |
1384 | 13.7k | if (theSlot->value.regexp.code) |
1385 | 13.2k | mxMarkChunk(theSlot->value.regexp.code); |
1386 | 13.7k | if (theSlot->value.regexp.data) |
1387 | 13.7k | mxMarkChunk(theSlot->value.regexp.data); |
1388 | 13.7k | break; |
1389 | | |
1390 | 3.60M | case XS_ACCESSOR_KIND: |
1391 | 3.60M | aSlot = theSlot->value.accessor.getter; |
1392 | 3.60M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1393 | 3.54M | fxCheckCStack(the); |
1394 | 3.54M | fxMarkInstance(the, aSlot, fxMarkValue); |
1395 | 3.54M | } |
1396 | 3.60M | aSlot = theSlot->value.accessor.setter; |
1397 | 3.60M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1398 | 641k | fxCheckCStack(the); |
1399 | 641k | fxMarkInstance(the, aSlot, fxMarkValue); |
1400 | 641k | } |
1401 | 3.60M | break; |
1402 | 37.1M | case XS_HOME_KIND: |
1403 | 37.1M | aSlot = theSlot->value.home.object; |
1404 | 37.1M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1405 | 757k | fxCheckCStack(the); |
1406 | 757k | fxMarkInstance(the, aSlot, fxMarkValue); |
1407 | 757k | } |
1408 | 37.1M | aSlot = theSlot->value.home.module; |
1409 | 37.1M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1410 | 7.38k | fxCheckCStack(the); |
1411 | 7.38k | fxMarkInstance(the, aSlot, fxMarkValue); |
1412 | 7.38k | } |
1413 | 37.1M | break; |
1414 | 272 | case XS_MODULE_KIND: |
1415 | 59.4k | case XS_PROGRAM_KIND: |
1416 | 59.4k | #if mxKeysGarbageCollection |
1417 | 59.4k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1418 | 11.6k | fxMarkID(the, theSlot->value.module.id); |
1419 | 59.4k | #endif |
1420 | 59.4k | aSlot = theSlot->value.module.realm; |
1421 | 59.4k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1422 | 59.1k | fxCheckCStack(the); |
1423 | 59.1k | fxMarkInstance(the, aSlot, fxMarkValue); |
1424 | 59.1k | } |
1425 | 59.4k | 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 | 96.7M | case XS_KEY_KIND: |
1437 | 96.7M | if (theSlot->value.key.string) |
1438 | 96.7M | mxMarkChunk(theSlot->value.key.string); |
1439 | 96.7M | 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 | 1.64M | case XS_ERROR_KIND: |
1447 | 1.64M | aSlot = theSlot->value.error.info; |
1448 | 1.64M | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1449 | 1.64M | fxMarkInstance(the, aSlot, fxMarkValue); |
1450 | 1.64M | break; |
1451 | 27 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1452 | 71 | case XS_DISPOSABLE_STACK_KIND: |
1453 | 187k | case XS_LIST_KIND: |
1454 | 187k | aSlot = theSlot->value.list.first; |
1455 | 200k | while (aSlot) { |
1456 | 12.9k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1457 | 12.9k | aSlot->flag |= XS_MARK_FLAG; |
1458 | 12.9k | fxMarkValue(the, aSlot); |
1459 | 12.9k | } |
1460 | 12.9k | aSlot = aSlot->next; |
1461 | 12.9k | } |
1462 | 187k | 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 | 110 | case XS_MAP_KIND: |
1478 | 4.74k | case XS_SET_KIND: |
1479 | 4.74k | { |
1480 | 4.74k | txSlot** anAddress = theSlot->value.table.address; |
1481 | 4.74k | txInteger aLength = theSlot->value.table.length; |
1482 | 28.6k | while (aLength) { |
1483 | 23.9k | aSlot = *anAddress; |
1484 | 36.6k | while (aSlot) { |
1485 | 12.6k | aSlot->flag |= XS_MARK_FLAG; |
1486 | 12.6k | aSlot = aSlot->next; |
1487 | 12.6k | } |
1488 | 23.9k | anAddress++; |
1489 | 23.9k | aLength--; |
1490 | 23.9k | } |
1491 | 4.74k | } |
1492 | 4.74k | mxMarkChunk(theSlot->value.table.address); |
1493 | 4.74k | break; |
1494 | | |
1495 | 74.2k | case XS_WEAK_MAP_KIND: |
1496 | 74.5k | case XS_WEAK_SET_KIND: |
1497 | 74.5k | aSlot = theSlot->value.weakList.first; |
1498 | 96.8k | while (aSlot) { |
1499 | 22.3k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1500 | 22.3k | aSlot->flag |= XS_MARK_FLAG; |
1501 | 22.3k | fxMarkValue(the, aSlot); |
1502 | 22.3k | } |
1503 | 22.3k | aSlot = aSlot->next; |
1504 | 22.3k | } |
1505 | 74.5k | break; |
1506 | 57.6k | case XS_WEAK_ENTRY_KIND: |
1507 | 57.6k | aSlot = theSlot->value.weakEntry.check; |
1508 | 57.6k | if (aSlot->flag & XS_MARK_FLAG) { |
1509 | 21.9k | aSlot = theSlot->value.weakEntry.value; |
1510 | 21.9k | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1511 | 21.9k | aSlot->flag |= XS_MARK_FLAG; |
1512 | 21.9k | fxMarkValue(the, aSlot); |
1513 | 21.9k | } |
1514 | 21.9k | } |
1515 | 57.6k | break; |
1516 | 1.64M | case XS_WEAK_REF_KIND: |
1517 | 1.64M | aSlot = theSlot->value.weakRef.target; |
1518 | 1.64M | if (aSlot) { |
1519 | 1.64M | #ifdef mxSnapshot |
1520 | 1.64M | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1521 | 1.64M | fxMarkValue(the, aSlot); |
1522 | 1.64M | } |
1523 | 336 | else { |
1524 | 336 | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1525 | 336 | the->firstWeakRefLink = theSlot; |
1526 | 336 | } |
1527 | | #else |
1528 | | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1529 | | the->firstWeakRefLink = theSlot; |
1530 | | #endif |
1531 | 1.64M | } |
1532 | 1.64M | break; |
1533 | 77.6k | case XS_FINALIZATION_REGISTRY_KIND: |
1534 | 77.6k | aSlot = theSlot->value.finalizationRegistry.callback; |
1535 | 77.6k | if (aSlot) { |
1536 | 77.6k | aSlot->flag |= XS_MARK_FLAG; |
1537 | 77.6k | fxMarkValue(the, aSlot); |
1538 | 77.6k | aSlot = aSlot->next; |
1539 | 453k | while (aSlot) { |
1540 | 375k | aSlot->flag |= XS_MARK_FLAG; |
1541 | 375k | fxCheckCStack(the); |
1542 | 375k | fxMarkValue(the, aSlot); // holdings |
1543 | 375k | aSlot = aSlot->next; |
1544 | 375k | if (aSlot) { |
1545 | 375k | aSlot->flag |= XS_MARK_FLAG; |
1546 | | // weak target and token |
1547 | 375k | aSlot = aSlot->next; |
1548 | 375k | } |
1549 | 375k | } |
1550 | 77.6k | } |
1551 | 77.6k | 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 | 3.19M | case XS_SYMBOL_KIND: |
1561 | 3.19M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1562 | 342k | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1563 | 171k | fxMarkID(the, theSlot->value.symbol); |
1564 | 342k | } |
1565 | 3.19M | break; |
1566 | 120M | case XS_AT_KIND: |
1567 | 120M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1568 | 10.8M | fxMarkID(the, theSlot->value.at.id); |
1569 | 120M | break; |
1570 | 1.01G | #endif |
1571 | 1.01G | } |
1572 | 1.01G | } |
1573 | | |
1574 | | void fxMarkWeakStuff(txMachine* the) |
1575 | 83.6k | { |
1576 | 83.6k | txSlot* slot; |
1577 | 83.6k | txSlot** address; |
1578 | | |
1579 | 83.6k | { |
1580 | 83.6k | txSlot* list; |
1581 | 83.6k | txSlot** listAddress = &the->firstWeakListLink; |
1582 | 778k | while ((list = *listAddress)) { |
1583 | 694k | if (list->flag & XS_MARK_FLAG) { |
1584 | 215k | txSlot* listEntry; |
1585 | 215k | txSlot** listEntryAddress = &list->value.weakList.first; |
1586 | 295k | while ((listEntry = *listEntryAddress)) { |
1587 | 80.3k | txSlot* value = listEntry->value.weakEntry.value; |
1588 | 80.3k | if ((value->flag & XS_MARK_FLAG) && (value->kind != XS_UNINITIALIZED_KIND)) { |
1589 | 60.9k | listEntryAddress = &listEntry->next; |
1590 | 60.9k | } |
1591 | 19.3k | else { |
1592 | 19.3k | listEntry->flag &= ~XS_MARK_FLAG; |
1593 | 19.3k | *listEntryAddress = listEntry->next; |
1594 | 19.3k | } |
1595 | 80.3k | } |
1596 | 215k | listAddress = &list->value.weakList.link; |
1597 | 215k | } |
1598 | 479k | else { |
1599 | 479k | txSlot* listEntry = list->value.weakList.first; |
1600 | 576k | while (listEntry) { |
1601 | 96.8k | txSlot* key = listEntry->value.weakEntry.check; |
1602 | 96.8k | if (key->flag & XS_MARK_FLAG) { |
1603 | 96.8k | txSlot* keyEntry; |
1604 | 96.8k | txSlot** keyEntryAddress = &key->next; |
1605 | 150M | while ((keyEntry = *keyEntryAddress)) { |
1606 | 150M | if (!(keyEntry->flag & XS_INTERNAL_FLAG)) |
1607 | 53 | break; |
1608 | 150M | if ((keyEntry->kind == XS_WEAK_ENTRY_KIND) && (keyEntry->value.weakEntry.check == list)) { |
1609 | 96.8k | keyEntry->flag &= ~XS_MARK_FLAG; |
1610 | 96.8k | *keyEntryAddress = keyEntry->next; |
1611 | 96.8k | break; |
1612 | 96.8k | } |
1613 | 150M | keyEntryAddress = &keyEntry->next; |
1614 | 150M | } |
1615 | 96.8k | } |
1616 | 96.8k | listEntry = listEntry->next; |
1617 | 96.8k | } |
1618 | 479k | *listAddress = list->value.weakList.link; |
1619 | 479k | } |
1620 | 694k | } |
1621 | 83.6k | } |
1622 | 83.6k | address = &the->firstWeakRefLink; |
1623 | 83.9k | while ((slot = *address)) { |
1624 | 336 | if (!(slot->value.weakRef.target->flag & XS_MARK_FLAG)) |
1625 | 208 | slot->value.weakRef.target = C_NULL; |
1626 | 336 | *address = C_NULL; |
1627 | 336 | address = &(slot->value.weakRef.link); |
1628 | 336 | } |
1629 | | |
1630 | 83.6k | if (mxFinalizationRegistries.kind == XS_REFERENCE_KIND) { |
1631 | 83.6k | slot = mxFinalizationRegistries.value.reference->next; |
1632 | 286k | while (slot) { |
1633 | 202k | fxMarkFinalizationRegistry(the, slot->value.closure); |
1634 | 202k | slot = slot->next; |
1635 | 202k | } |
1636 | 83.6k | } |
1637 | 83.6k | } |
1638 | | |
1639 | | txSize fxMultiplyChunkSizes(txMachine* the, txSize a, txSize b) |
1640 | 73.0M | { |
1641 | 73.0M | txSize c; |
1642 | 73.0M | #if __has_builtin(__builtin_mul_overflow) |
1643 | 73.0M | 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 | 2 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
1650 | 2 | } |
1651 | 73.0M | return c; |
1652 | 73.0M | } |
1653 | | |
1654 | | void* fxNewChunk(txMachine* the, txSize size) |
1655 | 325M | { |
1656 | 325M | txSize offset = size; |
1657 | 325M | txChunk* chunk; |
1658 | 325M | txBoolean once = 1; |
1659 | 325M | size = fxAdjustChunkSize(the, size); |
1660 | 325M | chunk = fxFindChunk(the, size, &once); |
1661 | 325M | if (!chunk) { |
1662 | 3.33k | chunk = fxGrowChunk(the, size); |
1663 | 3.33k | } |
1664 | 325M | #ifdef mxMetering |
1665 | 325M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1666 | 325M | #endif |
1667 | 325M | return fxCheckChunk(the, chunk, size, offset); |
1668 | 325M | } |
1669 | | |
1670 | | void* fxNewGrowableChunk(txMachine* the, txSize size, txSize capacity) |
1671 | 4.45M | { |
1672 | | #if mxNoChunks |
1673 | | return fxNewChunk(the, size); |
1674 | | #else |
1675 | 4.45M | txSize offset = size; |
1676 | 4.45M | txChunk* chunk; |
1677 | 4.45M | txBoolean once = 1; |
1678 | 4.45M | size = fxAdjustChunkSize(the, size); |
1679 | 4.45M | capacity = fxAdjustChunkSize(the, capacity); |
1680 | 4.45M | chunk = fxFindChunk(the, capacity, &once); |
1681 | 4.45M | if (!chunk) { |
1682 | 82 | chunk = fxGrowChunk(the, capacity); |
1683 | 82 | if (!chunk) { |
1684 | 0 | chunk = fxFindChunk(the, size, &once); |
1685 | 0 | if (!chunk) { |
1686 | 0 | chunk = fxGrowChunk(the, size); |
1687 | 0 | } |
1688 | 0 | } |
1689 | 82 | } |
1690 | 4.45M | #ifdef mxMetering |
1691 | 4.45M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1692 | 4.45M | #endif |
1693 | 4.45M | return fxCheckChunk(the, chunk, size, offset); |
1694 | 4.45M | #endif |
1695 | 4.45M | } |
1696 | | |
1697 | | txSlot* fxNewSlot(txMachine* the) |
1698 | 772M | { |
1699 | 772M | txSlot* aSlot; |
1700 | 772M | txBoolean once = 1, allocate; |
1701 | | |
1702 | 772M | #if mxStress |
1703 | 772M | if (fxShouldStress()) { |
1704 | 40 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
1705 | 40 | once = 0; |
1706 | 40 | } |
1707 | 772M | #endif |
1708 | 772M | again: |
1709 | 772M | aSlot = the->freeHeap; |
1710 | 772M | if (aSlot) { |
1711 | 772M | the->freeHeap = aSlot->next; |
1712 | 772M | aSlot->next = C_NULL; |
1713 | 772M | aSlot->ID = XS_NO_ID; |
1714 | 772M | aSlot->flag = XS_NO_FLAG; |
1715 | 772M | #ifdef mxSnapshot |
1716 | 772M | #if mx32bitID |
1717 | 772M | aSlot->dummy = 0; |
1718 | | #elif INTPTR_MAX == INT64_MAX |
1719 | | aSlot->dummy = 0; |
1720 | | #endif |
1721 | 772M | #endif |
1722 | | #if mxPoisonSlots |
1723 | | ASAN_UNPOISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
1724 | | #endif |
1725 | 772M | the->currentHeapCount++; |
1726 | 772M | if (the->peakHeapCount < the->currentHeapCount) |
1727 | 294M | the->peakHeapCount = the->currentHeapCount; |
1728 | 772M | #ifdef mxMetering |
1729 | 772M | the->meterIndex += XS_SLOT_ALLOCATION_METERING; |
1730 | 772M | #endif |
1731 | 772M | return aSlot; |
1732 | 772M | } |
1733 | 8.90k | if (once) { |
1734 | 8.25k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0), isThrashing; |
1735 | | |
1736 | 8.25k | fxCollect(the, XS_ORGANIC_FLAG); |
1737 | | |
1738 | 8.25k | isThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0); |
1739 | 8.25k | allocate = wasThrashing && isThrashing; |
1740 | | |
1741 | 8.25k | once = 0; |
1742 | 8.25k | } |
1743 | 656 | else |
1744 | 656 | allocate = 1; |
1745 | 8.90k | if (allocate) { |
1746 | 2.98k | 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.98k | fxGrowSlots(the, !(the->collectFlag & XS_SKIPPED_COLLECT_FLAG) ? the->minimumHeapCount : 64); |
1751 | 2.98k | } |
1752 | 8.90k | goto again; |
1753 | 0 | return C_NULL; |
1754 | 772M | } |
1755 | | |
1756 | | void* fxRenewChunk(txMachine* the, void* theData, txSize size) |
1757 | 38.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 | 38.5M | txByte* aData = ((txByte*)theData) - sizeof(txChunk); |
1769 | 38.5M | txChunk* aChunk = (txChunk*)aData; |
1770 | 38.5M | txSize capacity = (txSize)(aChunk->temporary - aData); |
1771 | 38.5M | txBlock* aBlock = the->firstBlock; |
1772 | 38.5M | size = fxAdjustChunkSize(the, size); |
1773 | 38.5M | if (size <= capacity) { |
1774 | 13.8M | the->currentChunksSize += size - aChunk->size; |
1775 | 13.8M | if (the->peakChunksSize < the->currentChunksSize) |
1776 | 800k | the->peakChunksSize = the->currentChunksSize; |
1777 | 13.8M | aChunk->size = size; |
1778 | 13.8M | #ifdef mxMetering |
1779 | 13.8M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1780 | 13.8M | #endif |
1781 | 13.8M | return theData; |
1782 | 13.8M | } |
1783 | 66.2M | while (aBlock) { |
1784 | 58.0M | if (aChunk->temporary == aBlock->current) { |
1785 | 16.5M | txSize delta = size - capacity; |
1786 | 16.5M | if (aBlock->current + delta <= aBlock->limit) { |
1787 | 16.5M | the->currentChunksSize += size - aChunk->size; |
1788 | 16.5M | if (the->peakChunksSize < the->currentChunksSize) |
1789 | 1.40M | the->peakChunksSize = the->currentChunksSize; |
1790 | 16.5M | aBlock->current += delta; |
1791 | 16.5M | aChunk->temporary = aBlock->current; |
1792 | 16.5M | aChunk->size = size; |
1793 | 16.5M | #ifdef mxSnapshot |
1794 | 16.5M | c_memset(aData + capacity, 0, delta); |
1795 | 16.5M | #endif |
1796 | 16.5M | #ifdef mxMetering |
1797 | 16.5M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1798 | 16.5M | #endif |
1799 | 16.5M | return theData; |
1800 | 16.5M | } |
1801 | 1.18k | else { |
1802 | 1.18k | return C_NULL; |
1803 | 1.18k | } |
1804 | 16.5M | } |
1805 | 41.5M | aBlock = aBlock->nextBlock; |
1806 | 41.5M | } |
1807 | 8.16M | return C_NULL; |
1808 | 24.6M | #endif |
1809 | 24.6M | } |
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 | 59.1k | { |
1883 | 59.1k | txSize aTotal; |
1884 | | #if mxNoChunks |
1885 | | txChunk** address; |
1886 | | txChunk* chunk; |
1887 | | #else |
1888 | 59.1k | txBlock* aBlock; |
1889 | 59.1k | txByte* limit; |
1890 | 59.1k | txByte* next; |
1891 | 59.1k | #endif |
1892 | 59.1k | txByte* current; |
1893 | 59.1k | txByte* temporary; |
1894 | 59.1k | txSize aSize; |
1895 | 59.1k | txByte** aCodeAddress; |
1896 | 59.1k | txSlot* aSlot; |
1897 | 59.1k | txSlot* bSlot; |
1898 | 59.1k | txSlot* cSlot; |
1899 | 59.1k | txSlot* freeSlot; |
1900 | 59.1k | txJump* jump; |
1901 | | |
1902 | | #ifdef mxNever |
1903 | | startTime(&gxSweepChunkTime); |
1904 | | #endif |
1905 | | |
1906 | 59.1k | 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 | 59.1k | aBlock = the->firstBlock; |
1929 | 223k | while (aBlock) { |
1930 | 164k | current = ((txByte*)aBlock) + sizeof(txBlock); |
1931 | 164k | limit = aBlock->current; |
1932 | 164k | temporary = current; |
1933 | 581M | while (current < limit) { |
1934 | 581M | aSize = ((txChunk*)current)->size; |
1935 | 581M | next = ((txChunk*)current)->temporary; |
1936 | 581M | if (aSize & mxChunkFlag) { |
1937 | 324M | aSize &= ~mxChunkFlag; |
1938 | 324M | ((txChunk*)current)->temporary = temporary; |
1939 | 324M | temporary += aSize; |
1940 | 324M | aTotal += aSize; |
1941 | 324M | } |
1942 | 256M | else { |
1943 | 256M | ((txChunk*)current)->temporary = C_NULL; |
1944 | 256M | } |
1945 | 581M | ((txChunk*)current)->size = (txSize)(next - current); |
1946 | 581M | current = next; |
1947 | 581M | } |
1948 | 164k | aBlock->temporary = temporary; |
1949 | 164k | aBlock = aBlock->nextBlock; |
1950 | 164k | } |
1951 | 59.1k | #endif |
1952 | 59.1k | the->currentChunksSize = aTotal; |
1953 | | |
1954 | 59.1k | aCodeAddress = &(the->code); |
1955 | 59.1k | aSlot = the->frame; |
1956 | 1.83M | while (aSlot) { |
1957 | 1.77M | mxCheck(the, aSlot->kind == XS_FRAME_KIND); |
1958 | 1.77M | if ((aSlot->flag & XS_C_FLAG) == 0) { |
1959 | 1.52M | bSlot = (aSlot + 3)->value.reference->next; |
1960 | 1.52M | if (bSlot->kind == XS_CODE_KIND) { |
1961 | 1.46M | current = bSlot->value.code.address; |
1962 | 1.46M | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1963 | 1.46M | if (temporary) { |
1964 | 1.46M | temporary += sizeof(txChunk); |
1965 | 1.46M | *aCodeAddress += temporary - current; |
1966 | 1.46M | } |
1967 | 1.46M | } |
1968 | 1.52M | } |
1969 | 250k | else { |
1970 | 250k | current = *aCodeAddress; |
1971 | 250k | if (current) { |
1972 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1973 | 0 | if (temporary) |
1974 | 0 | *aCodeAddress = temporary + sizeof(txChunk); |
1975 | 0 | } |
1976 | 250k | } |
1977 | 1.77M | aCodeAddress = &(aSlot->value.frame.code); |
1978 | 1.77M | aSlot = aSlot->next; |
1979 | 1.77M | } |
1980 | | |
1981 | 59.1k | jump = the->firstJump; |
1982 | 526k | while (jump) { |
1983 | 467k | if (jump->flag) { |
1984 | 60.3k | aSlot = jump->frame; |
1985 | 60.3k | bSlot = (aSlot + 3)->value.reference->next; |
1986 | 60.3k | if (bSlot->kind == XS_CODE_KIND) { |
1987 | 6.05k | current = bSlot->value.code.address; |
1988 | 6.05k | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1989 | 6.05k | if (temporary) { |
1990 | 6.05k | temporary += sizeof(txChunk); |
1991 | 6.05k | jump->code += temporary - current; |
1992 | 6.05k | } |
1993 | 6.05k | } |
1994 | 60.3k | } |
1995 | 406k | else { |
1996 | 406k | current = jump->code; |
1997 | 406k | 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 | 406k | } |
2003 | 467k | jump = jump->nextJump; |
2004 | 467k | } |
2005 | | |
2006 | 59.1k | aSlot = the->stack; |
2007 | 42.7M | while (aSlot < the->stackTop) { |
2008 | 42.7M | fxSweepValue(the, aSlot); |
2009 | 42.7M | aSlot++; |
2010 | 42.7M | } |
2011 | 59.1k | aSlot = the->cRoot; |
2012 | 59.1k | 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 | 59.1k | aTotal = 0; |
2023 | 59.1k | freeSlot = C_NULL; |
2024 | 59.1k | aSlot = the->firstHeap; |
2025 | 134k | while (aSlot) { |
2026 | 75.3k | bSlot = aSlot + 1; |
2027 | 75.3k | cSlot = aSlot->value.reference; |
2028 | 2.46G | while (bSlot < cSlot) { |
2029 | 2.46G | if (bSlot->flag & XS_MARK_FLAG) { |
2030 | 736M | bSlot->flag &= ~XS_MARK_FLAG; |
2031 | 736M | fxSweepValue(the, bSlot); |
2032 | 736M | aTotal++; |
2033 | 736M | } |
2034 | 1.73G | else { |
2035 | 1.73G | #ifndef mxLink |
2036 | 1.73G | if (bSlot->kind == XS_HOST_KIND) { |
2037 | 1.37k | 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 | 1.37k | else if (bSlot->value.host.variant.destructor) |
2042 | 0 | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
2043 | 1.37k | } |
2044 | 1.73G | #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.73G | bSlot->kind = XS_UNDEFINED_KIND; |
2054 | 1.73G | bSlot->next = freeSlot; |
2055 | | #if mxPoisonSlots |
2056 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
2057 | | #endif |
2058 | 1.73G | freeSlot = bSlot; |
2059 | 1.73G | } |
2060 | 2.46G | bSlot++; |
2061 | 2.46G | } |
2062 | 75.3k | aSlot = aSlot->next; |
2063 | 75.3k | } |
2064 | 59.1k | the->currentHeapCount = aTotal; |
2065 | 59.1k | 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 | 59.1k | aBlock = the->firstBlock; |
2086 | 223k | while (aBlock) { |
2087 | 164k | txByte* former = C_NULL; |
2088 | 164k | current = ((txByte*)aBlock) + sizeof(txBlock); |
2089 | 164k | limit = aBlock->current; |
2090 | 581M | while (current < limit) { |
2091 | 581M | aSize = ((txChunk*)current)->size; |
2092 | 581M | next = current + aSize; |
2093 | 581M | if ((temporary = ((txChunk*)current)->temporary)) { |
2094 | 324M | if (former) { |
2095 | 324M | ((txChunk*)former)->temporary = temporary; |
2096 | 324M | ((txChunk*)former)->size = (txSize)(temporary - former); |
2097 | 324M | } |
2098 | 324M | if (temporary != current) |
2099 | 28.5M | c_memmove(temporary, current, aSize); |
2100 | 324M | former = temporary; |
2101 | 324M | } |
2102 | 581M | current = next; |
2103 | 581M | } |
2104 | 164k | if (former) { |
2105 | 149k | ((txChunk*)former)->temporary = aBlock->temporary; |
2106 | 149k | ((txChunk*)former)->size = (txSize)(aBlock->temporary - former); |
2107 | 149k | } |
2108 | 164k | aBlock->current = aBlock->temporary; |
2109 | 164k | aBlock->temporary = C_NULL; |
2110 | 164k | aBlock = aBlock->nextBlock; |
2111 | 164k | } |
2112 | 59.1k | #endif |
2113 | | |
2114 | | #ifdef mxNever |
2115 | | stopTime(&gxCompactChunkTime); |
2116 | | #endif |
2117 | 59.1k | } |
2118 | | |
2119 | | void fxSweepValue(txMachine* the, txSlot* theSlot) |
2120 | 1.18G | { |
2121 | 1.18G | txSlot* aSlot; |
2122 | 1.18G | txByte* data; |
2123 | | |
2124 | 1.18G | #define mxSweepChunk(_THE_DATA, _THE_DATA_TYPE) \ |
2125 | 1.18G | if ((data = (txByte*)(((txChunk*)(((txByte*)(_THE_DATA)) - sizeof(txChunk)))->temporary))) \ |
2126 | 401M | ((_THE_DATA)) = (_THE_DATA_TYPE)(data + sizeof(txChunk)) |
2127 | | |
2128 | 1.18G | switch (theSlot->kind) { |
2129 | 249M | case XS_STRING_KIND: |
2130 | 249M | mxSweepChunk(theSlot->value.string, txString); |
2131 | 249M | break; |
2132 | 1.17k | case XS_BIGINT_KIND: |
2133 | 1.17k | mxSweepChunk(theSlot->value.bigint.data, txU4*); |
2134 | 1.17k | break; |
2135 | | |
2136 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
2137 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
2138 | 52.8M | case XS_ARRAY_KIND: |
2139 | 59.7M | case XS_STACK_KIND: |
2140 | 59.7M | 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 | 53.0M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
2146 | 53.0M | txIndex aLength = chunk->size / sizeof(txSlot); |
2147 | 53.0M | if (aLength > theSlot->value.array.length) |
2148 | 4.91k | aLength = theSlot->value.array.length; |
2149 | 455M | while (aLength) { |
2150 | 402M | fxSweepValue(the, aSlot); |
2151 | 402M | aSlot++; |
2152 | 402M | aLength--; |
2153 | 402M | } |
2154 | | #if mxNoChunks |
2155 | | #else |
2156 | 53.0M | mxSweepChunk(theSlot->value.array.address, txSlot*); |
2157 | 53.0M | #endif |
2158 | 53.0M | } |
2159 | 59.7M | break; |
2160 | 1.03M | case XS_ARRAY_BUFFER_KIND: |
2161 | 1.03M | if (theSlot->value.arrayBuffer.address) |
2162 | 1.03M | mxSweepChunk(theSlot->value.arrayBuffer.address, txByte*); |
2163 | 1.03M | break; |
2164 | 817k | case XS_CODE_KIND: |
2165 | 817k | mxSweepChunk(theSlot->value.code.address, txByte*); |
2166 | 817k | break; |
2167 | 59.1k | case XS_GLOBAL_KIND: |
2168 | 59.1k | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2169 | 59.1k | break; |
2170 | 59.5k | case XS_HOST_KIND: |
2171 | 59.5k | if (theSlot->value.host.data) { |
2172 | 428 | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
2173 | 112 | mxSweepChunk(theSlot->value.host.data, void*); |
2174 | 428 | } |
2175 | 59.5k | break; |
2176 | 7 | case XS_IDS_KIND: |
2177 | 7 | if (theSlot->value.IDs) |
2178 | 7 | mxSweepChunk(theSlot->value.IDs, txID*); |
2179 | 7 | break; |
2180 | 13.7k | case XS_REGEXP_KIND: |
2181 | 13.7k | if (theSlot->value.regexp.code) |
2182 | 13.2k | mxSweepChunk(theSlot->value.regexp.code, void*); |
2183 | 13.7k | if (theSlot->value.regexp.data) |
2184 | 13.7k | mxSweepChunk(theSlot->value.regexp.data, void*); |
2185 | 13.7k | break; |
2186 | 96.7M | case XS_KEY_KIND: |
2187 | 96.7M | if (theSlot->value.key.string) |
2188 | 96.7M | mxSweepChunk(theSlot->value.key.string, txString); |
2189 | 96.7M | break; |
2190 | 110 | case XS_MAP_KIND: |
2191 | 4.74k | case XS_SET_KIND: |
2192 | 4.74k | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2193 | 4.74k | break; |
2194 | 1.18G | } |
2195 | 1.18G | } |