Coverage Report

Created: 2026-04-12 06:36

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