Coverage Report

Created: 2025-08-03 06:59

/src/moddable/xs/sources/xsArray.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2016-2025  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
687k
#define mxArraySize(ARRAY) (((ARRAY)->value.array.address) ? (((txChunk*)(((txByte*)((ARRAY)->value.array.address)) - sizeof(txChunk)))->size) / sizeof(txSlot) : 0)
41
42
static txIndex fxCheckArrayLength(txMachine* the, txSlot* slot);
43
static txBoolean fxCallThisItem(txMachine* the, txSlot* function, txIndex index, txSlot* item);
44
static txSlot* fxCheckArray(txMachine* the, txSlot* slot, txBoolean mutable);
45
static txSlot* fxCheckArrayItems(txMachine* the, txSlot* array, txIndex from, txIndex to);
46
static int fxCompareArrayItem(txMachine* the, txSlot* function, txSlot* array, txInteger i);
47
static txSlot* fxCreateArray(txMachine* the, txFlag flag, txIndex length);
48
static txSlot* fxCreateArraySpecies(txMachine* the, txNumber length);
49
static void fxFindThisItem(txMachine* the, txSlot* function, txNumber index, txSlot* item);
50
static txNumber fxGetArrayLength(txMachine* the, txSlot* reference);
51
static txIndex fxGetArrayLimit(txMachine* the, txSlot* reference);
52
static void fxMoveThisItem(txMachine* the, txNumber from, txNumber to);
53
static void fxReduceThisItem(txMachine* the, txSlot* function, txIndex index);
54
static txBoolean fxSetArrayLength(txMachine* the, txSlot* array, txIndex target);
55
static void fx_Array_from_aux(txMachine* the, txSlot* function, txSlot* value, txIndex index);
56
static txIndex fx_Array_prototype_flatAux(txMachine* the, txSlot* source, txIndex length, txIndex start, txIndex depth, txSlot* function);
57
58
static txBoolean fxArrayDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask);
59
static txBoolean fxArrayDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index);
60
static txBoolean fxArrayGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot);
61
static txSlot* fxArrayGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag);
62
static txBoolean fxArrayHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index);
63
static void fxArrayOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* keys);
64
static txSlot* fxArraySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag);
65
66
const txBehavior ICACHE_FLASH_ATTR gxArrayBehavior = {
67
  fxArrayGetProperty,
68
  fxArraySetProperty,
69
  fxOrdinaryCall,
70
  fxOrdinaryConstruct,
71
  fxArrayDefineOwnProperty,
72
  fxArrayDeleteProperty,
73
  fxArrayGetOwnProperty,
74
  fxOrdinaryGetPropertyValue,
75
  fxOrdinaryGetPrototype,
76
  fxArrayHasProperty,
77
  fxOrdinaryIsExtensible,
78
  fxArrayOwnKeys,
79
  fxOrdinaryPreventExtensions,
80
  fxOrdinarySetPropertyValue,
81
  fxOrdinarySetPrototype,
82
};
83
84
void fxBuildArray(txMachine* the)
85
24.8k
{
86
24.8k
  txSlot* instance;
87
24.8k
  txSlot* slot;
88
24.8k
  txSlot* property;
89
24.8k
  txSlot* unscopable;
90
  
91
24.8k
  mxPush(mxObjectPrototype);
92
24.8k
  instance = fxNewArrayInstance(the);
93
94
24.8k
  fxNewHostFunction(the, mxCallback(fxArrayLengthGetter), 0, mxID(_length), XS_NO_ID);
95
24.8k
  property = mxFunctionInstanceHome(the->stack->value.reference);
96
24.8k
  property->value.home.object = instance;
97
24.8k
  fxNewHostFunction(the, mxCallback(fxArrayLengthSetter), 1, mxID(_length), XS_NO_ID);
98
24.8k
  property = mxFunctionInstanceHome(the->stack->value.reference);
99
24.8k
  property->value.home.object = instance;
100
24.8k
  mxPushUndefined();
101
24.8k
  the->stack->flag = XS_DONT_DELETE_FLAG;
102
24.8k
  the->stack->kind = XS_ACCESSOR_KIND;
103
24.8k
  the->stack->value.accessor.getter = (the->stack + 2)->value.reference;
104
24.8k
  the->stack->value.accessor.setter = (the->stack + 1)->value.reference;
105
24.8k
  mxPull(mxArrayLengthAccessor);
106
24.8k
  mxPop();
107
24.8k
  mxPop();
108
109
24.8k
  slot = fxLastProperty(the, instance);
110
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_at), 1, mxID(_at), XS_DONT_ENUM_FLAG);
111
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_concat), 1, mxID(_concat), XS_DONT_ENUM_FLAG);
112
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_copyWithin), 2, mxID(_copyWithin), XS_DONT_ENUM_FLAG);
113
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_entries), 0, mxID(_entries), XS_DONT_ENUM_FLAG);
114
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_every), 1, mxID(_every), XS_DONT_ENUM_FLAG);
115
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_fill), 1, mxID(_fill), XS_DONT_ENUM_FLAG);
116
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_filter), 1, mxID(_filter), XS_DONT_ENUM_FLAG);
117
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_find), 1, mxID(_find), XS_DONT_ENUM_FLAG);
118
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_findIndex), 1, mxID(_findIndex), XS_DONT_ENUM_FLAG);
119
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_findLast), 1, mxID(_findLast), XS_DONT_ENUM_FLAG);
120
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_findLastIndex), 1, mxID(_findLastIndex), XS_DONT_ENUM_FLAG);
121
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_flat), 0, mxID(_flat), XS_DONT_ENUM_FLAG);
122
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_flatMap), 1, mxID(_flatMap), XS_DONT_ENUM_FLAG);
123
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_forEach), 1, mxID(_forEach), XS_DONT_ENUM_FLAG);
124
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_includes), 1, mxID(_includes), XS_DONT_ENUM_FLAG);
125
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_indexOf), 1, mxID(_indexOf), XS_DONT_ENUM_FLAG);
126
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_join), 1, mxID(_join), XS_DONT_ENUM_FLAG);
127
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_keys), 0, mxID(_keys), XS_DONT_ENUM_FLAG);
128
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_lastIndexOf), 1, mxID(_lastIndexOf), XS_DONT_ENUM_FLAG);
129
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_map), 1, mxID(_map), XS_DONT_ENUM_FLAG);
130
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_pop), 0, mxID(_pop), XS_DONT_ENUM_FLAG);
131
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_push), 1, mxID(_push), XS_DONT_ENUM_FLAG);
132
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_reduce), 1, mxID(_reduce), XS_DONT_ENUM_FLAG);
133
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_reduceRight), 1, mxID(_reduceRight), XS_DONT_ENUM_FLAG);
134
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_reverse), 0, mxID(_reverse), XS_DONT_ENUM_FLAG);
135
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_shift), 0, mxID(_shift), XS_DONT_ENUM_FLAG);
136
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG);
137
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_some), 1, mxID(_some), XS_DONT_ENUM_FLAG);
138
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_sort), 1, mxID(_sort), XS_DONT_ENUM_FLAG);
139
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_splice), 2, mxID(_splice), XS_DONT_ENUM_FLAG);
140
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_toLocaleString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG);
141
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_toString), 0, mxID(_toString), XS_DONT_ENUM_FLAG);
142
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_unshift), 1, mxID(_unshift), XS_DONT_ENUM_FLAG);
143
24.8k
  property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_values), 0, mxID(_values), XS_DONT_ENUM_FLAG);
144
24.8k
  mxPushSlot(property);
145
24.8k
  mxPull(mxArrayIteratorFunction);
146
24.8k
  slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_iterator), XS_DONT_ENUM_FLAG);
147
24.8k
  unscopable = fxLastProperty(the, fxNewInstance(the));
148
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_copyWithin), XS_NO_FLAG);
149
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_at), XS_NO_FLAG);
150
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_entries), XS_NO_FLAG);
151
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_fill), XS_NO_FLAG);
152
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_find), XS_NO_FLAG);
153
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_findIndex), XS_NO_FLAG);
154
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_findLast), XS_NO_FLAG);
155
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_findLastIndex), XS_NO_FLAG);
156
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_flat), XS_NO_FLAG);
157
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_flatMap), XS_NO_FLAG);
158
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_includes), XS_NO_FLAG);
159
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_keys), XS_NO_FLAG);
160
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_values), XS_NO_FLAG);
161
24.8k
#if mxECMAScript2023
162
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_toReversed), XS_NO_FLAG);
163
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_toSorted), XS_NO_FLAG);
164
24.8k
  unscopable = fxNextBooleanProperty(the, unscopable, 1, mxID(_toSpliced), XS_NO_FLAG);
165
24.8k
#endif
166
24.8k
  slot = fxNextSlotProperty(the, slot, the->stack++, mxID(_Symbol_unscopables), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
167
24.8k
#if mxECMAScript2023
168
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_toReversed), 0, mxID(_toReversed), XS_DONT_ENUM_FLAG);
169
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_toSorted), 1, mxID(_toSorted), XS_DONT_ENUM_FLAG);
170
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_toSpliced), 2, mxID(_toSpliced), XS_DONT_ENUM_FLAG);
171
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_prototype_with), 2, mxID(_with), XS_DONT_ENUM_FLAG);
172
24.8k
#endif
173
24.8k
  mxArrayPrototype = *the->stack;
174
24.8k
  slot = fxBuildHostConstructor(the, mxCallback(fx_Array), 1, mxID(_Array));
175
24.8k
  mxArrayConstructor = *the->stack;
176
24.8k
  slot = fxLastProperty(the, slot);
177
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_from), 1, mxID(_from), XS_DONT_ENUM_FLAG);
178
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_isArray), 1, mxID(_isArray), XS_DONT_ENUM_FLAG);
179
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Array_of), 0, mxID(_of), XS_DONT_ENUM_FLAG);
180
24.8k
  slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG);
181
24.8k
  mxPop();
182
183
24.8k
  mxPush(mxIteratorPrototype);
184
24.8k
  slot = fxLastProperty(the, fxNewObjectInstance(the));
185
24.8k
  slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayIterator_prototype_next), 0, mxID(_next), XS_DONT_ENUM_FLAG);
186
24.8k
  slot = fxNextStringXProperty(the, slot, "Array Iterator", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG);
187
24.8k
  mxPull(mxArrayIteratorPrototype);
