Coverage Report

Created: 2026-01-17 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsMapSet.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2023  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 mxTableMinLength
41
1.91M
  #define mxTableMinLength (1)
42
#endif
43
#ifndef mxTableMaxLength
44
3.39M
  #define mxTableMaxLength (1024 * 1024)
45
#endif
46
23.5M
#define mxTableThreshold(LENGTH) (((LENGTH) >> 1) + ((LENGTH) >> 2))
47
48
static txSlot* fxCheckMapInstance(txMachine* the, txSlot* slot, txBoolean mutable);
49
static txSlot* fxCheckMapKey(txMachine* the);
50
static txSlot* fxNewMapIteratorInstance(txMachine* the, txSlot* iterable, txInteger kind);
51
52
static txSlot* fxCheckSetInstance(txMachine* the, txSlot* slot, txBoolean mutable);
53
static txSlot* fxCheckSetValue(txMachine* the);
54
55
static void fxNewSetResult(txMachine* the, txSlot* table, txSlot* list, txSlot** tableAddress, txSlot** listAddress);
56
static txSlot* fxCheckSetRecord(txMachine* the, txInteger* otherSize, txSlot** otherHas, txSlot** otherKeys);
57
static txBoolean fxSetRecordHas(txMachine* the, txSlot* other, txSlot* otherHas, txSlot* value);
58
static void fxSetRecordKeys(txMachine* the, txSlot* other, txSlot* otherKeys, txSlot** iterator, txSlot** next, txSlot** value);
59
60
static txSlot* fxNewSetIteratorInstance(txMachine* the, txSlot* iterable, txInteger kind);
61
62
static txSlot* fxCanonicalizeKeyedCollectionKey(txSlot* key);
63
static void fxClearEntries(txMachine* the, txSlot* table, txSlot* list, txBoolean paired);
64
static txBoolean fxDeleteEntry(txMachine* the, txSlot* table, txSlot* list, txSlot* slot, txBoolean paired, txBoolean fit); 
65
static txSlot* fxGetEntry(txMachine* the, txSlot* table, txSlot* slot);
66
static void fxPurgeEntries(txMachine* the, txSlot* list);
67
static void fxResizeEntries(txMachine* the, txSlot* table, txSlot* list);
68
static void fxSetEntry(txMachine* the, txSlot* table, txSlot* list, txSlot* slot, txSlot* pair); 
69
static txBoolean fxTestEntry(txMachine* the, txSlot* a, txSlot* b);
70
71
static txSlot* fxCanBeHeldWeakly(txMachine* the, txSlot* slot);
72
73
static txSlot* fxCheckWeakMapInstance(txMachine* the, txSlot* slot, txBoolean mutable);
74
static txSlot* fxCheckWeakMapKey(txMachine* the, txBoolean mutable);
75
76
static txSlot* fxCheckWeakSetInstance(txMachine* the, txSlot* slot, txBoolean mutable);
77
static txSlot* fxCheckWeakSetValue(txMachine* the, txBoolean mutable);
78
79
static txBoolean fxDeleteWeakEntry(txMachine* the, txSlot* link, txSlot* slot); 
80
static txSlot* fxGetWeakEntry(txMachine* the, txSlot* link, txSlot* slot);
81
static void fxSetWeakEntry(txMachine* the, txSlot* link, txSlot* slot, txSlot* pair); 
82
83
static void fxKeepDuringJobs(txMachine* the, txSlot* target);
84
static txSlot* fxNewWeakRefInstance(txMachine* the);
85
86
static void fx_FinalizationRegistryCleanup(txMachine* the, txSlot* registry, txSlot* callback);
87
88
void fxBuildMapSet(txMachine* the)
89
33.0k
{
90
33.0k
  txSlot* slot;
91
33.0k
  txSlot* property;
92
  
93
  /* MAP */
94
33.0k
  mxPush(mxObjectPrototype);
95
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
96
33.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_Map_prototype_size), C_NULL, mxID(_size), XS_DONT_ENUM_FLAG);
97
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_clear), 0, mxID(_clear), XS_DONT_ENUM_FLAG);
98
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_delete), 1, mxID(_delete), XS_DONT_ENUM_FLAG);
99
33.0k
  property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_entries), 0, mxID(_entries), XS_DONT_ENUM_FLAG);
100
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_forEach), 1, mxID(_forEach), XS_DONT_ENUM_FLAG);
101
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_get), 1, mxID(_get), XS_DONT_ENUM_FLAG);
102
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_has), 1, mxID(_has), XS_DONT_ENUM_FLAG);
103
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_keys), 0, mxID(_keys), XS_DONT_ENUM_FLAG);
104
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_set), 2, mxID(_set), XS_DONT_ENUM_FLAG);
105
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_prototype_values), 0, mxID(_values), XS_DONT_ENUM_FLAG);
106
33.0k
  slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_iterator), XS_DONT_ENUM_FLAG);
107
33.0k
  slot = fxNextStringXProperty(the, slot, "Map", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
108
33.0k
  mxMapPrototype = *the->stack;
109
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Map), 0, mxID(_Map));
110
33.0k
  mxMapConstructor = *the->stack;
111
33.0k
  slot = fxLastProperty(the, slot);
112
33.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
113
33.0k
#if mxECMAScript2024
114
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Map_groupBy), 2, mxID(_groupBy), XS_DONT_ENUM_FLAG);
115
33.0k
#endif
116
33.0k
  mxPop();
117
  
118
33.0k
  mxPush(mxIteratorPrototype);
119
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
120
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_MapIterator_prototype_next), 0, mxID(_next), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG);
121
33.0k
  slot = fxNextStringXProperty(the, slot, "Map Iterator", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
122
33.0k
  mxPull(mxMapIteratorPrototype);
123
  
124
  /* SET */
125
33.0k
  mxPush(mxObjectPrototype);
126
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
127
33.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_Set_prototype_size), C_NULL, mxID(_size), XS_DONT_ENUM_FLAG);
128
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_add), 1, mxID(_add), XS_DONT_ENUM_FLAG);
129
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_clear), 0, mxID(_clear), XS_DONT_ENUM_FLAG);
130
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_delete), 1, mxID(_delete), XS_DONT_ENUM_FLAG);
131
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_entries), 0, mxID(_entries), XS_DONT_ENUM_FLAG);
132
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_forEach), 1, mxID(_forEach), XS_DONT_ENUM_FLAG);
133
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_has), 1, mxID(_has), XS_DONT_ENUM_FLAG);
134
33.0k
  property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_values), 0, mxID(_values), XS_DONT_ENUM_FLAG);
135
33.0k
  slot = fxNextSlotProperty(the, slot, property, mxID(_keys), XS_DONT_ENUM_FLAG);
136
33.0k
  slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_iterator), XS_DONT_ENUM_FLAG);
137
33.0k
  slot = fxNextStringXProperty(the, slot, "Set", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
138
33.0k
#if mxECMAScript2025
139
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_difference), 1, mxID(_difference), XS_DONT_ENUM_FLAG);
140
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_intersection), 1, mxID(_intersection), XS_DONT_ENUM_FLAG);
141
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_isDisjointFrom), 1, mxID(_isDisjointFrom), XS_DONT_ENUM_FLAG);
142
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_isSubsetOf), 1, mxID(_isSubsetOf), XS_DONT_ENUM_FLAG);
143
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_isSupersetOf), 1, mxID(_isSupersetOf), XS_DONT_ENUM_FLAG);
144
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_symmetricDifference), 1, mxID(_symmetricDifference), XS_DONT_ENUM_FLAG);
145
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Set_prototype_union), 1, mxID(_union), XS_DONT_ENUM_FLAG);
146
33.0k
#endif
147
33.0k
  mxSetPrototype = *the->stack;
148
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Set), 0, mxID(_Set));
149
33.0k
  mxSetConstructor = *the->stack;
150
33.0k
  slot = fxLastProperty(the, slot);
151
33.0k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
152
33.0k
  mxPop();
153
  
154
33.0k
  mxPush(mxIteratorPrototype);
155
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
156
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_SetIterator_prototype_next), 0, mxID(_next), XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG);
157
33.0k
  slot = fxNextStringXProperty(the, slot, "Set Iterator", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
158
33.0k
  mxPull(mxSetIteratorPrototype);
159
160
  /* WEAK MAP */
161
33.0k
  mxPush(mxObjectPrototype);
162
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
163
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakMap_prototype_delete), 1, mxID(_delete), XS_DONT_ENUM_FLAG);
164
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakMap_prototype_get), 1, mxID(_get), XS_DONT_ENUM_FLAG);
165
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakMap_prototype_has), 1, mxID(_has), XS_DONT_ENUM_FLAG);
166
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakMap_prototype_set), 2, mxID(_set), XS_DONT_ENUM_FLAG);
167
33.0k
  slot = fxNextStringXProperty(the, slot, "WeakMap", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
168
33.0k
  mxWeakMapPrototype = *the->stack;
169
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_WeakMap), 0, mxID(_WeakMap));
170
33.0k
  mxWeakMapConstructor = *the->stack;
171
33.0k
  mxPop();
172
  
173
  /* WEAK SET */
174
33.0k
  mxPush(mxObjectPrototype);
175
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
176
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakSet_prototype_add), 1, mxID(_add), XS_DONT_ENUM_FLAG);
177
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakSet_prototype_delete), 1, mxID(_delete), XS_DONT_ENUM_FLAG);
178
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakSet_prototype_has), 1, mxID(_has), XS_DONT_ENUM_FLAG);
179
33.0k
  slot = fxNextStringXProperty(the, slot, "WeakSet", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
180
33.0k
  mxWeakSetPrototype = *the->stack;
181
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_WeakSet), 0, mxID(_WeakSet));
182
33.0k
  mxWeakSetConstructor = *the->stack;
183
33.0k
  mxPop();
184
  
185
  /* WEAK REF */
186
33.0k
  mxPush(mxObjectPrototype);
187
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
188
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_WeakRef_prototype_deref), 0, mxID(_deref), XS_DONT_ENUM_FLAG);
189
33.0k
  slot = fxNextStringXProperty(the, slot, "WeakRef", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
190
33.0k
  mxWeakRefPrototype = *the->stack;
191
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_WeakRef), 1, mxID(_WeakRef));
192
33.0k
  mxWeakRefConstructor = *the->stack;
193
33.0k
  mxPop();
194
  
195
  /* FINALIZATION REGISTRY */
196
33.0k
  mxPush(mxObjectPrototype);
197
33.0k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
198
//  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_FinalizationRegistry_prototype_cleanupSome), 0, mxID(_cleanupSome), XS_DONT_ENUM_FLAG);
199
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_FinalizationRegistry_prototype_register), 2, mxID(_register), XS_DONT_ENUM_FLAG);
200
33.0k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_FinalizationRegistry_prototype_unregister), 1, mxID(_unregister), XS_DONT_ENUM_FLAG);
201
33.0k
  slot = fxNextStringXProperty(the, slot, "FinalizationRegistry", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
202
33.0k
  mxFinalizationRegistryPrototype = *the->stack;
203
33.0k
  slot = fxBuildHostConstructor(the, mxCallback(fx_FinalizationRegistry), 1, mxID(_FinalizationRegistry));
204
33.0k
  mxFinalizationRegistryConstructor = *the->stack;
205
33.0k
  mxPop();
206
33.0k
}
207
208
txSlot* fxCheckMapInstance(txMachine* the, txSlot* slot, txBoolean mutable)
209
4.12k
{
210
4.12k
  if (slot->kind == XS_REFERENCE_KIND) {
211
3.94k
    txSlot* instance = slot->value.reference;
212
3.94k
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_MAP_KIND) && (instance != mxMapPrototype.value.reference)) {
213
3.52k
      if (mutable && (slot->flag & XS_DONT_SET_FLAG))
214
0
        mxTypeError("this: read-only Map instance");
215
3.52k
      return instance;
216
3.52k
    }
217
3.94k
  }
218
4.12k
  mxTypeError("this: not a Map instance");
