Coverage Report

Created: 2025-11-24 06:36

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