Coverage Report

Created: 2026-10-17 07:17

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