Coverage Report

Created: 2025-06-13 06:17

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