219
0
  return C_NULL;
220
4.12k
}
221
222
txSlot* fxCheckMapKey(txMachine* the)
223
3.15k
{
224
3.15k
  if (mxArgc > 0) {
225
3.15k
    txSlot* slot = mxArgv(0);
226
3.15k
    return slot;
227
3.15k
  }
228
3.15k
  mxTypeError("no key");
229
0
  return C_NULL;
230
3.15k
}
231
232
txSlot* fxNewMapInstance(txMachine* the)
233
340k
{
234
340k
  txSlot* map;
235
340k
  txSlot* table;
236
340k
  txSlot* list;
237
340k
  txSlot* size;
238
340k
  txSlot** address;
239
340k
  map = fxNewSlot(the);
240
340k
  map->kind = XS_INSTANCE_KIND;
241
340k
  map->value.instance.garbage = C_NULL;
242
340k
  map->value.instance.prototype = the->stack->value.reference;
243
340k
  the->stack->kind = XS_REFERENCE_KIND;
244
340k
  the->stack->value.reference = map;
245
340k
  table = map->next = fxNewSlot(the);
246
340k
  list = table->next = fxNewSlot(the);
247
340k
  size = list->next = fxNewSlot(the);
248
340k
  address = (txSlot**)fxNewChunk(the, mxTableMinLength * sizeof(txSlot*));
249
340k
  c_memset(address, 0, mxTableMinLength * sizeof(txSlot*));
250
  /* TABLE */
251
340k
  table->flag = XS_INTERNAL_FLAG;
252
340k
  table->kind = XS_MAP_KIND;
253
340k
  table->value.table.address = address;
254
340k
  table->value.table.length = mxTableMinLength;
255
  /* LIST */
256
340k
  list->flag = XS_INTERNAL_FLAG;
257
340k
  list->kind = XS_LIST_KIND;
258
340k
  list->value.list.first = C_NULL;
259
340k
  list->value.list.last = C_NULL;
260
  /* SIZE */
261
340k
  size->flag = XS_INTERNAL_FLAG;
262
340k
  size->kind = XS_INTEGER_KIND;
263
340k
  size->value.integer = 0;
264
340k
  return map;
265
340k
}
266
267
void fx_Map(txMachine* the)
268
340k
{
269
340k
  txSlot *function, *iterable, *iterator, *next, *value;
270
340k
  if (mxIsUndefined(mxTarget))
271
75
    mxTypeError("call: Map");
272
340k
  mxPushSlot(mxTarget);
273
340k
  fxGetPrototypeFromConstructor(the, &mxMapPrototype);
274
340k
  fxNewMapInstance(the);
275
340k
  mxPullSlot(mxResult);
276
340k
  if (mxArgc < 1)
277
339k
    return;
278
815
  iterable = mxArgv(0);
279
815
  if ((iterable->kind == XS_UNDEFINED_KIND) || (iterable->kind == XS_NULL_KIND))
280
6
    return;
281
809
  mxPushSlot(mxResult);
282
809
  mxGetID(mxID(_set)); 
283
809
  function = the->stack;  
284
809
  if (!fxIsCallable(the, function))  
285
1
    mxTypeError("result.set: not a function");
286
808
  mxTemporary(iterator);
287
808
  mxTemporary(next);
288
808
  fxGetIterator(the, iterable, iterator, next, 0);  
289
808
  mxTemporary(value);
290
2.93k
  while (fxIteratorNext(the, iterator, next, value)) {
291
2.16k
    mxTry(the) {
292
2.16k
      if (value->kind != XS_REFERENCE_KIND)
293
22
        mxTypeError("item: not an object");
294
2.14k
      mxPushSlot(mxResult);
295
2.14k
      mxPushSlot(function);
296
2.14k
      mxCall();
297
2.14k
      mxPushSlot(value);
298
2.14k
      mxGetIndex(0);
299
2.14k
      mxPushSlot(value);
300
2.14k
      mxGetIndex(1);
301
2.14k
      mxRunCount(2);
302
2.14k
      mxPop();
303
2.14k
    }
304
2.14k
    mxCatch(the) {
305
22
      fxIteratorReturn(the, iterator, 1);
306
22
      fxJump(the);
307
22
    }
308
2.16k
  }
309
808
}
310
311
static void fx_Map_groupByAux(txMachine* the)
312
2.27k
{
313
2.27k
  txSlot* instance = mxResult->value.reference;
314
2.27k
  txSlot* table = instance->next;
315
2.27k
  txSlot* list = table->next;
316
2.27k
  txSlot* key = the->stack;
317
2.27k
  txSlot* entry = fxGetEntry(the, table, key);
318
2.27k
  if (entry)
319
2.05k
    mxPushSlot(entry->next);
320
219
  else {
321
219
    mxPush(mxArrayPrototype);
322
219
    fxNewArrayInstance(the);
323
219
    fxSetEntry(the, table, list, key, the->stack);
324
219
  }
325
2.27k
}
326
327
void fx_Map_groupBy(txMachine* the)
328
46
{
329
46
  txSlot *instance, *key, *value;
330
46
  mxPush(mxMapPrototype);
331
46
  instance = fxNewMapInstance(the);
332
46
  mxPullSlot(mxResult);
333
46
  fxGroupBy(the, fx_Map_groupByAux);
334
46
  key = instance->next->next->value.list.first;
335
265
  while (key) {
336
219
    value = key->next;
337
219
    fxCacheArray(the, value->value.reference);
338
219
    key = value->next;
339
219
  }
340
46
}
341
342
void fx_Map_prototype_clear(txMachine* the)
343
347
{
344
347
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_MUTABLE);
345
347
  txSlot* table = instance->next;
346
347
  txSlot* list = table->next;
347
347
  fxClearEntries(the, table, list, 1);
348
347
}
349
350
void fx_Map_prototype_delete(txMachine* the)
351
138
{
352
138
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_MUTABLE);
353
138
  txSlot* table = instance->next;
354
138
  txSlot* list = table->next;
355
138
  txSlot* key = fxCheckMapKey(the);
356
138
  mxResult->value.boolean = fxDeleteEntry(the, table, list, key, 1, 1);
357
138
  mxResult->kind = XS_BOOLEAN_KIND;
358
138
}
359
360
void fx_Map_prototype_entries(txMachine* the)
361
104
{
362
104
  fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
363
104
  fxNewMapIteratorInstance(the, mxThis, 2);
364
104
}
365
366
void fx_Map_prototype_forEach(txMachine* the)
367
46
{
368
46
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
369
46
  txSlot* table = instance->next;
370
46
  txSlot* list = table->next;
371
46
  txSlot* function = fxArgToCallback(the, 0);
372
46
  txSlot* key;
373
46
  txSlot* value;
374
46
  mxPushList();
375
46
  key = the->stack->value.list.first = list->value.list.first;
376
67
  while (key) {
377
21
    value = key->next;
378
21
    if (!(key->flag & XS_DONT_ENUM_FLAG)) {
379
      /* THIS */
380
21
      if (mxArgc > 1)
381
6
        mxPushSlot(mxArgv(1));
382
15
      else
383
15
        mxPushUndefined();
384
      /* FUNCTION */
385
21
      mxPushSlot(function);
386
21
      mxCall();
387
      /* ARGUMENTS */
388
21
      mxPushSlot(value);
389
21
      mxPushSlot(key);
390
21
      mxPushSlot(mxThis);
391
21
      mxRunCount(3);
392
21
      mxPop();
393
21
    }
394
21
    key = the->stack->value.list.first = value->next;
395
21
  }
396
46
  mxPop();
397
46
}
398
399
void fx_Map_prototype_get(txMachine* the)
400
291
{
401
291
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
402
291
  txSlot* table = instance->next;
403
291
  txSlot* key = fxCheckMapKey(the);
404
291
  txSlot* result = fxGetEntry(the, table, key);
405
291
  if (result) {
406
203
    txSlot* value = result->next;
407
203
    mxResult->kind = value->kind;
408
203
    mxResult->value = value->value;
409
203
  }
410
291
}
411
412
void fx_Map_prototype_has(txMachine* the)
413
360
{
414
360
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
415
360
  txSlot* table = instance->next;
416
360
  txSlot* key = fxCheckMapKey(the);
417
360
  txSlot* result = fxGetEntry(the, table, key);
418
360
  mxResult->kind = XS_BOOLEAN_KIND;
419
360
  mxResult->value.boolean = (result) ? 1 : 0;
420
360
}
421
422
void fx_Map_prototype_keys(txMachine* the)
423
49
{
424
49
  fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
425
49
  fxNewMapIteratorInstance(the, mxThis, 0);
426
49
}
427
428
void fx_Map_prototype_set(txMachine* the)
429
2.45k
{
430
2.45k
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_MUTABLE);
431
2.45k
  txSlot* table = instance->next;
432
2.45k
  txSlot* list = table->next;
433
2.45k
  txSlot* key = fxCheckMapKey(the);
434
2.45k
  fxSetEntry(the, table, list, key, (mxArgc > 1) ? mxArgv(1) : &mxUndefined);
435
2.45k
  *mxResult = *mxThis;
436
2.45k
}
437
438
void fx_Map_prototype_size(txMachine* the)
439
288
{
440
288
  txSlot* instance = fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
441
288
  txSlot* table = instance->next;
442
288
  txSlot* list = table->next;
443
288
  mxResult->kind = XS_INTEGER_KIND;
444
288
  mxResult->value.integer = list->next->value.integer;
445
288
}
446
447
void fx_Map_prototype_values(txMachine* the)
448
45
{
449
45
  fxCheckMapInstance(the, mxThis, XS_IMMUTABLE);
450
45
  fxNewMapIteratorInstance(the, mxThis, 1);
451
45
}
452
453
txSlot* fxNewMapIteratorInstance(txMachine* the, txSlot* iterable, txInteger kind) 
454
49
{
455
49
  txSlot* instance;
456
49
  txSlot* property;
457
49
  mxPush(mxMapIteratorPrototype);
458
49
  instance = fxNewIteratorInstance(the, iterable, mxID(_Map));
459
49
  property = fxLastProperty(the, instance);
460
49
  property->kind = XS_LIST_KIND;
461
49
  property->value.list.first = C_NULL;
462
49
  property->value.list.last = C_NULL;
463
49
  property = fxNextIntegerProperty(the, property, kind, XS_NO_ID, XS_INTERNAL_FLAG);
464
49
  mxPullSlot(mxResult);
465
49
  return instance;
466
49
}
467
468
void fx_MapIterator_prototype_next(txMachine* the)
469
72
{
470
72
  txSlot* iterator = fxCheckIteratorInstance(the, mxThis, mxID(_Map));
471
72
  txSlot* result = iterator->next;
472
72
  txSlot* iterable = result->next;
473
72
  mxResult->kind = result->kind;
474
72
  mxResult->value = result->value;
475
72
  result = fxCheckIteratorResult(the, result);
476
72
  if (result->next->value.boolean == 0) {
477
59
    txSlot* list = iterable->next;
478
59
    txInteger kind = list->next->value.integer;
479
59
    txSlot* key = list->value.list.first;
480
59
    if (key)
481
22
      key = key->next->next;
482
37
    else
483
37
      key = iterable->value.reference->next->next->value.list.first;
484
61
    while (key && (key->flag & XS_DONT_ENUM_FLAG))
485
2
      key = key->next->next;
486
59
    if (key) {
487
44
      txSlot* value = key->next;
488
44
      if (kind == 2) {
489
22
        mxPushSlot(key);
490
22
        mxPushSlot(value);
491
22
        fxConstructArrayEntry(the, result);
492
22
      }
493
22
      else if (kind == 1) {
494
6
        result->kind = value->kind;
495
6
        result->value = value->value;
496
6
      }
497
16
      else {
498
16
        result->kind = key->kind;
499
16
        result->value = key->value;
500
16
      }
501
44
      list->value.list.first = key;
502
44
    }
503
15
    else {
504
15
      result->kind = XS_UNDEFINED_KIND;
505
15
      result->next->value.boolean = 1;
506
15
      list->value.list.first = C_NULL;
507
15
    }
508
59
  }
509
72
}
510
511
txSlot* fxCheckSetInstance(txMachine* the, txSlot* slot, txBoolean mutable)
512
21.6M
{
513
21.6M
  if (slot->kind == XS_REFERENCE_KIND) {
514
21.6M
    txSlot* instance = slot->value.reference;
515
21.6M
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_SET_KIND) && (instance != mxSetPrototype.value.reference)) {
516
21.6M
      if (mutable && (slot->flag & XS_DONT_SET_FLAG))
517
0
        mxTypeError("this: read-only Set instance");
518
21.6M
      return instance;
519
21.6M
    }
