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