188
24.8k
}
189
190
txNumber fxArgToIndex(txMachine* the, txInteger argi, txNumber index, txNumber length)
191
4.82M
{
192
4.82M
  if ((mxArgc > argi) && (mxArgv(argi)->kind != XS_UNDEFINED_KIND)) {
193
2.29M
    txNumber i = c_trunc(fxToNumber(the, mxArgv(argi)));
194
2.29M
    if (c_isnan(i) || (i == 0))
195
816k
      i = 0;
196
2.29M
    if (i < 0) {
197
376k
      i = length + i;
198
376k
      if (i < 0)
199
153k
        i = 0;
200
376k
    }
201
1.92M
    else if (i > length)
202
986k
      i = length;
203
2.29M
    index = i;
204
2.29M
  }
205
4.82M
  return index;
206
4.82M
}
207
208
txInteger fxArgToIndexInteger(txMachine* the, txInteger argi, txInteger index, txInteger length)
209
423k
{
210
423k
  if (mxArgc <= argi)
211
68
    return index;
212
213
423k
  txSlot *slot = mxArgv(argi);
214
423k
  if (slot->kind != XS_INTEGER_KIND)
215
91.7k
    return fxArgToIndex(the, argi, index, length);
216
217
331k
  index = slot->value.integer;
218
331k
  if (index < 0) {
219
1.23k
    index = length + index;
220
1.23k
    if (index < 0)
221
1.20k
      index = 0;
222
1.23k
  }
223
330k
  else if (index > length)
224
329k
    index = length;
225
226
331k
  return index;
227
423k
}
228
229
txNumber fxArgToLastIndex(txMachine* the, txInteger argi, txNumber index, txNumber length)
230
152k
{
231
152k
  if (mxArgc > argi) {
232
1.36k
    txNumber i = c_trunc(fxToNumber(the, mxArgv(argi)));
233
1.36k
    if (c_isnan(i) || (i == 0))
234
18
      i = 0;
235
1.36k
    if (i < 0) {
236
17
      i = length + i;
237
17
      if (i < 0)
238
4
        index = 0;
239
13
      else
240
13
        index = i + 1;
241
17
    }
242
1.35k
    else if (i < length)
243
31
      index = i + 1;
244
1.36k
  }
245
152k
  return index;
246
152k
}
247
248
txNumber fxArgToRange(txMachine* the, txInteger argi, txNumber index, txNumber min, txNumber max)
249
350k
{
250
350k
  if ((mxArgc > argi) && (mxArgv(argi)->kind != XS_UNDEFINED_KIND)) {
251
350k
    txNumber i = c_trunc(fxToNumber(the, mxArgv(argi)));
252
350k
    if (c_isnan(i))
253
42
      i = min;
254
350k
    if (i <= min)
255
118
      i = min;
256
350k
    else if (i > max)
257
274k
      i = max;
258
350k
    index = i;
259
350k
  }
260
350k
  return index;
261
350k
}
262
263
txNumber fxArgToRelativeIndex(txMachine* the, txInteger argi, txNumber index, txNumber length)
264
16.9k
{
265
16.9k
  if ((mxArgc > argi) && (mxArgv(argi)->kind != XS_UNDEFINED_KIND)) {
266
16.9k
    txNumber i = c_trunc(fxToNumber(the, mxArgv(argi)));
267
16.9k
    if (c_isnan(i) || (i == 0))
268
3.88k
      i = 0;
269
16.9k
    if (i < 0)
270
13.0k
      i = length + i;
271
16.9k
    index = i;
272
16.9k
  }
273
16.9k
  return index;
274
16.9k
}
275
276
void fxCacheArray(txMachine* the, txSlot* instance)
277
11.3M
{
278
11.3M
  txSlot* array = instance->next;
279
11.3M
  txIndex length = array->value.array.length;
280
11.3M
  if (length) {
281
8.26M
    txSlot* address = (txSlot *)fxNewChunk(the, fxMultiplyChunkSizes(the, length, sizeof(txSlot)));
282
8.26M
    txSlot* srcSlot = array->next;
283
8.26M
    txSlot* dstSlot = address;
284
8.26M
    txIndex index = 0;
285
44.2M
    while (srcSlot) {
286
35.9M
      dstSlot->next = C_NULL;
287
35.9M
      *((txIndex*)dstSlot) = index; 
288
35.9M
      dstSlot->ID = XS_NO_ID;
289
35.9M
      dstSlot->flag = XS_NO_FLAG;
290
35.9M
      dstSlot->kind = srcSlot->kind;
291
35.9M
      dstSlot->value = srcSlot->value;
292
35.9M
      srcSlot = srcSlot->next;
293
35.9M
      dstSlot++;
294
35.9M
      index++;
295
35.9M
    }
296
8.26M
    array->value.array.address = address;
297
8.26M
    array->next = C_NULL;
298
8.26M
  }
299
11.3M
}
300
301
txBoolean fxCallThisItem(txMachine* the, txSlot* function, txIndex index, txSlot* item)
302
5.91M
{
303
5.91M
  mxPushSlot(mxThis);
304
5.91M
  if (mxHasIndex(index)) {
305
    /* THIS */
306
165k
    if (mxArgc > 1)
307
30
      mxPushSlot(mxArgv(1));
308
165k
    else
309
165k
      mxPushUndefined();
310
    /* FUNCTION */
311
165k
    mxPushSlot(function);
312
165k
    mxCall();
313
    /* ARGUMENTS */
314
165k
    mxPushSlot(mxThis);
315
165k
    mxGetIndex(index);
316
165k
    if (item) {
317
1.28k
      item->kind = the->stack->kind;
318
1.28k
      item->value = the->stack->value;
319
1.28k
    }
320
165k
    mxPushUnsigned(index);
321
165k
    mxPushSlot(mxThis);
322
165k
    mxRunCount(3);
323
165k
    return 1;
324
165k
  }
325
5.75M
  return 0;
326
5.91M
}
327
328
txSlot* fxCheckArray(txMachine* the, txSlot* slot, txBoolean mutable)
329
3.44M
{
330
3.44M
  txSlot* instance = fxToInstance(the, slot);
331
3.44M
  txSlot* array = instance->next;
332
3.44M
  if (array && (array->kind == XS_ARRAY_KIND) && (array->ID == XS_ARRAY_BEHAVIOR)) {
333
#if mxAliasInstance
334
    if (instance->ID) {
335
      txSlot* alias = the->aliasArray[instance->ID];
336
      if (alias)
337
        array = alias->next;
338
      else if (mutable) {
339
        instance = fxAliasInstance(the, instance);
340
        array = instance->next;
341
      }
342
    }
343
#endif
344
3.44M
    {
345
3.44M
      txSlot* address = array->value.array.address;
346
3.44M
      txIndex size = (address) ? (((txChunk*)(((txByte*)address) - sizeof(txChunk)))->size) / sizeof(txSlot) : 0;
347
3.44M
      txSlot* prototype = instance->value.instance.prototype;
348
3.44M
      if (array->value.array.length != size)
349
1.12M
        return C_NULL;
350
2.31M
      if (mutable && ((instance->flag & XS_DONT_PATCH_FLAG) || (array->flag & XS_DONT_SET_FLAG)))
351
8
        return C_NULL;
352
6.93M
      while (prototype) {
353
4.62M
        txSlot* property = prototype->next;
354
6.93M
        while (property) {
355
6.93M
          if (property->flag & XS_INTERNAL_FLAG) {
356
2.31M
            if ((property->kind == XS_ARRAY_KIND) && (property->value.array.address != C_NULL)) 
357
1.62k
              return C_NULL;
358
2.31M
          }
359
4.62M
          else 
360
4.62M
            break;
361
2.31M
          property = property->next;
362
2.31M
        }
363
4.62M
        prototype = prototype->value.instance.prototype;
364
4.62M
      }        
365
2.31M
      return array;
366
2.31M
    }
367
2.31M
  }
368
396
  return C_NULL;
369
3.44M
}
370
371
txSlot* fxCheckArrayItems(txMachine* the, txSlot* array, txIndex from, txIndex to)
372
1.16M
{
373
1.16M
  txSlot* address = array->value.array.address;
374
1.16M
  txIndex length = array->value.array.length;
375
1.16M
  if (length < from)
376
1
    return C_NULL;
377
1.16M
  if (length < to)
378
490
    return C_NULL;
379
1.16M
  address += from;
380
3.27M
  while (from < to) {
381
2.11M
    if (address->flag)
382
2
      return C_NULL;
383
2.11M
    if (address->kind == XS_ACCESSOR_KIND)
384
2
      return C_NULL;
385
2.11M
    address++;
386
2.11M
    from++;
387
2.11M
  }
388
1.16M
  return array;
389
1.16M
}
390
391
txIndex fxCheckArrayLength(txMachine* the, txSlot* slot)
392
5.30M
{
393
5.30M
  if (slot->kind == XS_INTEGER_KIND) {
394
5.13M
    if (slot->value.integer >= 0)
395
5.13M
      return (txIndex)slot->value.integer;
396
5.13M
  }
397
166k
  else if (slot->kind == XS_NUMBER_KIND) {
398
166k
    txIndex length = (txIndex)slot->value.number;
399
166k
    txNumber check = length;
400
166k
    if (slot->value.number == check)
401
166k
      return length;
402
166k
  }
403
36
  else {
404
36
    txUnsigned length;
405
36
    txNumber check;
406
36
    mxPushSlot(slot);
407
36
    length = fxToUnsigned(the, the->stack);
408
36
    mxPop();
409
36
    mxPushSlot(slot);
410
36
    check = fxToNumber(the, the->stack);
411
36
    mxPop();
412
36
    if (length == check)
413
33
      return length;
414
36
  }
415
5.30M
  mxRangeError("invalid length");
416
0
  return 0;
417
5.30M
}
418
419
int fxCompareArrayItem(txMachine* the, txSlot* function, txSlot* array, txInteger i)
420
525k
{
421
525k
  txSlot* address = array->value.array.address;
422
525k
  txSlot* a = address + i;
423
525k
  txSlot* b = the->stack;
424
525k
  txSlot* ai = a->next;
425
525k
  txSlot* bi = b->next;
426
525k
  int result;
427
  
428
525k
  if (a->kind == XS_UNDEFINED_KIND)
429
332
    result = (b->kind == XS_UNDEFINED_KIND) ? 0 : 1;
430
524k
  else if (b->kind == XS_UNDEFINED_KIND)
431
67
    result = -1;
432
524k
  else {
433
524k
    if (function) {
434
      /* THIS */
435
333k
      mxPushUndefined();
436
      /* FUNCTION */
437
333k
      mxPushSlot(function);
438
333k
      mxCall();
439
      /* ARGUMENTS */
440
333k
      mxPushSlot(a);
441
333k
      mxPushSlot(b);
442
333k
      mxRunCount(2);
443
333k
      if (the->stack->kind == XS_INTEGER_KIND)
444
219k
        result = the->stack->value.integer;
445
114k
      else {
446
114k
        txNumber number = fxToNumber(the, the->stack);
447
114k
        result = (number < 0) ? -1 :  (number > 0) ? 1 : 0;
448
114k
      }
449
333k
      mxPop();
450
333k
    }
451
190k
    else {
452
190k
      mxPushSlot(a);
453
190k
      mxPushSlot(b);
454
190k
      fxToString(the, the->stack + 1);
455
190k
      fxToString(the, the->stack);
456
190k
      result = fxUTF8Compare((the->stack + 1)->value.string, the->stack->value.string);
457
190k
      mxPop();
458
190k
      mxPop();
459
190k
      mxMeterSome(3);
460
190k
    }
461
524k
  }
462
525k
  if (result == 0)
463
153k
    result = (bi > ai) ? -1 : (bi < ai) ? 1 : 0;
464
525k
  return result;
465
525k
}
466
467
void fxConstructArrayEntry(txMachine* the, txSlot* entry)
468
9.16k
{
469
9.16k
  txSlot* value = the->stack;
470
9.16k
  txSlot* key = the->stack + 1;
471
9.16k
  txSlot* instance;
472
9.16k
  txSlot* array;
473
9.16k
  txSlot* item;
474
9.16k
  mxPush(mxArrayPrototype);
475
9.16k
  instance = fxNewArrayInstance(the);
476
9.16k
  array = instance->next;
477
9.16k
  fxSetIndexSize(the, array, 2, XS_CHUNK);
478
9.16k
  item = array->value.array.address;
479
9.16k
  *((txIndex*)item) = 0;
480
9.16k
  item->ID = XS_NO_ID;
481
9.16k
  item->kind = key->kind;
482
9.16k
  item->value = key->value;
483
9.16k
  item++;
484
9.16k
  *((txIndex*)item) = 1;
485
9.16k
  item->ID = XS_NO_ID;
486
9.16k
  item->kind = value->kind;
487
9.16k
  item->value = value->value;
488
9.16k
  entry->kind = the->stack->kind;
489
9.16k
  entry->value = the->stack->value;
490
9.16k
  the->stack += 3;
491
9.16k
}
492
493
txSlot* fxCreateArray(txMachine* the, txFlag flag, txIndex length)
494
636k
{
495
636k
  if (mxIsReference(mxThis) && mxIsConstructor(mxThis->value.reference))
496
69
    mxPushSlot(mxThis);
497
636k
  else
498
636k
    mxPush(mxArrayConstructor);
499
636k
  mxNew();
500
636k
  if (flag) {
501
387k
    mxPushUnsigned(length);
502
387k
    mxRunCount(1);
503
387k
  }
504
249k
  else
505
249k
    mxRunCount(0);
506
636k
  mxPullSlot(mxResult);
507
636k
  return fxCheckArray(the, mxResult, XS_MUTABLE);
508
636k
}
509
510
txSlot* fxCreateArraySpecies(txMachine* the, txNumber length)
511
164k
{
512
164k
  txSlot* instance = fxToInstance(the, mxThis);
513
164k
  txFlag flag = 1;
514
164k
  if (fxIsArray(the, instance)) {
515
162k
    mxPushSlot(mxThis);
516
162k
    mxGetID(mxID(_constructor));
517
162k
    if (mxIsReference(the->stack)) {
518
162k
      mxGetID(mxID(_Symbol_species));
519
162k
      if (the->stack->kind == XS_NULL_KIND)
520
3
        the->stack->kind = XS_UNDEFINED_KIND;
521
162k
    }
522
162k
  }
523
1.57k
  else
524
1.57k
    mxPushUndefined();
525
164k
    if (the->stack->kind == XS_UNDEFINED_KIND) {
526
1.57k
    *the->stack = mxArrayConstructor;
527
1.57k
        flag = 0;
528
1.57k
    }
529
162k
  else if (mxIsReference(the->stack) && mxIsConstructor(the->stack->value.reference)) {
530
162k
    if (the->stack->value.reference != mxArrayConstructor.value.reference)
531
21
      flag = 0;
532
162k
  }
533
42
  else
534
42
    mxTypeError("invalid constructor");
535
164k
  mxNew();
536
164k
  mxPushNumber(length);
537
164k
  mxRunCount(1);
538
164k
  mxPullSlot(mxResult);
539
164k
  return (flag) ? mxResult->value.reference->next : C_NULL;
540
164k
}
541
542
void fxFindThisItem(txMachine* the, txSlot* function, txNumber index, txSlot* item)
543
57.3k
{
544
  /* THIS */
545
57.3k
  if (mxArgc > 1)
546
4
    mxPushSlot(mxArgv(1));
547
57.3k
  else
548
57.3k
    mxPushUndefined();
549
  /* FUNCTION */
550
57.3k
  mxPushSlot(function);
551
57.3k
  mxCall();
552
  /* ARGUMENTS */
553
57.3k
  mxPushSlot(mxThis);
554
57.3k
  mxGetIndex((txIndex)index);
555
57.3k
  if (item) {
556
128
    item->kind = the->stack->kind;
557
128
    item->value = the->stack->value;
558
128
  }
559
57.3k
  mxPushNumber(index);
560
57.3k
  mxPushSlot(mxThis);
561
  /* ARGC */
562
57.3k
  mxRunCount(3);
563
57.3k
}
564
565
txNumber fxGetArrayLength(txMachine* the, txSlot* reference)
566
2.33M
{
567
2.33M
  txNumber length;
568
2.33M
  txSlot* instance = fxToInstance(the, reference);
569
2.33M
  mxPushReference(instance);
570
2.33M
  mxGetID(mxID(_length));
571
2.33M
  length = fxToLength(the, the->stack);
572
2.33M
  mxPop();
573
2.33M
  return length;
574
2.33M
}
575
576
txIndex fxGetArrayLimit(txMachine* the, txSlot* reference)
577
5.38M
{
578
5.38M
  txNumber length;
579
5.38M
  txSlot* instance = fxToInstance(the, reference);
580
5.38M
  txSlot* array = instance->next;
581
5.38M
  if (array && (array->kind == XS_ARRAY_KIND) && (array->ID == XS_ARRAY_BEHAVIOR)) {
582
#if mxAliasInstance
583
    if (instance->ID) {
584
      txSlot* alias = the->aliasArray[instance->ID];
585
      if (alias)
586
        array = alias->next;
587
    }
588
#endif
589
5.38M
    return array->value.array.length;
590
5.38M
  }
591
375
  if (array && (array->kind == XS_TYPED_ARRAY_KIND) && (array->ID == XS_TYPED_ARRAY_BEHAVIOR)) {
592
57
    txSlot* view = array->next;
593
57
    txSlot* buffer = view->next;
594
57
    if (mxThis->value.reference != instance) { // iterator
595
57
      if (fxIsDataViewOutOfBound(the, view, buffer))
596
0
        mxTypeError("out of bound buffer");
597
57
    }
598
57
    return fxGetDataViewSize(the, view, buffer) >> array->value.typedArray.dispatch->shift;
599
57
  }
600
318
  mxPushReference(instance);
601
318
  mxGetID(mxID(_length));
602
318
  length = fxToLength(the, the->stack);
603
318
  mxPop();
604
318
  if (length > 0xFFFFFFFF) { // @@ practical limit for iterations
605
8
    txSlot* result = instance->next;
606
8
    length = 0;
607
8
    while (result && (result->flag & XS_INTERNAL_FLAG)) {
608
7
      if (result->kind == XS_ARRAY_KIND) {
609
7
        length = result->value.array.length;
610
7
        break;
611
7
      }
612
0
      result = result->next;
613
0
    }
614
8
  }
615
318
  return (txIndex)length;
616
375
}
617
618
void fxIndexArray(txMachine* the, txSlot* array) 
619
5.64M
{
620
5.64M
  txSlot* address = array->value.array.address;
621
5.64M
  if (address) {
622
795k
    txIndex size = (((txChunk*)(((txByte*)address) - sizeof(txChunk)))->size) / sizeof(txSlot);
623
795k
    txIndex index = 0;
624
3.27M
    while (index < size) {
625
2.47M
      *((txIndex*)address) = index; 
626
2.47M
      address->flag = XS_NO_FLAG;
627
2.47M
      address++;
628
2.47M
      index++;
629
2.47M
    }
630
795k
  }
631
5.64M
}
632
633
txBoolean fxIsArray(txMachine* the, txSlot* instance) 
634
534k
{
635
546k
again:
636
546k
  if (instance) {
637
546k
    txSlot* internal = instance->next;
638
546k
    if (internal && (internal->flag & XS_INTERNAL_FLAG)) {
639
445k
      if ((internal->kind == XS_ARRAY_KIND) && (internal->ID == XS_ARRAY_BEHAVIOR))
640
216k
        return 1;
641
229k
      if (internal->kind == XS_PROXY_KIND) {
642
11.3k
        instance = internal->value.proxy.target;
643
11.3k
        if (instance)
644
11.3k
          goto again;
645
11.3k
        mxTypeError("revoked proxy");
646
647
11.3k
      }
648
229k
    }
649
546k
  }
650
318k
  return 0;
651
546k
}
652
653
void fxMoveThisItem(txMachine* the, txNumber from, txNumber to)
654
1.57M
{
655
1.57M
  mxPushSlot(mxThis);
656
1.57M
  mxPushNumber(from);
657
1.57M
  if (mxHasAt()) {
658
230k
    mxPushSlot(mxThis);
659
230k
    mxPushNumber(from);
660
230k
    mxGetAt();
661
230k
    mxPushSlot(mxThis);
662
230k
    mxPushNumber(to);
663
230k
    mxSetAt();
664
230k
    mxPop();
665
230k
  }
666
1.34M
  else {
667
1.34M
    mxPushSlot(mxThis);
668
1.34M
    mxPushNumber(to);
669
1.34M
    mxDeleteAt();
670
1.34M
    mxPop();
671
1.34M
  }
672
1.57M
}
673
674
txSlot* fxNewArrayInstance(txMachine* the)
675
19.2M
{
676
19.2M
  txSlot* instance;
677
19.2M
  txSlot* property;
678
19.2M
  instance = fxNewObjectInstance(the);
679
19.2M
  instance->flag |= XS_EXOTIC_FLAG;
680
19.2M
  property = instance->next = fxNewSlot(the);
681
19.2M
  property->flag = XS_INTERNAL_FLAG | XS_DONT_DELETE_FLAG | XS_DONT_ENUM_FLAG;
682
19.2M
  property->ID = XS_ARRAY_BEHAVIOR;
683
19.2M
  property->kind = XS_ARRAY_KIND;
684
19.2M
  property->value.array.length = 0;
685
19.2M
  property->value.array.address = C_NULL;
686
19.2M
  return instance;
687
19.2M
}
688
689
void fxReduceThisItem(txMachine* the, txSlot* function, txIndex index)
690
9.23k
{
691
9.23k
  mxPushSlot(mxThis);
692
9.23k
  if (fxHasIndex(the, index)) {
693
    /* THIS */
694
9.11k
    mxPushUndefined();
695
    /* FUNCTION */
696
9.11k
    mxPushSlot(function);
697
9.11k
    mxCall();
698
    /* ARGUMENTS */
699
9.11k
    mxPushSlot(mxResult);
700
9.11k
    mxPushSlot(mxThis);
701
9.11k
    mxGetIndex(index);
702
9.11k
    mxPushUnsigned(index);
703
9.11k
    mxPushSlot(mxThis);
704
9.11k
    mxRunCount(4);
705
9.11k
    mxPullSlot(mxResult);
706
9.11k
  }
707
9.23k
}
708
709
txBoolean fxSetArrayLength(txMachine* the, txSlot* array, txIndex length)
710
5.30M
{
711
5.30M
  txSlot* address = array->value.array.address;
712
5.30M
  txSlot* chunk = address;
713
5.30M
  txBoolean success = 1;
714
5.30M
  if (address) {
715
433k
    txSize size = (((txChunk*)(((txByte*)chunk) - sizeof(txChunk)))->size) / sizeof(txSlot);
716
433k
    txSlot* result = address + size;
717
433k
    txSlot* limit = result;
718
433k
    txIndex at;
719
1.47M
    while (result > address) {
720
1.47M
      result--;
721
1.47M
      at = *((txIndex*)result);
722
1.47M
      if (length > at) {
723
433k
        result++;
724
433k
        break;
725
433k
      }
726
1.04M
      else if (result->flag & XS_DONT_DELETE_FLAG) {
727
4
        result++;
728
4
        length = at + 1;
729
4
        success = 0;
730
4
        break;
731
4
      }
732
1.47M
    }
733
433k
    if (result < limit) {
734
151k
      if (result > address) {
735
151k
        size = mxPtrDiff(result - address);
736
151k
        chunk = (txSlot*)fxNewChunk(the, fxMultiplyChunkSizes(the, size, sizeof(txSlot)));
737
151k
        address = array->value.array.address;
738
151k
        c_memcpy(chunk, address, size * sizeof(txSlot));
739
151k
      }
740
97
      else
741
97
        chunk = C_NULL;
742
151k
    }  
743
433k
  }
744
5.30M
  array->value.array.length = length;
745
5.30M
  array->value.array.address = chunk;
746
5.30M
  return success;
747
5.30M
}
748
749
void fxSortArrayItems(txMachine* the, txSlot* function, txSlot* array, txNumber LENGTH, txSlot* target)
750
147k
{
751
147k
  txBoolean flag = mxThis->value.reference != target->value.reference;
752
147k
  txSlot* instance = C_NULL;
753
147k
  txIndex index;
754
147k
    txSlot* item;
755
147k
  txIndex length;
756
147k
  txIndex size;
757
147k
again:
758
147k
  if (!array) {
759
147k
    LENGTH = fxGetArrayLength(the, mxThis);
760
147k
    if (LENGTH > 0xFFFFFFFF)
761
0
      mxRangeError("array overflow");
762
147k
    mxPush(mxArrayPrototype);
763
147k
    instance = fxNewArrayInstance(the);
764
147k
    array = instance->next;
765
147k
    item = array;
766
147k
        index = 0;
767
2.46M
    while (index < LENGTH) {
768
2.31M
      mxPushSlot(mxThis);
769
2.31M
      if (flag || fxHasIndex(the, index)) {
770
2.20M
        item->next = fxNewSlot(the);
771
2.20M
        item = item->next;
772
2.20M
        array->value.array.length++;
773
2.20M
        mxPushSlot(mxThis);
774
2.20M
        mxGetIndex(index);
775
2.20M
        mxPullSlot(item);
776
2.20M
      }
777
2.31M
      index++;
778
2.31M
    }
779
147k
    fxCacheArray(the, instance);
780
147k
  }
781
147k
  length = array->value.array.length;
782
147k
  size = mxArraySize(array);
783
  /* like GCC qsort */
784
147k
  #define CHECK \
785
540k
    if (size != mxArraySize(array)) { \
786
0
      array = C_NULL; \
787
0
      goto again; \
788
0
    }
789
147k
  #define COMPARE(INDEX) \
790
529k
    fxCompareArrayItem(the, function, array, INDEX)
791
147k
  #define COPY \
792
366k
    to->next = from->next; \
793
366k
    to->ID = from->ID; \
794
366k
    to->kind = from->kind; \
795
366k
    to->value = from->value
796
147k
  #define MOVE(FROM,TO) \
797
147k
    from = array->value.array.address + (FROM); \
798
131k
    to = array->value.array.address + (TO); \
799
131k
    COPY
800
147k
  #define PUSH(INDEX) \
801
147k
    from = array->value.array.address + (INDEX); \
802
125k
    mxPushUndefined(); \
803
125k
    to = the->stack; \
804
125k
    COPY
805
147k
  #define PULL(INDEX) \
806
147k
    from = the->stack++; \
807
109k
    to = array->value.array.address + (INDEX); \
808
109k
    COPY
809
147k
  if (length > 0) {
810
30.2k
    txIndex i, j;
811
30.2k
    txSlot* from;
812
30.2k
    txSlot* to;
813
30.2k
    if (length > mxSortThreshold) {
814
9.19k
      txIndex lo = 0, hi = length - 1;
815
9.19k
      txSortPartition stack[mxSortPartitionCount];
816
9.19k
      txSortPartition *top = stack + 1;
817
24.5k
      while (stack < top) {
818
15.3k
        txIndex mid = lo + ((hi - lo) >> 1);
819
15.3k
        PUSH(mid);
820
15.3k
        if (COMPARE(lo) > 0) {
821
6.25k
          CHECK;
822
6.25k
          MOVE(lo, mid);
823
6.25k
          PULL(lo);
824
6.25k
          PUSH(mid);
825
6.25k
        }
826
9.14k
        else
827
15.3k
          CHECK;
828
15.3k
        if (COMPARE(hi) < 0) {
829
3.18k
          CHECK;
830
3.18k
          MOVE(hi, mid);
831
3.18k
          PULL(hi);
832
3.18k
          PUSH(mid);
833
3.18k
          if (COMPARE(lo) > 0) {
834
552
            CHECK;
835
552
            MOVE(lo, mid);
836
552
            PULL(lo);
837
552
            PUSH(mid);
838
552
          }
839
2.63k
          else
840
3.18k
            CHECK;
841
3.18k
        }
842
12.2k
        else
843
15.3k
          CHECK;
844
15.3k
        i = lo + 1;
845
15.3k
        j = hi - 1;
846
30.6k
        do {
847
169k
          while ((COMPARE(i) < 0) && (i <= j)) { CHECK; i++; }
848
61.3k
                    CHECK;
849
149k
          while ((COMPARE(j) > 0) && (i <= j)) { CHECK; j--; }
850
61.3k
          CHECK;
851
61.3k
          if (i < j) {
852
16.7k
            PUSH(i);
853
16.7k
            MOVE(j, i);
854
16.7k
            PULL(j);
855
16.7k
            i++;
856
16.7k
            j--;
857
16.7k
          }
858
13.9k
          else if (i == j) {
859
6.65k
            i++;
860
6.65k
            j--;
861
6.65k
            break;
862
6.65k
          }
863
61.3k
        } while (i <= j);
864
15.3k
        if ((j - lo) <= mxSortThreshold) {
865
11.1k
          if ((hi - i) <= mxSortThreshold) {
866
8.92k
            top--;
867
8.92k
            lo = top->lo; 
868
8.92k
            hi = top->hi;
869
8.92k
          }
870
2.19k
          else {
871
2.19k
            lo = i;
872
2.19k
          }
873
11.1k
        }
874
4.28k
        else if ((hi - i) <= mxSortThreshold) {
875
1.50k
          hi = j;
876
1.50k
        }
877
2.77k
        else if ((j - lo) > (hi - i)) {
878
262
          top->lo = lo;
879
262
          top->hi = j; 
880
262
          top++;
881
262
          lo = i;
882
262
        }
883
2.51k
        else {
884
2.51k
          top->lo = i;
885
2.51k
          top->hi = hi; 
886
2.51k
          top++;
887
2.51k
          hi = j;
888
2.51k
        }
889
15.3k
        mxPop();
890
15.3k
      }
891
9.19k
    }
892
113k
    for (i = 1; i < length; i++) {
893
83.0k
      PUSH(i);
894
187k
      for (j = i; (j > 0) && (COMPARE(j - 1) > 0); j--) {
895
104k
        CHECK;
896
104k
        MOVE(j - 1, j);
897
104k
      }
898
166k
            CHECK;
899
166k
      PULL(j);
900
166k
    }
901
30.2k
  }
902
147k
  if (instance) {
903
145k
    index = 0;
904
257k
    while (index < length) {
905
111k
      item = array->value.array.address + index;
906
111k
      mxPushSlot(item);
907
111k
      mxPushSlot(target);
908
111k
      if (flag)
909
131
        mxDefineIndex(index, 0, XS_GET_ONLY);
910
111k
      else
911
111k
        mxSetIndex(index);
912
111k
      mxPop();
913
111k
      index++;
914
111k
    }
915
263k
    while (index < LENGTH) {
916
117k
      mxPushSlot(target);
917
117k
      mxDeleteIndex(index);
918
117k
      index++;
919
117k
    }
920
145k
    mxPop();
921
145k
  }
922
1.53k
  else
923
1.53k
    fxIndexArray(the, array);
924
147k
}
925
926
txNumber fxToLength(txMachine* the, txSlot* slot)
927
12.2M
{
928
12.3M
again:
929
12.3M
  if (slot->kind == XS_INTEGER_KIND) {
930
9.87M
    txInteger length = slot->value.integer;
931
9.87M
    if (length < 0)
932
10
      length = 0;
933
9.87M
    slot->value.number = (txNumber)length;
934
9.87M
    slot->kind = XS_NUMBER_KIND;
935
9.87M
    return (txNumber)length;
936
9.87M
  }
937
2.47M
  if (slot->kind == XS_NUMBER_KIND) {
938
2.36M
    txNumber length = slot->value.number;
939
2.36M
    if (c_isnan(length))
940
9.48k
      length = 0;
941
2.35M
    else if (length <= 0)
942
201
      length = 0;
943
2.35M
    else if (length > C_MAX_SAFE_INTEGER)
944
96.3k
      length = C_MAX_SAFE_INTEGER;
945
2.26M
    else
946
2.26M
      length = c_trunc(length);
947
2.36M
    slot->value.number = length;
948
2.36M
    return length;
949
2.36M
  }
950
105k
  fxToNumber(the, slot);
951
105k
  goto again;
952
2.47M
}
953
954
void fxArrayLengthGetter(txMachine* the)
955
3.75M
{
956
3.75M
  txSlot* instance = fxToInstance(the, mxThis);
957
3.75M
  txSlot* array;
958
3.75M
  while (instance) {
959
3.75M
    if (instance->flag & XS_EXOTIC_FLAG) {
960
3.75M
      array = instance->next;
961
3.75M
      if ((array->kind == XS_ARRAY_KIND) && (array->ID == XS_ARRAY_BEHAVIOR))
962
3.75M
        break;
963
3.75M
    }
964
144
    instance = fxGetPrototype(the, instance);
965
144
  }
966
3.75M
  if (!instance)
967
0
    return;
968
#if mxAliasInstance
969
  if (instance->ID) {
970
    txSlot* alias = the->aliasArray[instance->ID];
971
    if (alias)
972
      array = alias->next;
973
  }
974
#endif
975
3.75M
  if (((txInteger)array->value.array.length) < 0) {
976
65
    mxResult->value.number = array->value.array.length;
977
65
    mxResult->kind = XS_NUMBER_KIND;
978
65
  }
979
3.75M
  else {
980
3.75M
    mxResult->value.integer = (txInteger)array->value.array.length;
981
3.75M
    mxResult->kind = XS_INTEGER_KIND;
982
3.75M
  }
983
3.75M
}
984
985
void fxArrayLengthSetter(txMachine* the)
986
4.75M
{
987
4.75M
  txSlot* instance = fxToInstance(the, mxThis);
988
4.75M
  txSlot* array;
989
4.75M
  txIndex length;
990
4.75M
  while (instance) {
991
4.75M
    if (instance->flag & XS_EXOTIC_FLAG) {
992
4.75M
      array = instance->next;
993
4.75M
      if (array->ID == XS_ARRAY_BEHAVIOR)
994
4.75M
        break;
995
4.75M
    }
996
10
    instance = fxGetPrototype(the, instance);
997
10
  }
998
4.75M
  if (!instance)
999
0
    return;
1000
#if mxAliasInstance
1001
  if (instance->ID) {
1002
    txSlot* alias = the->aliasArray[instance->ID];
1003
    if (!alias)
1004
      alias = fxAliasInstance(the, instance);
1005
    array = alias->next;
1006
  }
1007
#endif
1008
4.75M
  length = fxCheckArrayLength(the, mxArgv(0));
1009
4.75M
  if (array->flag & XS_DONT_SET_FLAG) {
1010
2
    if (the->frame->next->flag & XS_STRICT_FLAG)
1011
1
      mxTypeError("set length: not writable");
1012
1
    else
1013
1
      return;
1014
2
  }
1015
4.75M
  fxSetArrayLength(the, array, length);
1016
4.75M
}
1017
1018
txBoolean fxArrayDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* descriptor, txFlag mask) 
1019
18.7M
{
1020
18.7M
  if (id == mxID(_length)) {
1021
159
    txSlot* array = instance->next;
1022
159
    txSlot slot;
1023
159
    txBoolean result = 1;
1024
159
        txIndex length = ((descriptor->kind != XS_UNINITIALIZED_KIND) && (descriptor->kind != XS_ACCESSOR_KIND)) ? fxCheckArrayLength(the, descriptor) : 0;
1025
159
        slot.flag = array->flag;
1026
159
    slot.ID = id;
1027
159
    slot.kind = XS_NUMBER_KIND;
1028
159
    slot.value.number = array->value.array.length;
1029
159
    if (!fxIsPropertyCompatible(the, &slot, descriptor, mask))
1030
34
      return 0;
1031
#if mxAliasInstance
1032
    if (instance->ID) {
1033
      txSlot* alias = the->aliasArray[instance->ID];
1034
      if (!alias) {
1035
        alias = fxAliasInstance(the, instance);
1036
        array = alias->next;
1037
      }
1038
    }
1039
#endif
1040
125
    if (descriptor->kind != XS_UNINITIALIZED_KIND) {
1041
24
      if (array->value.array.length != length)
1042
19
        result = fxSetArrayLength(the, array, length);
1043
24
    }
1044
125
    if ((mask & XS_DONT_SET_FLAG) && (descriptor->flag & XS_DONT_SET_FLAG) && !(array->flag & XS_DONT_SET_FLAG))
1045
80
      array->flag |= XS_DONT_SET_FLAG;
1046
125
    return result;
1047
159
  }
1048
18.7M
  return fxOrdinaryDefineOwnProperty(the, instance, id, index, descriptor, mask);
1049
18.7M
}
1050
1051
txBoolean fxArrayDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index)
1052
724k
{
1053
724k
  if (id == mxID(_length))
1054
1
    return 0;
1055
724k
  return fxOrdinaryDeleteProperty(the, instance, id, index);
1056
724k
}
1057
1058
txBoolean fxArrayGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* descriptor)
1059
925k
{
1060
925k
  if (id == mxID(_length)) {
1061
48.5k
    txSlot* array = instance->next;
1062
48.5k
    descriptor->flag = array->flag;
1063
48.5k
    descriptor->ID = id;
1064
48.5k
    descriptor->kind = XS_NUMBER_KIND;
1065
48.5k
    descriptor->value.number = array->value.array.length;
1066
48.5k
    return 1;
1067
48.5k
  }
1068
876k
  return fxOrdinaryGetOwnProperty(the, instance, id, index, descriptor);
1069
925k
}
1070
1071
txSlot* fxArrayGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag)
1072
144M
{
1073
144M
  if (id == mxID(_length))
1074
3.75M
    return &mxArrayLengthAccessor;
1075
140M
  return fxOrdinaryGetProperty(the, instance, id, index, flag);
1076
144M
}
1077
1078
txBoolean fxArrayHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index) 
1079
33.1M
{
1080
33.1M
  if (id == mxID(_length))
1081
4
    return 1;
1082
33.1M
  return fxOrdinaryHasProperty(the, instance, id, index);
1083
33.1M
}
1084
1085
void fxArrayOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* keys)
1086
44.5k
{
1087
44.5k
  txSlot* property = instance->next;
1088
44.5k
  keys = fxQueueIndexKeys(the, property, flag, keys);
1089
44.5k
  if (flag & XS_EACH_NAME_FLAG)
1090
44.5k
    keys = fxQueueKey(the, mxID(_length), 0, keys);
1091
44.5k
  property = property->next;
1092
44.5k
  fxQueueIDKeys(the, property, flag, keys);
1093
44.5k
}
1094
1095
txSlot* fxArraySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag)
1096
24.5M
{
1097
24.5M
  if (id == mxID(_length)) {
1098
4.75M
    txSlot* array = instance->next;
1099
4.75M
    if (array->flag & XS_DONT_SET_FLAG)
1100
546
      return array;
1101
4.75M
    return &mxArrayLengthAccessor;
1102
4.75M
  }
1103
19.8M
  return fxOrdinarySetProperty(the, instance, id, index, flag);
1104
24.5M
}
1105
1106
void fx_Array(txMachine* the)
1107
961k
{
1108
961k
  txSlot* instance;
1109
961k
  txSlot* array;
1110
961k
  txSlot* argument;
1111
961k
  txIndex count = (txIndex)mxArgc;
1112
961k
  txBoolean flag = 0;
1113
961k
  txIndex index = 0;
1114
961k
  txSlot* slot;
1115
  
1116
961k
  if (mxIsUndefined(mxTarget))
1117
159k
    mxPushSlot(mxFunction);
1118
801k
  else
1119
801k
    mxPushSlot(mxTarget);
1120
961k
  fxGetPrototypeFromConstructor(the, &mxArrayPrototype);
1121
961k
  instance = fxNewArrayInstance(the);
1122
961k
  mxPullSlot(mxResult);
1123
961k
  array = instance->next; 
1124
  
1125
961k
  if (count == 1) {
1126
552k
    argument = mxArgv(0);
1127
552k
    if ((argument->kind == XS_INTEGER_KIND) || (argument->kind == XS_NUMBER_KIND)) {
1128
552k
      count = fxCheckArrayLength(the, mxArgv(0));
1129
552k
      flag = 1;
1130
552k
    }
1131
552k
  }
1132
961k
  if (array) {
1133
961k
    if (flag)
1134
552k
      fxSetArrayLength(the, array, count);
1135
409k
    else {
1136
409k
      fxSetIndexSize(the, array, count, XS_CHUNK);
1137
409k
      slot = array->value.array.address;
1138
728k
      while (index < count) {
1139
318k
        argument = mxArgv(index);
1140
318k
        *((txIndex*)slot) = index;
1141
318k
        slot->ID = XS_NO_ID;
1142
318k
        slot->kind = argument->kind;
1143
318k
        slot->value = argument->value;
1144
318k
        slot++;
1145
318k
        index++;
1146
318k
      }
1147
409k
    }
1148
961k
  }
1149
5
  else {
1150
5
    mxPushNumber(count);
1151
5
    mxPushSlot(mxThis);
1152
5
    mxSetID(mxID(_length));
1153
5
    mxPop();
1154
5
    if (!flag) {
1155
0
      while (index < count) {
1156
0
        mxPushSlot(mxArgv(index));
1157
0
        mxPushSlot(mxThis);
1158
0
        mxDefineIndex(index, 0, XS_GET_ONLY);
1159
0
        mxPop();
1160
0
        index++;
1161
0
      }
1162
0
    }
1163
5
  }
1164
961k
}
1165
1166
void fx_Array_from(txMachine* the)
1167
636k
{
1168
636k
  txSlot* function = (mxArgc > 1) ? fxArgToCallback(the, 1) : C_NULL;
1169
636k
  txIndex length = 0;
1170
636k
  txSlot* iterator;
1171
636k
  txSlot* next;
1172
636k
  txSlot* value;
1173
636k
  if (mxArgc > 0) {
1174
494k
    mxPushSlot(mxArgv(0));
1175
494k
    mxGetID(mxID(_Symbol_iterator));
1176
494k
    if (mxIsUndefined(the->stack) || mxIsNull(the->stack)) {
1177
244k
      txIndex index = 0;
1178
244k
      mxPushSlot(mxArgv(0));
1179
244k
      mxGetID(mxID(_length));
1180
244k
      if (mxIsUndefined(the->stack))
1181
244k
        length = 0;
1182
7
      else
1183
7
        length = fxCheckArrayLength(the, the->stack);
1184
244k
      mxPop();
1185
244k
      fxCreateArray(the, 1, length);
1186
244k
      while (index < length) {
1187
57
        mxPushSlot(mxArgv(0));
1188
57
        mxGetIndex(index);
1189
57
        fx_Array_from_aux(the, function, the->stack, index);
1190
57
        mxPop();
1191
57
        index++;
1192
57
      }
1193
244k
    }
1194
249k
    else {
1195
249k
      fxCreateArray(the, 0, 0);
1196
249k
      mxTemporary(iterator);
1197
249k
      mxTemporary(next);
1198
249k
      fxGetIterator(the, mxArgv(0), iterator, next, 0);
1199
249k
      mxTemporary(value);
1200
249k
      length = 0;
1201
9.30M
      while (fxIteratorNext(the, iterator, next, value)) {
1202
9.05M
        mxTry(the) {
1203
9.05M
          fx_Array_from_aux(the, function, value, length);
1204
9.05M
          length++;
1205
9.05M
        }
1206
9.05M
        mxCatch(the) {
1207
2
          fxIteratorReturn(the, iterator, 1);
1208
2
          fxJump(the);
1209
2
        }
1210
9.05M
      }
1211
249k
      mxPop();
1212
249k
    }
1213
494k
  }
1214
142k
  else {
1215
142k
    fxCreateArray(the, 1, 0);
1216
142k
  }
1217
636k
  mxPushUnsigned(length);
1218
636k
  mxPushSlot(mxResult);
1219
636k
  mxSetID(mxID(_length));
1220
636k
  mxPop();
1221
636k
}
1222
1223
void fx_Array_from_aux(txMachine* the, txSlot* function, txSlot* value, txIndex index)
1224
9.05M
{
1225
9.05M
  if (function) {
1226
    /* THIS */
1227
34.2k
    if (mxArgc > 2)
1228
11
      mxPushSlot(mxArgv(2));
1229
34.1k
    else
1230
34.1k
      mxPushUndefined();
1231
    /* FUNCTION */
1232
34.2k
    mxPushSlot(function);
1233
34.2k
    mxCall();
1234
    /* ARGUMENTS */
1235
34.2k
    mxPushSlot(value);
1236
34.2k
    mxPushInteger(index);
1237
34.2k
    mxRunCount(2);
1238
34.2k
  }
1239
9.02M
  else
1240
9.02M
    mxPushSlot(value);
1241
9.05M
  mxPushSlot(mxResult);
1242
9.05M
  mxDefineIndex(index, 0, XS_GET_ONLY);
1243
9.05M
  mxPop();
1244
9.05M
}
1245
1246
void fx_Array_isArray(txMachine* the)
1247
305
{
1248
305
  mxResult->kind = XS_BOOLEAN_KIND;
1249
305
  mxResult->value.boolean = (mxArgc > 0) ? fxIsArray(the, fxGetInstance(the, mxArgv(0))) : 0;
1250
305
}
1251
1252
void fx_Array_of(txMachine* the)
1253
32
{
1254
32
  txIndex count = (txIndex)mxArgc, index = 0;
1255
32
  txSlot* array = fxCreateArray(the, 1, count);
1256
32
  if (array) {
1257
15
    txSlot* slot;
1258
15
    fxSetIndexSize(the, array, count, XS_CHUNK);
1259
15
    slot = array->value.array.address;
1260
15
    while (index < count) {
1261
0
      txSlot* argument = mxArgv(index);
1262
0
      *((txIndex*)slot) = index;
1263
0
      slot->ID = XS_NO_ID;
1264
0
      slot->kind = argument->kind;
1265
0
      slot->value = argument->value;
1266
0
      slot++;
1267
0
      mxMeterSome(4);
1268
0
      index++;
1269
0
    }
1270
15
    mxMeterSome(4);
1271
15
  }
1272
17
  else {
1273
55
    while (index < count) {
1274
38
      mxPushSlot(mxArgv(index));
1275
38
      mxPushSlot(mxResult);
1276
38
      mxDefineIndex(index, 0, XS_GET_ONLY);
1277
38
      mxPop();
1278
38
      index++;
1279
38
    }
1280
17
    mxPushInteger(count);
1281
17
    mxPushSlot(mxResult);
1282
17
    mxSetID(mxID(_length));
1283
17
    mxPop();
1284
17
  }
1285
32
}
1286
1287
void fx_Array_prototype_at(txMachine* the)
1288
334
{
1289
334
  txSlot* array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
1290
334
  txNumber length = (array) ? array->value.array.length : fxGetArrayLength(the, mxThis);
1291
334
  txNumber index = (mxArgc > 0) ? c_trunc(fxToNumber(the, mxArgv(0))) : C_NAN;
1292
334
  if (c_isnan(index) || (index == 0))
1293
135
    index = 0;
1294
334
  if (index < 0)
1295
175
    index = length + index;
1296
334
  if ((0 <= index) && (index < length)) {
1297
150
    mxPushSlot(mxThis);
1298
150
    mxPushNumber(index);
1299
150
    mxGetAt();
1300
150
    mxPullSlot(mxResult);
1301
150
  }
1302
334
}
1303
1304
void fx_Array_prototype_concat(txMachine* the)
1305
3.13k
{
1306
3.13k
  txSlot* resultArray = fxCreateArraySpecies(the, 0);
1307
3.13k
  txIndex resultLength = 0;
1308
3.13k
  txInteger c = mxArgc;
1309
3.13k
  txInteger i = -1;
1310
3.13k
  if (resultArray) {
1311
1.63k
    txSlot* list = fxNewInstance(the);
1312
1.63k
    txSlot* slot = list;
1313
1.63k
    txSlot* resultSlot;
1314
1.63k
    txIndex holeCount = 0;
1315
1.63k
    mxPushSlot(mxThis);
1316
103k
    for (;;) {
1317
103k
      txSlot* argument = the->stack;
1318
103k
      txBoolean flag = 0;
1319
103k
      if (mxIsReference(argument)) {
1320
29.9k
        mxPushSlot(argument);
1321
29.9k
        mxGetID(mxID(_Symbol_isConcatSpreadable));
1322
29.9k
        if (mxIsUndefined(the->stack))
1323
29.8k
          flag = fxIsArray(the, argument->value.reference);
1324
40
        else
1325
40
          flag = fxToBoolean(the, the->stack);
1326
29.9k
        mxPop();
1327
29.9k
      }
1328
103k
      if (flag) { 
1329
3.25k
        txIndex length, index;
1330
3.25k
        mxPushSlot(argument);
1331
3.25k
        mxGetID(mxID(_length));
1332
3.25k
        length = (txIndex)fxToLength(the, the->stack);
1333
3.25k
        mxPop();
1334
3.25k
                if (resultLength + length < resultLength)
1335
2
                    mxTypeError("array overflow");
1336
3.25k
        index = 0;
1337
166k
        while (index < length) {
1338
163k
          mxPushSlot(argument);
1339
163k
          if (fxHasIndex(the, index)) {
1340
163k
            mxPushSlot(argument);
1341
163k
            mxGetIndex(index);
1342
163k
            slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG);
1343
163k
            mxMeterSome(2);
1344
163k
            mxPop();
1345
163k
          }
1346
401
          else {
1347
401
            slot = slot->next = fxNewSlot(the);
1348
401
            slot->kind = XS_UNINITIALIZED_KIND;
1349
401
            holeCount++;
1350
401
          }
1351
163k
          index++;
1352
163k
          resultLength++;
1353
163k
        }
1354
3.25k
      }
1355
100k
      else {
1356
100k
        slot = fxNextSlotProperty(the, slot, argument, XS_NO_ID, XS_NO_FLAG);
1357
100k
        mxMeterSome(4);
1358
100k
        resultLength++;
1359
100k
        if (resultLength == 0)
1360
0
          mxTypeError("array overflow");
1361
100k
      }
1362
103k
      mxPop();
1363
103k
      i++;
1364
103k
      if (i == c)
1365
1.63k
        break;
1366
101k
      mxPushSlot(mxArgv(i));
1367
101k
    }
1368
1.63k
    fxSetIndexSize(the, resultArray, resultLength - holeCount, XS_CHUNK);
1369
1.63k
    resultArray->value.array.length = resultLength;
1370
1.63k
    resultSlot = resultArray->value.array.address;
1371
1.63k
    slot = list->next;
1372
1.63k
    resultLength = 0;
1373
265k
    while (slot) {
1374
263k
      if (slot->kind != XS_UNINITIALIZED_KIND) {
1375
263k
        *((txIndex*)resultSlot) = resultLength;
1376
263k
        resultSlot->ID = XS_NO_ID;
1377
263k
        resultSlot->kind = slot->kind;
1378
263k
        resultSlot->value = slot->value;
1379
263k
        resultSlot++;
1380
263k
      }
1381
263k
      slot = slot->next;
1382
263k
      resultLength++;
1383
263k
    }
1384
1.63k
    mxMeterSome(3);
1385
1.63k
    mxPop();
1386
1.63k
  }