520
21.6M
  }
521
21.6M
  mxTypeError("this: not a Set instance");
522
0
  return C_NULL;
523
21.6M
}
524
525
txSlot* fxCheckSetValue(txMachine* the)
526
21.3M
{
527
21.3M
  if (mxArgc > 0) {
528
21.3M
    txSlot* slot = mxArgv(0);
529
21.3M
    return slot;
530
21.3M
  }
531
21.3M
  mxTypeError("no value");
532
0
  return C_NULL;
533
21.3M
}
534
535
txSlot* fxCheckSetRecord(txMachine* the, txInteger* otherSize, txSlot** otherHas, txSlot** otherKeys)
536
114k
{
537
114k
  txSlot* other;
538
114k
  txNumber size;
539
114k
  if (mxArgc < 1)
540
1
    mxTypeError("other is no object");
541
114k
  other = mxArgv(0);  
542
114k
  if (!mxIsReference(other))
543
54
    mxTypeError("other is no object");
544
    
545
114k
  mxPushSlot(other);
546
114k
  mxGetID(mxID(_size));  
547
114k
  size = fxToNumber(the, the->stack);
548
114k
  if (c_isnan(size))
549
11
    mxTypeError("other.size is NaN");
550
114k
  size = c_trunc(size);
551
114k
  if (size < 0)
552
0
    mxRangeError("other.size < 0");
553
114k
  if (otherSize)
554
114k
    *otherSize= (txInteger)size;
555
114k
  mxPop();
556
  
557
114k
  mxPushSlot(other);
558
114k
  mxGetID(mxID(_has));
559
114k
  if (!fxIsCallable(the, the->stack))
560
3
    mxTypeError("other.has is no function");
561
114k
  if (otherHas)
562
114k
    *otherHas = the->stack;
563
      
564
114k
  mxPushSlot(other);
565
114k
  mxGetID(mxID(_keys));
566
114k
  if (!fxIsCallable(the, the->stack))
567
3
    mxTypeError("other.keys is no function");
568
114k
  if (otherKeys)
569
177
    *otherKeys = the->stack;
570
    
571
114k
  return other;
572
114k
}
573
574
txSlot* fxNewSetInstance(txMachine* the, txInteger tableLength)
575
892k
{
576
892k
  txSlot* set;
577
892k
  txSlot* table;
578
892k
  txSlot* list;
579
892k
  txSlot* size;
580
892k
  txSlot** address;
581
892k
  set = fxNewSlot(the);
582
892k
  set->kind = XS_INSTANCE_KIND;
583
892k
  set->value.instance.garbage = C_NULL;
584
892k
  set->value.instance.prototype = the->stack->value.reference;
585
892k
  the->stack->kind = XS_REFERENCE_KIND;
586
892k
  the->stack->value.reference = set;
587
892k
  table = set->next = fxNewSlot(the);
588
892k
  list = table->next = fxNewSlot(the);
589
892k
  size = list->next = fxNewSlot(the);
590
892k
  address = (txSlot**)fxNewChunk(the, tableLength * sizeof(txSlot*));
591
892k
  c_memset(address, 0, tableLength * sizeof(txSlot*));
592
  /* TABLE */
593
892k
  table->flag = XS_INTERNAL_FLAG;
594
892k
  table->kind = XS_SET_KIND;
595
892k
  table->value.table.address = address;
596
892k
  table->value.table.length = tableLength;
597
  /* LIST */
598
892k
  list->flag = XS_INTERNAL_FLAG;
599
892k
  list->kind = XS_LIST_KIND;
600
892k
  list->value.list.first = C_NULL;
601
892k
  list->value.list.last = C_NULL;
602
  /* SIZE */
603
892k
  size->flag = XS_INTERNAL_FLAG;
604
892k
  size->kind = XS_INTEGER_KIND;
605
892k
  size->value.integer = 0;
606
892k
  return set;
607
892k
}
608
609
void fxNewSetResult(txMachine* the, txSlot* table, txSlot* list, txSlot** tableAddress, txSlot** listAddress)
610
112
{
611
112
  txSlot *resultInstance, *resultTable, *resultList, *value;
612
112
  mxPush(mxSetPrototype);
613
112
  resultInstance = fxNewSetInstance(the, (list) ? table->value.table.length : mxTableMinLength);
614
112
  mxPullSlot(mxResult);
615
112
  resultTable = resultInstance->next;
616
112
  resultList = resultTable->next;
617
112
  if (list) {
618
85
    value = list->value.list.first;
619
373
    while (value) {
620
288
      fxSetEntry(the, resultTable, resultList, value, C_NULL);
621
288
      value = value->next;
622
288
    }  
623
85
  }  
624
112
  *tableAddress = resultTable;
625
112
  *listAddress = resultList;
626
112
}
627
628
txBoolean fxSetRecordHas(txMachine* the, txSlot* other, txSlot* otherHas, txSlot* value)
629
114k
{
630
114k
  txBoolean result;
631
114k
  mxPushSlot(other);
632
114k
  mxPushSlot(otherHas);
633
114k
  mxCall();
634
114k
  mxPushSlot(value);
635
114k
  mxRunCount(1);
636
114k
  result = fxToBoolean(the, the->stack);
637
114k
  mxPop();
638
114k
  return result;
639
114k
}
640
641
void fxSetRecordKeys(txMachine* the, txSlot* other, txSlot* otherKeys, txSlot** iterator, txSlot** next, txSlot** value)
642
117
{
643
117
  mxPushSlot(other);
644
117
  mxPushSlot(otherKeys);
645
117
  mxCall();
646
117
  mxRunCount(0);
647
117
  *iterator = the->stack;
648
117
  mxDub();
649
117
  mxGetID(mxID(_next));
650
117
  *next = the->stack;
651
117
  mxPushUndefined();
652
117
  *value = the->stack;
653
117
}
654
655
void fx_Set(txMachine* the)
656
892k
{
657
892k
  txSlot *function, *iterable, *iterator, *next, *value;
658
892k
  if (mxIsUndefined(mxTarget))
659
17
    mxTypeError("call: Set");
660
892k
  mxPushSlot(mxTarget);
661
892k
  fxGetPrototypeFromConstructor(the, &mxSetPrototype);
662
892k
  fxNewSetInstance(the, mxTableMinLength);
663
892k
  mxPullSlot(mxResult);
664
892k
  if (mxArgc < 1)
665
188
    return;
666
892k
  iterable = mxArgv(0);
667
892k
  if ((iterable->kind == XS_UNDEFINED_KIND) || (iterable->kind == XS_NULL_KIND))
668
124k
    return;
669
767k
  mxPushSlot(mxResult);
670
767k
  mxGetID(mxID(_add)); 
671
767k
  function = the->stack;  
672
767k
  if (!fxIsCallable(the, function))  
673
1
    mxTypeError("result.add: not a function");
674
767k
  mxTemporary(iterator);
675
767k
  mxTemporary(next);
676
767k
  fxGetIterator(the, iterable, iterator, next, 0);  
677
767k
  mxTemporary(value);
678
21.8M
  while (fxIteratorNext(the, iterator, next, value)) {
679
21.0M
    mxTry(the) {
680
21.0M
      mxPushSlot(mxResult);
681
21.0M
      mxPushSlot(function);
682
21.0M
      mxCall();
683
21.0M
      mxPushSlot(value);
684
21.0M
      mxRunCount(1);
685
21.0M
      mxPop();
686
21.0M
    }
687
21.0M
    mxCatch(the) {
688
1
      fxIteratorReturn(the, iterator, 1);
689
1
      fxJump(the);
690
1
    }
691
21.0M
  }
692
767k
}
693
694
void fx_Set_prototype_add(txMachine* the)
695
21.1M
{
696
21.1M
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_MUTABLE);
697
21.1M
  txSlot* table = instance->next;
698
21.1M
  txSlot* list = table->next;
699
21.1M
  txSlot* value = fxCheckSetValue(the);
700
21.1M
  fxSetEntry(the, table, list, value, C_NULL);
701
21.1M
  *mxResult = *mxThis;
702
21.1M
}
703
704
void fx_Set_prototype_clear(txMachine* the)
705
28
{
706
28
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_MUTABLE);
707
28
  txSlot* table = instance->next;
708
28
  txSlot* list = table->next;
709
28
  fxClearEntries(the, table, list, 0);
710
28
}
711
712
void fx_Set_prototype_delete(txMachine* the)
713
125k
{
714
125k
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_MUTABLE);
715
125k
  txSlot* table = instance->next;
716
125k
  txSlot* list = table->next;
717
125k
  txSlot* value = fxCheckSetValue(the);
718
125k
  mxResult->value.boolean = fxDeleteEntry(the, table, list, value, 0, 1);
719
125k
  mxResult->kind = XS_BOOLEAN_KIND;
