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