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