720
125k
}
721
722
void fx_Set_prototype_difference(txMachine* the)
723
100
{
724
100
  txSlot* stack = the->stack;
725
100
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
726
100
  txSlot* table = instance->next;
727
100
  txSlot* list = table->next;
728
100
  txInteger size = list->next->value.integer, otherSize;
729
100
  txSlot *otherHas, *otherKeys, *resultTable, *resultList, *iterator, *next, *value;
730
100
  txSlot *other = fxCheckSetRecord(the, &otherSize, &otherHas, &otherKeys);
731
100
  fxNewSetResult(the, table, list, &resultTable, &resultList);
732
100
  if (size <= otherSize) {
733
31
    mxPushList();
734
31
    value = the->stack->value.list.first = list->value.list.first;
735
120
    while (value) {
736
89
      if (!(value->flag & XS_DONT_ENUM_FLAG)) {
737
89
        if (fxSetRecordHas(the, other, otherHas, value))
738
53
          fxDeleteEntry(the, resultTable, resultList, value, 0, 0);
739
89
      }
740
89
      value = the->stack->value.list.first = value->next;
741
89
    }
742
31
  }
743
69
  else {
744
69
    fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
745
145k
    while (fxIteratorNext(the, iterator, next, value)) {
746
145k
      fxCanonicalizeKeyedCollectionKey(value);
747
145k
      fxDeleteEntry(the, resultTable, resultList, value, 0, 0);
748
145k
    }
749
69
  }
750
100
  fxResizeEntries(the, resultTable, resultList);
751
100
  fxPurgeEntries(the, resultList);
752
100
  the->stack = stack;
753
100
}
754
755
void fx_Set_prototype_entries(txMachine* the)
756
25
{
757
25
  fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
758
25
  fxNewSetIteratorInstance(the, mxThis, 2);
759
25
}
760
761
void fx_Set_prototype_forEach(txMachine* the)
762
24
{
763
24
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
764
24
  txSlot* table = instance->next;
765
24
  txSlot* list = table->next;
766
24
  txSlot* function = fxArgToCallback(the, 0);
767
24
  txSlot* value;
768
24
  mxPushList();
769
24
  value = the->stack->value.list.first = list->value.list.first;
770
44
  while (value) {
771
20
    if (!(value->flag & XS_DONT_ENUM_FLAG)) {
772
      /* THIS */
773
20
      if (mxArgc > 1)
774
2
        mxPushSlot(mxArgv(1));
775
18
      else
776
18
        mxPushUndefined();
777
      /* FUNCTION */
778
20
      mxPushSlot(function);
779
20
      mxCall();
780
      /* ARGUMENTS */
781
20
      mxPushSlot(value);
782
20
      mxPushSlot(value);
783
20
      mxPushSlot(mxThis);
784
20
      mxRunCount(3);
785
20
      mxPop();
786
20
    }
787
20
    value = the->stack->value.list.first = value->next;
788
20
  }
789
24
  mxPop();
790
24
}
791
792
void fx_Set_prototype_has(txMachine* the)
793
114k
{
794
114k
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
795
114k
  txSlot* table = instance->next;
796
114k
  txSlot* value = fxCheckSetValue(the);
797
114k
  txSlot* result = fxGetEntry(the, table, value);
798
114k
  mxResult->kind = XS_BOOLEAN_KIND;
799
114k
  mxResult->value.boolean = (result) ? 1 : 0;
800
114k
}
801
802
void fx_Set_prototype_intersection(txMachine* the)
803
108
{
804
108
  txSlot* stack = the->stack;
805
108
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
806
108
  txSlot* table = instance->next;
807
108
  txSlot* list = table->next;
808
108
  txInteger size = list->next->value.integer, otherSize;
809
108
  txSlot *otherHas, *otherKeys, *resultTable, *resultList, *iterator, *next, *value;
810
108
  txSlot *other = fxCheckSetRecord(the, &otherSize, &otherHas, &otherKeys);
811
108
  fxNewSetResult(the, table, C_NULL, &resultTable, &resultList);
812
108
  if (size <= otherSize) {
813
10
    mxPushList();
814
10
    value = the->stack->value.list.first = list->value.list.first;
815
19
    while (value) {
816
9
      if (!(value->flag & XS_DONT_ENUM_FLAG)) {
817
9
        if (fxSetRecordHas(the, other, otherHas, value))
818
6
          fxSetEntry(the, resultTable, resultList, value, C_NULL);
819
9
      }
820
9
      value = the->stack->value.list.first = value->next;
821
9
    }
822
10
  }
823
98
  else {
824
98
    fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
825
120k
    while (fxIteratorNext(the, iterator, next, value)) {
826
120k
      fxCanonicalizeKeyedCollectionKey(value);
827
120k
      if (fxGetEntry(the, table, value))
828
9
        fxSetEntry(the, resultTable, resultList, value, C_NULL);
829
120k
    }
830
98
  }
831
108
  the->stack = stack;
832
108
}
833
834
void fx_Set_prototype_isDisjointFrom(txMachine* the)
835
99
{
836
99
  txSlot* stack = the->stack;
837
99
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
838
99
  txSlot* table = instance->next;
839
99
  txSlot* list = table->next;
840
99
  txInteger size = list->next->value.integer, otherSize;
841
99
  txSlot *otherHas, *otherKeys, *iterator, *next, *value;
842
99
  txSlot *other = fxCheckSetRecord(the, &otherSize, &otherHas, &otherKeys);
843
99
  mxResult->value.boolean = 0;
844
99
  mxResult->kind = XS_BOOLEAN_KIND;
845
99
  if (size <= otherSize) {
846
17
    mxPushList();
847
17
    value = the->stack->value.list.first = list->value.list.first;
848
34
    while (value) {
849
21
      if (!(value->flag & XS_DONT_ENUM_FLAG)) {
850
21
        if (fxSetRecordHas(the, other, otherHas, value))
851
4
          goto bail;
852
21
      }
853
17
      value = the->stack->value.list.first = value->next;
854
17
    }
855
17
  }
856
82
  else {
857
82
    fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
858
364k
    while (fxIteratorNext(the, iterator, next, value)) {
859
364k
      if (fxGetEntry(the, table, value)) {
860
6
        fxIteratorReturn(the, iterator, 0);
861
6
        goto bail;
862
6
      }
863
364k
    }
864
82
  }
865
89
  mxResult->value.boolean = 1;
866
89
bail:
867
38
  the->stack = stack;
868
38
}
869
870
void fx_Set_prototype_isSubsetOf(txMachine* the)
871
114k
{
872
114k
  txSlot* stack = the->stack;
873
114k
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
874
114k
  txSlot* table = instance->next;
875
114k
  txSlot* list = table->next;
876
114k
  txInteger size = list->next->value.integer, otherSize;
877
114k
  txSlot *otherHas, *value;
878
114k
  txSlot *other = fxCheckSetRecord(the, &otherSize, &otherHas, C_NULL);
879
114k
  mxResult->value.boolean = 0;
880
114k
  mxResult->kind = XS_BOOLEAN_KIND;
881
114k
  if (size > otherSize)
882
2
    goto bail;
883
114k
  mxPushList();
884
114k
  value = the->stack->value.list.first = list->value.list.first;
885
228k
  while (value) {
886
114k
    if (!(value->flag & XS_DONT_ENUM_FLAG)) {
887
114k
      if (!fxSetRecordHas(the, other, otherHas, value))
888
5
        goto bail;
889
114k
    }
890
114k
    value = the->stack->value.list.first = value->next;
891
114k
  }
892
114k
  mxResult->value.boolean = 1;
893
114k
bail:
894
114k
  the->stack = stack;
895
114k
}
896
897
void fx_Set_prototype_isSupersetOf(txMachine* the)
898
122
{
899
122
  txSlot* stack = the->stack;
900
122
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
901
122
  txSlot* table = instance->next;
902
122
  txSlot* list = table->next;
903
122
  txInteger size = list->next->value.integer, otherSize;
904
122
  txSlot *otherKeys, *iterator, *next, *value;
905
122
  txSlot *other = fxCheckSetRecord(the, &otherSize, C_NULL, &otherKeys);
906
122
  mxResult->value.boolean = 0;
907
122
  mxResult->kind = XS_BOOLEAN_KIND;
908
122
  if (size < otherSize)
909
2
    goto bail;
910
120
  fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
911
109k
  while (fxIteratorNext(the, iterator, next, value)) {
912
109k
    if (!fxGetEntry(the, table, value)) {
913
10
      fxIteratorReturn(the, iterator, 0);
914
10
      goto bail;
915
10
    }
916
109k
  }
917
110
  mxResult->value.boolean = 1;
918
110
bail:
919
20
  the->stack = stack;
920
20
}
921
922
void fx_Set_prototype_size(txMachine* the)
923
114k
{
924
114k
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
925
114k
  txSlot* table = instance->next;
926
114k
  txSlot* list = table->next;
927
114k
  mxResult->kind = XS_INTEGER_KIND;
928
114k
  mxResult->value.integer = list->next->value.integer;
929
114k
}
930
931
void fx_Set_prototype_symmetricDifference(txMachine* the)
932
76
{
933
76
  txSlot* stack = the->stack;
934
76
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
935
76
  txSlot* table = instance->next;
936
76
  txSlot* list = table->next;
937
76
  txSlot *otherKeys, *resultTable, *resultList, *iterator, *next, *value;
938
76
  txSlot *other = fxCheckSetRecord(the, C_NULL, C_NULL, &otherKeys);
939
76
  fxNewSetResult(the, table, list, &resultTable, &resultList);
940
76
  fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
941
34.4k
  while (fxIteratorNext(the, iterator, next, value)) {
942
34.4k
    fxCanonicalizeKeyedCollectionKey(value);
943
34.4k
    if (fxGetEntry(the, table, value))
944
29
      fxDeleteEntry(the, resultTable, resultList, value, 0, 0);
945
34.3k
    else
946
34.3k
      fxSetEntry(the, resultTable, resultList, value, C_NULL);
947
34.4k
  }
948
76
  fxResizeEntries(the, resultTable, resultList);
949
76
  fxPurgeEntries(the, resultList);
950
76
  the->stack = stack;
951
76
}
952
953
void fx_Set_prototype_union(txMachine* the)
954
84
{
955
84
  txSlot* stack = the->stack;
956
84
  txSlot* instance = fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
957
84
  txSlot* table = instance->next;
958
84
  txSlot* list = table->next;
959
84
  txSlot *otherKeys, *resultTable, *resultList, *iterator, *next, *value;
960
84
  txSlot *other = fxCheckSetRecord(the, C_NULL, C_NULL, &otherKeys);
961
84
  fxNewSetResult(the, table, list, &resultTable, &resultList);
962
84
  fxSetRecordKeys(the, other, otherKeys, &iterator, &next, &value);
963
114
  while (fxIteratorNext(the, iterator, next, value)) {
964
30
    fxCanonicalizeKeyedCollectionKey(value);
965
30
    fxSetEntry(the, resultTable, resultList, value, C_NULL);
966
30
  }
967
84
  the->stack = stack;
968
84
}
969
970
void fx_Set_prototype_values(txMachine* the)
971
297
{
972
297
  fxCheckSetInstance(the, mxThis, XS_IMMUTABLE);
973
297
  fxNewSetIteratorInstance(the, mxThis, 1);
974
297
}
975
976
txSlot* fxNewSetIteratorInstance(txMachine* the, txSlot* iterable, txInteger kind) 
977
189
{
978
189
  txSlot* instance;
979
189
  txSlot* property;
980
189
  mxPush(mxSetIteratorPrototype);
981
189
  instance = fxNewIteratorInstance(the, iterable, mxID(_Set));
982
189
  property = fxLastProperty(the, instance);
983
189
  property->kind = XS_LIST_KIND;
984
189
  property->value.list.first = C_NULL;
985
189
  property->value.list.last = C_NULL;
986
189
  property = fxNextIntegerProperty(the, property, kind, XS_NO_ID, XS_INTERNAL_FLAG);
987
189
  mxPullSlot(mxResult);
988
189
  return instance;
989
189
}
990
991
void fx_SetIterator_prototype_next(txMachine* the)
992
534
{
993
534
  txSlot* iterator = fxCheckIteratorInstance(the, mxThis, mxID(_Set));
994
534
  txSlot* result = iterator->next;
995
534
  txSlot* iterable = result->next;
996
534
  mxResult->kind = result->kind;
997
534
  mxResult->value = result->value;
998
534
  result = fxCheckIteratorResult(the, result);
999
534
  if (result->next->value.boolean == 0) {
1000
499
    txSlot* list = iterable->next;
1001
499
    txInteger kind = list->next->value.integer;
1002
499
    txSlot* value = list->value.list.first;
1003
499
    if (value)
1004
338
      value = value->next;
1005
161
    else
1006
161
      value = iterable->value.reference->next->next->value.list.first;
1007
499
    while (value && (value->flag & XS_DONT_ENUM_FLAG))
1008
0
      value = value->next;
1009
499
    if (value) {
1010
349
      if (kind == 2) {
1011
6
        mxPushSlot(value);
1012
6
        mxPushSlot(value);
1013
6
        fxConstructArrayEntry(the, result);
1014
6
      }
1015
343
      else {
1016
343
        result->kind = value->kind;
1017
343
        result->value = value->value;
1018
343
      }
1019
349
      list->value.list.first = value;
1020
349
    }
1021
150
    else {
1022
150
      result->kind = XS_UNDEFINED_KIND;
1023
150
      result->next->value.boolean = 1;
1024
150
      list->value.list.first = C_NULL;
1025
150
    }
1026
499
  }
1027
534
}
1028
1029
txSlot* fxCanonicalizeKeyedCollectionKey(txSlot* key)
1030
300k
{
1031
300k
  if ((key->kind == XS_NUMBER_KIND) && (key->value.number == 0)) { \
1032
6
    key->kind = XS_INTEGER_KIND; \
1033
6
    key->value.integer = 0; \
1034
6
  }
1035
300k
  return key;
1036
300k
}
1037
1038
void fxClearEntries(txMachine* the, txSlot* table, txSlot* list, txBoolean paired)
1039
41
{
1040
41
  txSlot* slot = list->value.list.first;
1041
154
  while (slot) {
1042
113
    slot->flag = XS_DONT_ENUM_FLAG;
1043
113
    slot->kind = XS_UNDEFINED_KIND;
1044
113
    slot = slot->next;
1045
113
  }
1046
41
  c_memset(table->value.table.address, 0, table->value.table.length * sizeof(txSlot*));
1047
41
  list->next->value.integer = 0;
1048
41
  fxResizeEntries(the, table, list);
1049
41
  fxPurgeEntries(the, list);
1050
41
}
1051
1052
txBoolean fxDeleteEntry(txMachine* the, txSlot* table, txSlot* list, txSlot* key, txBoolean paired, txBoolean fit) 
1053
271k
{
1054
271k
  txSlot* info = list->next;
1055
271k
  txU4 sum = fxSumEntry(the, key);
1056
271k
  txU4 index = sum & (table->value.table.length - 1);
1057
271k
  txSlot** address = &(table->value.table.address[index]);
1058
271k
  txSlot* entry;
1059
271k
  txSlot* first;
1060
271k
  txSlot* last;
1061
271k
  while ((entry = *address)) {
1062
62.8k
    if (entry->value.entry.sum == sum) {
1063
62.8k
      first = entry->value.entry.slot;
1064
62.8k
      if (fxTestEntry(the, first, key)) {
1065
62.7k
        *address = entry->next;
1066
62.7k
        entry->next = C_NULL;
1067
62.7k
        first->flag = XS_DONT_ENUM_FLAG;
1068
62.7k
        first->kind = XS_UNDEFINED_KIND;
1069
62.7k
        if (paired) {
1070
94
          last = first->next;
1071
94
          last->flag = XS_DONT_ENUM_FLAG;
1072
94
          last->kind = XS_UNDEFINED_KIND;
1073
94
        }
1074
62.7k
        info->value.integer--;
1075
62.7k
        if (fit) {
1076
62.6k
          fxResizeEntries(the, table, list);
1077
62.6k
          fxPurgeEntries(the, list);
1078
62.6k
        }
1079
62.7k
        return 1;
1080
62.7k
      }
1081
62.8k
    }
1082
98
    address = &entry->next;
1083
98
  }
1084
208k
  return 0;
1085
271k
}
1086
1087
txSlot* fxGetEntry(txMachine* the, txSlot* table, txSlot* slot) 
1088
745k
{
1089
745k
  txU4 sum = fxSumEntry(the, slot);
1090
745k
  txU4 index = sum & (table->value.table.length - 1);
1091
745k
  txSlot* entry = table->value.table.address[index];
1092
745k
  txSlot* result;
1093
1.25M
  while (entry) {
1094
731k
    if (entry->value.entry.sum == sum) {
1095
334k
      result = entry->value.entry.slot;
1096
334k
      if (fxTestEntry(the, result, slot))
1097
225k
        return result;
1098
334k
    }
1099
505k
    entry = entry->next;
1100
505k
  }
1101
519k
  return C_NULL;
1102
745k
}
1103
1104
void fxPurgeEntries(txMachine* the, txSlot* list) 
1105
62.7k
{
1106
62.7k
  txSlot* former = C_NULL;
1107
62.7k
  txSlot** address = &(list->value.list.first);
1108
62.7k
  txSlot* slot;
1109
376k
  while ((slot = *address)) {
1110
313k
    if (slot->flag & XS_DONT_ENUM_FLAG) {
1111
62.9k
      *address = slot->next;
1112
62.9k
    }
1113
250k
    else {
1114
250k
      former = slot;
1115
250k
      address = &slot->next;
1116
250k
    }
1117
313k
  }
1118
62.7k
  list->value.list.last = former;
1119
62.7k
}
1120
1121
void fxResizeEntries(txMachine* the, txSlot* table, txSlot* list) 
1122
11.7M
{
1123
11.7M
  txSize size = list->next->value.integer;
1124
11.7M
  txSize formerLength = table->value.table.length;
1125
11.7M
  txSize currentLength = formerLength;
1126
11.7M
  txSize high = mxTableThreshold(formerLength);
1127
11.7M
  txSize low = mxTableThreshold(formerLength) >> 1;
1128
11.7M
  if (high < size) {
1129
3.39M
    currentLength = formerLength << 1;
1130
3.39M
    if (currentLength > mxTableMaxLength)
1131
0
      currentLength = mxTableMaxLength;
1132
3.39M
  }
1133
8.36M
  else if (low >= size) {
1134
333
    currentLength = formerLength >> 1;
1135
333
    if (currentLength < mxTableMinLength)
1136
18
      currentLength = mxTableMinLength;
1137
333
  }
1138
11.7M
  if (formerLength != currentLength) {
1139
3.39M
    txSlot** currentAddress = (txSlot**)fxNewChunk(the, currentLength * sizeof(txSlot*));
1140
3.39M
    if (currentAddress) {
1141
3.39M
      txSlot** formerAddress = table->value.table.address;
1142
1143
3.39M
            txSize currentMask = currentLength - 1;
1144
3.39M
      c_memset(currentAddress, 0, currentLength * sizeof(txSlot*));
1145
23.2M
      while (formerLength) {
1146
19.8M
        txSlot* entry;
1147
37.2M
        while ((entry = *formerAddress)) {
1148
17.3M
          txU4 index = entry->value.entry.sum & currentMask;
1149
17.3M
           *formerAddress = entry->next;
1150
17.3M
          entry->next = currentAddress[index];
1151
17.3M
          currentAddress[index] = entry;
1152
17.3M
        }
1153
19.8M
        formerLength--;
1154
19.8M
        formerAddress++;
1155
19.8M
      }
1156
3.39M
      table->value.table.address = currentAddress;
1157
3.39M
      table->value.table.length = currentLength;
1158
3.39M
    }
1159
3.39M
  }
1160
//  {
1161
//    txSize holes = 0;
1162
//    txSize collisions = 0;
1163
//    txSize i =  0;
1164
//    while (i < table->value.table.length) {
1165
//      txSize j = 0;
1166
//      txSlot* entry = table->value.table.address[i];
1167
//      while (entry) {
1168
//        j++;
1169
//        entry = entry->next;
1170
//      }
1171
//      if (j == 0)
1172
//        holes++;
1173
//      else if (collisions < j)
1174
//        collisions = j;
1175
//      i++;
1176
//    }
1177
//    fprintf(stderr, "# size %d capacity %d holes %d collisions <%d\n", size, table->value.table.length, holes, collisions);
1178
//  }
1179
11.7M
}
1180
1181
void fxSetEntry(txMachine* the, txSlot* table, txSlot* list, txSlot* key, txSlot* pair) 
1182
21.1M
{
1183
21.1M
  txU4 sum = fxSumEntry(the, key);
1184
21.1M
  txU4 index = sum & (table->value.table.length - 1);
1185
21.1M
  txSlot** address = &(table->value.table.address[index]);
1186
21.1M
  txSlot* entry = *address;
1187
21.1M
  txSlot* first;
1188
21.1M
  txSlot* last;
1189
27.9M
  while (entry) {
1190
16.2M
    if (entry->value.entry.sum == sum) {
1191
9.50M
      first = entry->value.entry.slot;
1192
9.50M
      if (fxTestEntry(the, first, key)) {
1193
9.50M
        if (pair) {
1194
227
          last = first->next;
1195
227
          last->kind = pair->kind;
1196
227
          last->value = pair->value;
1197
227
        }
1198
9.50M
        return;
1199
9.50M
      }
1200
9.50M
    }
1201
6.73M
    entry = entry->next;
1202
6.73M
  }
1203
11.6M
  first = fxNewSlot(the);
1204
11.6M
  first->kind = key->kind;
1205
11.6M
  first->value = key->value;
1206
11.6M
  mxPushClosure(first);
1207
11.6M
  if (pair) {
1208
2.42k
    first->next = last = fxNewSlot(the);
1209
2.42k
    last->kind = pair->kind;
1210
2.42k
    last->value = pair->value;
1211
2.42k
    mxPushClosure(last);
1212
2.42k
  }
1213
11.6M
  entry = fxNewSlot(the);
1214
11.6M
  address = &(table->value.table.address[index]);
1215
11.6M
  entry->next = *address;
1216
11.6M
  entry->kind = XS_ENTRY_KIND;
1217
11.6M
  entry->value.entry.slot = first;
1218
11.6M
  entry->value.entry.sum = sum;
1219
11.6M
  *address = entry;
1220
11.6M
  if (list->value.list.last)
1221
10.9M
    list->value.list.last->next = first;
1222
730k
  else
1223
730k
    list->value.list.first = first;
1224
11.6M
  if (pair)
1225
2.42k
    list->value.list.last = last;
1226
11.6M
  else
1227
11.6M
    list->value.list.last = first;
1228
11.6M
  if (pair)
1229
2.42k
    mxPop();
1230
11.6M
  mxPop();
1231
11.6M
  list->next->value.integer++;
1232
11.6M
  fxResizeEntries(the, table, list);
1233
11.6M
}
1234
1235
txU4 fxSumEntry(txMachine* the, txSlot* slot) 
1236
22.2M
{
1237
22.2M
  txU1 kind = slot->kind;
1238
22.2M
  txU8 sum;
1239
  
1240
22.2M
  if ((XS_STRING_KIND == kind) || (XS_STRING_X_KIND == kind)) {
1241
    // Dan Bernstein: http://www.cse.yorku.ca/~oz/hash.html
1242
21.2M
    txU1 *string = (txU1*)slot->value.string;
1243
21.2M
    sum = 5381;
1244
55.0M
    while ((kind = c_read8(string++))) {
1245
33.7M
      sum = ((sum << 5) + sum) + kind;
1246
33.7M
    }
1247
21.2M
  }
1248
915k
  else {
1249
915k
    if (XS_REFERENCE_KIND == kind) {
1250
435
      sum = (txU8)(((uintptr_t)slot->value.reference) / sizeof(txSlot));
1251
435
    }
1252
915k
    else if (XS_INTEGER_KIND == kind) {
1253
56.3k
      fxToNumber(the, slot);
1254
56.3k
      sum = *((txU8*)&slot->value.number);
1255
56.3k
    }
1256
858k
    else if (XS_NUMBER_KIND == kind) {
1257
116k
      if (slot->value.number == 0) {
1258
221
        sum = 0;
1259
221
      }
1260
116k
      else {
1261
116k
        if (c_isnan(slot->value.number)) {
1262
1.50k
        #if mxCanonicalNaN
1263
1.50k
          slot->value.number = *gxCanonicalNaN64;
1264
        #else       
1265
          slot->value.number = C_NAN;
1266
        #endif
1267
1.50k
        }
1268
116k
        sum = *((txU8*)&slot->value.number);
1269
116k
      }
1270
116k
    }
1271
741k
    else if ((XS_BIGINT_KIND == kind) || (XS_BIGINT_X_KIND == kind)) {
1272
206
      sum = fxToBigUint64(the, slot);
1273
206
    }
1274
741k
    else if (XS_SYMBOL_KIND == kind) {
1275
58
      sum = slot->value.symbol;
1276
58
    }
1277
741k
    else if (XS_BOOLEAN_KIND == kind) {
1278
401
      sum = slot->value.boolean;
1279
401
    }
1280
741k
    else {
1281
741k
      sum = 0;
1282
741k
    }
1283
    // Thomas Wang: http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
1284
915k
    sum = (~sum) + (sum << 18); // sum = (sum << 18) - sum - 1;
1285
915k
    sum = sum ^ (sum >> 31);
1286
915k
    sum = sum * 21; // sum = (sum + (sum << 2)) + (sum << 4);
1287
915k
    sum = sum ^ (sum >> 11);
1288
915k
    sum = sum + (sum << 6);
1289
915k
    sum = sum ^ (sum >> 22);
1290
915k
  }
1291
22.2M
  sum &= 0xFFFFFFFF;
1292
22.2M
  return (txU4)sum;
1293
22.2M
}
1294
1295
txBoolean fxTestEntry(txMachine* the, txSlot* a, txSlot* b)
1296
9.89M
{ 
1297
9.89M
  txBoolean result = 0;
1298
9.89M
  if (a->kind == b->kind) {
1299
9.79M
    if ((XS_UNDEFINED_KIND == a->kind) || (XS_NULL_KIND == a->kind))
1300
193k
      result = 1;
1301
9.59M
    else if (XS_BOOLEAN_KIND == a->kind)
1302
268
      result = a->value.boolean == b->value.boolean;
1303
9.59M
    else if (XS_INTEGER_KIND == a->kind)
1304
0
      result = a->value.integer == b->value.integer;
1305
9.59M
        else if (XS_NUMBER_KIND == a->kind)
1306
171k
      result = ((c_isnan(a->value.number) && c_isnan(b->value.number)) || (a->value.number == b->value.number));
1307
9.42M
    else if ((XS_STRING_KIND == a->kind) || (XS_STRING_X_KIND == a->kind))
1308
9.42M
      result = c_strcmp(a->value.string, b->value.string) == 0;
1309
408
    else if (XS_SYMBOL_KIND == a->kind)
1310
26
      result = a->value.symbol == b->value.symbol;
1311
382
    else if ((XS_BIGINT_KIND == a->kind) || (XS_BIGINT_X_KIND == a->kind))
1312
121
      result = gxTypeBigInt.compare(the, 0, 1, 0, a, b);
1313
261
    else if (XS_REFERENCE_KIND == a->kind)
1314
261
      result = a->value.reference == b->value.reference;
1315
9.79M
  }
1316
108k
  else if ((XS_INTEGER_KIND == a->kind) && (XS_NUMBER_KIND == b->kind))
1317
0
    result = (!c_isnan(b->value.number)) && ((txNumber)(a->value.integer) == b->value.number);
1318
108k
  else if ((XS_NUMBER_KIND == a->kind) && (XS_INTEGER_KIND == b->kind))
1319
0
    result = (!c_isnan(a->value.number)) && (a->value.number == (txNumber)(b->value.integer));
1320
108k
  else if ((XS_STRING_KIND == a->kind) && (XS_STRING_X_KIND == b->kind))
1321
0
    result = c_strcmp(a->value.string, b->value.string) == 0;
1322
108k
  else if ((XS_STRING_X_KIND == a->kind) && (XS_STRING_KIND == b->kind))
1323
0
    result = c_strcmp(a->value.string, b->value.string) == 0;
1324
108k
  else if ((XS_BIGINT_KIND == a->kind) && (XS_BIGINT_X_KIND == b->kind))
1325
0
    result = gxTypeBigInt.compare(the, 0, 1, 0, a, b);
1326
108k
  else if ((XS_BIGINT_X_KIND == a->kind) && (XS_BIGINT_KIND == b->kind))
1327
0
    result = gxTypeBigInt.compare(the, 0, 1, 0, a, b);
1328
9.89M
  return result;
1329
9.89M
}
1330
1331
txSlot* fxCanBeHeldWeakly(txMachine* the, txSlot* slot)
1332
1.40M
{
1333
1.40M
  if (slot->kind == XS_REFERENCE_KIND)
1334
1.33M
    slot = slot->value.reference;
1335
70.4k
#if mxKeysGarbageCollection
1336
70.4k
  else if (slot->kind == XS_SYMBOL_KIND) {
1337
70.0k
    slot = fxGetKey(the, slot->value.symbol);
1338
70.0k
    if (slot->kind == XS_REFERENCE_KIND)
1339
70.0k
      slot = slot->value.reference;
1340
13
    else
1341
13
      slot = C_NULL;
1342
70.0k
  }
1343
367
#endif
1344
367
  else
1345
367
    slot = C_NULL;
1346
1.40M
  return slot;
1347
1.40M
}
1348
1349
txSlot* fxCheckWeakMapInstance(txMachine* the, txSlot* slot, txBoolean mutable)
1350
357k
{
1351
357k
  if (slot->kind == XS_REFERENCE_KIND) {
1352
357k
    txSlot* instance = slot->value.reference;
1353
357k
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_WEAK_MAP_KIND) && (instance != mxWeakMapPrototype.value.reference)) {
1354
357k
      if (mutable && (slot->flag &  XS_DONT_SET_FLAG))
1355
0
        mxTypeError("this: read-only WeakMap instance");
1356
357k
      return instance;
1357
357k
    }