1387
1.49k
  else {
1388
1.49k
    mxPushSlot(mxThis);
1389
1.52k
    for (;;) {
1390
1.52k
      txSlot* argument = the->stack;
1391
1.52k
      txBoolean flag = 0;
1392
1.52k
      if (mxIsReference(argument)) {
1393
1.51k
        mxPushSlot(argument);
1394
1.51k
        mxGetID(mxID(_Symbol_isConcatSpreadable));
1395
1.51k
        if (mxIsUndefined(the->stack))
1396
1.50k
          flag = fxIsArray(the, argument->value.reference);
1397
6
        else
1398
6
          flag = fxToBoolean(the, the->stack);
1399
1.51k
        mxPop();
1400
1.51k
      }
1401
1.52k
      if (flag) { 
1402
18
        txIndex length, index;
1403
18
        mxPushSlot(argument);
1404
18
        mxGetID(mxID(_length));
1405
18
        length = (txIndex)fxToLength(the, the->stack);
1406
18
        mxPop();
1407
18
        index = 0;
1408
121
        while (index < length) {
1409
103
          mxPushSlot(argument);
1410
103
          if (fxHasIndex(the, index)) {
1411
52
            mxPushSlot(argument);
1412
52
            mxGetIndex(index);
1413
52
            mxPushSlot(mxResult);
1414
52
            mxDefineIndex(resultLength, 0, XS_GET_ONLY);
1415
52
            mxPop();
1416
52
          }
1417
103
          index++;
1418
103
          resultLength++;
1419
103
        }
1420
18
      }
1421
1.50k
      else {
1422
1.50k
        mxPushSlot(argument);
1423
1.50k
        mxPushSlot(mxResult);
1424
1.50k
        mxDefineIndex(resultLength, 0, XS_GET_ONLY);
1425
1.50k
        mxPop();
1426
1.50k
        resultLength++;
1427
1.50k
      }
1428
1.52k
      mxPop();
1429
1.52k
      i++;
1430
1.52k
      if (i == c)
1431
1.49k
        break;
1432
30
      mxPushSlot(mxArgv(i));
1433
30
    }
1434
1.49k
    mxPushInteger(resultLength);
1435
1.49k
    mxPushSlot(mxResult);
1436
1.49k
    mxSetID(mxID(_length));
1437
1.49k
    mxPop();
1438
1.49k
  }
