Coverage Report

Created: 2025-10-29 06:26

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