1358
357k
  }
1359
357k
  mxTypeError("this: not a WeakMap instance");
1360
0
  return C_NULL;
1361
357k
}
1362
1363
txSlot* fxCheckWeakMapKey(txMachine* the, txBoolean mutable)
1364
357k
{
1365
357k
  if (mxArgc > 0) {
1366
357k
    txSlot* slot = fxCanBeHeldWeakly(the, mxArgv(0));
1367
357k
    if (slot && mutable && (slot->flag & XS_MARK_FLAG))
1368
0
      mxTypeError("key: read-only");
1369
357k
    return slot;
1370
357k
  }
1371
2
  return C_NULL;
1372
357k
}
1373
1374
txSlot* fxNewWeakMapInstance(txMachine* the)
1375
412k
{
1376
412k
  txSlot* map;
1377
412k
  txSlot* list;
1378
412k
  map = fxNewSlot(the);
1379
412k
  map->kind = XS_INSTANCE_KIND;
1380
412k
  map->value.instance.garbage = C_NULL;
1381
412k
  map->value.instance.prototype = the->stack->value.reference;
1382
412k
  the->stack->kind = XS_REFERENCE_KIND;
1383
412k
  the->stack->value.reference = map;
1384
  /* LIST */
1385
412k
  list = map->next = fxNewSlot(the);
1386
412k
  list->flag = XS_INTERNAL_FLAG;
1387
412k
  list->kind = XS_WEAK_MAP_KIND;
1388
412k
  list->value.weakList.first = C_NULL;
1389
412k
  list->value.weakList.link = the->firstWeakListLink;
1390
412k
  the->firstWeakListLink = list;
1391
412k
  return map;
1392
412k
}
1393
1394
void fx_WeakMap(txMachine* the)
1395
412k
{
1396
412k
  txSlot *function, *iterable, *iterator, *next, *value;
1397
412k
  if (mxIsUndefined(mxTarget))
1398
4
    mxTypeError("call: WeakMap");
1399
412k
  mxPushSlot(mxTarget);
1400
412k
  fxGetPrototypeFromConstructor(the, &mxWeakMapPrototype);
1401
412k
  fxNewWeakMapInstance(the);
1402
412k
  mxPullSlot(mxResult);
1403
412k
  if (mxArgc < 1)
1404
73.3k
    return;
1405
339k
  iterable = mxArgv(0);
1406
339k
  if ((iterable->kind == XS_UNDEFINED_KIND) || (iterable->kind == XS_NULL_KIND))
1407
14
    return;
1408
339k
  mxPushSlot(mxResult);
1409
339k
  mxGetID(mxID(_set)); 
1410
339k
  function = the->stack;  
1411
339k
  if (!fxIsCallable(the, function))  
1412
3
    mxTypeError("result.set: not a function");
1413
339k
  mxTemporary(iterator);
1414
339k
  mxTemporary(next);
1415
339k
  fxGetIterator(the, iterable, iterator, next, 0);  
1416
339k
  mxTemporary(value);
1417
678k
  while (fxIteratorNext(the, iterator, next, value)) {
1418
339k
    mxTry(the) {
1419
339k
      mxPushSlot(mxResult);
1420
339k
      mxPushSlot(function);
1421
339k
      mxCall();
1422
339k
      if (value->kind != XS_REFERENCE_KIND)
1423
22
        mxTypeError("item: not an object");
1424
339k
      mxPushSlot(value);
1425
339k
      mxGetIndex(0);
1426
339k
      mxPushSlot(value);
1427
339k
      mxGetIndex(1);
1428
339k
      mxRunCount(2);
1429
339k
      mxPop();
1430
339k
    }
1431
339k
    mxCatch(the) {
1432
24
      fxIteratorReturn(the, iterator, 1);
1433
24
      fxJump(the);
1434
24
    }
1435
339k
  }
1436
339k
}
1437
1438
void fx_WeakMap_prototype_delete(txMachine* the)
1439
56
{
1440
56
  txSlot* instance = fxCheckWeakMapInstance(the, mxThis, XS_MUTABLE);
1441
56
  txSlot* key = fxCheckWeakMapKey(the, XS_MUTABLE);
1442
56
  mxResult->value.boolean = (key) ? fxDeleteWeakEntry(the, instance->next, key) : 0;
1443
56
  mxResult->kind = XS_BOOLEAN_KIND;
1444
56
}
1445
1446
void fx_WeakMap_prototype_get(txMachine* the)
1447
580
{
1448
580
  txSlot* instance = fxCheckWeakMapInstance(the, mxThis, XS_IMMUTABLE);
1449
580
  txSlot* key = fxCheckWeakMapKey(the, XS_IMMUTABLE);
1450
580
  txSlot* result = (key) ? fxGetWeakEntry(the, instance->next, key) : C_NULL;
1451
580
  if (result) {
1452
364
    txSlot* value = result->value.weakEntry.value;
1453
364
    mxResult->kind = value->kind;
1454
364
    mxResult->value = value->value;
1455
364
  }
1456
580
}
1457
1458
void fx_WeakMap_prototype_has(txMachine* the)
1459
222
{
1460
222
  txSlot* instance = fxCheckWeakMapInstance(the, mxThis, XS_IMMUTABLE);
1461
222
  txSlot* key = fxCheckWeakMapKey(the, XS_IMMUTABLE);
1462
222
  txSlot* result = (key) ? fxGetWeakEntry(the, instance->next, key) : C_NULL;
1463
222
  mxResult->kind = XS_BOOLEAN_KIND;
1464
222
  mxResult->value.boolean = (result) ? 1 : 0;
1465
222
}
1466
1467
void fx_WeakMap_prototype_set(txMachine* the)
1468
356k
{
1469
356k
  txSlot* instance = fxCheckWeakMapInstance(the, mxThis, XS_MUTABLE);
1470
356k
  txSlot* key = fxCheckWeakMapKey(the, XS_MUTABLE);
1471
356k
  if (!key)
1472
16
    mxTypeError("key: not an object");
1473
356k
  fxSetWeakEntry(the, instance->next, key, (mxArgc > 1) ? mxArgv(1) : &mxUndefined);
1474
356k
  *mxResult = *mxThis;
1475
356k
}
1476
1477
txSlot* fxCheckWeakSetInstance(txMachine* the, txSlot* slot, txBoolean mutable)
1478
929k
{
1479
929k
  if (slot->kind == XS_REFERENCE_KIND) {
1480
929k
    txSlot* instance = slot->value.reference;
1481
929k
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_WEAK_SET_KIND) && (instance != mxWeakSetPrototype.value.reference)) {
1482
929k
      if (mutable && (slot->flag & XS_DONT_SET_FLAG))
1483
0
        mxTypeError("this: read-only WeakSet instance");
1484
929k
      return instance;
1485
929k
    }
