Coverage Report

Created: 2025-12-14 06:18

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