Coverage Report

Created: 2026-09-03 07:12

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