1486
929k
  }
1487
929k
  mxTypeError("this: not a WeakSet instance");
1488
0
  return C_NULL;
1489
929k
}
1490
1491
txSlot* fxCheckWeakSetValue(txMachine* the, txBoolean mutable)
1492
929k
{
1493
929k
  if (mxArgc > 0) {
1494
929k
    txSlot* slot = fxCanBeHeldWeakly(the, mxArgv(0));
1495
929k
    if (slot && mutable && (slot->flag & XS_MARK_FLAG))
1496
0
      mxTypeError("value: read-only");
1497
929k
    return slot;
1498
929k
  }
1499
7
  return C_NULL;
1500
929k
}
1501
1502
txSlot* fxNewWeakSetInstance(txMachine* the)
1503
472k
{
1504
472k
  txSlot* set;
1505
472k
  txSlot* list;
1506
472k
  set = fxNewSlot(the);
1507
472k
  set->kind = XS_INSTANCE_KIND;
1508
472k
  set->value.instance.garbage = C_NULL;
1509
472k
  set->value.instance.prototype = the->stack->value.reference;
1510
472k
  the->stack->kind = XS_REFERENCE_KIND;
1511
472k
  the->stack->value.reference = set;
1512
  /* LIST */
1513
472k
  list = set->next = fxNewSlot(the);
1514
472k
  list->flag = XS_INTERNAL_FLAG;
1515
472k
  list->kind = XS_WEAK_SET_KIND;
1516
472k
  list->value.weakList.first = C_NULL;
1517
472k
  list->value.weakList.link = the->firstWeakListLink;
1518
472k
  the->firstWeakListLink = list;
1519
472k
  return set;
1520
472k
}
1521
1522
void fx_WeakSet(txMachine* the)
1523
472k
{
1524
472k
  txSlot *function, *iterable, *iterator, *next, *value;
1525
472k
  if (mxIsUndefined(mxTarget))
1526
20
    mxTypeError("call: WeakSet");
1527
472k
  mxPushSlot(mxTarget);
1528
472k
  fxGetPrototypeFromConstructor(the, &mxWeakSetPrototype);
1529
472k
  fxNewWeakSetInstance(the);
1530
472k
  mxPullSlot(mxResult);
1531
472k
  if (mxArgc < 1)
1532
472k
    return;
1533
16
  iterable = mxArgv(0);
1534
16
  if ((iterable->kind == XS_UNDEFINED_KIND) || (iterable->kind == XS_NULL_KIND))
1535
6
    return;
1536
10
  mxPushSlot(mxResult);
1537
10
  mxGetID(mxID(_add)); 
1538
10
  function = the->stack;  
1539
10
  if (!fxIsCallable(the, function))  
1540
1
    mxTypeError("result.add: not a function");
1541
9
  mxTemporary(iterator);
1542
9
  mxTemporary(next);
1543
9
  fxGetIterator(the, iterable, iterator, next, 0);  
1544
9
  mxTemporary(value);
1545
19
  while (fxIteratorNext(the, iterator, next, value)) {
1546
11
    mxTry(the) {
1547
11
      mxPushSlot(mxResult);
1548
11
      mxPushSlot(function);
1549
11
      mxCall();
1550
11
      mxPushSlot(value);
1551
11
      mxRunCount(1);
1552
11
      mxPop();
1553
11
    }
1554
11
    mxCatch(the) {
1555
1
      fxIteratorReturn(the, iterator, 1);
1556
1
      fxJump(the);
1557
1
    }
1558
11
  }
1559
9
}
1560
1561
void fx_WeakSet_prototype_add(txMachine* the)
1562
429k
{
1563
429k
  txSlot* instance = fxCheckWeakSetInstance(the, mxThis, XS_MUTABLE);
1564
429k
  txSlot* value = fxCheckWeakSetValue(the, XS_MUTABLE);
1565
429k
  if (!value)
1566
25
    mxTypeError("value: not an object");
1567
429k
  fxSetWeakEntry(the, instance->next, value, &mxUndefined);
1568
429k
  *mxResult = *mxThis;
1569
429k
}
1570
1571
void fx_WeakSet_prototype_has(txMachine* the)
1572
162
{
1573
162
  txSlot* instance = fxCheckWeakSetInstance(the, mxThis, XS_IMMUTABLE);
1574
162
  txSlot* value = fxCheckWeakSetValue(the, XS_IMMUTABLE);
1575
162
  txSlot* result = (value) ? fxGetWeakEntry(the, instance->next, value) : C_NULL;
1576
162
  mxResult->kind = XS_BOOLEAN_KIND;
1577
162
  mxResult->value.boolean = (result) ? 1 : 0;
1578
162
}
1579
1580
void fx_WeakSet_prototype_delete(txMachine* the)
1581
499k
{
1582
499k
  txSlot* instance = fxCheckWeakSetInstance(the, mxThis, XS_MUTABLE);
1583
499k
  txSlot* value = fxCheckWeakSetValue(the, XS_MUTABLE);
1584
499k
  mxResult->value.boolean = (value) ? fxDeleteWeakEntry(the, instance->next, value) : 0;
1585
499k
  mxResult->kind = XS_BOOLEAN_KIND;
1586
499k
}
1587
1588
txBoolean fxDeleteWeakEntry(txMachine* the, txSlot* list, txSlot* key) 
1589
499k
{
1590
499k
  txSlot* slot = (key->flag & XS_EXOTIC_FLAG) ? key->next : key;
1591
499k
  txSlot** address = &slot->next;
1592
1.32M
  while ((slot = *address)) {
1593
1.12M
    if (!(slot->flag & XS_INTERNAL_FLAG))
1594
196k
      break;
1595
930k
    if ((slot->kind == XS_WEAK_ENTRY_KIND) && (slot->value.weakEntry.check == list)) {
1596
107k
      slot->value.weakEntry.value->kind = XS_UNINITIALIZED_KIND;
1597
107k
      *address = slot->next;
1598
107k
      return 1;
1599
107k
    }      
1600
823k
    address = &slot->next;
1601
823k
  }
1602
391k
  return 0;
1603
499k
}
1604
1605
txSlot* fxGetWeakEntry(txMachine* the, txSlot* list, txSlot* key) 
1606
645
{
1607
645
  txSlot* slot = (key->flag & XS_EXOTIC_FLAG) ? key->next : key;
1608
645
    slot = slot->next;
1609
66.0k
  while (slot) {
1610
65.8k
    if (!(slot->flag & XS_INTERNAL_FLAG))
1611
4
      break;
1612
65.8k
    if ((slot->kind == XS_WEAK_ENTRY_KIND) && (slot->value.weakEntry.check == list))
1613
420
      return slot;
1614
65.4k
    slot = slot->next;
1615
65.4k
  }
1616
225
  return C_NULL;
1617
645
}
1618
1619
void fxSetWeakEntry(txMachine* the, txSlot* list, txSlot* key, txSlot* value) 
1620
786k
{
1621
786k
  txSlot* slot = (key->flag & XS_EXOTIC_FLAG) ? key->next : key;
1622
786k
  txSlot** address = &slot->next;
1623
786k
  txSlot* keyEntry;
1624
786k
  txSlot* listEntry;
1625
786k
  txSlot* closure;
1626
479M
  while ((slot = *address)) {
1627
479M
    if (!(slot->flag & XS_INTERNAL_FLAG))
1628
138
      break;
1629
479M
    if ((slot->kind == XS_WEAK_ENTRY_KIND) && (slot->value.weakEntry.check == list)) {
1630
321k
      slot = slot->value.weakEntry.value;
1631
321k
      slot->kind = value->kind;
1632
321k
      slot->value = value->value;
1633
321k
      return;
1634
321k
    }      
1635
478M
    address = &slot->next;
1636
478M
  }
1637
  
1638
464k
  keyEntry = fxNewSlot(the);
1639
464k
  mxPushClosure(keyEntry);
1640
464k
  listEntry = fxNewSlot(the);
1641
464k
  mxPushClosure(listEntry);
1642
464k
  closure = fxNewSlot(the);
1643
464k
  closure->kind = value->kind;
1644
464k
  closure->value = value->value;
1645
  
1646
464k
  slot = (key->flag & XS_EXOTIC_FLAG) ? key->next : key;
1647
464k
  address = &slot->next;
1648
478M
  while ((slot = *address)) {
1649
477M
    if (!(slot->flag & XS_INTERNAL_FLAG))
1650
138
      break;
1651
477M
    address = &slot->next;
1652
477M
  }
1653
  
1654
464k
  keyEntry->next = *address;
1655
464k
  keyEntry->flag = XS_INTERNAL_FLAG;
1656
464k
  keyEntry->kind = XS_WEAK_ENTRY_KIND;
1657
464k
  keyEntry->value.weakEntry.check = list;
1658
464k
  keyEntry->value.weakEntry.value = closure;
1659
464k
  *address = keyEntry;
1660
  
1661
464k
  listEntry->next = list->value.weakList.first;
1662
464k
  listEntry->flag = XS_INTERNAL_FLAG;
1663
464k
  listEntry->kind = XS_WEAK_ENTRY_KIND;
1664
464k
  listEntry->value.weakEntry.check = key;
1665
464k
  listEntry->value.weakEntry.value = closure;
1666
464k
  list->value.weakList.first = listEntry;
1667
  
1668
464k
  mxPop();
1669
464k
  mxPop();
1670
464k
}
1671
1672
void fxKeepDuringJobs(txMachine* the, txSlot* target)
1673
94
{
1674
94
  txSlot* instance = mxDuringJobs.value.reference;
1675
94
  txSlot** address = &(instance->next);
1676
94
  txSlot* slot;
1677
125
  while ((slot = *address)) {
1678
57
    if (slot->value.reference == target)
1679
26
      return;
1680
31
    address = &(slot->next);
1681
31
  }
1682
68
  *address = slot = fxNewSlot(the);
1683
68
  slot->value.reference = target;
1684
68
  slot->kind = XS_REFERENCE_KIND;
1685
68
}
1686
1687
txSlot* fxCheckWeakRefInstance(txMachine* the, txSlot* slot)
1688
49
{
1689
49
  if (slot->kind == XS_REFERENCE_KIND) {
1690
36
    txSlot* instance = slot->value.reference;
1691
36
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_WEAK_REF_KIND))
1692
19
      return instance;