1439
3.13k
}
1440
1441
void fx_Array_prototype_copyWithin(txMachine* the)
1442
1.07M
{
1443
1.07M
  txNumber length = fxGetArrayLength(the, mxThis);
1444
1.07M
  txNumber to = fxArgToIndex(the, 0, 0, length);
1445
1.07M
  txNumber from = fxArgToIndex(the, 1, 0, length);
1446
1.07M
  txNumber final = fxArgToIndex(the, 2, length, length);
1447
1.07M
  txNumber count = (final > from) ? final - from : 0;
1448
1.07M
  txSlot* array = fxCheckArray(the, mxThis, XS_MUTABLE);
1449
1.07M
  if (count > length - to)
1450
617k
    count = length - to;
1451
1.07M
  if (array) {
1452
427k
    if (count > 0) {
1453
173k
      if (from < to)
1454
173k
        array = fxCheckArrayItems(the, array, (txIndex)from, (txIndex)(to + count));
1455
58
      else
1456
58
        array = fxCheckArrayItems(the, array, (txIndex)to, (txIndex)(from + count));
1457
173k
    }
1458
427k
  }
1459
1.07M
  if (array) {
1460
427k
    if (count > 0) {
1461
173k
      c_memmove(array->value.array.address + (txIndex)to, array->value.array.address + (txIndex)from, (txIndex)count * sizeof(txSlot));
1462
173k
      fxIndexArray(the, array);
1463
173k
      mxMeterSome((txU4)count * 10);
1464
173k
    }
1465
427k
  }
1466
650k
  else {
1467
650k
    txNumber direction;
1468
650k
    if ((from < to) && (to < from + count)) {
1469
14.7k
      direction = -1;
1470
14.7k
      from += count - 1;
1471
14.7k
      to += count - 1;
1472
14.7k
    }
1473
635k
    else
1474
635k
      direction = 1;
1475
1.24M
    while (count > 0) {
1476
591k
      fxMoveThisItem(the, from, to);
1477
591k
      from += direction;
1478
591k
      to += direction;
1479
591k
      count--;
1480
591k
      mxCheckMetering();
1481
591k
    }  
1482
650k
  }  
1483
1.07M
  mxResult->kind = mxThis->kind;
1484
1.07M
  mxResult->value = mxThis->value;
1485
1.07M
}
1486
1487
void fx_Array_prototype_entries(txMachine* the)
1488
15
{
1489
15
  txSlot* property;
1490
15
  fxToInstance(the, mxThis);
1491
15
  mxPush(mxArrayIteratorPrototype);
1492
15
  property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array)));
