Coverage Report

Created: 2026-08-31 06:30

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