1693
36
  }
1694
49
  mxTypeError("this is no WeakRef instance");
1695
0
  return C_NULL;
1696
49
}
1697
1698
txSlot* fxNewWeakRefInstance(txMachine* the)
1699
75
{
1700
75
  txSlot* slot;
1701
75
  txSlot* instance = fxNewSlot(the);
1702
75
  instance->kind = XS_INSTANCE_KIND;
1703
75
  instance->value.instance.garbage = C_NULL;
1704
75
  instance->value.instance.prototype = the->stack->value.reference;
1705
75
  the->stack->kind = XS_REFERENCE_KIND;
1706
75
  the->stack->value.reference = instance;
1707
75
  slot = instance->next = fxNewSlot(the);
1708
75
  slot->flag = XS_INTERNAL_FLAG;
1709
75
  slot->kind = XS_WEAK_REF_KIND;
1710
75
  slot->value.weakRef.target = C_NULL;
1711
75
  slot->value.weakRef.link = C_NULL;
1712
75
  return instance;
1713
75
}
1714
1715
void fx_WeakRef(txMachine* the)
1716
95
{
1717
95
  txSlot* target;
1718
95
  txSlot* instance;
1719
95
  if (mxIsUndefined(mxTarget))
1720
3
    mxTypeError("call: WeakRef");
1721
92
  if (mxArgc < 1)
1722
3
    mxTypeError("no target");
1723
89
  target = fxCanBeHeldWeakly(the, mxArgv(0));
1724
89
  if (!target)
1725
14
    mxTypeError("target: not an object");
1726
75
  mxPushSlot(mxTarget);
1727
75
  fxGetPrototypeFromConstructor(the, &mxWeakRefPrototype);
1728
75
  instance = fxNewWeakRefInstance(the);
1729
75
  mxPullSlot(mxResult);
1730
75
  fxKeepDuringJobs(the, target);
1731
75
  instance->next->value.weakRef.target = target;
1732
75
}
1733
1734
void fx_WeakRef_prototype_deref(txMachine* the)
1735
49
{
1736
49
  txSlot* instance = fxCheckWeakRefInstance(the, mxThis);
1737
49
  txSlot* target = instance->next->value.weakRef.target;
1738
49
  if (target) {
1739
19
    txSlot* property = target->next;
1740
19
    if (property && (property->flag & XS_INTERNAL_FLAG) && (property->kind == XS_SYMBOL_KIND)) {
1741
6
      mxResult->value.symbol = property->value.symbol;
1742
6
      mxResult->kind = XS_SYMBOL_KIND;
1743
6
    }
1744
13
    else {
1745
13
      mxResult->value.reference = target;
1746
13
      mxResult->kind = XS_REFERENCE_KIND;
1747
13
    }
1748
19
    fxKeepDuringJobs(the, target);
1749
19
  }
1750
49
}
1751
1752
txSlot* fxCheckFinalizationRegistryInstance(txMachine* the, txSlot* slot)
1753
118k
{
1754
118k
  if (slot->kind == XS_REFERENCE_KIND) {
1755
118k
    txSlot* instance = slot->value.reference;
1756
118k
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_CLOSURE_KIND) && (slot->value.closure->kind == XS_FINALIZATION_REGISTRY_KIND)) {
1757
118k
      if (slot->flag & XS_MARK_FLAG)
1758
0
        mxTypeError("this: read-only FinalizationRegistry instance");
1759
118k
      return instance;
1760
118k
    }