1493
15
  property = fxNextIntegerProperty(the, property, 2, XS_NO_ID, XS_INTERNAL_FLAG);
1494
15
  mxPullSlot(mxResult);
1495
15
}
1496
1497
void fx_Array_prototype_every(txMachine* the)
1498
17.0k
{
1499
17.0k
  txIndex length = fxGetArrayLimit(the, mxThis);
1500
17.0k
  txIndex index = 0;
1501
17.0k
  txSlot* function = fxArgToCallback(the, 0);
1502
17.0k
  mxResult->kind = XS_BOOLEAN_KIND;
1503
17.0k
  mxResult->value.boolean = 1;
1504
1.18M
  while (index < length) {
1505
1.17M
    if (fxCallThisItem(the, function, index, C_NULL)) {
1506
17.0k
      mxResult->value.boolean = fxToBoolean(the, the->stack);
1507
17.0k
      mxPop();
1508
17.0k
      if (!mxResult->value.boolean)
1509
11
        break;
1510
17.0k
    }
1511
1.17M
    index++;
1512
1.17M
    mxCheckMetering();
1513
1.17M
  }
1514
17.0k
}
1515
1516
void fx_Array_prototype_fill(txMachine* the)
1517
264k
{
1518
264k
  txSlot* value;
1519
264k
  txSlot* array;
1520
264k
  if (mxArgc > 0)
1521
264k
    mxPushSlot(mxArgv(0));
1522
4
  else
1523
4
    mxPushUndefined();
1524
264k
  value = the->stack;
1525
264k
  array = fxCheckArray(the, mxThis, XS_MUTABLE);
1526
264k
  if (array)
1527
219k
    array = fxCheckArrayItems(the, array, 0, array->value.array.length);
1528
264k
  if (array) {
1529
219k
    txIndex length = array->value.array.length;
1530
219k
    txIndex start = (txIndex)fxArgToIndex(the, 1, 0, length);
1531
219k
    txIndex end = (txIndex)fxArgToIndex(the, 2, length, length);
1532
219k
    txSlot* address;
1533
219k
    txIndex size;
1534
219k
    if ((start == 0) && (end == length)) {
1535
219k
      fxSetIndexSize(the, array, length, XS_CHUNK);
1536
219k
      fxIndexArray(the, array);
1537
219k
    }
1538
219k
    address = array->value.array.address;
1539
219k
    size = (address) ? (((txChunk*)(((txByte*)address) - sizeof(txChunk)))->size) / sizeof(txSlot) : 0;
1540
219k
    if (length == size) {
1541
608k
      while (start < end) {
1542
389k
        txSlot* slot = array->value.array.address + start;
1543
389k
        if (slot->flag) {
1544
0
          mxPushSlot(value);
1545
0
          mxPushSlot(mxThis);
1546
0
          mxSetIndex(start);
1547
0
          mxPop();
1548
0
          mxMeterSome(1);
1549
0
        }
1550
389k
        else {
1551
389k
          slot->ID = XS_NO_ID;
1552
389k
          slot->kind = value->kind;
1553
389k
          slot->value = value->value;
1554
389k
          mxMeterSome(5);
1555
389k
        }
1556
389k
        start++;
1557
389k
        mxCheckMetering();
1558
389k
      }
1559
      
1560
219k
    }
1561
1
    else {
1562
1
      while (start < end) {
1563
0
        mxPushSlot(value);
1564
0
        mxPushSlot(mxThis);
1565
0
        mxSetIndex(start);
1566
0
        mxPop();
1567
0
        mxMeterSome(1);
1568
0
        start++;
1569
0
        mxCheckMetering();
1570
0
      }
1571
1
    }
1572
219k
  }
1573
45.4k
  else {
1574
45.4k
    txNumber length = fxGetArrayLength(the, mxThis);
1575
45.4k
    txNumber start = fxArgToIndex(the, 1, 0, length);
1576
45.4k
    txNumber end = fxArgToIndex(the, 2, length, length);
1577
45.4k
    txSlot* value = the->stack;
1578
301k
    while (start < end) {
1579
255k
      mxPushSlot(value);
1580
255k
      mxPushSlot(mxThis);
1581
255k
      mxPushNumber(start);
1582
255k
      mxSetAt();
1583
255k
      mxPop();
1584
255k
      start++;
1585
255k
      mxCheckMetering();
1586
255k
    }
1587
45.4k
  }
1588
264k
  mxPop();
1589
264k
  mxResult->kind = mxThis->kind;
1590
264k
  mxResult->value = mxThis->value;
1591
264k
}
1592
1593
void fx_Array_prototype_filter(txMachine* the)
1594
62
{
1595
62
  txIndex length = fxGetArrayLimit(the, mxThis);
1596
62
  txIndex index = 0;
1597
62
  txSlot* function = fxArgToCallback(the, 0);
1598
62
  txSlot* resultArray = fxCreateArraySpecies(the, 0);
1599
62
  txIndex resultLength = 0;
1600
62
  txSlot* item;
1601
62
  mxPushUndefined();
1602
62
  item = the->stack;
1603
62
  if (resultArray) {
1604
30
    txSlot* list = fxNewInstance(the);
1605
30
    txSlot* slot = list;
1606
30
    txSlot* resultSlot;
1607
1.00M
    while (index < length) {
1608
1.00M
      if (fxCallThisItem(the, function, index, item)) {
1609
236
        if (fxToBoolean(the, the->stack)) {
1610
162
          slot = fxNextSlotProperty(the, slot, item, XS_NO_ID, XS_NO_FLAG);
1611
162
          mxMeterSome(4);
1612
162
          resultLength++;
1613
162
        }
1614
236
        mxPop();
1615
236
      }
1616
1.00M
      index++;
1617
1.00M
      mxCheckMetering();
1618
1.00M
    }
1619
30
    fxSetIndexSize(the, resultArray, resultLength, XS_CHUNK);
1620
30
    resultSlot = resultArray->value.array.address;
1621
30
    slot = list->next;
1622
30
    index = 0;
1623
192
    while (slot) {
1624
162
      *((txIndex*)resultSlot) = index;
1625
162
      resultSlot->ID = XS_NO_ID;
1626
162
      resultSlot->kind = slot->kind;
1627
162
      resultSlot->value = slot->value;
1628
162
      resultSlot++;
1629
162
      slot = slot->next;
1630
162
      index++;
1631
162
    }
1632
30
    mxPop();
1633
30
    mxMeterSome(-1);
1634
30
  }
1635
32
  else {
1636
34.9k
    while (index < length) {
1637
34.9k
      if (fxCallThisItem(the, function, index, item)) {
1638
1.04k
        if (fxToBoolean(the, the->stack)) {
1639
202
          mxPushSlot(item);
1640
202
          mxPushSlot(mxResult);
1641
202
          mxDefineIndex(resultLength, 0, XS_GET_ONLY);
1642
202
          mxPop();
1643
202
          resultLength++;
1644
202
        }
1645
1.04k
        mxPop();
1646
1.04k
      }
1647
34.9k
      index++;
1648
34.9k
      mxCheckMetering();
1649
34.9k
    }
1650
32
  }
1651
62
  mxPop();
1652
62
}
1653
1654
void fx_Array_prototype_find(txMachine* the)
1655
39
{
1656
39
  txIndex length = fxGetArrayLimit(the, mxThis);
1657
39
  txIndex index = 0;
1658
39
  txSlot* function = fxArgToCallback(the, 0);
1659
39
  txSlot* item;
1660
39
  mxPushUndefined();
1661
39
  item = the->stack;
1662
92
  while (index < length) {
1663
65
    fxFindThisItem(the, function, index, item);
1664
65
    if (fxToBoolean(the, the->stack++)) {
1665
12
      mxResult->kind = item->kind;
1666
12
      mxResult->value = item->value;
1667
12
      break;
1668
12
    }
1669
53
    index++;
1670
53
  }
1671
39
  mxPop();
1672
39
}
1673
1674
void fx_Array_prototype_findIndex(txMachine* the)
1675
67
{
1676
67
  txIndex length = fxGetArrayLimit(the, mxThis);
1677
67
  txIndex index = 0;
1678
67
  txSlot* function = fxArgToCallback(the, 0);
1679
67
  fxInteger(the, mxResult, -1);
1680
121
  while (index < length) {
1681
67
    fxFindThisItem(the, function, index, C_NULL);
1682
67
    if (fxToBoolean(the, the->stack++)) {
1683
13
      fxUnsigned(the, mxResult, index);
1684
13
      break;
1685
13
    }
1686
54
    index++;
1687
54
  }
1688
67
}
1689
1690
void fx_Array_prototype_findLast(txMachine* the)
1691
51
{
1692
51
  txNumber index = fxGetArrayLength(the, mxThis);
1693
51
  txSlot* function = fxArgToCallback(the, 0);
1694
51
  txSlot* item;
1695
51
  mxPushUndefined();
1696
51
  item = the->stack;
1697
101
  while (index > 0) {
1698
63
    index--;
1699
63
    fxFindThisItem(the, function, index, item);
1700
63
    if (fxToBoolean(the, the->stack++)) {
1701
13
      mxResult->kind = item->kind;
1702
13
      mxResult->value = item->value;
1703
13
      break;
1704
13
    }
1705
63
  }
1706
51
  mxPop();
1707
51
}
1708
1709
void fx_Array_prototype_findLastIndex(txMachine* the)
1710
32
{
1711
32
  txNumber index = fxGetArrayLength(the, mxThis);
1712
32
  txSlot* function = fxArgToCallback(the, 0);
1713
32
  fxInteger(the, mxResult, -1);
1714
57.1k
  while (index > 0) {
1715
57.1k
    index--;
1716
57.1k
    fxFindThisItem(the, function, index, C_NULL);
1717
57.1k
    if (fxToBoolean(the, the->stack++)) {
1718
8
      fxUnsigned(the, mxResult, (txUnsigned)index);
1719
8
      break;
1720
8
    }
1721
57.1k
  }
1722
32
}
1723
1724
void fx_Array_prototype_flat(txMachine* the)
1725
40
{
1726
40
  txIndex length, depth = 1;
1727
40
  mxPushSlot(mxThis);
1728
40
  mxGetID(mxID(_length));
1729
40
  length = (txIndex)fxToLength(the, the->stack);
1730
40
  mxPop();
1731
40
  if ((mxArgc > 0) && !mxIsUndefined(mxArgv(0)))
1732
16
    depth = (txIndex)fxToLength(the, mxArgv(0));
1733
40
  fxCreateArraySpecies(the, 0);
1734
40
  fx_Array_prototype_flatAux(the, mxThis, length, 0, depth, C_NULL);
1735
40
}
1736
1737
txIndex fx_Array_prototype_flatAux(txMachine* the, txSlot* source, txIndex length, txIndex start, txIndex depth, txSlot* function)
1738
81
{
1739
81
  txSlot* item;
1740
81
  txIndex index = 0;
1741
378
  while (index < length) {
1742
297
    mxPushSlot(source);
1743
297
    if (fxHasIndex(the, index)) {
1744
188
      if (function) {
1745
        /* THIS */
1746
24
        if (mxArgc > 1)
1747
1
          mxPushSlot(mxArgv(1));
1748
23
        else
1749
23
          mxPushUndefined();
1750
        /* FUNCTION */
1751
24
        mxPushSlot(function);
1752
24
        mxCall();
1753
        /* ARGUMENTS */
1754
24
        mxPushSlot(source);
1755
24
        mxGetIndex(index);
1756
24
        mxPushUnsigned(index);
1757
24
        mxPushSlot(mxThis);
1758
24
        mxRunCount(3);
1759
24
      }
1760
164
      else {
1761
164
        mxPushSlot(source);
1762
164
        mxGetIndex(index);
1763
164
      }
1764
188
      item = the->stack;
1765
188
      if ((depth > 0) && mxIsReference(item) && fxIsArray(the, fxToInstance(the, item))) {
1766
46
        txIndex itemLength;
1767
46
        mxPushSlot(item);
1768
46
        mxGetID(mxID(_length));
1769
46
        itemLength = (txIndex)fxToLength(the, the->stack);
1770
46
        mxPop();
1771
46
        start = fx_Array_prototype_flatAux(the, item, itemLength, start, depth - 1, C_NULL);
1772
46
      }
1773
142
      else {
1774
142
        mxPushSlot(mxResult);
1775
142
        mxDefineIndex(start, 0, XS_GET_ONLY);
1776
142
        start++;
1777
142
      }
1778
188
    }
1779
297
    index++;
1780
297
  }
1781
81
  return start;
1782
81
}
1783
1784
void fx_Array_prototype_flatMap(txMachine* the)
1785
33
{
1786
33
  txIndex length = (txIndex)fxGetArrayLength(the, mxThis);
1787
33
  txSlot* function = fxArgToCallback(the, 0);
1788
33
  fxCreateArraySpecies(the, 0);
1789
33
  fx_Array_prototype_flatAux(the, mxThis, length, 0, 1, function);
1790
33
}
1791
1792
void fx_Array_prototype_forEach(txMachine* the)
1793
599
{
1794
599
  txIndex length = fxGetArrayLimit(the, mxThis);
1795
599
  txIndex index = 0;
1796
599
  txSlot* function = fxArgToCallback(the, 0);
1797
1.12M
  while (index < length) {
1798
1.12M
    if (fxCallThisItem(the, function, index, C_NULL))
1799
55.6k
      mxPop();
1800
1.12M
    index++;
1801
1.12M
    mxCheckMetering();
1802
1.12M
  }
1803
599
}
1804
1805
void fx_Array_prototype_includes(txMachine* the)
1806
44.3k
{
1807
44.3k
  txSlot* array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
1808
44.3k
  txSlot* argument;
1809
44.3k
  if (mxArgc > 0)
1810
44.3k
    mxPushSlot(mxArgv(0));
1811
10
  else
1812
10
    mxPushUndefined();
1813
44.3k
  argument = the->stack;
1814
44.3k
  fxBoolean(the, mxResult, 0);
1815
44.3k
  if (array) {
1816
34.5k
    txIndex length = array->value.array.length;
1817
34.5k
    if (length) {
1818
34.5k
      txIndex index = (txIndex)fxArgToIndex(the, 1, 0, length);
1819
102k
      while (index < length) {
1820
83.7k
        mxPushSlot(mxThis);
1821
83.7k
        mxGetIndex(index);
1822
83.7k
        if (fxIsSameValue(the, the->stack++, argument, 1)) {
1823
15.3k
          mxResult->value.boolean = 1;
1824
15.3k
          break;
1825
15.3k
        }
1826
68.3k
        index++;
1827
68.3k
        mxCheckMetering();
1828
68.3k
      }
1829
34.5k
    }
1830
34.5k
  }
1831
9.80k
  else {
1832
9.80k
    txNumber length = fxGetArrayLength(the, mxThis);
1833
9.80k
    if (length) {
1834
9.76k
      txNumber index = fxArgToIndex(the, 1, 0, length);
1835
98.3k
      while (index < length) {
1836
95.4k
        mxPushSlot(mxThis);
1837
95.4k
        mxPushNumber(index);
1838
95.4k
        mxGetAt();
1839
95.4k
        if (fxIsSameValue(the, the->stack++, argument, 1)) {
1840
6.86k
          mxResult->value.boolean = 1;
1841
6.86k
          break;
1842
6.86k
        }
1843
88.6k
        index++;
1844
88.6k
        mxCheckMetering();
1845
88.6k
      }
1846
9.76k
    }
1847
9.80k
  }
1848
44.3k
  mxPop();
1849
44.3k
}
1850
1851
void fx_Array_prototype_indexOf(txMachine* the)
1852
21.4k
{
1853
21.4k
  txSlot* array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
1854
21.4k
  txSlot* argument;
1855
21.4k
  if (mxArgc > 0)
1856
20.9k
    mxPushSlot(mxArgv(0));
1857
539
  else
1858
539
    mxPushUndefined();
1859
21.4k
  argument = the->stack;
1860
21.4k
  fxInteger(the, mxResult, -1);
1861
21.4k
  if (array) {
1862
21.3k
    txIndex length = array->value.array.length;
1863
21.3k
    if (length) {
1864
19.7k
      txIndex index = (txIndex)fxArgToIndex(the, 1, 0, length);
1865
403k
      while (index < length) {
1866
384k
        mxPushSlot(mxThis);
1867
384k
        if (fxHasIndex(the, index)) {
1868
384k
          mxPushSlot(mxThis);
1869
384k
          mxGetIndex(index);
1870
384k
          if (fxIsSameSlot(the, the->stack++, argument)) {
1871
662
            fxUnsigned(the, mxResult, index);
1872
662
            break;
1873
662
          }
1874
384k
        }
1875
384k
        index++;
1876
384k
        mxCheckMetering();
1877
384k
      }
1878
19.7k
    }
1879
21.3k
  }
1880
127
  else {
1881
127
    txNumber length = fxGetArrayLength(the, mxThis);
1882
127
    if (length) {
1883
112
      txNumber index = fxArgToIndex(the, 1, 0, length);
1884
2.11M
      while (index < length) {
1885
2.11M
        mxPushSlot(mxThis);
1886
2.11M
        mxPushNumber(index);
1887
2.11M
        if (mxHasAt()) {
1888
239
          mxPushSlot(mxThis);
1889
239
          mxPushNumber(index);
1890
239
          mxGetAt();
1891
239
          if (fxIsSameSlot(the, the->stack++, argument)) {
1892
70
            fxNumber(the, mxResult, index);
1893
70
            break;
1894
70
          }
1895
239
        }
1896
2.11M
        index++;
1897
2.11M
        mxCheckMetering();
1898
2.11M
      }
1899
112
    }
1900
127
  }
1901
21.4k
  mxPop();
1902
21.4k
}
1903
1904
void fx_Array_prototype_join(txMachine* the)
1905
4.71M
{
1906
4.71M
  txIndex length = fxGetArrayLimit(the, mxThis);
1907
4.71M
  txIndex index = 0;
1908
4.71M
  txString string;
1909
4.71M
  txSlot* list = fxNewInstance(the);
1910
4.71M
  txSlot* slot = list;
1911
4.71M
  txBoolean comma = 0;
1912
4.71M
  txInteger size = 0;
1913
4.71M
  if ((mxArgc > 0) && (mxArgv(0)->kind != XS_UNDEFINED_KIND)) {
1914
31
    mxPushSlot(mxArgv(0));
1915
31
    string = fxToString(the, the->stack);
1916
31
    the->stack->kind += XS_KEY_KIND - XS_STRING_KIND;
1917
31
    the->stack->value.key.sum = mxStringLength(string);
1918
31
  }
1919
4.71M
  else {
1920
4.71M
    mxPushStringX(",");
1921
4.71M
    the->stack->kind += XS_KEY_KIND - XS_STRING_KIND;
1922
4.71M
    the->stack->value.key.sum = 1;
1923
4.71M
  }
1924
28.1M
  while (index < length) {
1925
23.4M
    if (comma) {
1926
18.9M
      slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG);
1927
18.9M
      size = fxAddChunkSizes(the, size, slot->value.key.sum);
1928
18.9M
    }
1929
4.42M
    else
1930
4.42M
      comma = 1;
1931
23.4M
    mxPushSlot(mxThis);
1932
23.4M
    mxGetIndex(index);
1933
23.4M
    if ((the->stack->kind != XS_UNDEFINED_KIND) && (the->stack->kind != XS_NULL_KIND)) {
1934
12.9M
      slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG);
1935
12.9M
      string = fxToString(the, slot);
1936
12.9M
      slot->kind += XS_KEY_KIND - XS_STRING_KIND;
1937
12.9M
      slot->value.key.sum = mxStringLength(string);
1938
12.9M
      size = fxAddChunkSizes(the, size, slot->value.key.sum);
1939
12.9M
    }
