Coverage Report

Created: 2026-07-16 06:43

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