1761
118k
  }
1762
118k
  mxTypeError("this: not a FinalizationRegistry instance");
1763
0
  return C_NULL;
1764
118k
}
1765
1766
void fx_FinalizationRegistry(txMachine* the)
1767
78.2k
{
1768
78.2k
  txSlot* callback;
1769
78.2k
  txSlot* instance;
1770
78.2k
  txSlot* property;
1771
78.2k
  txSlot* registry;
1772
78.2k
  txSlot* slot;
1773
78.2k
  if (mxIsUndefined(mxTarget))
1774
3
    mxTypeError("call: FinalizationRegistry");
1775
78.2k
  if (mxArgc < 1)
1776
3
    mxTypeError("no callback");
1777
78.2k
  callback = mxArgv(0);
1778
78.2k
  if (!fxIsCallable(the, callback))
1779
31
    mxTypeError("callback: not a function");
1780
78.2k
  mxPushSlot(mxTarget);
1781
78.2k
  fxGetPrototypeFromConstructor(the, &mxFinalizationRegistryPrototype);
1782
78.2k
  instance = fxNewSlot(the);
1783
78.2k
  instance->kind = XS_INSTANCE_KIND;
1784
78.2k
  instance->value.instance.garbage = C_NULL;
1785
78.2k
  instance->value.instance.prototype = the->stack->value.reference;
1786
78.2k
  the->stack->kind = XS_REFERENCE_KIND;
1787
78.2k
  the->stack->value.reference = instance;
1788
78.2k
  mxPullSlot(mxResult);
1789
78.2k
  property = instance->next = fxNewSlot(the);
1790
78.2k
  property->flag = XS_INTERNAL_FLAG;
1791
78.2k
  property->kind = XS_CLOSURE_KIND;
1792
78.2k
  property->value.closure = C_NULL;
1793
78.2k
  registry = fxNewSlot(the);
1794
78.2k
  registry->kind = XS_FINALIZATION_REGISTRY_KIND;
1795
78.2k
  registry->value.finalizationRegistry.callback = C_NULL;
1796
78.2k
  registry->value.finalizationRegistry.flags = XS_NO_FLAG;
1797
78.2k
  property->value.closure = registry;
1798
78.2k
  slot = fxNewSlot(the);
1799
78.2k
  slot->kind = callback->kind;
1800
78.2k
  slot->value = callback->value;
1801
78.2k
  registry->value.finalizationRegistry.callback = slot;
1802
78.2k
}
1803
1804
1805
#if 0
1806
// removed from FinalizationRegistry specification
1807
void fx_FinalizationRegistry_prototype_cleanupSome(txMachine* the)
1808
{
1809
  txSlot* instance;
1810
  txSlot* registry;
1811
  txSlot* callback = C_NULL;
1812
  txSlot** address;
1813
  txSlot* slot;
1814
  if (!mxIsReference(mxThis))
1815
    mxTypeError("this: not an object");
1816
  instance = fxCheckFinalizationRegistryInstance(the, mxThis);
1817
  registry = instance->next->value.closure;
1818
  if (mxArgc > 0) {
1819
    callback = mxArgv(0);
1820
    if (mxIsUndefined(callback))
1821
      callback = C_NULL;
1822
    else if (!fxIsCallable(the, callback))
1823
      mxTypeError("callback: not a function");
1824
  }
1825
  fx_FinalizationRegistryCleanup(the, registry, callback);
1826
  callback = registry->value.finalizationRegistry.callback;
1827
  if (callback->next == C_NULL) {
1828
    address = &(mxFinalizationRegistries.value.reference->next);
1829
    while ((slot = *address)) {
1830
      if (slot->value.closure == registry) {
1831
        *address = slot->next;
1832
        return;
1833
      }
1834
      address = &(slot->next);
1835
    }
1836
  }
1837
}
1838
#endif
1839
1840
void fx_FinalizationRegistry_prototype_register(txMachine* the)
1841
117k
{
1842
117k
  txSlot* instance;
1843
117k
  txSlot* registry;
1844
117k
  txSlot* target;
1845
117k
  txSlot* token = C_NULL;
1846
117k
  txSlot* callback;
1847
117k
  txSlot** address;
1848
117k
  txSlot* slot;
1849
117k
  if (!mxIsReference(mxThis))
1850
13
    mxTypeError("this: not an object");
1851
117k
  instance = fxCheckFinalizationRegistryInstance(the, mxThis);
1852
117k
  registry = instance->next->value.closure;
1853
117k
  if (mxArgc < 1)
1854
0
    mxTypeError("no target");
1855
117k
  target = fxCanBeHeldWeakly(the, mxArgv(0));
1856
117k
  if (!target)
1857
13
    mxTypeError("target: not an object");
1858
117k
  if (mxArgc > 1) {
1859
117k
    if (fxIsSameValue(the, mxArgv(0), mxArgv(1), 1))
1860
8
      mxTypeError("target and holdings are the same");
1861
117k
  }
1862
117k
  if (mxArgc > 2) {
1863
150
    token = mxArgv(2);
1864
150
    if (mxIsUndefined(token))
1865
17
      token = C_NULL;
1866
133
    else {
1867
133
      token = fxCanBeHeldWeakly(the, token);
1868
133
      if (!token)
1869
12
        mxTypeError("token: not an object");
1870
133
    }
1871
150
  }
1872
117k
  callback = registry->value.finalizationRegistry.callback;
1873
117k
  address = &(callback->next);
1874
230k
  while ((slot = *address))
1875
112k
    address = &(slot->next);
1876
117k
  slot = *address = fxNewSlot(the);
1877
117k
  if (mxArgc > 1) {
1878
117k
    slot->kind = mxArgv(1)->kind;
1879
117k
    slot->value = mxArgv(1)->value;
1880
117k
  }
1881
117k
  slot = slot->next = fxNewSlot(the);
1882
117k
  slot->kind = XS_FINALIZATION_CELL_KIND;
1883
117k
  slot->value.finalizationCell.target = target;
1884
117k
  slot->value.finalizationCell.token = token;
1885
  
1886
117k
  address = &(mxFinalizationRegistries.value.reference->next);
1887
97.9M
  while ((slot = *address)) {
1888
97.8M
    if (slot->value.closure == registry)
1889
55.9k
      return;
1890
97.8M
    address = &(slot->next);
1891
97.8M
  }
1892
61.9k
  slot = *address = fxNewSlot(the);
1893
61.9k
  slot->kind = XS_CLOSURE_KIND;
1894
61.9k
  slot->value.closure = registry;
1895
61.9k
}  
1896
1897
void fx_FinalizationRegistry_prototype_unregister(txMachine* the)
1898
225
{
1899
225
  txSlot* instance;
1900
225
  txSlot* token;
1901
225
  txSlot* registry;
1902
225
  txSlot* callback;
1903
225
  txSlot** address;
1904
225
  txSlot* slot;
1905
225
  if (!mxIsReference(mxThis))
1906
13
    mxTypeError("this: not an object");
1907
212
  instance = fxCheckFinalizationRegistryInstance(the, mxThis);
1908
212
  if (mxArgc < 1)
1909
0
    mxTypeError("no token");
1910
212
  token = fxCanBeHeldWeakly(the, mxArgv(0));
1911
212
  if (!token)
1912
13
    mxTypeError("token: not an object");
1913
199
  mxResult->kind = XS_BOOLEAN_KIND;
1914
199
  mxResult->value.boolean = 0;
1915
199
  registry = instance->next->value.closure;
1916
199
  callback = registry->value.finalizationRegistry.callback;
1917
199
  address = &(callback->next);
1918
515
  while ((slot = *address)) {
1919
316
    slot = slot->next;
1920
316
    if (slot->value.finalizationCell.token && fxIsSameInstance(the, slot->value.finalizationCell.token, token)) {
1921
39
      *address = slot->next;
1922
39
      mxResult->value.boolean = 1;
1923
39
    }
1924
277
    else
1925
277
      address = &(slot->next);
1926
316
  }
1927
199
  if (callback->next == C_NULL) {
1928
83
    address = &(mxFinalizationRegistries.value.reference->next);
1929
98
    while ((slot = *address)) {
1930
23
      if (slot->value.closure == registry) {
1931
8
        *address = slot->next;
1932
8
        return;
1933
8
      }
1934
15
      address = &(slot->next);
1935
15
    }
1936
83
  }
1937
199
}
1938
1939
void fx_FinalizationRegistryCleanup(txMachine* the, txSlot* registry, txSlot* callback)
1940
17
{
1941
17
  txSlot* slot;
1942
17
  txUnsigned flags;
1943
17
  txSlot** address;
1944
17
  txSlot* value;
1945
1946
17
  if (!(registry->value.finalizationRegistry.flags & XS_FINALIZATION_REGISTRY_CHANGED))
1947
0
    return;
1948
    
1949
17
  slot = registry->value.finalizationRegistry.callback->next;
1950
17
  flags = 0;
1951
17
  while (slot) {
1952
17
    slot = slot->next;
1953
17
    if (slot->value.finalizationCell.target == C_NULL) {
1954
17
      flags = 1;
1955
17
      break;
1956
17
    }
1957
0
    slot = slot->next;
1958
0
  }
1959
17
  if (!flags)
1960
0
    return;
1961
17
  if (!callback)
1962
17
    callback = registry->value.finalizationRegistry.callback;
1963
17
  flags = registry->value.finalizationRegistry.flags;
1964
17
  {
1965
17
    mxTry(the) {
1966
17
      address = &(registry->value.finalizationRegistry.callback->next);
1967
61
      while ((value = *address)) {
1968
44
        slot = value->next;
1969
44
        if (slot->value.finalizationCell.target == C_NULL) {
1970
30
          *address = slot->next;
1971
30
          mxPushUndefined();
1972
30
          mxPushSlot(callback);
1973
30
          mxCall();
1974
30
          mxPushSlot(value);
1975
30
          mxRunCount(1);
1976
30
          mxPop();
1977
30
        }
1978
14
        else
1979
14
          address = &(slot->next);
1980
44
      }
1981
17
      registry->value.finalizationRegistry.flags = flags;
1982
17
    }
1983
17
    mxCatch(the) {
1984
0
      registry->value.finalizationRegistry.flags = flags;
1985
0
      fxJump(the);
1986
0
    }
1987
17
  }
1988
  
1989
17
  slot = registry->value.finalizationRegistry.callback->next;
1990
31
  while (slot) {
1991
14
    slot = slot->next;
1992
14
    if (slot->value.finalizationCell.target == C_NULL)
1993
0
      break;
1994
14
    slot = slot->next;
1995
14
  }
1996
17
  if (!slot)
1997
17
    registry->value.finalizationRegistry.flags &= ~XS_FINALIZATION_REGISTRY_CHANGED;
1998
17
}
1999
2000
void fxCleanupFinalizationRegistries(txMachine* the)
2001
249k
{
2002
249k
  txSlot** address = &(mxFinalizationRegistries.value.reference->next);
2003
249k
  txSlot* closure;
2004
249k
  while ((closure = *address)) {
2005
91
    txSlot* registry = closure->value.closure;
2006
91
    if (registry->value.finalizationRegistry.flags & XS_FINALIZATION_REGISTRY_CHANGED) {
2007
17
      fx_FinalizationRegistryCleanup(the, registry, C_NULL);
2008
17
      address = &(mxFinalizationRegistries.value.reference->next);
2009
17
    }
2010
74
    else
2011
74
      address = &(closure->next);
2012
91
  }
2013
249k
}
2014
2015