1940
23.4M
    mxPop();
1941
23.4M
    index++;
1942
1943
23.4M
    mxCheckMetering();
1944
23.4M
  }
1945
4.71M
  mxPop();
1946
4.71M
  string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1));
1947
4.71M
  slot = list->next;
1948
34.0M
  while (slot) {
1949
29.3M
    c_memcpy(string, slot->value.key.string, slot->value.key.sum);
1950
29.3M
    string += slot->value.key.sum;
1951
29.3M
    slot = slot->next;
1952
29.3M
  }
1953
4.71M
  *string = 0;
1954
4.71M
  mxResult->kind = XS_STRING_KIND;
1955
4.71M
  mxPop();
1956
4.71M
}
1957
1958
void fx_Array_prototype_keys(txMachine* the)
1959
6
{
1960
6
  txSlot* property;
1961
6
  fxToInstance(the, mxThis);
1962
6
  mxPush(mxArrayIteratorPrototype);
1963
6
  property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array)));
1964
6
  property = fxNextIntegerProperty(the, property, 1, XS_NO_ID, XS_INTERNAL_FLAG);
1965
6
  mxPullSlot(mxResult);
1966
6
}
1967
1968
void fx_Array_prototype_lastIndexOf(txMachine* the)
1969
152k
{
1970
152k
  txSlot* array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
1971
152k
  txSlot* argument;
1972
152k
  if (mxArgc > 0)
1973
103k
    mxPushSlot(mxArgv(0));
1974
49.4k
  else
1975
49.4k
    mxPushUndefined();
1976
152k
  argument = the->stack;
1977
152k
  fxInteger(the, mxResult, -1);
1978
152k
  if (array) {
1979
122k
    txIndex length = array->value.array.length;
1980
122k
    if (length) {
1981
122k
      txIndex index = (txIndex)fxArgToLastIndex(the, 1, length, length);
1982
667k
      while (index > 0) {
1983
566k
        index--;
1984
566k
        mxPushSlot(mxThis);
1985
566k
        if (fxHasIndex(the, index)) {
1986
566k
          mxPushSlot(mxThis);
1987
566k
          mxGetIndex(index);
1988
566k
          if (fxIsSameSlot(the, the->stack++, argument)) {
1989
21.5k
            fxUnsigned(the, mxResult, index);
1990
21.5k
            break;
1991
21.5k
          }
1992
566k
        }
1993
545k
        mxCheckMetering();
1994
545k
      }
1995
122k
    }
1996
122k
  }
1997
30.4k
  else {
1998
30.4k
    txNumber length = fxGetArrayLength(the, mxThis);
1999
30.4k
    if (length) {
2000
30.4k
      txNumber index = fxArgToLastIndex(the, 1, length, length);
2001
2.63M
      while (index > 0) {
2002
2.60M
        index--;
2003
2.60M
        mxPushSlot(mxThis);
2004
2.60M
        mxPushNumber(index);
2005
2.60M
        if (mxHasAt()) {
2006
148k
          mxPushSlot(mxThis);
2007
148k
          mxPushNumber(index);
2008
148k
          mxGetAt();
2009
148k
          if (fxIsSameSlot(the, the->stack++, argument)) {
2010
1.09k
            fxNumber(the, mxResult, index);
2011
1.09k
            break;
2012
1.09k
          }
2013
148k
        }
2014
2.60M
        mxCheckMetering();
2015
2.60M
      }
2016
30.4k
    }
2017
30.4k
  }
2018
152k
  mxPop();
2019
152k
}
2020
2021
void fx_Array_prototype_map(txMachine* the)
2022
68
{
2023
68
  txNumber LENGTH = fxGetArrayLength(the, mxThis);
2024
68
  txSlot* function = fxArgToCallback(the, 0);
2025
68
  txSlot* resultArray = fxCreateArraySpecies(the, LENGTH);
2026
68
  txIndex length = (txIndex)LENGTH;
2027
68
  txIndex index = 0;
2028
68
  if (resultArray) {
2029
30
    txIndex resultLength = 0;
2030
30
    fxSetIndexSize(the, resultArray, length, XS_CHUNK);
2031
1.53M
    while (index < length) {
2032
1.53M
      if (fxCallThisItem(the, function, index, C_NULL)) {
2033
30.0k
        txSlot* slot = resultArray->value.array.address + resultLength;
2034
30.0k
        *((txIndex*)slot) = index;
2035
30.0k
        slot->ID = XS_NO_ID;
2036
30.0k
        slot->kind = the->stack->kind;
2037
30.0k
        slot->value = the->stack->value;
2038
30.0k
        resultLength++;
2039
30.0k
        mxMeterSome(2);
2040
30.0k
        mxPop();
2041
30.0k
      }
2042
1.53M
      index++;
2043
1.53M
      mxCheckMetering();
2044
1.53M
    }
2045
30
    if (resultLength < length) {
2046
9
      fxSetIndexSize(the, resultArray, resultLength, XS_CHUNK);
2047
9
      resultArray->value.array.length = length;
2048
9
    }
2049
30
  }
2050
38
  else {
2051
61.2k
    while (index < length) {
2052
61.1k
      if (fxCallThisItem(the, function, index, C_NULL)) {
2053
61.0k
        mxPushSlot(mxResult);
2054
61.0k
        mxDefineIndex(index, 0, XS_GET_ONLY);
2055
61.0k
        mxPop();
2056
61.0k
      }
2057
61.1k
      index++;
2058
61.1k
      mxCheckMetering();
2059
61.1k
    }
2060
38
  }
2061
68
}
2062
2063
void fx_Array_prototype_pop(txMachine* the)
2064
515
{
2065
515
  txSlot* array = fxCheckArray(the, mxThis, XS_MUTABLE);
2066
515
  if (array) {
2067
377
    txIndex length = array->value.array.length;
2068
377
    if (length > 0)
2069
319
      array = fxCheckArrayItems(the, array, length - 1, length);
2070
377
  }
2071
515
  if (array) {
2072
377
    txIndex length = array->value.array.length;
2073
377
    txSlot* address;
2074
377
    mxMeterSome(2);
2075
377
    if (length > 0) {
2076
319
      length--;
2077
319
      address = array->value.array.address + length;
2078
319
      mxResult->kind = address->kind;
2079
319
      mxResult->value = address->value;
2080
319
      fxSetIndexSize(the, array, length, XS_CHUNK);
2081
319
      mxMeterSome(8);
2082
319
    }
2083
377
    mxMeterSome(4);
2084
377
  }
2085
138
  else {
2086
138
    txNumber length = fxGetArrayLength(the, mxThis);
2087
138
    if (length > 0) {
2088
121
      length--;
2089
121
      mxPushSlot(mxThis);
2090
121
      mxPushNumber(length);
2091
121
      mxGetAt();
2092
121
      mxPullSlot(mxResult);
2093
121
      mxPushSlot(mxThis);
2094
121
      mxPushNumber(length);
2095
121
      mxDeleteAt();
2096
121
      mxPop();
2097
121
    }
2098
138
    mxPushNumber(length);
2099
138
    mxPushSlot(mxThis);
2100
138
    mxSetID(mxID(_length));
2101
138
    mxPop();
2102
138
  }
2103
515
}
2104
2105
void fx_Array_prototype_push(txMachine* the)
2106
240k
{
2107
240k
  txIndex c = mxArgc, i = 0;
2108
240k
  txSlot* array = fxCheckArray(the, mxThis, XS_MUTABLE);
2109
240k
  if (array) {
2110
238k
    txIndex length = array->value.array.length;
2111
238k
    txSlot* address;
2112
238k
    mxMeterSome(2);
2113
238k
    if (length + c < length)
2114
0
      mxRangeError("array overflow");
2115
238k
    fxSetIndexSize(the, array, length + c, XS_GROWABLE_CHUNK);
2116
238k
    address = array->value.array.address + length;
2117
477k
    while (i < c) {
2118
238k
      txSlot* argument = mxArgv(i);
2119
238k
      *((txIndex*)address) = length + i;
2120
238k
      address->ID = XS_NO_ID;
2121
238k
      address->kind = argument->kind;
2122
238k
      address->value = argument->value;
2123
238k
      address++;
2124
238k
      mxMeterSome(5);
2125
238k
      i++;
2126
238k
    }
2127
238k
    mxPushUnsigned(length + c);
2128
238k
    mxMeterSome(2);
2129
238k
  }
2130
1.65k
  else {
2131
1.65k
    txNumber length = fxGetArrayLength(the, mxThis);
2132
1.65k
    if (length + c > C_MAX_SAFE_INTEGER)
2133
10
      mxTypeError("unsafe integer");
2134
3.27k
    while (i < c) {
2135
1.62k
      mxPushSlot(mxArgv(i));
2136
1.62k
      mxPushSlot(mxThis);
2137
1.62k
      mxPushNumber(length + i);
2138
1.62k
      mxSetAt();
2139
1.62k
      mxPop();
2140
1.62k
      i++;
2141
1.62k
    }
2142
1.64k
    mxPushNumber(length + c);
2143
1.64k
    mxPushSlot(mxThis);
2144
1.64k
    mxSetID(mxID(_length));
2145
1.64k
  }
2146
240k
  mxPullSlot(mxResult);
2147
240k
}
2148
2149
void fx_Array_prototype_reduce(txMachine* the)
2150
45
{
2151
45
  txIndex length = fxGetArrayLimit(the, mxThis);
2152
45
  txIndex index = 0;
2153
45
  txSlot* function = fxArgToCallback(the, 0);
2154
45
  if (mxArgc > 1)
2155
27
    *mxResult = *mxArgv(1);
2156
18
  else {
2157
18
    txBoolean flag = 0;
2158
122
    while (!flag && (index < length)) {
2159
104
      mxPushSlot(mxThis);
2160
104
      if (fxHasIndex(the, index)) {
2161
10
        mxPushSlot(mxThis);
2162
10
        mxGetIndex(index);
2163
10
        mxPullSlot(mxResult);
2164
10
        flag = 1;
2165
10
      }
2166
104
      index++;
2167
104
    }
2168
18
    if (!flag)
2169
7
      mxTypeError("no initial value");
2170
18
  }
2171
8.99k
  while (index < length) {
2172
8.95k
    fxReduceThisItem(the, function, index);
2173
8.95k
    index++;
2174
8.95k
  }
2175
38
}
2176
2177
void fx_Array_prototype_reduceRight(txMachine* the)
2178
27
{
2179
27
  txIndex length = fxGetArrayLimit(the, mxThis);
2180
27
  txIndex index = length;
2181
27
  txSlot* function = fxArgToCallback(the, 0);
2182
27
  if (mxArgc > 1)
2183
10
    *mxResult = *mxArgv(1);
2184
17
  else {
2185
17
    txBoolean flag = 0;
2186
78
    while (!flag && (index > 0)) {
2187
61
      index--;
2188
61
      mxPushSlot(mxThis);
2189
61
      if (fxHasIndex(the, index)) {
2190
7
        mxPushSlot(mxThis);
2191
7
        mxGetIndex(index);
2192
7
        mxPullSlot(mxResult);
2193
7
        flag = 1;
2194
7
      }
2195
61
    }
2196
17
    if (!flag)
2197
9
      mxTypeError("no initial value");
2198
17
  }
2199
298
  while (index > 0) {
2200
280
    index--;
2201
280
    fxReduceThisItem(the, function, index);
2202
280
  }
2203
18
}
2204
2205
void fx_Array_prototype_reverse(txMachine* the)
2206
25
{
2207
25
  txSlot* lowerSlot;
2208
25
  txSlot* upperSlot;
2209
25
  txNumber length = fxGetArrayLength(the, mxThis);
2210
25
  txNumber middle = c_trunc(length / 2);
2211
25
  txNumber lower = 0;
2212
920
  while (lower != middle) {
2213
895
    txNumber upper = length - lower - 1;
2214
895
    mxPushSlot(mxThis);
2215
895
    mxPushNumber(lower);
2216
895
    if (mxHasAt()) {
2217
54
      mxPushSlot(mxThis);
2218
54
      mxPushNumber(lower);
2219
54
      mxGetAt();
2220
54
      lowerSlot = the->stack;
2221
54
    }
2222
841
    else
2223
841
      lowerSlot = C_NULL;
2224
895
    mxPushSlot(mxThis);
2225
895
    mxPushNumber(upper);
2226
895
    if (mxHasAt()) {
2227
55
      mxPushSlot(mxThis);
2228
55
      mxPushNumber(upper);
2229
55
      mxGetAt();
2230
55
      upperSlot = the->stack;
2231
55
    }
2232
840
    else
2233
840
      upperSlot = C_NULL;
2234
895
    if (upperSlot && lowerSlot) {
2235
48
      mxPushSlot(upperSlot);
2236
48
      mxPushSlot(mxThis);
2237
48
      mxPushNumber(lower);
2238
48
      mxSetAt();
2239
48
      mxPop();
2240
48
      mxPushSlot(lowerSlot);
2241
48
      mxPushSlot(mxThis);
2242
48
      mxPushNumber(upper);
2243
48
      mxSetAt();
2244
48
      mxPop();
2245
48
      mxPop();
2246
48
      mxPop();
2247
48
    }
2248
847
    else if (upperSlot) {
2249
7
      mxPushSlot(upperSlot);
2250
7
      mxPushSlot(mxThis);
2251
7
      mxPushNumber(lower);
2252
7
      mxSetAt();
2253
7
      mxPop();
2254
7
      mxPushSlot(mxThis);
2255
7
      mxPushNumber(upper);
2256
7
      mxDeleteAt();
2257
7
      mxPop();
2258
7
      mxPop();
2259
7
    }
2260
840
    else if (lowerSlot) {
2261
6
      mxPushSlot(mxThis);
2262
6
      mxPushNumber(lower);
2263
6
      mxDeleteAt();
2264
6
      mxPop();
2265
6
      mxPushSlot(lowerSlot);
2266
6
      mxPushSlot(mxThis);
2267
6
      mxPushNumber(upper);
2268
6
      mxSetAt();
2269
6
      mxPop();
2270
6
      mxPop();
2271
6
    }
2272
895
    lower++;
2273
895
    mxCheckMetering();
2274
895
  }
2275
25
  *mxResult = *mxThis;
2276
25
}
2277
2278
void fx_Array_prototype_shift(txMachine* the)
2279
98
{
2280
98
  txSlot* array = fxCheckArray(the, mxThis, XS_MUTABLE);
2281
98
  if (array)
2282
61
    array = fxCheckArrayItems(the, array, 0, array->value.array.length);
2283
98
  if (array) {
2284
61
    txIndex length = array->value.array.length;
2285
61
    txSlot* address;
2286
61
    mxMeterSome(2);
2287
61
    if (length > 0) {
2288
51
      mxMeterSome(3);
2289
51
      address = array->value.array.address;
2290
51
      length--;
2291
51
      mxResult->kind = address->kind;
2292
51
      mxResult->value = address->value;
2293
51
      c_memmove(address, address + 1, length * sizeof(txSlot));
2294
51
      fxSetIndexSize(the, array, length, XS_CHUNK);
2295
51
      fxIndexArray(the, array);
2296
51
      mxMeterSome(length * 10);
2297
51
      mxMeterSome(3);
2298
51
    }
2299
61
    mxMeterSome(4);
2300
61
  }
2301
37
  else {
2302
37
    txNumber length = fxGetArrayLength(the, mxThis);
2303
37
    if (length > 0) {
2304
18
      txNumber index = 1;
2305
18
      mxPushSlot(mxThis);
2306
18
      mxGetIndex(0);
2307
18
      mxPullSlot(mxResult);
2308
1.74M
      while (index < length) {
2309
1.74M
        mxPushSlot(mxThis);
2310
1.74M
        mxPushNumber(index);
2311
1.74M
        if (mxHasAt()) {
2312
8
          mxPushSlot(mxThis);
2313
8
          mxPushNumber(index);
2314
8
          mxGetAt();
2315
8
          mxPushSlot(mxThis);
2316
8
          mxPushNumber(index - 1);
2317
8
          mxSetAt();
2318
8
          mxPop();
2319
8
        }
2320
1.74M
        else {
2321
1.74M
          mxPushSlot(mxThis);
2322
1.74M
          mxPushNumber(index - 1);
2323
1.74M
          mxDeleteAt();
2324
1.74M
          mxPop();
2325
1.74M
        }
2326
1.74M
        index++;
2327
1.74M
        mxCheckMetering();
2328
1.74M
      }
2329
18
      length--;
2330
18
      mxPushSlot(mxThis);
2331
18
      mxDeleteIndex((txIndex)length);
2332
18
      mxPop();
2333
18
    }
2334
37
    mxPushNumber(length);
2335
37
    mxPushSlot(mxThis);
2336
37
    mxSetID(mxID(_length));
2337
37
    mxPop();
2338
37
  }
2339
98
}
2340
2341
void fx_Array_prototype_slice(txMachine* the)
2342
14.8k
{
2343
14.8k
  txNumber LENGTH = fxGetArrayLength(the, mxThis);
2344
14.8k
  txNumber START = fxArgToIndex(the, 0, 0, LENGTH);
2345
14.8k
  txNumber END = fxArgToIndex(the, 1, LENGTH, LENGTH);
2346
14.8k
  txNumber COUNT = (END > START) ? END - START : 0;
2347
14.8k
  txSlot* resultArray = fxCreateArraySpecies(the, COUNT);
2348
14.8k
  txSlot* array = C_NULL;
2349
14.8k
  if (resultArray)
2350
14.8k
    array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
2351
14.8k
  if (array)
2352
14.7k
    array = fxCheckArrayItems(the, array, (txIndex)START, (txIndex)(START + COUNT));
2353
14.8k
  if (array) {
2354
14.2k
    txIndex start = (txIndex)START;
2355
14.2k
    txIndex count = (txIndex)COUNT;
2356
14.2k
    if (count) {
2357
14.0k
      fxSetIndexSize(the, resultArray, count, XS_CHUNK);
2358
14.0k
      c_memcpy(resultArray->value.array.address, array->value.array.address + start, count * sizeof(txSlot));
2359
14.0k
      fxIndexArray(the, resultArray);
2360
14.0k
      mxMeterSome(count * 10);
2361
14.0k
    }
2362
14.2k
    mxMeterSome(3);
2363
14.2k
  }
2364
605
  else {
2365
605
    txNumber INDEX = 0;
2366
749k
    while (START < END) {
2367
749k
      mxPushSlot(mxThis);
2368
749k
      mxPushNumber(START);
2369
749k
      if (mxHasAt()) {
2370
95
        mxPushSlot(mxThis);
2371
95
        mxPushNumber(START);
2372
95
        mxGetAt();
2373
95
        mxPushSlot(mxResult);
2374
95
        mxPushNumber(INDEX);
2375
95
        mxDefineAt(0, XS_GET_ONLY);
2376
95
        mxPop();
2377
95
      }
2378
749k
      INDEX++;
2379
749k
      START++;
2380
749k
      mxCheckMetering();
2381
749k
    }
2382
605
    mxPushNumber(COUNT);
2383
605
    mxPushSlot(mxResult);
2384
605
    mxSetID(mxID(_length));
2385
605
  }
2386
14.8k
}
2387
2388
void fx_Array_prototype_some(txMachine* the)
2389
120
{
2390
120
  txIndex length = fxGetArrayLimit(the, mxThis);
2391
120
  txIndex index = 0;
2392
120
  txSlot* function = fxArgToCallback(the, 0);
2393
120
  mxResult->kind = XS_BOOLEAN_KIND;
2394
120
  mxResult->value.boolean = 0;
2395
1.00M
  while (index < length) {
2396
1.00M
    if (fxCallThisItem(the, function, index, C_NULL)) {
2397
479
      mxResult->value.boolean = fxToBoolean(the, the->stack);
2398
479
      mxPop();
2399
479
      if (mxResult->value.boolean)
2400
100
        break;
2401
479
    }
2402
1.00M
    index++;
2403
1.00M
    mxCheckMetering();
2404
1.00M
  }
2405
120
}
2406
2407
2408
void fx_Array_prototype_sort(txMachine* the)
2409
145k
{
2410
145k
  txSlot* function = C_NULL;
2411
145k
  /*txSlot* array =*/ fxCheckArray(the, mxThis, XS_MUTABLE);
2412
145k
  if (mxArgc > 0) {
2413
45
    txSlot* slot = mxArgv(0);
2414
45
    if (slot->kind != XS_UNDEFINED_KIND) {
2415
44
      if (fxIsCallable(the, slot))
2416
25
        function = slot;
2417
19
      else
2418
19
        mxTypeError("compare: not a function");
2419
44
    }
2420
45
  }
2421
//  if (function)
2422
145k
    fxSortArrayItems(the, function, C_NULL, fxGetArrayLength(the, mxThis), mxThis);
2423
//  else {
2424
//    if (array)
2425
//      array = fxCheckArrayItems(the, array, 0, array->value.array.length);
2426
//    fxSortArrayItems(the, function, array, fxGetArrayLength(the, mxThis), mxThis);
2427
//  }
2428
145k
  mxResult->kind = mxThis->kind;
2429
145k
  mxResult->value = mxThis->value;
2430
145k
}
2431
2432
void fx_Array_prototype_splice(txMachine* the)
2433
146k
{
2434
146k
  txIndex c = (txIndex)mxArgc;
2435
146k
  txNumber LENGTH = fxGetArrayLength(the, mxThis);
2436
146k
  txNumber START = fxArgToIndex(the, 0, 0, LENGTH);
2437
146k
  txNumber INSERTIONS, DELETIONS;
2438
146k
  txSlot* resultArray;
2439
146k
  txSlot* array = C_NULL;
2440
146k
  if (c == 0) {
2441
15
    INSERTIONS = 0;
2442
15
    DELETIONS = 0;
2443
15
  }
2444
146k
  else if (c == 1) {
2445
939
    INSERTIONS = 0;
2446
939
    DELETIONS = LENGTH - START;
2447
939
  }
2448
145k
  else {
2449
145k
    INSERTIONS = c - 2;
2450
145k
    DELETIONS = fxArgToRange(the, 1, 0, 0, LENGTH - START);
2451
145k
  }
2452
146k
  if (LENGTH + INSERTIONS - DELETIONS > C_MAX_SAFE_INTEGER)
2453
9
    mxTypeError("unsafe integer");
2454
146k
  resultArray = fxCreateArraySpecies(the, DELETIONS);
2455
146k
  if (resultArray)
2456
146k
    array = fxCheckArray(the, mxThis, XS_MUTABLE);
2457
146k
  if (array) {
2458
145k
    if (INSERTIONS == DELETIONS)
2459
109k
      array = fxCheckArrayItems(the, array, (txIndex)START, (txIndex)(START + DELETIONS));
2460
36.0k
    else
2461
36.0k
      array = fxCheckArrayItems(the, array, (txIndex)START, (txIndex)LENGTH);
2462
145k
  }
2463
146k
  if (array) {
2464
145k
    txSlot* address;
2465
145k
    txIndex length = (txIndex)LENGTH;
2466
145k
    txIndex start = (txIndex)START;
2467
145k
    txIndex insertions = (txIndex)INSERTIONS;
2468
145k
    txIndex deletions = (txIndex)DELETIONS;
2469
145k
    txIndex index;
2470
145k
    if (LENGTH + INSERTIONS - DELETIONS > 0xFFFFFFFF)
2471
0
      mxTypeError("array overflow");
2472
145k
    fxSetIndexSize(the, resultArray, deletions, XS_CHUNK);
2473
145k
    c_memcpy(resultArray->value.array.address, array->value.array.address + start, deletions * sizeof(txSlot));
2474
145k
    fxIndexArray(the, resultArray);
2475
145k
    mxMeterSome(deletions * 10);
2476
145k
    mxMeterSome(4);
2477
145k
    if (insertions < deletions) {
2478
36.0k
      c_memmove(array->value.array.address + start + insertions, array->value.array.address + start + deletions, (length - (start + deletions)) * sizeof(txSlot));
2479
36.0k
      fxSetIndexSize(the, array, length - (deletions - insertions), XS_CHUNK);
2480
36.0k
      mxMeterSome((length - (start + deletions)) * 10);
2481
36.0k
      mxMeterSome((deletions - insertions) * 4);
2482
36.0k
    }
2483
109k
    else if (insertions > deletions) {
2484
3
      fxSetIndexSize(the, array, length + (insertions - deletions), XS_CHUNK);
2485
3
      c_memmove(array->value.array.address + start + insertions, array->value.array.address + start + deletions, (length - (start + deletions)) * sizeof(txSlot));
2486
3
      mxMeterSome((length - (start + deletions)) * 10);
2487
3
    }
2488
145k
    address = array->value.array.address + start;
2489
145k
    index = 2;
2490
145k
    while (index < c) {
2491
24
      txSlot* argument = mxArgv(index);
2492
24
      address->ID = XS_NO_ID;
2493
24
      address->kind = argument->kind;
2494
24
      address->value = argument->value;
2495
24
      address++;
2496
24
      mxMeterSome(5);
2497
24
      index++;
2498
24
      mxCheckMetering();
2499
24
    }
2500
145k
    fxIndexArray(the, array);
2501
145k
    mxMeterSome(4);
2502
145k
  }
2503
747
  else { 
2504
747
    txNumber INDEX = 0;
2505
2.20k
    while (INDEX < DELETIONS) {
2506
1.45k
      txNumber FROM = START + INDEX;
2507
1.45k
      mxPushSlot(mxThis);
2508
1.45k
      mxPushNumber(FROM);
2509
1.45k
      if (mxHasAt()) {
2510
775
        mxPushSlot(mxThis);
2511
775
        mxPushNumber(FROM);
2512
775
        mxGetAt();
2513
775
        mxPushSlot(mxResult);
2514
775
        mxPushNumber(INDEX);
2515
775
        mxDefineAt(0, XS_GET_ONLY);
2516
775
        mxPop();
2517
775
      }
2518
1.45k
      INDEX++;
2519
1.45k
      mxCheckMetering();
2520
1.45k
    }
2521
747
    mxPushNumber(DELETIONS);
2522
747
    mxPushSlot(mxResult);
2523
747
    mxSetID(mxID(_length));
2524
747
    mxPop();
2525
747
    if (INSERTIONS < DELETIONS) {
2526
711
      INDEX = START;
2527
111k
      while (INDEX < (LENGTH - DELETIONS)) {
2528
111k
        fxMoveThisItem(the, INDEX + DELETIONS, INDEX + INSERTIONS);
2529
111k
        INDEX++;
2530
111k
        mxCheckMetering();
2531
111k
      }
2532
711
      INDEX = LENGTH;
2533
2.15k
      while (INDEX > (LENGTH - DELETIONS + INSERTIONS)) {
2534
1.44k
        mxPushSlot(mxThis);
2535
1.44k
        mxPushNumber(INDEX - 1);
2536
1.44k
        mxDeleteAt();
2537
1.44k
        mxPop();
2538
1.44k
        INDEX--;
2539
1.44k
        mxCheckMetering();
2540
1.44k
      }
2541
711
    }
2542
36
    else if (INSERTIONS > DELETIONS) {
2543
14
      INDEX = LENGTH - DELETIONS;
2544
41
      while (INDEX > START) {
2545
27
        fxMoveThisItem(the, INDEX + DELETIONS - 1, INDEX + INSERTIONS - 1);
2546
27
        INDEX--;
2547
27
        mxCheckMetering();
2548
27
      }
2549
14
    }
2550
747
    INDEX = 0;
2551
776
    while (INDEX < INSERTIONS) {
2552
29
      mxPushSlot(mxArgv(2 + (txInteger)INDEX));
2553
29
      mxPushSlot(mxThis);
2554
29
      mxPushNumber(START + INDEX);
2555
29
      mxSetAt();
2556
29
      mxPop();
2557
29
      INDEX++;
2558
29
      mxCheckMetering();
2559
29
    }
2560
747
    mxPushNumber(LENGTH - DELETIONS + INSERTIONS);
2561
747
    mxPushSlot(mxThis);
2562
747
    mxSetID(mxID(_length));
2563
747
    mxPop();
2564
747
  }
2565
146k
}
2566
2567
void fx_Array_prototype_toLocaleString(txMachine* the)
2568
76
{
2569
76
  txIndex length = fxGetArrayLimit(the, mxThis);
2570
76
  txIndex index = 0;
2571
76
  txString string;
2572
76
  txSlot* list = fxNewInstance(the);
2573
76
  txSlot* slot = list;
2574
76
  txBoolean comma = 0;
2575
76
  txInteger size = 0;
2576
    
2577
76
  mxPushStringX(",");
2578
76
  the->stack->kind += XS_KEY_KIND - XS_STRING_KIND;
2579
76
  the->stack->value.key.sum = 1;
2580
156
  while (index < length) {
2581
80
    if (comma) {
2582
13
      slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG);
2583
13
      size = fxAddChunkSizes(the, size, slot->value.key.sum);
2584
13
    }
2585
67
    else
2586
67
      comma = 1;
2587
80
    mxPushSlot(mxThis);
2588
80
    mxGetIndex(index);
2589
80
    if ((the->stack->kind != XS_UNDEFINED_KIND) && (the->stack->kind != XS_NULL_KIND)) {
2590
28
      mxDub();
2591
28
      mxGetID(mxID(_toLocaleString));
2592
28
      mxCall();
2593
28
      mxRunCount(0);
2594
28
      slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG);
2595
28
      string = fxToString(the, slot);
2596
28
      slot->kind += XS_KEY_KIND - XS_STRING_KIND;
2597
28
      slot->value.key.sum = mxStringLength(string);
2598
28
      size = fxAddChunkSizes(the, size, slot->value.key.sum);
2599
28
    }
