Coverage Report

Created: 2025-10-10 06:16

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