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