2600
80
    mxPop();
2601
80
    index++;
2602
    
2603
80
    mxCheckMetering();
2604
80
  }
2605
76
  string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1));
2606
76
  slot = list->next;
2607
116
  while (slot) {
2608
40
    c_memcpy(string, slot->value.key.string, slot->value.key.sum);
2609
40
    string += slot->value.key.sum;
2610
40
    slot = slot->next;
2611
40
  }
2612
76
  *string = 0;
2613
76
  mxResult->kind = XS_STRING_KIND;
2614
76
  mxPop();
2615
76
}
2616
2617
void fx_Array_prototype_toReversed(txMachine* the)
2618
8
{
2619
8
  txNumber LENGTH = fxGetArrayLength(the, mxThis);
2620
8
  txIndex length, to, from;
2621
8
  if (LENGTH > 0xFFFFFFFF)
2622
1
    mxRangeError("array overflow");
2623
7
  length = (txIndex)LENGTH;
2624
7
  fxNewArray(the, length);
2625
7
  mxPullSlot(mxResult);
2626
7
  from = length - 1;
2627
7
  to = 0;
2628
18
  while (to < length) {
2629
11
    mxPushSlot(mxThis);
2630
11
    mxPushUnsigned(from);
2631
11
    mxGetAt();
2632
11
    mxPushSlot(mxResult);
2633
11
    mxPushUnsigned(to);
2634
11
    mxDefineAt(0, XS_GET_ONLY);
2635
11
    mxPop();
2636
11
    from--;
2637
11
    to++;
2638
11
    mxCheckMetering();
2639
11
  }
2640
7
}
2641
2642
void fx_Array_prototype_toSorted(txMachine* the)
2643
22.4k
{
2644
22.4k
  txSlot* function = C_NULL;
2645
22.4k
  txNumber LENGTH;
2646
22.4k
  if (mxArgc > 0) {
2647
22.4k
    txSlot* slot = mxArgv(0);
2648
22.4k
    if (slot->kind != XS_UNDEFINED_KIND) {
2649
22.4k
      if (fxIsCallable(the, slot))
2650
0
        function = slot;
2651
22.4k
      else
2652
22.4k
        mxTypeError("compare: not a function");
2653
22.4k
    }
2654
22.4k
  }
2655
22
  LENGTH = fxGetArrayLength(the, mxThis);
2656
22
  if (LENGTH > 0xFFFFFFFF)
2657
1
    mxRangeError("array overflow");
2658
21
  fxNewArray(the, (txIndex)LENGTH);
2659
21
  mxPullSlot(mxResult);
2660
21
  fxSortArrayItems(the, function, C_NULL, LENGTH, mxResult);
2661
21
}
2662
2663
void fx_Array_prototype_toSpliced(txMachine* the)
2664
694k
{
2665
694k
  txIndex c = (txIndex)mxArgc, i;
2666
694k
  txNumber LENGTH = fxGetArrayLength(the, mxThis);
2667
694k
  txNumber START = fxArgToIndex(the, 0, 0, LENGTH);
2668
694k
  txNumber INSERTIONS, SKIP, RESULT_LENGTH;
2669
694k
  txSlot* array = C_NULL;
2670
694k
  if (c == 0) {
2671
411k
    INSERTIONS = 0;
2672
411k
    SKIP = 0;
2673
411k
  }
2674
283k
  else if (c == 1) {
2675
79.1k
    INSERTIONS = 0;
2676
79.1k
    SKIP = LENGTH - START;
2677
79.1k
  }
2678
204k
  else {
2679
204k
    INSERTIONS = c - 2;
2680
204k
    SKIP = fxArgToRange(the, 1, 0, 0, LENGTH - START);
2681
204k
  }
2682
694k
  RESULT_LENGTH = LENGTH + INSERTIONS - SKIP;
2683
694k
  if (RESULT_LENGTH > C_MAX_SAFE_INTEGER)
2684
7
    mxTypeError("unsafe integer");
2685
694k
  if (RESULT_LENGTH > 0xFFFFFFFF)
2686
19
    mxRangeError("array overflow");
2687
694k
  array = fxCheckArray(the, mxThis, XS_IMMUTABLE);
2688
694k
  if (array)
2689
305k
    array = fxCheckArrayItems(the, array, (txIndex)0, (txIndex)START);
2690
694k
  if (array)
2691
305k
    array = fxCheckArrayItems(the, array, (txIndex)(START + SKIP), (txIndex)LENGTH);
2692
694k
  if (array) {
2693
305k
    txIndex length = (txIndex)LENGTH;
2694
305k
    txIndex start = (txIndex)START;
2695
305k
    txIndex skip = (txIndex)SKIP;
2696
305k
    txIndex rest = length - (start + skip);
2697
305k
    txSlot* resultArray;
2698
305k
    txSlot* resultAddress;
2699
305k
    txSlot* address;
2700
305k
    fxNewArray(the, (txIndex)RESULT_LENGTH);
2701
305k
    mxPullSlot(mxResult);
2702
305k
    resultArray = mxResult->value.reference->next;
2703
305k
    resultAddress = resultArray->value.array.address;
2704
305k
    address = array->value.array.address;
2705
305k
    if (start > 0) {
2706
82.9k
      c_memcpy(resultAddress, address, start * sizeof(txSlot));
2707
82.9k
      mxMeterSome(start * 10);
2708
82.9k
      resultAddress += start;
2709
82.9k
      address += start;
2710
82.9k
    }
2711
305k
    for (i = 2; i < c; i++) {
2712
28
      txSlot* argument = mxArgv(i);
2713
28
      resultAddress->ID = XS_NO_ID;
2714
28
      resultAddress->kind = argument->kind;
2715
28
      resultAddress->value = argument->value;
2716
28
      resultAddress++;
2717
28
      mxMeterSome(5);
2718
28
      mxCheckMetering();
2719
28
    }
2720
305k
    address += skip;
2721
305k
    if (rest > 0) {
2722
70.7k
      c_memcpy(resultAddress, address, rest * sizeof(txSlot));
2723
70.7k
      mxMeterSome(rest * 10);
2724
70.7k
    }
2725
305k
    fxIndexArray(the, resultArray);
2726
305k
    mxMeterSome(4);
2727
305k
  }
2728
389k
  else {
2729
389k
    txNumber from = 0;
2730
389k
    txNumber to = 0;
2731
389k
    fxNewArray(the, 0);
2732
389k
    mxPullSlot(mxResult);
2733
777k
    while (from < START) {
2734
388k
      mxPushSlot(mxThis);
2735
388k
      mxPushUnsigned(from);
2736
388k
      mxGetAt();
2737
388k
      mxPushSlot(mxResult);
2738
388k
      mxPushUnsigned(to);
2739
388k
      mxDefineAt(0, XS_GET_ONLY);
2740
388k
      mxPop();
2741
388k
      from++;
2742
388k
      to++;
2743
388k
      mxCheckMetering();
2744
388k
    }
2745
389k
    for (i = 2; i < c; i++) {
2746
26
      mxPushSlot(mxArgv(i));
2747
26
      mxPushSlot(mxResult);
2748
26
      mxPushNumber(to);
2749
26
      mxDefineAt(0, XS_GET_ONLY);
2750
26
      mxPop();
2751
26
      to++;
2752
26
      mxCheckMetering();
2753
26
    }
2754
389k
    from += SKIP;
2755
1.02M
    while (from < LENGTH) {
2756
634k
      mxPushSlot(mxThis);
2757
634k
      mxPushUnsigned(from);
2758
634k
      mxGetAt();
2759
634k
      mxPushSlot(mxResult);
2760
634k
      mxPushUnsigned(to);
2761
634k
      mxDefineAt(0, XS_GET_ONLY);
2762
634k
      mxPop();
2763
634k
      from++;
2764
634k
      to++;
2765
634k
      mxCheckMetering();
2766
634k
    }
2767
389k
  }
2768
694k
}
2769
2770
void fx_Array_prototype_toString(txMachine* the)
2771
4.71M
{
2772
4.71M
  mxPushSlot(mxThis);
2773
4.71M
  mxDub();
2774
4.71M
  mxGetID(mxID(_join));
2775
4.71M
  if (fxIsCallable(the, the->stack)) {
2776
4.71M
    mxCall();
2777
4.71M
    mxRunCount(0);
2778
4.71M
    mxPullSlot(mxResult);
2779
4.71M
  }
2780
585
  else {
2781
585
    mxPop();
2782
585
    mxPop();
2783
585
    fx_Object_prototype_toString(the);
2784
585
  }
2785
4.71M
}
2786
2787
void fx_Array_prototype_unshift(txMachine* the)
2788
69
{
2789
69
  txIndex c = mxArgc, i;
2790
69
  txSlot* array = fxCheckArray(the, mxThis, XS_MUTABLE);
2791
69
  if (array)
2792
13
    array = fxCheckArrayItems(the, array, 0, array->value.array.length);
2793
69
  if (array) {
2794
13
    txSlot* address;
2795
13
    txIndex length = array->value.array.length;
2796
13
    if (length + c < length)
2797
0
      mxRangeError("array overflow");
2798
13
    if (c > 0) {
2799
10
      fxSetIndexSize(the, array, length + c, XS_GROWABLE_CHUNK);
2800
10
      address = array->value.array.address;
2801
10
      c_memmove(address + c, address, length * sizeof(txSlot));
2802
10
      mxMeterSome(length * 10);
2803
10
      i = 0;
2804
27
      while (i < c) {
2805
17
        txSlot* argument = mxArgv(i);
2806
17
        address->ID = XS_NO_ID;
2807
17
        address->kind = argument->kind;
2808
17
        address->value = argument->value;
2809
17
        address++;
2810
17
        mxMeterSome(4);
2811
17
        i++;
2812
17
        mxCheckMetering();
2813
17
      }
2814
10
      fxIndexArray(the, array);
2815
10
    }
2816
13
    mxPushUnsigned(length + c);
2817
13
    mxMeterSome(2);
2818
13
  }
2819
56
  else {
2820
56
    txNumber length = fxGetArrayLength(the, mxThis);
2821
56
    txNumber index = length;
2822
56
    if (c > 0) {
2823
36
      if (length + c > C_MAX_SAFE_INTEGER)
2824
11
        mxTypeError("unsafe integer");
2825
874k
      while (index > 0) {
2826
874k
        fxMoveThisItem(the, index - 1, index + c - 1);
2827
874k
        index--;
2828
874k
        mxCheckMetering();
2829
874k
      }
2830
25
      i = 0;
2831
48
      while (i < c) {
2832
23
        mxPushSlot(mxArgv(i));
2833
23
        mxPushSlot(mxThis);
2834
23
        mxSetIndex(i);
2835
23
        mxPop();
2836
23
        i++;
2837
23
        mxCheckMetering();
2838
23
      }
2839
25
    }
2840
45
    mxPushNumber(length + c);
2841
45
    mxPushSlot(mxThis);
2842
45
    mxSetID(mxID(_length));
2843
45
  }
2844
58
  mxPullSlot(mxResult);
2845
58
}
2846
2847
void fx_Array_prototype_values(txMachine* the)
2848
259k
{
2849
259k
  txSlot* property;
2850
259k
  fxToInstance(the, mxThis);
2851
259k
  mxPush(mxArrayIteratorPrototype);
2852
259k
  property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array)));
