/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 | 72.1M | { |
62 | 72.1M | if (!gxStress) |
63 | 72.1M | return 0; |
64 | | |
65 | 0 | if (gxStress > 0) |
66 | 0 | return 1; |
67 | | |
68 | 0 | gxStress += 1; |
69 | 0 | return 0 == gxStress; |
70 | 0 | } |
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 | 156M | #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 | 13.4M | { |
144 | 13.4M | txSize c; |
145 | 13.4M | #if __has_builtin(__builtin_add_overflow) |
146 | 13.4M | if (__builtin_add_overflow(a, b, &c)) { |
147 | | #else |
148 | | c = a + b; |
149 | | if (((a ^ c) & (b ^ c)) < 0) { |
150 | | #endif |
151 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
152 | 0 | } |
153 | 13.4M | return c; |
154 | 13.4M | } |
155 | | |
156 | | txSize fxAdjustChunkSize(txMachine* the, txSize size) |
157 | 11.4M | { |
158 | 11.4M | txSize adjust = sizeof(txChunk); |
159 | 11.4M | txSize modulo = size & (sizeof(size_t) - 1); |
160 | 11.4M | if (modulo) |
161 | 6.27M | adjust += sizeof(size_t) - modulo; |
162 | 11.4M | return fxAddChunkSizes(the, size, adjust); |
163 | 11.4M | } |
164 | | |
165 | | void fxAllocate(txMachine* the, txCreation* theCreation) |
166 | 6.51k | { |
167 | | #ifdef mxNever |
168 | | startTime(&gxLifeTime); |
169 | | #endif |
170 | 6.51k | #if mxStress |
171 | 6.51k | gxStress = 0; |
172 | 6.51k | #endif |
173 | | |
174 | 6.51k | the->currentChunksSize = 0; |
175 | 6.51k | the->peakChunksSize = 0; |
176 | 6.51k | the->maximumChunksSize = 0; |
177 | 6.51k | the->minimumChunksSize = theCreation->incrementalChunkSize; |
178 | | |
179 | 6.51k | the->currentHeapCount = 0; |
180 | 6.51k | the->peakHeapCount = 0; |
181 | 6.51k | the->maximumHeapCount = 0; |
182 | 6.51k | the->minimumHeapCount = theCreation->incrementalHeapCount; |
183 | | |
184 | 6.51k | the->firstBlock = C_NULL; |
185 | 6.51k | the->firstHeap = C_NULL; |
186 | | |
187 | | #if mxNoChunks |
188 | | the->maximumChunksSize = theCreation->initialChunkSize; |
189 | | #else |
190 | 6.51k | fxGrowChunks(the, theCreation->initialChunkSize); |
191 | 6.51k | #endif |
192 | | |
193 | 6.51k | the->stackBottom = fxAllocateSlots(the, theCreation->stackCount); |
194 | 6.51k | the->stackTop = the->stackBottom + theCreation->stackCount; |
195 | 6.51k | the->stackIntrinsics = the->stackTop; |
196 | 6.51k | the->stackPrototypes = the->stackTop - XS_INTRINSICS_COUNT; |
197 | 6.51k | the->stack = the->stackTop; |
198 | | #ifdef mxInstrument |
199 | | the->stackPeak = the->stackTop; |
200 | | #endif |
201 | | |
202 | 6.51k | fxGrowSlots(the, theCreation->initialHeapCount); |
203 | | |
204 | 6.51k | the->keyCount = (txID)theCreation->initialKeyCount; |
205 | 6.51k | the->keyDelta = (txID)theCreation->incrementalKeyCount; |
206 | 6.51k | the->keyIndex = 0; |
207 | 6.51k | the->keyArray = (txSlot **)c_malloc_uint32(theCreation->initialKeyCount * sizeof(txSlot*)); |
208 | 6.51k | if (!the->keyArray) |
209 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
210 | | |
211 | 6.51k | the->nameModulo = theCreation->nameModulo; |
212 | 6.51k | the->nameTable = (txSlot **)c_malloc_uint32(theCreation->nameModulo * sizeof(txSlot*)); |
213 | 6.51k | if (!the->nameTable) |
214 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
215 | | |
216 | 6.51k | the->symbolModulo = theCreation->symbolModulo; |
217 | 6.51k | the->symbolTable = (txSlot **)c_malloc_uint32(theCreation->symbolModulo * sizeof(txSlot*)); |
218 | 6.51k | if (!the->symbolTable) |
219 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
220 | | |
221 | 6.51k | fxAllocateStringInfoCache(the); |
222 | | |
223 | 6.51k | the->stackLimit = fxCStackLimit(); |
224 | | |
225 | 6.51k | the->cRoot = C_NULL; |
226 | 6.51k | the->parserBufferSize = theCreation->parserBufferSize; |
227 | 6.51k | the->parserTableModulo = theCreation->parserTableModulo; |
228 | | |
229 | 6.51k | #ifdef mxDebug |
230 | 6.51k | the->pathCount = 256; |
231 | 6.51k | the->pathValue = c_malloc(the->pathCount); |
232 | 6.51k | if (!the->pathValue) |
233 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
234 | 6.51k | #endif |
235 | 6.51k | } |
236 | | |
237 | | void* fxCheckChunk(txMachine* the, txChunk* chunk, txSize size, txSize offset) |
238 | 11.4M | { |
239 | 11.4M | if (chunk) { |
240 | 11.4M | txByte* data = (txByte*)chunk; |
241 | | #if mxNoChunks |
242 | | chunk->size = size; |
243 | | the->currentChunksSize += size; |
244 | | #else |
245 | 11.4M | txSize capacity = (txSize)(chunk->temporary - data); |
246 | 11.4M | #ifdef mxSnapshot |
247 | 11.4M | #if INTPTR_MAX == INT64_MAX |
248 | 11.4M | chunk->dummy = 0; |
249 | 11.4M | #endif |
250 | | #ifdef mxSnapshotRandomInit |
251 | | arc4random_buf(data + sizeof(txChunk), offset); |
252 | | #endif |
253 | 11.4M | #endif |
254 | 11.4M | offset += sizeof(txChunk); |
255 | 11.4M | c_memset(data + offset, 0, capacity - offset); |
256 | 11.4M | chunk->size = size; |
257 | 11.4M | the->currentChunksSize += capacity; |
258 | 11.4M | #endif |
259 | 11.4M | if (the->peakChunksSize < the->currentChunksSize) |
260 | 8.39M | the->peakChunksSize = the->currentChunksSize; |
261 | 11.4M | return data + sizeof(txChunk); |
262 | 11.4M | } |
263 | 0 | fxReport(the, "# Chunk allocation: failed for %ld bytes\n", (long)size); |
264 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
265 | 0 | return C_NULL; |
266 | 11.4M | } |
267 | | |
268 | | #if defined(__clang__) || defined (__GNUC__) |
269 | | __attribute__((no_sanitize_address)) |
270 | | #endif |
271 | | void fxCheckCStack(txMachine* the) |
272 | 156M | { |
273 | 156M | char x; |
274 | 156M | char *stack = &x; |
275 | 156M | if (stack <= the->stackLimit) { |
276 | 0 | fxAbort(the, XS_NATIVE_STACK_OVERFLOW_EXIT); |
277 | 0 | } |
278 | 156M | } |
279 | | |
280 | | void fxCollect(txMachine* the, txFlag theFlag) |
281 | 12.0k | { |
282 | 12.0k | txSize aCount; |
283 | 12.0k | txSlot* freeSlot; |
284 | 12.0k | txSlot* aSlot; |
285 | 12.0k | txSlot* bSlot; |
286 | 12.0k | txSlot* cSlot; |
287 | | |
288 | 12.0k | if ((the->collectFlag & XS_COLLECTING_FLAG) == 0) { |
289 | 0 | the->collectFlag |= XS_SKIPPED_COLLECT_FLAG; |
290 | 0 | return; |
291 | 0 | } |
292 | 12.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 | 12.0k | if (theFlag & XS_COMPACT_FLAG) { |
308 | 3.89k | fxInvalidateStringInfoCache(the); |
309 | 3.89k | fxMark(the, fxMarkValue); |
310 | 3.89k | fxMarkWeakStuff(the); |
311 | | #ifdef mxNever |
312 | | stopTime(&gxMarkTime); |
313 | | #endif |
314 | 3.89k | fxSweep(the); |
315 | 3.89k | } |
316 | 8.11k | else { |
317 | 8.11k | fxMark(the, fxMarkReference); |
318 | 8.11k | fxMarkWeakStuff(the); |
319 | | #ifdef mxNever |
320 | | stopTime(&gxMarkTime); |
321 | | startTime(&gxSweepSlotTime); |
322 | | #endif |
323 | 8.11k | aCount = 0; |
324 | 8.11k | freeSlot = C_NULL; |
325 | 8.11k | aSlot = the->firstHeap; |
326 | 24.8k | while (aSlot) { |
327 | 16.7k | bSlot = aSlot + 1; |
328 | 16.7k | cSlot = aSlot->value.reference; |
329 | 549M | while (bSlot < cSlot) { |
330 | 549M | if (bSlot->flag & XS_MARK_FLAG) { |
331 | 352M | bSlot->flag &= ~XS_MARK_FLAG; |
332 | | |
333 | 352M | if (bSlot->kind == XS_REFERENCE_KIND) { |
334 | 76.0M | mxCheck(the, bSlot->value.reference->kind == XS_INSTANCE_KIND); |
335 | 76.0M | } |
336 | | |
337 | 352M | aCount++; |
338 | 352M | } |
339 | 197M | else { |
340 | 197M | if (bSlot->kind == XS_HOST_KIND) { |
341 | 430 | 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 | 430 | else if (bSlot->value.host.variant.destructor) |
346 | 0 | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
347 | 430 | } |
348 | | #if mxInstrument |
349 | | if ((bSlot->kind == XS_MODULE_KIND) && (bSlot->ID == XS_MODULE_BEHAVIOR)) |
350 | | the->loadedModulesCount--; |
351 | | #endif |
352 | 197M | bSlot->kind = XS_UNDEFINED_KIND; |
353 | 197M | bSlot->next = freeSlot; |
354 | | #if mxPoisonSlots |
355 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
356 | | #endif |
357 | 197M | freeSlot = bSlot; |
358 | 197M | } |
359 | 549M | bSlot++; |
360 | 549M | } |
361 | 16.7k | aSlot = aSlot->next; |
362 | 16.7k | } |
363 | 8.11k | the->currentHeapCount = aCount; |
364 | 8.11k | the->freeHeap = freeSlot; |
365 | | #ifdef mxNever |
366 | | stopTime(&gxSweepSlotTime); |
367 | | #endif |
368 | 8.11k | } |
369 | | |
370 | 12.0k | aSlot = the->stack; |
371 | 29.9M | while (aSlot < the->stackTop) { |
372 | 29.9M | aSlot->flag &= ~XS_MARK_FLAG; |
373 | 29.9M | aSlot++; |
374 | 29.9M | } |
375 | | |
376 | 12.0k | the->collectFlag &= ~(XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
377 | | |
378 | 12.0k | if (theFlag & XS_COMPACT_FLAG) { |
379 | 3.89k | if ((the->maximumChunksSize - the->currentChunksSize) < the->minimumChunksSize) |
380 | 1.17k | the->collectFlag |= XS_TRASHING_CHUNKS_FLAG; |
381 | 2.72k | else |
382 | 2.72k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
383 | 3.89k | } |
384 | | |
385 | 12.0k | if ((the->maximumHeapCount - the->currentHeapCount) < the->minimumHeapCount) |
386 | 11.3k | the->collectFlag |= XS_TRASHING_SLOTS_FLAG; |
387 | 703 | else |
388 | 703 | 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 | 12.0k | #if defined(mxInstrument) || defined(mxProfile) |
423 | 12.0k | fxCheckProfiler(the, C_NULL); |
424 | 12.0k | #endif |
425 | 12.0k | } |
426 | | |
427 | | txSlot* fxDuplicateSlot(txMachine* the, txSlot* theSlot) |
428 | 0 | { |
429 | 0 | txSlot* result; |
430 | | |
431 | 0 | result = fxNewSlot(the); |
432 | 0 | result->ID = theSlot->ID; |
433 | 0 | result->kind = theSlot->kind; |
434 | 0 | result->flag = theSlot->flag & ~XS_MARK_FLAG; |
435 | 0 | result->value = theSlot->value; |
436 | 0 | return result; |
437 | 0 | } |
438 | | |
439 | | void* fxFindChunk(txMachine* the, txSize size, txBoolean *once) |
440 | 11.4M | { |
441 | 11.4M | txBlock* block; |
442 | 11.4M | txChunk* chunk; |
443 | 11.4M | #if mxStress |
444 | 11.4M | if (fxShouldStress()) { |
445 | 0 | if (*once) { |
446 | 0 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
447 | 0 | *once = 0; |
448 | 0 | } |
449 | 0 | } |
450 | 11.4M | #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 | 11.4M | again: |
466 | 11.4M | block = the->firstBlock; |
467 | 12.9M | while (block) { |
468 | 12.9M | if ((block->current + size) <= block->limit) { |
469 | 11.4M | chunk = (txChunk*)(block->current); |
470 | 11.4M | block->current += size; |
471 | 11.4M | chunk->temporary = block->current; |
472 | 11.4M | return chunk; |
473 | 11.4M | } |
474 | 1.47M | block = block->nextBlock; |
475 | 1.47M | } |
476 | 4.17k | if (*once) { |
477 | 3.89k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0), isThrashing; |
478 | 3.89k | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
479 | 3.89k | isThrashing = ((the->collectFlag & XS_TRASHING_CHUNKS_FLAG) != 0); |
480 | 3.89k | *once = 0; |
481 | 3.89k | if (wasThrashing && isThrashing) |
482 | 329 | return C_NULL; |
483 | 3.56k | goto again; |
484 | 3.89k | } |
485 | 282 | return C_NULL; |
486 | 4.17k | } |
487 | | |
488 | | txSlot* fxFindKey(txMachine* the) |
489 | 3.71M | { |
490 | 3.71M | #if mxKeysGarbageCollection |
491 | 3.71M | txBoolean once = 1; |
492 | 3.71M | #endif |
493 | 3.71M | txID id; |
494 | 3.71M | txSlot* result; |
495 | 3.71M | more: |
496 | 3.71M | id = the->keyIndex; |
497 | 3.71M | if (id < the->keyCount) { |
498 | 3.68M | result = fxNewSlot(the); |
499 | 3.68M | result->ID = id; |
500 | 3.68M | the->keyArray[id - the->keyOffset] = result; |
501 | 3.68M | the->keyIndex++; |
502 | 3.68M | return result; |
503 | 3.68M | } |
504 | 25.5k | #if mxKeysGarbageCollection |
505 | 32.4k | again: |
506 | 32.4k | result = the->keyholeList; |
507 | 32.4k | if (result) { |
508 | 25.3k | the->keyholeCount--; |
509 | 25.3k | the->keyholeList = result->next; |
510 | 25.3k | result->next = C_NULL; |
511 | 25.3k | return result; |
512 | 25.3k | } |
513 | 7.04k | if (once) { |
514 | 6.85k | fxCollect(the, XS_COLLECT_KEYS_FLAG | XS_ORGANIC_FLAG); |
515 | 6.85k | once = 0; |
516 | 6.85k | goto again; |
517 | 6.85k | } |
518 | 189 | #endif |
519 | 189 | else { |
520 | 189 | fxGrowKeys(the, 1); |
521 | 189 | goto more; |
522 | 189 | } |
523 | 0 | return C_NULL; |
524 | 7.04k | } |
525 | | |
526 | | void fxFree(txMachine* the) |
527 | 6.51k | { |
528 | 6.51k | 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 | 6.51k | fxFreeStringInfoCache(the); |
537 | | |
538 | 6.51k | if (the->symbolTable) |
539 | 6.51k | c_free_uint32(the->symbolTable); |
540 | 6.51k | the->symbolTable = C_NULL; |
541 | 6.51k | if (the->nameTable) |
542 | 6.51k | c_free_uint32(the->nameTable); |
543 | 6.51k | the->nameTable = C_NULL; |
544 | 6.51k | if (the->keyArray) |
545 | 6.51k | c_free_uint32(the->keyArray); |
546 | 6.51k | the->keyArray = C_NULL; |
547 | | |
548 | 13.7k | while (the->firstHeap) { |
549 | 7.24k | aHeap = the->firstHeap; |
550 | 7.24k | the->firstHeap = aHeap->next; |
551 | 7.24k | fxFreeSlots(the, aHeap); |
552 | 7.24k | } |
553 | 6.51k | the->firstHeap = C_NULL; |
554 | | |
555 | 6.51k | if (the->stackBottom) |
556 | 6.51k | fxFreeSlots(the, the->stackBottom); |
557 | 6.51k | the->stackBottom = C_NULL; |
558 | 6.51k | the->stackTop = C_NULL; |
559 | 6.51k | the->stackIntrinsics = C_NULL; |
560 | 6.51k | the->stackPrototypes = C_NULL; |
561 | 6.51k | 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 | 6.51k | { |
575 | 6.51k | txBlock* aBlock; |
576 | 13.6k | while (the->firstBlock) { |
577 | 7.13k | aBlock = the->firstBlock; |
578 | 7.13k | the->firstBlock = aBlock->nextBlock; |
579 | 7.13k | fxFreeChunks(the, aBlock); |
580 | 7.13k | } |
581 | 6.51k | the->firstBlock = C_NULL; |
582 | 6.51k | } |
583 | 6.51k | #endif |
584 | | |
585 | 6.51k | #ifdef mxDebug |
586 | 6.51k | if (the->pathValue) |
587 | 6.51k | c_free(the->pathValue); |
588 | 6.51k | the->pathValue = C_NULL; |
589 | 6.51k | #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 | 6.51k | } |
606 | | |
607 | | void* fxGrowChunk(txMachine* the, txSize size) |
608 | 611 | { |
609 | 611 | txBlock* block = fxGrowChunks(the, size); |
610 | 611 | txChunk* chunk = C_NULL; |
611 | 611 | if (block) { |
612 | 611 | chunk = (txChunk*)(block->current); |
613 | 611 | block->current += size; |
614 | 611 | chunk->temporary = block->current; |
615 | 611 | } |
616 | 611 | return chunk; |
617 | 611 | } |
618 | | |
619 | | void* fxGrowChunks(txMachine* the, txSize size) |
620 | 7.13k | { |
621 | 7.13k | txByte* buffer; |
622 | 7.13k | txBlock* block = C_NULL; |
623 | | |
624 | 7.13k | 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 | 7.13k | if ((the->firstBlock != C_NULL) && (!(the->collectFlag & XS_SKIPPED_COLLECT_FLAG))) { |
630 | 611 | txSize modulo = size % (the->minimumChunksSize ? the->minimumChunksSize : 16); |
631 | 611 | if (modulo) |
632 | 608 | size = fxAddChunkSizes(the, size, the->minimumChunksSize - modulo); |
633 | 611 | } |
634 | 7.13k | size = fxAddChunkSizes(the, size, sizeof(txBlock)); |
635 | 7.13k | buffer = fxAllocateChunks(the, size); |
636 | 7.13k | if (buffer) { |
637 | 7.13k | #ifdef mxSnapshot |
638 | 7.13k | c_memset(buffer, 0, size); |
639 | 7.13k | #endif |
640 | 7.13k | if ((the->firstBlock != C_NULL) && (the->firstBlock->limit == buffer)) { |
641 | 0 | the->firstBlock->limit += size; |
642 | 0 | block = the->firstBlock; |
643 | 0 | } |
644 | 7.13k | else { |
645 | 7.13k | block = (txBlock*)buffer; |
646 | 7.13k | block->nextBlock = the->firstBlock; |
647 | 7.13k | block->current = buffer + sizeof(txBlock); |
648 | 7.13k | block->limit = buffer + size; |
649 | 7.13k | block->temporary = C_NULL; |
650 | 7.13k | the->firstBlock = block; |
651 | 7.13k | size -= sizeof(txBlock); |
652 | 7.13k | } |
653 | 7.13k | 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 | 7.13k | } |
659 | 7.13k | the->collectFlag &= ~XS_TRASHING_CHUNKS_FLAG; |
660 | 7.13k | return block; |
661 | 7.13k | } |
662 | | |
663 | | void fxGrowKeys(txMachine* the, txID theCount) |
664 | 189 | { |
665 | 189 | if (the->keyDelta > 0) { |
666 | 189 | txID keyDelta = (theCount > the->keyDelta) ? theCount : the->keyDelta; |
667 | 189 | txID keyCount = (the->keyCount + keyDelta) - the->keyOffset; |
668 | 189 | txSlot** keyArray = c_realloc(the->keyArray, keyCount * sizeof(txSlot*)); |
669 | 189 | if (keyArray == C_NULL) |
670 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
671 | 189 | the->keyArray = keyArray; |
672 | 189 | the->keyCount = keyCount + the->keyOffset; |
673 | 189 | } |
674 | 0 | else |
675 | 0 | fxAbort(the, XS_NO_MORE_KEYS_EXIT); |
676 | 189 | } |
677 | | |
678 | | void fxGrowSlots(txMachine* the, txSize theCount) |
679 | 7.24k | { |
680 | 7.24k | txSlot* aHeap; |
681 | 7.24k | txSlot* aSlot; |
682 | | |
683 | 7.24k | aHeap = fxAllocateSlots(the, theCount); |
684 | 7.24k | 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 | 7.24k | if ((void *)-1 == aHeap) |
689 | 0 | return; |
690 | | |
691 | 7.24k | 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 | 7.24k | else { |
707 | 7.24k | the->maximumHeapCount += theCount - 1; |
708 | 7.24k | aHeap->next = the->firstHeap; |
709 | 7.24k | aHeap->ID = 0; |
710 | 7.24k | aHeap->flag = 0; |
711 | 7.24k | aHeap->kind = 0; |
712 | 7.24k | aHeap->value.reference = aHeap + theCount; |
713 | 7.24k | theCount -= 2; |
714 | 7.24k | the->firstHeap = aHeap; |
715 | 7.24k | aSlot = aHeap + 1; |
716 | 7.24k | } |
717 | 237M | while (theCount--) { |
718 | 237M | txSlot* next = aSlot + 1; |
719 | 237M | aSlot->next = next; |
720 | 237M | aSlot->flag = XS_NO_FLAG; |
721 | 237M | aSlot->kind = XS_UNDEFINED_KIND; |
722 | | #if mxPoisonSlots |
723 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
724 | | #endif |
725 | 237M | aSlot = next; |
726 | 237M | } |
727 | 7.24k | aSlot->next = the->freeHeap; |
728 | 7.24k | aSlot->flag = XS_NO_FLAG; |
729 | 7.24k | aSlot->kind = XS_UNDEFINED_KIND; |
730 | | #if mxPoisonSlots |
731 | | ASAN_POISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
732 | | #endif |
733 | 7.24k | the->freeHeap = aHeap + 1; |
734 | 7.24k | 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 | 7.24k | } |
742 | | |
743 | | void fxMark(txMachine* the, void (*theMarker)(txMachine*, txSlot*)) |
744 | 12.0k | { |
745 | 12.0k | txSlot** p; |
746 | 12.0k | txSlot** q; |
747 | 12.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 | 12.0k | slot = the->stackTop; |
762 | 29.9M | while (slot > the->stack) { |
763 | 29.9M | slot--; |
764 | 29.9M | (*theMarker)(the, slot); |
765 | 29.9M | } |
766 | 12.0k | slot = the->cRoot; |
767 | 12.0k | while (slot) { |
768 | 0 | (*theMarker)(the, slot); |
769 | 0 | slot = slot->next; |
770 | 0 | } |
771 | | |
772 | 12.0k | #if mxKeysGarbageCollection |
773 | 12.0k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
774 | 6.85k | txInteger deletions = 0; |
775 | 6.85k | p = the->keyArray; |
776 | 6.85k | q = p + the->keyIndex - the->keyOffset; |
777 | 7.02M | while (p < q) { |
778 | 7.02M | slot = *p++; |
779 | 7.02M | if (!(slot->flag & XS_MARK_FLAG)) { |
780 | 514k | if (slot->flag & XS_DONT_DELETE_FLAG) |
781 | 488k | slot->flag |= XS_MARK_FLAG; |
782 | 26.1k | else if (slot->flag & XS_DONT_ENUM_FLAG) |
783 | 26.1k | deletions++; |
784 | 514k | } |
785 | 7.02M | } |
786 | | |
787 | | // fprintf(stderr, "\n### KEYS GC %d", deletions); |
788 | 6.85k | p = the->nameTable; |
789 | 6.85k | q = the->nameTable + the->nameModulo; |
790 | 10.2M | while ((p < q) && deletions) { |
791 | 10.2M | txSlot** address = p; |
792 | 15.4M | while (((slot = *address)) && deletions) { |
793 | 5.15M | if (slot->flag & XS_MARK_FLAG) |
794 | 5.12M | address = &(slot->next); |
795 | 26.1k | else { |
796 | 26.1k | *address = slot->next; |
797 | 26.1k | deletions--; |
798 | 26.1k | } |
799 | 5.15M | } |
800 | 10.2M | p++; |
801 | 10.2M | } |
802 | | // fprintf(stderr, " => %d", deletions); |
803 | | |
804 | 6.85k | the->keyholeCount = 0; |
805 | 6.85k | the->keyholeList = C_NULL; |
806 | 6.85k | p = the->keyArray; |
807 | 6.85k | q = p + the->keyIndex - the->keyOffset; |
808 | 7.02M | while (p < q) { |
809 | 7.02M | slot = *p; |
810 | 7.02M | if (slot->flag & XS_MARK_FLAG) |
811 | 6.99M | (*theMarker)(the, slot); |
812 | 26.1k | 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 | 26.1k | slot->flag = XS_INTERNAL_FLAG | XS_MARK_FLAG; |
818 | 26.1k | slot->next = the->keyholeList; |
819 | 26.1k | slot->kind = XS_UNDEFINED_KIND; |
820 | 26.1k | the->keyholeCount++; |
821 | 26.1k | the->keyholeList = slot; |
822 | 26.1k | } |
823 | 7.02M | p++; |
824 | 7.02M | } |
825 | | // fprintf(stderr, "\n"); |
826 | 6.85k | } |
827 | 5.14k | else |
828 | 5.14k | #endif |
829 | 5.14k | { |
830 | 5.14k | p = the->keyArray; |
831 | 5.14k | q = p + the->keyIndex - the->keyOffset; |
832 | 2.93M | while (p < q) { |
833 | 2.92M | slot = *p++; |
834 | 2.92M | slot->flag |= XS_MARK_FLAG; |
835 | 2.92M | (*theMarker)(the, slot); |
836 | 2.92M | } |
837 | 5.14k | } |
838 | 12.0k | } |
839 | | |
840 | | #if mxKeysGarbageCollection |
841 | | void fxMarkID(txMachine* the, txID id) |
842 | 24.0M | { |
843 | 24.0M | txSlot* slot; |
844 | 24.0M | if (id == XS_NO_ID) |
845 | 691k | return; |
846 | 23.3M | if (id < the->keyOffset) |
847 | 0 | return; |
848 | 23.3M | id -= the->keyOffset; |
849 | 23.3M | slot = the->keyArray[id]; |
850 | 23.3M | slot->flag |= XS_MARK_FLAG; |
851 | 23.3M | } |
852 | | #endif |
853 | | |
854 | | void fxMarkFinalizationRegistry(txMachine* the, txSlot* registry) |
855 | 0 | { |
856 | 0 | txSlot* slot = registry->value.finalizationRegistry.callback->next; |
857 | 0 | txSlot* instance; |
858 | 0 | while (slot) { |
859 | 0 | slot = slot->next; |
860 | 0 | if (slot) { |
861 | 0 | instance = slot->value.finalizationCell.target; |
862 | 0 | if (instance && !(instance->flag & XS_MARK_FLAG)) { |
863 | 0 | slot->value.finalizationCell.target = C_NULL; |
864 | 0 | registry->value.finalizationRegistry.flags |= XS_FINALIZATION_REGISTRY_CHANGED; |
865 | 0 | } |
866 | 0 | instance = slot->value.finalizationCell.token; |
867 | 0 | if (instance && !(instance->flag & XS_MARK_FLAG)) |
868 | 0 | slot->value.finalizationCell.token = C_NULL; |
869 | 0 | slot = slot->next; |
870 | 0 | } |
871 | 0 | } |
872 | 0 | } |
873 | | |
874 | | void fxMarkInstance(txMachine* the, txSlot* theCurrent, void (*theMarker)(txMachine*, txSlot*)) |
875 | 80.7M | { |
876 | 80.7M | txSlot* aProperty; |
877 | 80.7M | txSlot* aTemporary; |
878 | | |
879 | 80.7M | mxCheck(the, theCurrent->kind == XS_INSTANCE_KIND); |
880 | 80.7M | aProperty = theCurrent; |
881 | 80.7M | theCurrent->value.instance.garbage = C_NULL; |
882 | 615M | for (;;) { |
883 | 615M | if (aProperty) { |
884 | 456M | if (!(aProperty->flag & XS_MARK_FLAG)) { |
885 | 456M | aProperty->flag |= XS_MARK_FLAG; |
886 | 456M | switch (aProperty->kind) { |
887 | 159M | case XS_INSTANCE_KIND: |
888 | 159M | aTemporary = aProperty->value.instance.prototype; |
889 | 159M | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
890 | 48.0k | aProperty->value.instance.prototype = theCurrent; |
891 | 48.0k | theCurrent = aTemporary; |
892 | 48.0k | theCurrent->value.instance.garbage = aProperty; |
893 | 48.0k | aProperty = theCurrent; |
894 | 48.0k | } |
895 | 159M | else |
896 | 159M | aProperty = aProperty->next; |
897 | 159M | break; |
898 | 79.3M | case XS_REFERENCE_KIND: |
899 | 79.3M | #if mxKeysGarbageCollection |
900 | 79.3M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
901 | 4.73M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
902 | 4.73M | fxMarkID(the, aProperty->ID); |
903 | 4.73M | } |
904 | 79.3M | #endif |
905 | 79.3M | aTemporary = aProperty->value.reference; |
906 | 79.3M | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
907 | 78.4M | aProperty->value.reference = theCurrent; |
908 | 78.4M | theCurrent = aTemporary; |
909 | 78.4M | theCurrent->value.instance.garbage = aProperty; |
910 | 78.4M | aProperty = theCurrent; |
911 | 78.4M | } |
912 | 888k | else |
913 | 888k | aProperty = aProperty->next; |
914 | 79.3M | break; |
915 | | |
916 | 0 | case XS_PROXY_KIND: |
917 | 0 | aTemporary = aProperty->value.proxy.handler; |
918 | 0 | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
919 | 0 | aProperty->flag |= XS_INSPECTOR_FLAG; |
920 | 0 | aProperty->value.proxy.handler = theCurrent; |
921 | 0 | theCurrent = aTemporary; |
922 | 0 | theCurrent->value.instance.garbage = aProperty; |
923 | 0 | aProperty = theCurrent; |
924 | 0 | } |
925 | 0 | else { |
926 | 0 | aTemporary = aProperty->value.proxy.target; |
927 | 0 | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
928 | 0 | aProperty->value.proxy.target = theCurrent; |
929 | 0 | theCurrent = aTemporary; |
930 | 0 | theCurrent->value.instance.garbage = aProperty; |
931 | 0 | aProperty = theCurrent; |
932 | 0 | } |
933 | 0 | else |
934 | 0 | aProperty = aProperty->next; |
935 | 0 | } |
936 | 0 | break; |
937 | | |
938 | 0 | case XS_CLOSURE_KIND: |
939 | 0 | #if mxKeysGarbageCollection |
940 | 0 | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
941 | 0 | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
942 | 0 | fxMarkID(the, aProperty->ID); |
943 | 0 | } |
944 | 0 | #endif |
945 | 0 | aTemporary = aProperty->value.closure; |
946 | 0 | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
947 | 0 | aTemporary->flag |= XS_MARK_FLAG; |
948 | 0 | if (aTemporary->kind == XS_REFERENCE_KIND) { |
949 | 0 | aTemporary = aTemporary->value.reference; |
950 | 0 | if (!(aTemporary->flag & XS_MARK_FLAG)) { |
951 | 0 | aProperty->value.closure->value.reference = theCurrent; |
952 | 0 | theCurrent = aTemporary; |
953 | 0 | theCurrent->value.instance.garbage = aProperty; |
954 | 0 | aProperty = theCurrent; |
955 | | |
956 | 0 | } |
957 | 0 | } |
958 | 0 | else { |
959 | 0 | (*theMarker)(the, aTemporary); |
960 | 0 | aProperty = aProperty->next; |
961 | 0 | } |
962 | 0 | } |
963 | 0 | else |
964 | 0 | aProperty = aProperty->next; |
965 | 0 | break; |
966 | | |
967 | 7.12M | case XS_CALLBACK_KIND: |
968 | 7.12M | case XS_CODE_KIND: |
969 | 7.12M | #if mxKeysGarbageCollection |
970 | 7.12M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
971 | 4.07M | fxMarkID(the, aProperty->ID); |
972 | 7.12M | #endif |
973 | 7.12M | (*theMarker)(the, aProperty); |
974 | 7.12M | aProperty = aProperty->next; |
975 | 7.12M | break; |
976 | | |
977 | 210M | default: |
978 | 210M | #if mxKeysGarbageCollection |
979 | 210M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
980 | 27.0M | if (!(aProperty->flag & XS_INTERNAL_FLAG)) |
981 | 11.3M | fxMarkID(the, aProperty->ID); |
982 | 27.0M | } |
983 | 210M | #endif |
984 | 210M | (*theMarker)(the, aProperty); |
985 | 210M | aProperty = aProperty->next; |
986 | 210M | break; |
987 | 456M | } |
988 | 456M | } |
989 | 0 | else |
990 | 0 | aProperty = aProperty->next; |
991 | 456M | } |
992 | 159M | else if (theCurrent->value.instance.garbage) { |
993 | 78.5M | aProperty = theCurrent->value.instance.garbage; |
994 | 78.5M | theCurrent->value.instance.garbage = C_NULL; |
995 | 78.5M | switch (aProperty->kind) { |
996 | 48.0k | case XS_INSTANCE_KIND: |
997 | 48.0k | aTemporary = aProperty->value.instance.prototype; |
998 | 48.0k | aProperty->value.instance.prototype = theCurrent; |
999 | 48.0k | theCurrent = aTemporary; |
1000 | 48.0k | aProperty = aProperty->next; |
1001 | 48.0k | break; |
1002 | 78.4M | case XS_REFERENCE_KIND: |
1003 | 78.4M | aTemporary = aProperty->value.reference; |
1004 | 78.4M | aProperty->value.reference = theCurrent; |
1005 | 78.4M | theCurrent = aTemporary; |
1006 | 78.4M | aProperty = aProperty->next; |
1007 | 78.4M | break; |
1008 | 0 | case XS_PROXY_KIND: |
1009 | 0 | if (aProperty->flag & XS_INSPECTOR_FLAG) { |
1010 | 0 | aProperty->flag &= ~XS_INSPECTOR_FLAG; |
1011 | 0 | aTemporary = aProperty->value.proxy.handler; |
1012 | 0 | aProperty->value.proxy.handler = theCurrent; |
1013 | 0 | theCurrent = aTemporary; |
1014 | | |
1015 | 0 | aTemporary = aProperty->value.proxy.target; |
1016 | 0 | if (aTemporary && !(aTemporary->flag & XS_MARK_FLAG)) { |
1017 | 0 | aProperty->value.proxy.target = theCurrent; |
1018 | 0 | theCurrent = aTemporary; |
1019 | 0 | theCurrent->value.instance.garbage = aProperty; |
1020 | 0 | aProperty = theCurrent; |
1021 | 0 | } |
1022 | 0 | else { |
1023 | 0 | aProperty = aProperty->next; |
1024 | 0 | } |
1025 | 0 | } |
1026 | 0 | else { |
1027 | 0 | aTemporary = aProperty->value.proxy.target; |
1028 | 0 | aProperty->value.proxy.target = theCurrent; |
1029 | 0 | theCurrent = aTemporary; |
1030 | 0 | aProperty = aProperty->next; |
1031 | 0 | } |
1032 | 0 | break; |
1033 | 0 | case XS_CLOSURE_KIND: |
1034 | 0 | aTemporary = aProperty->value.closure->value.reference; |
1035 | 0 | aProperty->value.closure->value.reference = theCurrent; |
1036 | 0 | theCurrent = aTemporary; |
1037 | 0 | aProperty = aProperty->next; |
1038 | 0 | break; |
1039 | 78.5M | } |
1040 | 78.5M | } |
1041 | 80.7M | else |
1042 | 80.7M | break; |
1043 | 615M | } |
1044 | 80.7M | } |
1045 | | |
1046 | | void fxMarkReference(txMachine* the, txSlot* theSlot) |
1047 | 221M | { |
1048 | 221M | txSlot* aSlot; |
1049 | 221M | switch (theSlot->kind) { |
1050 | 39.6M | case XS_REFERENCE_KIND: |
1051 | 39.6M | aSlot = theSlot->value.reference; |
1052 | 39.6M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1053 | 38.7M | fxMarkInstance(the, aSlot, fxMarkReference); |
1054 | 39.6M | break; |
1055 | 0 | case XS_CLOSURE_KIND: |
1056 | 0 | aSlot = theSlot->value.closure; |
1057 | 0 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1058 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1059 | 0 | fxMarkReference(the, aSlot); |
1060 | 0 | } |
1061 | 0 | break; |
1062 | 0 | case XS_INSTANCE_KIND: |
1063 | 0 | if (!(theSlot->flag & XS_MARK_FLAG)) |
1064 | 0 | fxMarkInstance(the, theSlot, fxMarkReference); |
1065 | 0 | break; |
1066 | 470k | case XS_ACCESSOR_KIND: |
1067 | 470k | aSlot = theSlot->value.accessor.getter; |
1068 | 470k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1069 | 462k | fxCheckCStack(the); |
1070 | 462k | fxMarkInstance(the, aSlot, fxMarkReference); |
1071 | 462k | } |
1072 | 470k | aSlot = theSlot->value.accessor.setter; |
1073 | 470k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1074 | 64.8k | fxCheckCStack(the); |
1075 | 64.8k | fxMarkInstance(the, aSlot, fxMarkReference); |
1076 | 64.8k | } |
1077 | 470k | break; |
1078 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1079 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1080 | 105M | case XS_ARRAY_KIND: |
1081 | 105M | case XS_STACK_KIND: |
1082 | 105M | fxCheckCStack(the); |
1083 | 105M | if ((aSlot = theSlot->value.array.address)) { |
1084 | 21.1M | txIndex aLength = (((txChunk*)(((txByte*)aSlot) - sizeof(txChunk)))->size) / sizeof(txSlot); |
1085 | 21.1M | if (aLength > theSlot->value.array.length) |
1086 | 0 | aLength = theSlot->value.array.length; |
1087 | 58.1M | while (aLength) { |
1088 | 37.0M | fxMarkReference(the, aSlot); |
1089 | 37.0M | aSlot++; |
1090 | 37.0M | aLength--; |
1091 | 37.0M | } |
1092 | 21.1M | } |
1093 | 105M | break; |
1094 | 4.81M | case XS_CALLBACK_KIND: |
1095 | 4.81M | aSlot = theSlot->value.callback.closures; |
1096 | 4.81M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1097 | 0 | fxCheckCStack(the); |
1098 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1099 | 0 | } |
1100 | 4.81M | break; |
1101 | 0 | case XS_CODE_KIND: |
1102 | | // continue |
1103 | 16.2k | case XS_CODE_X_KIND: |
1104 | 16.2k | aSlot = theSlot->value.code.closures; |
1105 | 16.2k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1106 | 0 | fxCheckCStack(the); |
1107 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1108 | 0 | } |
1109 | 16.2k | break; |
1110 | 4.82M | case XS_HOME_KIND: |
1111 | 4.82M | aSlot = theSlot->value.home.object; |
1112 | 4.82M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1113 | 0 | fxCheckCStack(the); |
1114 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1115 | 0 | } |
1116 | 4.82M | aSlot = theSlot->value.home.module; |
1117 | 4.82M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1118 | 0 | fxCheckCStack(the); |
1119 | 0 | fxMarkInstance(the, aSlot, fxMarkReference); |
1120 | 0 | } |
1121 | 4.82M | break; |
1122 | 0 | case XS_MODULE_KIND: |
1123 | 8.11k | case XS_PROGRAM_KIND: |
1124 | 8.11k | #if mxKeysGarbageCollection |
1125 | 8.11k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1126 | 6.85k | fxMarkID(the, theSlot->value.module.id); |
1127 | 8.11k | #endif |
1128 | 8.11k | aSlot = theSlot->value.module.realm; |
1129 | 8.11k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1130 | 8.11k | fxCheckCStack(the); |
1131 | 8.11k | fxMarkInstance(the, aSlot, fxMarkReference); |
1132 | 8.11k | } |
1133 | 8.11k | 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 | 8.11k | case XS_HOST_KIND: |
1145 | 8.11k | if (theSlot->value.host.data) { |
1146 | 0 | 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 | 0 | } |
1149 | 8.11k | 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 | 9 | case XS_ERROR_KIND: |
1165 | 9 | aSlot = theSlot->value.error.info; |
1166 | 9 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1167 | 8 | fxMarkInstance(the, aSlot, fxMarkReference); |
1168 | 9 | break; |
1169 | 0 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1170 | 0 | case XS_DISPOSABLE_STACK_KIND: |
1171 | 24.3k | case XS_LIST_KIND: |
1172 | 24.3k | fxCheckCStack(the); |
1173 | 24.3k | aSlot = theSlot->value.list.first; |
1174 | 24.3k | while (aSlot) { |
1175 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1176 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1177 | 0 | fxMarkReference(the, aSlot); |
1178 | 0 | } |
1179 | 0 | aSlot = aSlot->next; |
1180 | 0 | } |
1181 | 24.3k | 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 | 0 | case XS_MAP_KIND: |
1197 | 0 | case XS_SET_KIND: |
1198 | 0 | { |
1199 | 0 | txSlot** anAddress = theSlot->value.table.address; |
1200 | 0 | txInteger aLength = theSlot->value.table.length; |
1201 | 0 | while (aLength) { |
1202 | 0 | aSlot = *anAddress; |
1203 | 0 | while (aSlot) { |
1204 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1205 | 0 | aSlot = aSlot->next; |
1206 | 0 | } |
1207 | 0 | anAddress++; |
1208 | 0 | aLength--; |
1209 | 0 | } |
1210 | 0 | } |
1211 | 0 | break; |
1212 | 0 | case XS_WEAK_MAP_KIND: |
1213 | 0 | case XS_WEAK_SET_KIND: |
1214 | 0 | aSlot = theSlot->value.weakList.first; |
1215 | 0 | while (aSlot) { |
1216 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1217 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1218 | 0 | fxMarkReference(the, aSlot); |
1219 | 0 | } |
1220 | 0 | aSlot = aSlot->next; |
1221 | 0 | } |
1222 | 0 | break; |
1223 | 0 | case XS_WEAK_ENTRY_KIND: |
1224 | 0 | aSlot = theSlot->value.weakEntry.check; |
1225 | 0 | if (aSlot->flag & XS_MARK_FLAG) { |
1226 | 0 | aSlot = theSlot->value.weakEntry.value; |
1227 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1228 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1229 | 0 | fxMarkReference(the, aSlot); |
1230 | 0 | } |
1231 | 0 | } |
1232 | 0 | break; |
1233 | 0 | case XS_WEAK_REF_KIND: |
1234 | 0 | aSlot = theSlot->value.weakRef.target; |
1235 | 0 | if (aSlot) { |
1236 | 0 | #ifdef mxSnapshot |
1237 | 0 | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1238 | 0 | fxMarkReference(the, aSlot); |
1239 | 0 | } |
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 | 0 | } |
1249 | 0 | break; |
1250 | 0 | case XS_FINALIZATION_REGISTRY_KIND: |
1251 | 0 | aSlot = theSlot->value.finalizationRegistry.callback; |
1252 | 0 | if (aSlot) { |
1253 | 0 | fxCheckCStack(the); |
1254 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1255 | 0 | fxMarkReference(the, aSlot); |
1256 | 0 | aSlot = aSlot->next; |
1257 | 0 | while (aSlot) { |
1258 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1259 | 0 | fxMarkReference(the, aSlot); // holdings |
1260 | 0 | aSlot = aSlot->next; |
1261 | 0 | if (aSlot) { |
1262 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1263 | | // weak target and token |
1264 | 0 | aSlot = aSlot->next; |
1265 | 0 | } |
1266 | 0 | } |
1267 | 0 | } |
1268 | 0 | 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 | 243k | case XS_SYMBOL_KIND: |
1277 | 243k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1278 | 205k | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1279 | 102k | fxMarkID(the, theSlot->value.symbol); |
1280 | 205k | } |
1281 | 243k | break; |
1282 | 3.81M | case XS_AT_KIND: |
1283 | 3.81M | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1284 | 3.78M | fxMarkID(the, theSlot->value.at.id); |
1285 | 3.81M | break; |
1286 | 221M | #endif |
1287 | 221M | } |
1288 | 221M | } |
1289 | | |
1290 | | void fxMarkValue(txMachine* the, txSlot* theSlot) |
1291 | 171M | { |
1292 | 171M | #define mxMarkChunk(_THE_DATA) \ |
1293 | 171M | ((txChunk*)(((txByte*)_THE_DATA) - sizeof(txChunk)))->size |= mxChunkFlag |
1294 | | |
1295 | 171M | txSlot* aSlot; |
1296 | 171M | switch (theSlot->kind) { |
1297 | 3.70M | case XS_STRING_KIND: |
1298 | 3.70M | mxMarkChunk(theSlot->value.string); |
1299 | 3.70M | break; |
1300 | 0 | case XS_BIGINT_KIND: |
1301 | 0 | mxMarkChunk(theSlot->value.bigint.data); |
1302 | 0 | break; |
1303 | 41.5M | case XS_REFERENCE_KIND: |
1304 | 41.5M | aSlot = theSlot->value.reference; |
1305 | 41.5M | if (!(aSlot->flag & XS_MARK_FLAG)) |
1306 | 41.1M | fxMarkInstance(the, aSlot, fxMarkValue); |
1307 | 41.5M | break; |
1308 | 0 | case XS_CLOSURE_KIND: |
1309 | 0 | aSlot = theSlot->value.closure; |
1310 | 0 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) { |
1311 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1312 | 0 | fxMarkValue(the, aSlot); |
1313 | 0 | } |
1314 | 0 | break; |
1315 | 0 | case XS_INSTANCE_KIND: |
1316 | 0 | if (!(theSlot->flag & XS_MARK_FLAG)) |
1317 | 0 | fxMarkInstance(the, theSlot, fxMarkValue); |
1318 | 0 | break; |
1319 | | |
1320 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
1321 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
1322 | 41.2M | case XS_ARRAY_KIND: |
1323 | 41.2M | case XS_STACK_KIND: |
1324 | 41.2M | fxCheckCStack(the); |
1325 | 41.2M | if ((aSlot = theSlot->value.array.address)) { |
1326 | 34.9M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
1327 | 34.9M | if (!(chunk->size & mxChunkFlag)) { |
1328 | 34.9M | txIndex aLength = chunk->size / sizeof(txSlot); |
1329 | 34.9M | if (aLength > theSlot->value.array.length) |
1330 | 0 | aLength = theSlot->value.array.length; |
1331 | 132M | while (aLength) { |
1332 | 97.5M | fxMarkValue(the, aSlot); |
1333 | 97.5M | aSlot++; |
1334 | 97.5M | aLength--; |
1335 | 97.5M | } |
1336 | 34.9M | mxMarkChunk(theSlot->value.array.address); |
1337 | 34.9M | } |
1338 | 34.9M | } |
1339 | 41.2M | break; |
1340 | 128 | case XS_ARRAY_BUFFER_KIND: |
1341 | 128 | if (theSlot->value.arrayBuffer.address) |
1342 | 96 | mxMarkChunk(theSlot->value.arrayBuffer.address); |
1343 | 128 | break; |
1344 | 2.31M | case XS_CALLBACK_KIND: |
1345 | 2.31M | aSlot = theSlot->value.callback.closures; |
1346 | 2.31M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1347 | 0 | fxCheckCStack(the); |
1348 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1349 | 0 | } |
1350 | 2.31M | break; |
1351 | 0 | case XS_CODE_KIND: |
1352 | 0 | mxMarkChunk(theSlot->value.code.address); |
1353 | | /* continue */ |
1354 | 0 | mxFallThrough; |
1355 | 7.78k | case XS_CODE_X_KIND: |
1356 | 7.78k | aSlot = theSlot->value.code.closures; |
1357 | 7.78k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1358 | 0 | fxCheckCStack(the); |
1359 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1360 | 0 | } |
1361 | 7.78k | break; |
1362 | 3.89k | case XS_GLOBAL_KIND: |
1363 | 3.89k | mxMarkChunk(theSlot->value.table.address); |
1364 | 3.89k | break; |
1365 | 3.98k | case XS_HOST_KIND: |
1366 | 3.98k | if (theSlot->value.host.data) { |
1367 | 95 | 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 | 95 | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
1370 | 95 | mxMarkChunk(theSlot->value.host.data); |
1371 | 95 | } |
1372 | 3.98k | break; |
1373 | 0 | case XS_IDS_KIND: |
1374 | 0 | if (theSlot->value.IDs) |
1375 | 0 | mxMarkChunk(theSlot->value.IDs); |
1376 | 0 | 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 | 0 | case XS_REGEXP_KIND: |
1386 | 0 | if (theSlot->value.regexp.code) |
1387 | 0 | mxMarkChunk(theSlot->value.regexp.code); |
1388 | 0 | if (theSlot->value.regexp.data) |
1389 | 0 | mxMarkChunk(theSlot->value.regexp.data); |
1390 | 0 | break; |
1391 | | |
1392 | 225k | case XS_ACCESSOR_KIND: |
1393 | 225k | aSlot = theSlot->value.accessor.getter; |
1394 | 225k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1395 | 221k | fxCheckCStack(the); |
1396 | 221k | fxMarkInstance(the, aSlot, fxMarkValue); |
1397 | 221k | } |
1398 | 225k | aSlot = theSlot->value.accessor.setter; |
1399 | 225k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1400 | 31.1k | fxCheckCStack(the); |
1401 | 31.1k | fxMarkInstance(the, aSlot, fxMarkValue); |
1402 | 31.1k | } |
1403 | 225k | break; |
1404 | 2.31M | case XS_HOME_KIND: |
1405 | 2.31M | aSlot = theSlot->value.home.object; |
1406 | 2.31M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1407 | 0 | fxCheckCStack(the); |
1408 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1409 | 0 | } |
1410 | 2.31M | aSlot = theSlot->value.home.module; |
1411 | 2.31M | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1412 | 0 | fxCheckCStack(the); |
1413 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1414 | 0 | } |
1415 | 2.31M | break; |
1416 | 0 | case XS_MODULE_KIND: |
1417 | 3.89k | case XS_PROGRAM_KIND: |
1418 | 3.89k | #if mxKeysGarbageCollection |
1419 | 3.89k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1420 | 0 | fxMarkID(the, theSlot->value.module.id); |
1421 | 3.89k | #endif |
1422 | 3.89k | aSlot = theSlot->value.module.realm; |
1423 | 3.89k | if (aSlot && !(aSlot->flag & XS_MARK_FLAG)) { |
1424 | 3.89k | fxCheckCStack(the); |
1425 | 3.89k | fxMarkInstance(the, aSlot, fxMarkValue); |
1426 | 3.89k | } |
1427 | 3.89k | 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 | 2.16M | case XS_KEY_KIND: |
1439 | 2.16M | if (theSlot->value.key.string) |
1440 | 2.16M | mxMarkChunk(theSlot->value.key.string); |
1441 | 2.16M | 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 | 40 | case XS_ERROR_KIND: |
1449 | 40 | aSlot = theSlot->value.error.info; |
1450 | 40 | if (aSlot && (!(aSlot->flag & XS_MARK_FLAG))) |
1451 | 40 | fxMarkInstance(the, aSlot, fxMarkValue); |
1452 | 40 | break; |
1453 | 0 | case XS_ASYNC_DISPOSABLE_STACK_KIND: |
1454 | 0 | case XS_DISPOSABLE_STACK_KIND: |
1455 | 11.6k | case XS_LIST_KIND: |
1456 | 11.6k | fxCheckCStack(the); |
1457 | 11.6k | aSlot = theSlot->value.list.first; |
1458 | 11.6k | while (aSlot) { |
1459 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1460 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1461 | 0 | fxMarkValue(the, aSlot); |
1462 | 0 | } |
1463 | 0 | aSlot = aSlot->next; |
1464 | 0 | } |
1465 | 11.6k | break; |
1466 | | |
1467 | 0 | case XS_PRIVATE_KIND: |
1468 | 0 | fxCheckCStack(the); |
1469 | 0 | aSlot = theSlot->value.private.check; |
1470 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) |
1471 | 0 | fxMarkInstance(the, aSlot, fxMarkValue); |
1472 | 0 | aSlot = theSlot->value.private.first; |
1473 | 0 | while (aSlot) { |
1474 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1475 | 0 | fxMarkValue(the, aSlot); |
1476 | 0 | aSlot = aSlot->next; |
1477 | 0 | } |
1478 | 0 | break; |
1479 | | |
1480 | 0 | case XS_MAP_KIND: |
1481 | 0 | case XS_SET_KIND: |
1482 | 0 | { |
1483 | 0 | txSlot** anAddress = theSlot->value.table.address; |
1484 | 0 | txInteger aLength = theSlot->value.table.length; |
1485 | 0 | while (aLength) { |
1486 | 0 | aSlot = *anAddress; |
1487 | 0 | while (aSlot) { |
1488 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1489 | 0 | aSlot = aSlot->next; |
1490 | 0 | } |
1491 | 0 | anAddress++; |
1492 | 0 | aLength--; |
1493 | 0 | } |
1494 | 0 | } |
1495 | 0 | mxMarkChunk(theSlot->value.table.address); |
1496 | 0 | break; |
1497 | | |
1498 | 0 | case XS_WEAK_MAP_KIND: |
1499 | 0 | case XS_WEAK_SET_KIND: |
1500 | 0 | aSlot = theSlot->value.weakList.first; |
1501 | 0 | while (aSlot) { |
1502 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1503 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1504 | 0 | fxMarkValue(the, aSlot); |
1505 | 0 | } |
1506 | 0 | aSlot = aSlot->next; |
1507 | 0 | } |
1508 | 0 | break; |
1509 | 0 | case XS_WEAK_ENTRY_KIND: |
1510 | 0 | aSlot = theSlot->value.weakEntry.check; |
1511 | 0 | if (aSlot->flag & XS_MARK_FLAG) { |
1512 | 0 | aSlot = theSlot->value.weakEntry.value; |
1513 | 0 | if (!(aSlot->flag & XS_MARK_FLAG)) { |
1514 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1515 | 0 | fxMarkValue(the, aSlot); |
1516 | 0 | } |
1517 | 0 | } |
1518 | 0 | break; |
1519 | 0 | case XS_WEAK_REF_KIND: |
1520 | 0 | aSlot = theSlot->value.weakRef.target; |
1521 | 0 | if (aSlot) { |
1522 | 0 | #ifdef mxSnapshot |
1523 | 0 | if (the->collectFlag & XS_ORGANIC_FLAG) { |
1524 | 0 | fxMarkValue(the, aSlot); |
1525 | 0 | } |
1526 | 0 | else { |
1527 | 0 | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1528 | 0 | the->firstWeakRefLink = theSlot; |
1529 | 0 | } |
1530 | | #else |
1531 | | theSlot->value.weakRef.link = the->firstWeakRefLink; |
1532 | | the->firstWeakRefLink = theSlot; |
1533 | | #endif |
1534 | 0 | } |
1535 | 0 | break; |
1536 | 0 | case XS_FINALIZATION_REGISTRY_KIND: |
1537 | 0 | aSlot = theSlot->value.finalizationRegistry.callback; |
1538 | 0 | if (aSlot) { |
1539 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1540 | 0 | fxMarkValue(the, aSlot); |
1541 | 0 | aSlot = aSlot->next; |
1542 | 0 | while (aSlot) { |
1543 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1544 | 0 | fxCheckCStack(the); |
1545 | 0 | fxMarkValue(the, aSlot); // holdings |
1546 | 0 | aSlot = aSlot->next; |
1547 | 0 | if (aSlot) { |
1548 | 0 | aSlot->flag |= XS_MARK_FLAG; |
1549 | | // weak target and token |
1550 | 0 | aSlot = aSlot->next; |
1551 | 0 | } |
1552 | 0 | } |
1553 | 0 | } |
1554 | 0 | 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 | 116k | case XS_SYMBOL_KIND: |
1564 | 116k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) { |
1565 | 0 | if (!(theSlot->flag & XS_INTERNAL_FLAG)) |
1566 | 0 | fxMarkID(the, theSlot->value.symbol); |
1567 | 0 | } |
1568 | 116k | break; |
1569 | 643k | case XS_AT_KIND: |
1570 | 643k | if (the->collectFlag & XS_COLLECT_KEYS_FLAG) |
1571 | 0 | fxMarkID(the, theSlot->value.at.id); |
1572 | 643k | break; |
1573 | 171M | #endif |
1574 | 171M | } |
1575 | 171M | } |
1576 | | |
1577 | | void fxMarkWeakStuff(txMachine* the) |
1578 | 12.0k | { |
1579 | 12.0k | txSlot* slot; |
1580 | 12.0k | txSlot** address; |
1581 | | |
1582 | 12.0k | { |
1583 | 12.0k | txSlot* list; |
1584 | 12.0k | txSlot** listAddress = &the->firstWeakListLink; |
1585 | 12.0k | while ((list = *listAddress)) { |
1586 | 0 | if (list->flag & XS_MARK_FLAG) { |
1587 | 0 | txSlot* listEntry; |
1588 | 0 | txSlot** listEntryAddress = &list->value.weakList.first; |
1589 | 0 | while ((listEntry = *listEntryAddress)) { |
1590 | 0 | txSlot* value = listEntry->value.weakEntry.value; |
1591 | 0 | if ((value->flag & XS_MARK_FLAG) && (value->kind != XS_UNINITIALIZED_KIND)) { |
1592 | 0 | listEntryAddress = &listEntry->next; |
1593 | 0 | } |
1594 | 0 | else { |
1595 | 0 | listEntry->flag &= ~XS_MARK_FLAG; |
1596 | 0 | *listEntryAddress = listEntry->next; |
1597 | 0 | } |
1598 | 0 | } |
1599 | 0 | listAddress = &list->value.weakList.link; |
1600 | 0 | } |
1601 | 0 | else { |
1602 | 0 | txSlot* listEntry = list->value.weakList.first; |
1603 | 0 | while (listEntry) { |
1604 | 0 | txSlot* key = listEntry->value.weakEntry.check; |
1605 | 0 | if (key->flag & XS_MARK_FLAG) { |
1606 | 0 | txSlot* keyEntry; |
1607 | 0 | txSlot** keyEntryAddress = &key->next; |
1608 | 0 | while ((keyEntry = *keyEntryAddress)) { |
1609 | 0 | if (!(keyEntry->flag & XS_INTERNAL_FLAG)) |
1610 | 0 | break; |
1611 | 0 | if ((keyEntry->kind == XS_WEAK_ENTRY_KIND) && (keyEntry->value.weakEntry.check == list)) { |
1612 | 0 | keyEntry->flag &= ~XS_MARK_FLAG; |
1613 | 0 | *keyEntryAddress = keyEntry->next; |
1614 | 0 | break; |
1615 | 0 | } |
1616 | 0 | keyEntryAddress = &keyEntry->next; |
1617 | 0 | } |
1618 | 0 | } |
1619 | 0 | listEntry = listEntry->next; |
1620 | 0 | } |
1621 | 0 | *listAddress = list->value.weakList.link; |
1622 | 0 | } |
1623 | 0 | } |
1624 | 12.0k | } |
1625 | 12.0k | address = &the->firstWeakRefLink; |
1626 | 12.0k | while ((slot = *address)) { |
1627 | 0 | if (!(slot->value.weakRef.target->flag & XS_MARK_FLAG)) |
1628 | 0 | slot->value.weakRef.target = C_NULL; |
1629 | 0 | *address = C_NULL; |
1630 | 0 | address = &(slot->value.weakRef.link); |
1631 | 0 | } |
1632 | | |
1633 | 12.0k | if (mxFinalizationRegistries.kind == XS_REFERENCE_KIND) { |
1634 | 12.0k | slot = mxFinalizationRegistries.value.reference->next; |
1635 | 12.0k | while (slot) { |
1636 | 0 | fxMarkFinalizationRegistry(the, slot->value.closure); |
1637 | 0 | slot = slot->next; |
1638 | 0 | } |
1639 | 12.0k | } |
1640 | 12.0k | } |
1641 | | |
1642 | | txSize fxMultiplyChunkSizes(txMachine* the, txSize a, txSize b) |
1643 | 4.48M | { |
1644 | 4.48M | txSize c; |
1645 | 4.48M | #if __has_builtin(__builtin_mul_overflow) |
1646 | 4.48M | 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 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
1653 | 0 | } |
1654 | 4.48M | return c; |
1655 | 4.48M | } |
1656 | | |
1657 | | void* fxNewChunk(txMachine* the, txSize size) |
1658 | 11.4M | { |
1659 | 11.4M | txSize offset = size; |
1660 | 11.4M | txChunk* chunk; |
1661 | 11.4M | txBoolean once = 1; |
1662 | 11.4M | size = fxAdjustChunkSize(the, size); |
1663 | 11.4M | chunk = fxFindChunk(the, size, &once); |
1664 | 11.4M | if (!chunk) { |
1665 | 611 | chunk = fxGrowChunk(the, size); |
1666 | 611 | } |
1667 | 11.4M | #ifdef mxMetering |
1668 | 11.4M | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1669 | 11.4M | #endif |
1670 | 11.4M | return fxCheckChunk(the, chunk, size, offset); |
1671 | 11.4M | } |
1672 | | |
1673 | | void* fxNewGrowableChunk(txMachine* the, txSize size, txSize capacity) |
1674 | 0 | { |
1675 | | #if mxNoChunks |
1676 | | return fxNewChunk(the, size); |
1677 | | #else |
1678 | 0 | txSize offset = size; |
1679 | 0 | txChunk* chunk; |
1680 | 0 | txBoolean once = 1; |
1681 | 0 | size = fxAdjustChunkSize(the, size); |
1682 | 0 | capacity = fxAdjustChunkSize(the, capacity); |
1683 | 0 | chunk = fxFindChunk(the, capacity, &once); |
1684 | 0 | if (!chunk) { |
1685 | 0 | chunk = fxGrowChunk(the, capacity); |
1686 | 0 | if (!chunk) { |
1687 | 0 | chunk = fxFindChunk(the, size, &once); |
1688 | 0 | if (!chunk) { |
1689 | 0 | chunk = fxGrowChunk(the, size); |
1690 | 0 | } |
1691 | 0 | } |
1692 | 0 | } |
1693 | 0 | #ifdef mxMetering |
1694 | 0 | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1695 | 0 | #endif |
1696 | 0 | return fxCheckChunk(the, chunk, size, offset); |
1697 | 0 | #endif |
1698 | 0 | } |
1699 | | |
1700 | | txSlot* fxNewSlot(txMachine* the) |
1701 | 60.6M | { |
1702 | 60.6M | txSlot* aSlot; |
1703 | 60.6M | txBoolean once = 1, allocate; |
1704 | | |
1705 | 60.6M | #if mxStress |
1706 | 60.6M | if (fxShouldStress()) { |
1707 | 0 | fxCollect(the, XS_COMPACT_FLAG | XS_ORGANIC_FLAG); |
1708 | 0 | once = 0; |
1709 | 0 | } |
1710 | 60.6M | #endif |
1711 | 60.6M | again: |
1712 | 60.6M | aSlot = the->freeHeap; |
1713 | 60.6M | if (aSlot) { |
1714 | 60.6M | the->freeHeap = aSlot->next; |
1715 | 60.6M | aSlot->next = C_NULL; |
1716 | 60.6M | aSlot->ID = XS_NO_ID; |
1717 | 60.6M | aSlot->flag = XS_NO_FLAG; |
1718 | 60.6M | #ifdef mxSnapshot |
1719 | 60.6M | #if mx32bitID |
1720 | 60.6M | aSlot->dummy = 0; |
1721 | | #elif INTPTR_MAX == INT64_MAX |
1722 | | aSlot->dummy = 0; |
1723 | | #endif |
1724 | 60.6M | #endif |
1725 | | #if mxPoisonSlots |
1726 | | ASAN_UNPOISON_MEMORY_REGION(&aSlot->value, sizeof(aSlot->value)); |
1727 | | #endif |
1728 | 60.6M | the->currentHeapCount++; |
1729 | 60.6M | if (the->peakHeapCount < the->currentHeapCount) |
1730 | 55.6M | the->peakHeapCount = the->currentHeapCount; |
1731 | 60.6M | #ifdef mxMetering |
1732 | 60.6M | the->meterIndex += XS_SLOT_ALLOCATION_METERING; |
1733 | 60.6M | #endif |
1734 | 60.6M | return aSlot; |
1735 | 60.6M | } |
1736 | 1.38k | if (once) { |
1737 | 1.25k | txBoolean wasThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0), isThrashing; |
1738 | | |
1739 | 1.25k | fxCollect(the, XS_ORGANIC_FLAG); |
1740 | | |
1741 | 1.25k | isThrashing = ((the->collectFlag & XS_TRASHING_SLOTS_FLAG) != 0); |
1742 | 1.25k | allocate = wasThrashing && isThrashing; |
1743 | | |
1744 | 1.25k | once = 0; |
1745 | 1.25k | } |
1746 | 131 | else |
1747 | 131 | allocate = 1; |
1748 | 1.38k | if (allocate) { |
1749 | 724 | 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 | 724 | fxGrowSlots(the, !(the->collectFlag & XS_SKIPPED_COLLECT_FLAG) ? the->minimumHeapCount : 64); |
1754 | 724 | } |
1755 | 1.38k | goto again; |
1756 | 0 | return C_NULL; |
1757 | 60.6M | } |
1758 | | |
1759 | | void* fxRenewChunk(txMachine* the, void* theData, txSize size) |
1760 | 5.82k | { |
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 | 5.82k | txByte* aData = ((txByte*)theData) - sizeof(txChunk); |
1772 | 5.82k | txChunk* aChunk = (txChunk*)aData; |
1773 | 5.82k | txSize capacity = (txSize)(aChunk->temporary - aData); |
1774 | 5.82k | txBlock* aBlock = the->firstBlock; |
1775 | 5.82k | size = fxAdjustChunkSize(the, size); |
1776 | 5.82k | if (size <= capacity) { |
1777 | 0 | the->currentChunksSize += size - aChunk->size; |
1778 | 0 | if (the->peakChunksSize < the->currentChunksSize) |
1779 | 0 | the->peakChunksSize = the->currentChunksSize; |
1780 | 0 | aChunk->size = size; |
1781 | 0 | #ifdef mxMetering |
1782 | 0 | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1783 | 0 | #endif |
1784 | 0 | return theData; |
1785 | 0 | } |
1786 | 14.3k | while (aBlock) { |
1787 | 8.59k | if (aChunk->temporary == aBlock->current) { |
1788 | 110 | txSize delta = size - capacity; |
1789 | 110 | if (aBlock->current + delta <= aBlock->limit) { |
1790 | 99 | the->currentChunksSize += size - aChunk->size; |
1791 | 99 | if (the->peakChunksSize < the->currentChunksSize) |
1792 | 35 | the->peakChunksSize = the->currentChunksSize; |
1793 | 99 | aBlock->current += delta; |
1794 | 99 | aChunk->temporary = aBlock->current; |
1795 | 99 | aChunk->size = size; |
1796 | 99 | #ifdef mxSnapshot |
1797 | 99 | c_memset(aData + capacity, 0, delta); |
1798 | 99 | #endif |
1799 | 99 | #ifdef mxMetering |
1800 | 99 | the->meterIndex += size * XS_CHUNK_ALLOCATION_METERING; |
1801 | 99 | #endif |
1802 | 99 | return theData; |
1803 | 99 | } |
1804 | 11 | else { |
1805 | 11 | return C_NULL; |
1806 | 11 | } |
1807 | 110 | } |
1808 | 8.48k | aBlock = aBlock->nextBlock; |
1809 | 8.48k | } |
1810 | 5.71k | return C_NULL; |
1811 | 5.82k | #endif |
1812 | 5.82k | } |
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 | 3.89k | { |
1886 | 3.89k | txSize aTotal; |
1887 | | #if mxNoChunks |
1888 | | txChunk** address; |
1889 | | txChunk* chunk; |
1890 | | #else |
1891 | 3.89k | txBlock* aBlock; |
1892 | 3.89k | txByte* limit; |
1893 | 3.89k | txByte* next; |
1894 | 3.89k | #endif |
1895 | 3.89k | txByte* current; |
1896 | 3.89k | txByte* temporary; |
1897 | 3.89k | txSize aSize; |
1898 | 3.89k | txByte** aCodeAddress; |
1899 | 3.89k | txSlot* aSlot; |
1900 | 3.89k | txSlot* bSlot; |
1901 | 3.89k | txSlot* cSlot; |
1902 | 3.89k | txSlot* freeSlot; |
1903 | 3.89k | txJump* jump; |
1904 | | |
1905 | | #ifdef mxNever |
1906 | | startTime(&gxSweepChunkTime); |
1907 | | #endif |
1908 | | |
1909 | 3.89k | 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 | 3.89k | aBlock = the->firstBlock; |
1932 | 13.8k | while (aBlock) { |
1933 | 10.0k | current = ((txByte*)aBlock) + sizeof(txBlock); |
1934 | 10.0k | limit = aBlock->current; |
1935 | 10.0k | temporary = current; |
1936 | 42.0M | while (current < limit) { |
1937 | 42.0M | aSize = ((txChunk*)current)->size; |
1938 | 42.0M | next = ((txChunk*)current)->temporary; |
1939 | 42.0M | if (aSize & mxChunkFlag) { |
1940 | 38.7M | aSize &= ~mxChunkFlag; |
1941 | 38.7M | ((txChunk*)current)->temporary = temporary; |
1942 | 38.7M | temporary += aSize; |
1943 | 38.7M | aTotal += aSize; |
1944 | 38.7M | } |
1945 | 3.22M | else { |
1946 | 3.22M | ((txChunk*)current)->temporary = C_NULL; |
1947 | 3.22M | } |
1948 | 42.0M | ((txChunk*)current)->size = (txSize)(next - current); |
1949 | 42.0M | current = next; |
1950 | 42.0M | } |
1951 | 10.0k | aBlock->temporary = temporary; |
1952 | 10.0k | aBlock = aBlock->nextBlock; |
1953 | 10.0k | } |
1954 | 3.89k | #endif |
1955 | 3.89k | the->currentChunksSize = aTotal; |
1956 | | |
1957 | 3.89k | aCodeAddress = &(the->code); |
1958 | 3.89k | aSlot = the->frame; |
1959 | 11.6k | while (aSlot) { |
1960 | 7.75k | mxCheck(the, aSlot->kind == XS_FRAME_KIND); |
1961 | 7.75k | if ((aSlot->flag & XS_C_FLAG) == 0) { |
1962 | 0 | bSlot = (aSlot + 2)->value.reference->next; |
1963 | 0 | if (bSlot->kind == XS_CODE_KIND) { |
1964 | 0 | current = bSlot->value.code.address; |
1965 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1966 | 0 | if (temporary) { |
1967 | 0 | temporary += sizeof(txChunk); |
1968 | 0 | *aCodeAddress += temporary - current; |
1969 | 0 | } |
1970 | 0 | } |
1971 | 0 | } |
1972 | 7.75k | else { |
1973 | 7.75k | current = *aCodeAddress; |
1974 | 7.75k | if (current) { |
1975 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1976 | 0 | if (temporary) |
1977 | 0 | *aCodeAddress = temporary + sizeof(txChunk); |
1978 | 0 | } |
1979 | 7.75k | } |
1980 | 7.75k | aCodeAddress = &(aSlot->value.frame.code); |
1981 | 7.75k | aSlot = aSlot->next; |
1982 | 7.75k | } |
1983 | | |
1984 | 3.89k | jump = the->firstJump; |
1985 | 15.5k | while (jump) { |
1986 | 11.6k | if (jump->flag) { |
1987 | 0 | aSlot = jump->frame; |
1988 | 0 | bSlot = (aSlot + 2)->value.reference->next; |
1989 | 0 | if (bSlot->kind == XS_CODE_KIND) { |
1990 | 0 | current = bSlot->value.code.address; |
1991 | 0 | temporary = (txByte*)(((txChunk*)(current - sizeof(txChunk)))->temporary); |
1992 | 0 | if (temporary) { |
1993 | 0 | temporary += sizeof(txChunk); |
1994 | 0 | jump->code += temporary - current; |
1995 | 0 | } |
1996 | 0 | } |
1997 | 0 | } |
1998 | 11.6k | else { |
1999 | 11.6k | current = jump->code; |
2000 | 11.6k | 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 | 11.6k | } |
2006 | 11.6k | jump = jump->nextJump; |
2007 | 11.6k | } |
2008 | | |
2009 | 3.89k | aSlot = the->stack; |
2010 | 7.31M | while (aSlot < the->stackTop) { |
2011 | 7.31M | fxSweepValue(the, aSlot); |
2012 | 7.31M | aSlot++; |
2013 | 7.31M | } |
2014 | 3.89k | aSlot = the->cRoot; |
2015 | 3.89k | 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 | 3.89k | aTotal = 0; |
2026 | 3.89k | freeSlot = C_NULL; |
2027 | 3.89k | aSlot = the->firstHeap; |
2028 | 10.5k | while (aSlot) { |
2029 | 6.67k | bSlot = aSlot + 1; |
2030 | 6.67k | cSlot = aSlot->value.reference; |
2031 | 218M | while (bSlot < cSlot) { |
2032 | 218M | if (bSlot->flag & XS_MARK_FLAG) { |
2033 | 114M | bSlot->flag &= ~XS_MARK_FLAG; |
2034 | 114M | fxSweepValue(the, bSlot); |
2035 | 114M | aTotal++; |
2036 | 114M | } |
2037 | 104M | else { |
2038 | 104M | #ifndef mxLink |
2039 | 104M | if (bSlot->kind == XS_HOST_KIND) { |
2040 | 460 | 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 | 460 | else if (bSlot->value.host.variant.destructor) |
2045 | 0 | (*(bSlot->value.host.variant.destructor))(bSlot->value.host.data); |
2046 | 460 | } |
2047 | 104M | #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 | 104M | bSlot->kind = XS_UNDEFINED_KIND; |
2057 | 104M | bSlot->next = freeSlot; |
2058 | | #if mxPoisonSlots |
2059 | | ASAN_POISON_MEMORY_REGION(&bSlot->value, sizeof(bSlot->value)); |
2060 | | #endif |
2061 | 104M | freeSlot = bSlot; |
2062 | 104M | } |
2063 | 218M | bSlot++; |
2064 | 218M | } |
2065 | 6.67k | aSlot = aSlot->next; |
2066 | 6.67k | } |
2067 | 3.89k | the->currentHeapCount = aTotal; |
2068 | 3.89k | 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 | 3.89k | aBlock = the->firstBlock; |
2089 | 13.8k | while (aBlock) { |
2090 | 10.0k | txByte* former = C_NULL; |
2091 | 10.0k | current = ((txByte*)aBlock) + sizeof(txBlock); |
2092 | 10.0k | limit = aBlock->current; |
2093 | 42.0M | while (current < limit) { |
2094 | 42.0M | aSize = ((txChunk*)current)->size; |
2095 | 42.0M | next = current + aSize; |
2096 | 42.0M | if ((temporary = ((txChunk*)current)->temporary)) { |
2097 | 38.7M | if (former) { |
2098 | 38.7M | ((txChunk*)former)->temporary = temporary; |
2099 | 38.7M | ((txChunk*)former)->size = (txSize)(temporary - former); |
2100 | 38.7M | } |
2101 | 38.7M | if (temporary != current) |
2102 | 2.05M | c_memmove(temporary, current, aSize); |
2103 | 38.7M | former = temporary; |
2104 | 38.7M | } |
2105 | 42.0M | current = next; |
2106 | 42.0M | } |
2107 | 10.0k | if (former) { |
2108 | 9.89k | ((txChunk*)former)->temporary = aBlock->temporary; |
2109 | 9.89k | ((txChunk*)former)->size = (txSize)(aBlock->temporary - former); |
2110 | 9.89k | } |
2111 | 10.0k | aBlock->current = aBlock->temporary; |
2112 | 10.0k | aBlock->temporary = C_NULL; |
2113 | 10.0k | aBlock = aBlock->nextBlock; |
2114 | 10.0k | } |
2115 | 3.89k | #endif |
2116 | | |
2117 | | #ifdef mxNever |
2118 | | stopTime(&gxCompactChunkTime); |
2119 | | #endif |
2120 | 3.89k | } |
2121 | | |
2122 | | void fxSweepValue(txMachine* the, txSlot* theSlot) |
2123 | 219M | { |
2124 | 219M | txSlot* aSlot; |
2125 | 219M | txByte* data; |
2126 | | |
2127 | 219M | #define mxSweepChunk(_THE_DATA, _THE_DATA_TYPE) \ |
2128 | 219M | if ((data = (txByte*)(((txChunk*)(((txByte*)(_THE_DATA)) - sizeof(txChunk)))->temporary))) \ |
2129 | 40.8M | ((_THE_DATA)) = (_THE_DATA_TYPE)(data + sizeof(txChunk)) |
2130 | | |
2131 | 219M | switch (theSlot->kind) { |
2132 | 3.70M | case XS_STRING_KIND: |
2133 | 3.70M | mxSweepChunk(theSlot->value.string, txString); |
2134 | 3.70M | break; |
2135 | 0 | case XS_BIGINT_KIND: |
2136 | 0 | mxSweepChunk(theSlot->value.bigint.data, txU4*); |
2137 | 0 | break; |
2138 | | |
2139 | 0 | case XS_ARGUMENTS_SLOPPY_KIND: |
2140 | 0 | case XS_ARGUMENTS_STRICT_KIND: |
2141 | 41.2M | case XS_ARRAY_KIND: |
2142 | 41.2M | case XS_STACK_KIND: |
2143 | 41.2M | 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 | 34.9M | txChunk* chunk = (txChunk*)(((txByte*)aSlot) - sizeof(txChunk)); |
2149 | 34.9M | txIndex aLength = chunk->size / sizeof(txSlot); |
2150 | 34.9M | if (aLength > theSlot->value.array.length) |
2151 | 0 | aLength = theSlot->value.array.length; |
2152 | 132M | while (aLength) { |
2153 | 97.5M | fxSweepValue(the, aSlot); |
2154 | 97.5M | aSlot++; |
2155 | 97.5M | aLength--; |
2156 | 97.5M | } |
2157 | | #if mxNoChunks |
2158 | | #else |
2159 | 34.9M | mxSweepChunk(theSlot->value.array.address, txSlot*); |
2160 | 34.9M | #endif |
2161 | 34.9M | } |
2162 | 41.2M | break; |
2163 | 128 | case XS_ARRAY_BUFFER_KIND: |
2164 | 128 | if (theSlot->value.arrayBuffer.address) |
2165 | 96 | mxSweepChunk(theSlot->value.arrayBuffer.address, txByte*); |
2166 | 128 | break; |
2167 | 0 | case XS_CODE_KIND: |
2168 | 0 | mxSweepChunk(theSlot->value.code.address, txByte*); |
2169 | 0 | break; |
2170 | 3.89k | case XS_GLOBAL_KIND: |
2171 | 3.89k | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2172 | 3.89k | break; |
2173 | 3.98k | case XS_HOST_KIND: |
2174 | 3.98k | if (theSlot->value.host.data) { |
2175 | 95 | if (theSlot->flag & XS_HOST_CHUNK_FLAG) |
2176 | 95 | mxSweepChunk(theSlot->value.host.data, void*); |
2177 | 95 | } |
2178 | 3.98k | break; |
2179 | 0 | case XS_IDS_KIND: |
2180 | 0 | if (theSlot->value.IDs) |
2181 | 0 | mxSweepChunk(theSlot->value.IDs, txID*); |
2182 | 0 | break; |
2183 | 0 | case XS_REGEXP_KIND: |
2184 | 0 | if (theSlot->value.regexp.code) |
2185 | 0 | mxSweepChunk(theSlot->value.regexp.code, void*); |
2186 | 0 | if (theSlot->value.regexp.data) |
2187 | 0 | mxSweepChunk(theSlot->value.regexp.data, void*); |
2188 | 0 | break; |
2189 | 2.16M | case XS_KEY_KIND: |
2190 | 2.16M | if (theSlot->value.key.string) |
2191 | 2.16M | mxSweepChunk(theSlot->value.key.string, txString); |
2192 | 2.16M | break; |
2193 | 0 | case XS_MAP_KIND: |
2194 | 0 | case XS_SET_KIND: |
2195 | 0 | mxSweepChunk(theSlot->value.table.address, txSlot**); |
2196 | 0 | break; |
2197 | 219M | } |
2198 | 219M | } |