Coverage Report

Created: 2025-06-24 07:03

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