2853
259k
  property = fxNextIntegerProperty(the, property, 0, XS_NO_ID, XS_INTERNAL_FLAG);
2854
259k
  mxPullSlot(mxResult);
2855
259k
}
2856
2857
void fx_Array_prototype_with(txMachine* the)
2858
16.9k
{
2859
16.9k
  txNumber LENGTH = fxGetArrayLength(the, mxThis), INDEX;
2860
16.9k
  txIndex length, index, i;
2861
16.9k
  if (LENGTH > 0xFFFFFFFF)
2862
1
    mxRangeError("array overflow");
2863
16.9k
  INDEX = fxArgToRelativeIndex(the, 0, 0, LENGTH);
2864
16.9k
  if ((INDEX < 0) || (LENGTH <= INDEX))
2865
22
    mxRangeError("invalid index");
2866
16.9k
  length = (txIndex)LENGTH;
2867
16.9k
  fxNewArray(the, length);
2868
16.9k
  mxPullSlot(mxResult);
2869
16.9k
  index = (txIndex)INDEX;
2870
16.9k
  i = 0;
2871
28.4k
  while (i < index) {
2872
11.4k
    mxPushSlot(mxThis);
2873
11.4k
    mxPushUnsigned(i);
2874
11.4k
    mxGetAt();
2875
11.4k
    mxPushSlot(mxResult);
2876
11.4k
    mxPushUnsigned(i);
2877
11.4k
    mxDefineAt(0, XS_GET_ONLY);
2878
11.4k
    mxPop();
2879
11.4k
    i++;
2880
11.4k
    mxCheckMetering();
2881
11.4k
  }
2882
16.9k
  if (mxArgc > 1)
2883
16.1k
    mxPushSlot(mxArgv(1));
2884
770
  else
2885
770
    mxPushUndefined();
2886
16.9k
  mxPushSlot(mxResult);
2887
16.9k
  mxPushUnsigned(i);
2888
16.9k
  mxDefineAt(0, XS_GET_ONLY);
2889
16.9k
  mxPop();
2890
16.9k
  i++;
2891
40.7k
  while (i < length) {
2892
23.7k
    mxPushSlot(mxThis);
2893
23.7k
    mxPushUnsigned(i);
2894
23.7k
    mxGetAt();
2895
23.7k
    mxPushSlot(mxResult);
2896
23.7k
    mxPushUnsigned(i);
2897
23.7k
    mxDefineAt(0, XS_GET_ONLY);
2898
23.7k
    mxPop();
2899
23.7k
    i++;
2900
23.7k
    mxCheckMetering();
2901
23.7k
  }
2902
16.9k
}
2903
2904
void fx_ArrayIterator_prototype_next(txMachine* the)
2905
656k
{
2906
656k
  txSlot* iterator = fxCheckIteratorInstance(the, mxThis, mxID(_Array));
2907
656k
  txSlot* result = iterator->next;
2908
656k
  txSlot* iterable = result->next;
2909
656k
  txSlot* index = iterable->next;
2910
656k
  txSlot* value = fxCheckIteratorResult(the, result);
2911
656k
  txSlot* done = value->next;
2912
656k
  if (!done->value.boolean) {
2913
656k
    txInteger kind = index->next->value.integer;
2914
656k
    txIndex length = fxGetArrayLimit(the, iterable);
2915
656k
    txIndex i = (txIndex)index->value.integer;
2916
656k
    if (i < length) {
2917
410k
      switch(kind) {
2918
410k
      case 0: 
2919
410k
        mxPushSlot(iterable);
2920
410k
        mxGetIndex(i);
2921
410k
        mxPullSlot(value);
2922
410k
        break;
2923
4
      case 1:
2924
4
        mxPushUnsigned(i);
2925
4
        mxPullSlot(value);
2926
4
        break;
2927
6
      case 2:
2928
6
        mxPushUnsigned(i);
2929
6
        mxPushSlot(iterable);
2930
6
        mxGetIndex(i);
2931
6
        fxConstructArrayEntry(the, value);
2932
6
        break;
2933
410k
      }
2934
410k
            index->value.integer = i + 1;
2935
410k
    }
2936
246k
    else {
2937
246k
      value->kind = XS_UNDEFINED_KIND;
2938
246k
      done->value.boolean = 1;
2939
246k
    }
2940
656k
  }
2941
656k
  mxResult->kind = result->kind;
2942
656k
  mxResult->value = result->value;
2943
656k
}
2944