/src/moddable/xs/sources/xsDataView.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2016-2026 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 | | static txSlot* fxArgToInstance(txMachine* the, txInteger i); |
41 | | |
42 | | static txSlot* fxCheckArrayBufferDetached(txMachine* the, txSlot* slot); |
43 | | static txSlot* fxCheckArrayBufferInstance(txMachine* the, txSlot* slot); |
44 | | static txSlot* fxCheckArrayBufferMutable(txMachine* the, txSlot* slot); |
45 | | static txSlot* fxNewArrayBufferInstance(txMachine* the); |
46 | | |
47 | | static txSlot* fxCheckDataViewInstance(txMachine* the, txSlot* slot, txBoolean mutable); |
48 | | static txInteger fxCheckDataViewSize(txMachine* the, txSlot* view, txSlot* buffer, txBoolean mutable); |
49 | | static txSlot* fxNewDataViewInstance(txMachine* the); |
50 | | |
51 | | static void fxCallTypedArrayItem(txMachine* the, txSlot* function, txSlot* dispatch, txSlot* view, txSlot* data, txInteger index, txSlot* item); |
52 | | static void fxCheckTypedArrayContentType(txMachine* the, txSlot* dispatch, txSlot* sourceDispatch); |
53 | | static txSlot* fxCheckTypedArrayInstance(txMachine* the, txSlot* slot); |
54 | | static txSlot* fxConstructTypedArray(txMachine* the); |
55 | | static txSlot* fxNewTypedArrayInstance(txMachine* the, txTypeDispatch* dispatch, txTypeAtomics* atomics); |
56 | | static void fxReduceTypedArrayItem(txMachine* the, txSlot* function, txSlot* dispatch, txSlot* view, txSlot* data, txInteger index); |
57 | | |
58 | | static txBoolean fxTypedArrayDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask); |
59 | | static txBoolean fxTypedArrayDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index); |
60 | | static txBoolean fxTypedArrayGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot); |
61 | | static txSlot* fxTypedArrayGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag); |
62 | | static txBoolean fxTypedArrayGetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* value, txSlot* receiver); |
63 | | static txBoolean fxTypedArrayHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index); |
64 | | static void fxTypedArrayOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* keys); |
65 | | static txBoolean fxTypedArrayPreventExtensions(txMachine* the, txSlot* instance); |
66 | | static txSlot* fxTypedArraySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag); |
67 | | static txBoolean fxTypedArraySetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* value, txSlot* receiver); |
68 | | |
69 | | static void fx_TypedArray_from_object(txMachine* the, txSlot* instance, txSlot* function, txSlot* _this); |
70 | | |
71 | | const txBehavior ICACHE_FLASH_ATTR gxTypedArrayBehavior = { |
72 | | fxTypedArrayGetProperty, |
73 | | fxTypedArraySetProperty, |
74 | | fxOrdinaryCall, |
75 | | fxOrdinaryConstruct, |
76 | | fxTypedArrayDefineOwnProperty, |
77 | | fxTypedArrayDeleteProperty, |
78 | | fxTypedArrayGetOwnProperty, |
79 | | fxTypedArrayGetPropertyValue, |
80 | | fxOrdinaryGetPrototype, |
81 | | fxTypedArrayHasProperty, |
82 | | fxOrdinaryIsExtensible, |
83 | | fxTypedArrayOwnKeys, |
84 | | fxTypedArrayPreventExtensions, |
85 | | fxTypedArraySetPropertyValue, |
86 | | fxOrdinarySetPrototype, |
87 | | }; |
88 | | |
89 | | void *fxArrayBuffer(txMachine* the, txSlot* slot, void* data, txInteger byteLength, txInteger maxByteLength) |
90 | 1.40M | { |
91 | 1.40M | txSlot* instance; |
92 | 1.40M | txSlot* arrayBuffer; |
93 | 1.40M | txSlot* bufferInfo; |
94 | 1.40M | if (byteLength < 0) |
95 | 0 | mxRangeError("invalid byteLength %ld", byteLength); |
96 | 1.40M | mxPush(mxArrayBufferPrototype); |
97 | 1.40M | instance = fxNewArrayBufferInstance(the); |
98 | 1.40M | arrayBuffer = instance->next; |
99 | 1.40M | arrayBuffer->value.arrayBuffer.address = fxNewChunk(the, byteLength); |
100 | 1.40M | bufferInfo = arrayBuffer->next; |
101 | 1.40M | bufferInfo->value.bufferInfo.length = byteLength; |
102 | 1.40M | bufferInfo->value.bufferInfo.maxLength = maxByteLength; |
103 | 1.40M | if (data != NULL) |
104 | 38.0k | c_memcpy(arrayBuffer->value.arrayBuffer.address, data, byteLength); |
105 | 1.37M | else |
106 | 1.37M | c_memset(arrayBuffer->value.arrayBuffer.address, 0, byteLength); |
107 | 1.40M | mxPullSlot(slot); |
108 | 1.40M | return arrayBuffer->value.arrayBuffer.address; |
109 | 1.40M | } |
110 | | |
111 | | void fxGetArrayBufferData(txMachine* the, txSlot* slot, txInteger byteOffset, void* data, txInteger byteLength) |
112 | 0 | { |
113 | 0 | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
114 | 0 | txSlot* arrayBuffer = instance->next; |
115 | 0 | txSlot* bufferInfo = arrayBuffer->next; |
116 | 0 | txInteger length = bufferInfo->value.bufferInfo.length; |
117 | 0 | if ((byteOffset < 0) || (length < byteOffset)) |
118 | 0 | mxRangeError("invalid byteOffset %ld", byteOffset); |
119 | 0 | if ((byteLength < 0) || (length < (byteOffset + byteLength))) |
120 | 0 | mxRangeError("invalid byteLength %ld", byteLength); |
121 | 0 | c_memcpy(data, arrayBuffer->value.arrayBuffer.address + byteOffset, byteLength); |
122 | 0 | } |
123 | | |
124 | | txInteger fxGetArrayBufferLength(txMachine* the, txSlot* slot) |
125 | 50.8M | { |
126 | 50.8M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
127 | 50.8M | txSlot* arrayBuffer = instance->next; |
128 | 50.8M | txSlot* bufferInfo = arrayBuffer->next; |
129 | 50.8M | return bufferInfo->value.bufferInfo.length; |
130 | 50.8M | } |
131 | | |
132 | | txInteger fxGetArrayBufferMaxLength(txMachine* the, txSlot* slot) |
133 | 0 | { |
134 | 0 | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
135 | 0 | txSlot* arrayBuffer = instance->next; |
136 | 0 | txSlot* bufferInfo = arrayBuffer->next; |
137 | 0 | return bufferInfo->value.bufferInfo.maxLength; |
138 | 0 | } |
139 | | |
140 | | void fxSetArrayBufferData(txMachine* the, txSlot* slot, txInteger byteOffset, void* data, txInteger byteLength) |
141 | 0 | { |
142 | 0 | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
143 | 0 | txSlot* arrayBuffer = instance->next; |
144 | 0 | txSlot* bufferInfo = arrayBuffer->next; |
145 | 0 | txInteger length = bufferInfo->value.bufferInfo.length; |
146 | 0 | if ((byteOffset < 0) || (length < byteOffset)) |
147 | 0 | mxRangeError("invalid byteOffset %ld", byteOffset); |
148 | 0 | if ((byteLength < 0) || (length < (byteOffset + byteLength))) |
149 | 0 | mxRangeError("invalid byteLength %ld", byteLength); |
150 | 0 | c_memcpy(arrayBuffer->value.arrayBuffer.address + byteOffset, data, byteLength); |
151 | 0 | } |
152 | | |
153 | | void fxSetArrayBufferLength(txMachine* the, txSlot* slot, txInteger target) |
154 | 2.56M | { |
155 | 2.56M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
156 | 2.56M | txSlot* arrayBuffer = instance->next; |
157 | 2.56M | txSlot* bufferInfo = arrayBuffer->next; |
158 | 2.56M | txInteger length = bufferInfo->value.bufferInfo.length; |
159 | 2.56M | txByte* address = arrayBuffer->value.arrayBuffer.address; |
160 | 2.56M | if (bufferInfo->value.bufferInfo.maxLength < 0) |
161 | 0 | fxReport(the, "# Use xsArrayBufferResizable instead of xsArrayBuffer\n"); |
162 | 2.56M | if (length != target) { |
163 | 2.56M | if (address) |
164 | 2.56M | address = (txByte*)fxRenewChunk(the, address, target); |
165 | 2.56M | if (address) { |
166 | 2.56M | if (length < target) |
167 | 2.55M | c_memset(address + length, 0, target - length); |
168 | 2.56M | } |
169 | 410 | else { |
170 | 410 | address = (txByte*)fxNewChunk(the, target); |
171 | 410 | if (length < target) { |
172 | 410 | c_memcpy(address, arrayBuffer->value.arrayBuffer.address, length); |
173 | 410 | c_memset(address + length, 0, target - length); |
174 | 410 | } |
175 | 0 | else |
176 | 0 | c_memcpy(address, arrayBuffer->value.arrayBuffer.address, target); |
177 | 410 | } |
178 | 2.56M | arrayBuffer->value.arrayBuffer.address = address; |
179 | 2.56M | bufferInfo->value.bufferInfo.length = target; |
180 | 2.56M | } |
181 | 2.56M | } |
182 | | |
183 | | void* fxToArrayBuffer(txMachine* the, txSlot* slot) |
184 | 3.92M | { |
185 | 3.92M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
186 | 3.92M | txSlot* arrayBuffer = instance->next; |
187 | 3.92M | return arrayBuffer->value.arrayBuffer.address; |
188 | 3.92M | } |
189 | | |
190 | | void fxBuildDataView(txMachine* the) |
191 | 38.0k | { |
192 | 38.0k | txSlot* instance; |
193 | 38.0k | txSlot* slot; |
194 | 38.0k | txInteger index; |
195 | 38.0k | const txTypeDispatch *dispatch; |
196 | 38.0k | const txTypeAtomics *atomics; |
197 | 38.0k | txSlot* property; |
198 | 38.0k | txSlot* constructor; |
199 | | |
200 | 38.0k | mxPush(mxObjectPrototype); |
201 | 38.0k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
202 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_byteLength), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
203 | 38.0k | #if mxECMAScript2023 |
204 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_detached), C_NULL, mxID(_detached), XS_DONT_ENUM_FLAG); |
205 | 38.0k | #endif |
206 | 38.0k | #if mxImmutableArrayBuffers |
207 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_immutable), C_NULL, mxID(_immutable), XS_DONT_ENUM_FLAG); |
208 | 38.0k | #endif |
209 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_maxByteLength), C_NULL, mxID(_maxByteLength), XS_DONT_ENUM_FLAG); |
210 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_resizable), C_NULL, mxID(_resizable), XS_DONT_ENUM_FLAG); |
211 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_concat), 1, mxID(_concat), XS_DONT_ENUM_FLAG); |
212 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_resize), 1, mxID(_resize), XS_DONT_ENUM_FLAG); |
213 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG); |
214 | 38.0k | #if mxImmutableArrayBuffers |
215 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_sliceToImmutable), 2, mxID(_sliceToImmutable), XS_DONT_ENUM_FLAG); |
216 | 38.0k | #endif |
217 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transfer), 0, mxID(_transfer), XS_DONT_ENUM_FLAG); |
218 | 38.0k | #if mxECMAScript2024 |
219 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transferToFixedLength), 0, mxID(_transferToFixedLength), XS_DONT_ENUM_FLAG); |
220 | 38.0k | #endif |
221 | 38.0k | #if mxImmutableArrayBuffers |
222 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transferToImmutable), 0, mxID(_transferToImmutable), XS_DONT_ENUM_FLAG); |
223 | 38.0k | #endif |
224 | 38.0k | slot = fxNextStringXProperty(the, slot, "ArrayBuffer", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
225 | 38.0k | mxArrayBufferPrototype = *the->stack; |
226 | 38.0k | slot = fxBuildHostConstructor(the, mxCallback(fx_ArrayBuffer), 1, mxID(_ArrayBuffer)); |
227 | 38.0k | mxArrayBufferConstructor = *the->stack; |
228 | 38.0k | slot = fxLastProperty(the, slot); |
229 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_fromBigInt), 1, mxID(_fromBigInt), XS_DONT_ENUM_FLAG); |
230 | | #ifndef mxCESU8 |
231 | | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_fromString), 1, mxID(_fromString), XS_DONT_ENUM_FLAG); |
232 | | #endif |
233 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_isView), 1, mxID(_isView), XS_DONT_ENUM_FLAG); |
234 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG); |
235 | 38.0k | mxPop(); |
236 | | |
237 | 38.0k | mxPush(mxObjectPrototype); |
238 | 38.0k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
239 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getBigInt64), 1, mxID(_getBigInt64), XS_DONT_ENUM_FLAG); |
240 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setBigInt64), 2, mxID(_setBigInt64), XS_DONT_ENUM_FLAG); |
241 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getBigUint64), 1, mxID(_getBigUint64), XS_DONT_ENUM_FLAG); |
242 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setBigUint64), 2, mxID(_setBigUint64), XS_DONT_ENUM_FLAG); |
243 | 38.0k | #if mxFloat16 |
244 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat16), 1, mxID(_getFloat16), XS_DONT_ENUM_FLAG); |
245 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat16), 2, mxID(_setFloat16), XS_DONT_ENUM_FLAG); |
246 | 38.0k | #endif |
247 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat32), 1, mxID(_getFloat32), XS_DONT_ENUM_FLAG); |
248 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat32), 2, mxID(_setFloat32), XS_DONT_ENUM_FLAG); |
249 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat64), 1, mxID(_getFloat64), XS_DONT_ENUM_FLAG); |
250 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat64), 2, mxID(_setFloat64), XS_DONT_ENUM_FLAG); |
251 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt8), 1, mxID(_getInt8), XS_DONT_ENUM_FLAG); |
252 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt8), 2, mxID(_setInt8), XS_DONT_ENUM_FLAG); |
253 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt16), 1, mxID(_getInt16), XS_DONT_ENUM_FLAG); |
254 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt16), 2, mxID(_setInt16), XS_DONT_ENUM_FLAG); |
255 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt32), 1, mxID(_getInt32), XS_DONT_ENUM_FLAG); |
256 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt32), 2, mxID(_setInt32), XS_DONT_ENUM_FLAG); |
257 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint8), 1, mxID(_getUint8), XS_DONT_ENUM_FLAG); |
258 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint8), 2, mxID(_setUint8), XS_DONT_ENUM_FLAG); |
259 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint16), 1, mxID(_getUint16), XS_DONT_ENUM_FLAG); |
260 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint16), 2, mxID(_setUint16), XS_DONT_ENUM_FLAG); |
261 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint32), 1, mxID(_getUint32), XS_DONT_ENUM_FLAG); |
262 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint32), 2, mxID(_setUint32), XS_DONT_ENUM_FLAG); |
263 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_buffer_get), C_NULL, mxID(_buffer), XS_DONT_ENUM_FLAG); |
264 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_byteLength_get), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
265 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_byteOffset_get), C_NULL, mxID(_byteOffset), XS_DONT_ENUM_FLAG); |
266 | 38.0k | slot = fxNextStringXProperty(the, slot, "DataView", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
267 | 38.0k | mxDataViewPrototype = *the->stack; |
268 | 38.0k | slot = fxBuildHostConstructor(the, mxCallback(fx_DataView), 1, mxID(_DataView)); |
269 | 38.0k | mxDataViewConstructor = *the->stack; |
270 | 38.0k | mxPop(); |
271 | | |
272 | 38.0k | mxPush(mxObjectPrototype); |
273 | 38.0k | instance = fxNewObjectInstance(the); |
274 | | |
275 | 38.0k | fxNewHostFunction(the, mxCallback(fxTypedArrayGetter), 0, XS_NO_ID, XS_NO_ID); |
276 | 38.0k | property = mxFunctionInstanceHome(the->stack->value.reference); |
277 | 38.0k | property->value.home.object = instance; |
278 | 38.0k | fxNewHostFunction(the, mxCallback(fxTypedArraySetter), 1, XS_NO_ID, XS_NO_ID); |
279 | 38.0k | property = mxFunctionInstanceHome(the->stack->value.reference); |
280 | 38.0k | property->value.home.object = instance; |
281 | 38.0k | mxPushUndefined(); |
282 | 38.0k | the->stack->flag = XS_DONT_DELETE_FLAG; |
283 | 38.0k | the->stack->kind = XS_ACCESSOR_KIND; |
284 | 38.0k | the->stack->value.accessor.getter = (the->stack + 2)->value.reference; |
285 | 38.0k | the->stack->value.accessor.setter = (the->stack + 1)->value.reference; |
286 | 38.0k | mxPull(mxTypedArrayAccessor); |
287 | 38.0k | mxPop(); |
288 | 38.0k | mxPop(); |
289 | | |
290 | 38.0k | slot = fxLastProperty(the, instance); |
291 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_at), 1, mxID(_at), XS_DONT_ENUM_FLAG); |
292 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_buffer_get), C_NULL, mxID(_buffer), XS_DONT_ENUM_FLAG); |
293 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_byteLength_get), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
294 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_byteOffset_get), C_NULL, mxID(_byteOffset), XS_DONT_ENUM_FLAG); |
295 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_length_get), C_NULL, mxID(_length), XS_DONT_ENUM_FLAG); |
296 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_toStringTag_get), C_NULL, mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG); |
297 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_copyWithin), 2, mxID(_copyWithin), XS_DONT_ENUM_FLAG); |
298 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_entries), 0, mxID(_entries), XS_DONT_ENUM_FLAG); |
299 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_every), 1, mxID(_every), XS_DONT_ENUM_FLAG); |
300 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_fill), 1, mxID(_fill), XS_DONT_ENUM_FLAG); |
301 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_filter), 1, mxID(_filter), XS_DONT_ENUM_FLAG); |
302 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_find), 1, mxID(_find), XS_DONT_ENUM_FLAG); |
303 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findIndex), 1, mxID(_findIndex), XS_DONT_ENUM_FLAG); |
304 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findLast), 1, mxID(_findLast), XS_DONT_ENUM_FLAG); |
305 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findLastIndex), 1, mxID(_findLastIndex), XS_DONT_ENUM_FLAG); |
306 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_forEach), 1, mxID(_forEach), XS_DONT_ENUM_FLAG); |
307 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_includes), 1, mxID(_includes), XS_DONT_ENUM_FLAG); |
308 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_indexOf), 1, mxID(_indexOf), XS_DONT_ENUM_FLAG); |
309 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_join), 1, mxID(_join), XS_DONT_ENUM_FLAG); |
310 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_keys), 0, mxID(_keys), XS_DONT_ENUM_FLAG); |
311 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_lastIndexOf), 1, mxID(_lastIndexOf), XS_DONT_ENUM_FLAG); |
312 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_map), 1, mxID(_map), XS_DONT_ENUM_FLAG); |
313 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reduce), 1, mxID(_reduce), XS_DONT_ENUM_FLAG); |
314 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reduceRight), 1, mxID(_reduceRight), XS_DONT_ENUM_FLAG); |
315 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reverse), 0, mxID(_reverse), XS_DONT_ENUM_FLAG); |
316 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_set), 1, mxID(_set), XS_DONT_ENUM_FLAG); |
317 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG); |
318 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_some), 1, mxID(_some), XS_DONT_ENUM_FLAG); |
319 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_sort), 1, mxID(_sort), XS_DONT_ENUM_FLAG); |
320 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_subarray), 2, mxID(_subarray), XS_DONT_ENUM_FLAG); |
321 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toLocaleString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG); |
322 | 38.0k | property = mxBehaviorGetProperty(the, mxArrayPrototype.value.reference, mxID(_toString), 0, XS_OWN); |
323 | 38.0k | slot = fxNextSlotProperty(the, slot, property, mxID(_toString), XS_DONT_ENUM_FLAG); |
324 | 38.0k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_values), 0, mxID(_values), XS_DONT_ENUM_FLAG); |
325 | 38.0k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_iterator), XS_DONT_ENUM_FLAG); |
326 | 38.0k | #if mxECMAScript2023 |
327 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toReversed), 0, mxID(_toReversed), XS_DONT_ENUM_FLAG); |
328 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toSorted), 1, mxID(_toSorted), XS_DONT_ENUM_FLAG); |
329 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_with), 2, mxID(_with), XS_DONT_ENUM_FLAG); |
330 | 38.0k | #endif |
331 | 38.0k | mxTypedArrayPrototype = *the->stack; |
332 | 38.0k | constructor = fxBuildHostConstructor(the, mxCallback(fx_TypedArray), 0, mxID(_TypedArray)); |
333 | 38.0k | mxTypedArrayConstructor = *the->stack; |
334 | 38.0k | slot = fxLastProperty(the, constructor); |
335 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_from), 1, mxID(_from), XS_DONT_ENUM_FLAG); |
336 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_of), 0, mxID(_of), XS_DONT_ENUM_FLAG); |
337 | 38.0k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG); |
338 | 494k | for (index = 0, dispatch = &gxTypeDispatches[0], atomics = &gxTypeAtomics[0]; index < mxTypeArrayCount; index++, dispatch++, atomics++) { |
339 | 456k | mxPush(mxTypedArrayPrototype); |
340 | 456k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
341 | 456k | slot = fxNextIntegerProperty(the, slot, dispatch->size, mxID(_BYTES_PER_ELEMENT), XS_GET_ONLY); |
342 | 456k | slot = fxBuildHostConstructor(the, mxCallback(fx_TypedArray), 3, mxID(dispatch->constructorID)); |
343 | 456k | the->stackIntrinsics[-1 - (txInteger)dispatch->constructorID] = *the->stack; //@@ |
344 | 456k | slot->value.instance.prototype = constructor; |
345 | 456k | property = mxFunctionInstanceHome(slot); |
346 | 456k | slot = property->next; |
347 | 456k | property = fxNextTypeDispatchProperty(the, property, (txTypeDispatch*)dispatch, (txTypeAtomics*)atomics, XS_NO_ID, XS_INTERNAL_FLAG); |
348 | 456k | property->next = slot; |
349 | 456k | slot = fxLastProperty(the, slot); |
350 | 456k | slot = fxNextIntegerProperty(the, slot, dispatch->size, mxID(_BYTES_PER_ELEMENT), XS_GET_ONLY); |
351 | 456k | mxPop(); |
352 | 456k | } |
353 | 38.0k | mxPop(); |
354 | | |
355 | 38.0k | #if mxUint8ArrayBase64 |
356 | 38.0k | mxPush(mxUint8ArrayConstructor); |
357 | 38.0k | instance = fxToInstance(the, the->stack); |
358 | 38.0k | slot = fxLastProperty(the, instance); |
359 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_fromBase64), 1, mxID(_fromBase64), XS_DONT_ENUM_FLAG); |
360 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_fromHex), 1, mxID(_fromHex), XS_DONT_ENUM_FLAG); |
361 | 38.0k | mxGetID(mxID(_prototype)); |
362 | 38.0k | instance = fxToInstance(the, the->stack); |
363 | 38.0k | slot = fxLastProperty(the, instance); |
364 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_setFromBase64), 1, mxID(_setFromBase64), XS_DONT_ENUM_FLAG); |
365 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_setFromHex), 1, mxID(_setFromHex), XS_DONT_ENUM_FLAG); |
366 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_toBase64), 0, mxID(_toBase64), XS_DONT_ENUM_FLAG); |
367 | 38.0k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_toHex), 0, mxID(_toHex), XS_DONT_ENUM_FLAG); |
368 | 38.0k | mxPop(); |
369 | 38.0k | #endif |
370 | 38.0k | } |
371 | | |
372 | | txInteger fxArgToByteLength(txMachine* the, txInteger argi, txInteger length) |
373 | 687k | { |
374 | 687k | txSlot *arg = mxArgv(argi); |
375 | 687k | if ((mxArgc > argi) && (arg->kind != XS_UNDEFINED_KIND)) { |
376 | 626k | txNumber value; |
377 | 626k | if (XS_INTEGER_KIND == arg->kind) { |
378 | 10.8k | txInteger value = arg->value.integer; |
379 | 10.8k | if (value < 0) |
380 | 110 | mxRangeError("byteLength < 0"); |
381 | 10.7k | return value; |
382 | 10.8k | } |
383 | 615k | value = c_trunc(fxToNumber(the, arg)); |
384 | 615k | if (c_isnan(value)) |
385 | 2.46k | return 0; |
386 | 613k | if (value < 0) |
387 | 215 | mxRangeError("byteLength < 0"); |
388 | 613k | if (0x7FFFFFFF < value) |
389 | 70 | mxRangeError("byteLength too big"); |
390 | 613k | return (txInteger)value; |
391 | 613k | } |
392 | 60.5k | return length; |
393 | 687k | } |
394 | | |
395 | | txS8 fxArgToSafeByteLength(txMachine* the, txInteger argi, txInteger length) |
396 | 867k | { |
397 | 867k | txSlot *arg = mxArgv(argi); |
398 | 867k | if ((mxArgc > argi) && (arg->kind != XS_UNDEFINED_KIND)) { |
399 | 865k | txNumber value; |
400 | 865k | if (XS_INTEGER_KIND == arg->kind) { |
401 | 649k | txS8 value = arg->value.integer; |
402 | 649k | if (value < 0) |
403 | 20 | mxRangeError("byteLength < 0"); |
404 | 649k | return value; |
405 | 649k | } |
406 | 215k | value = c_trunc(fxToNumber(the, arg)); |
407 | 215k | if (c_isnan(value)) |
408 | 556 | return 0; |
409 | 215k | if (value < 0) |
410 | 783 | mxRangeError("byteLength < 0"); |
411 | 214k | if (C_MAX_SAFE_INTEGER < value) |
412 | 118 | mxRangeError("byteLength too big"); |
413 | 214k | return (txS8)value; |
414 | 214k | } |
415 | 2.04k | return length; |
416 | 867k | } |
417 | | |
418 | | txSlot* fxArgToInstance(txMachine* the, txInteger i) |
419 | 31 | { |
420 | 31 | if (mxArgc > i) |
421 | 20 | return fxToInstance(the, mxArgv(i)); |
422 | 31 | mxTypeError("cannot coerce undefined to object"); |
423 | 0 | return C_NULL; |
424 | 31 | } |
425 | | |
426 | | txSlot* fxCheckArrayBufferDetached(txMachine* the, txSlot* slot) |
427 | 225k | { |
428 | 225k | slot = slot->value.reference->next; |
429 | 225k | if (slot->value.arrayBuffer.address == C_NULL) |
430 | 5 | mxTypeError("detached buffer"); |
431 | 225k | return slot; |
432 | 225k | } |
433 | | |
434 | | txSlot* fxCheckArrayBufferInstance(txMachine* the, txSlot* slot) |
435 | 57.4M | { |
436 | 57.4M | if (slot->kind == XS_REFERENCE_KIND) { |
437 | 57.4M | txSlot* instance = slot->value.reference; |
438 | 57.4M | txSlot* arrayBuffer = instance->next; |
439 | 57.4M | if (arrayBuffer && (arrayBuffer->flag & XS_INTERNAL_FLAG) && (arrayBuffer->kind == XS_ARRAY_BUFFER_KIND)) |
440 | 57.4M | return instance; |
441 | 57.4M | } |
442 | 188 | if (slot == mxThis) |
443 | 188 | mxTypeError("this: not an ArrayBuffer instance"); |
444 | 188 | mxTypeError("not an ArrayBuffer instance"); |
445 | 0 | return C_NULL; |
446 | 188 | } |
447 | | |
448 | | txSlot* fxCheckArrayBufferMutable(txMachine* the, txSlot* slot) |
449 | 224k | { |
450 | 224k | slot = slot->value.reference->next; |
451 | 224k | if (slot->flag & XS_DONT_SET_FLAG) |
452 | 11 | mxTypeError("ArrayBuffer instance is read-only"); |
453 | 224k | return slot; |
454 | 224k | } |
455 | | |
456 | | void fxConstructArrayBufferResult(txMachine* the, txSlot* constructor, txInteger length) |
457 | 62.3k | { |
458 | 62.3k | txSlot* instance; |
459 | 62.3k | if (constructor) |
460 | 58.6k | mxPushSlot(constructor); |
461 | 3.65k | else { |
462 | 3.65k | mxPushSlot(mxThis); |
463 | 3.65k | mxGetID(mxID(_constructor)); |
464 | 3.65k | fxToSpeciesConstructor(the, &mxArrayBufferConstructor); |
465 | 3.65k | } |
466 | 62.3k | mxNew(); |
467 | 62.3k | mxPushInteger(length); |
468 | 62.3k | mxRunCount(1); |
469 | 62.3k | if (the->stack->kind != XS_REFERENCE_KIND) |
470 | 0 | mxTypeError("not an object"); |
471 | 62.3k | instance = the->stack->value.reference; |
472 | 62.3k | if (!(instance->next) || (instance->next->kind != XS_ARRAY_BUFFER_KIND)) |
473 | 4 | mxTypeError("not an ArrayBuffer instance"); |
474 | 62.3k | if (instance->next->value.arrayBuffer.address == C_NULL) |
475 | 1 | mxTypeError("detached buffer"); |
476 | 62.3k | if (instance->next->flag & XS_DONT_SET_FLAG) |
477 | 7 | mxTypeError("read-only buffer"); |
478 | 62.3k | if (!constructor && (mxThis->value.reference == instance)) |
479 | 1 | mxTypeError("same ArrayBuffer instance"); |
480 | 62.3k | if (instance->next->next->value.bufferInfo.length < length) |
481 | 2 | mxTypeError("smaller ArrayBuffer instance"); |
482 | 62.3k | mxPullSlot(mxResult); |
483 | 62.3k | } |
484 | | |
485 | | txSlot* fxNewArrayBufferInstance(txMachine* the) |
486 | 2.25M | { |
487 | 2.25M | txSlot* instance; |
488 | 2.25M | txSlot* property; |
489 | 2.25M | instance = fxNewObjectInstance(the); |
490 | 2.25M | property = instance->next = fxNewSlot(the); |
491 | 2.25M | property->flag = XS_INTERNAL_FLAG; |
492 | 2.25M | property->kind = XS_ARRAY_BUFFER_KIND; |
493 | 2.25M | property->value.arrayBuffer.address = C_NULL; |
494 | 2.25M | property->value.arrayBuffer.detachKey = C_NULL; |
495 | 2.25M | property = property->next = fxNewSlot(the); |
496 | 2.25M | property->flag = XS_INTERNAL_FLAG; |
497 | 2.25M | property->kind = XS_BUFFER_INFO_KIND; |
498 | 2.25M | property->value.bufferInfo.length = 0; |
499 | 2.25M | property->value.bufferInfo.maxLength = -1; |
500 | 2.25M | return instance; |
501 | 2.25M | } |
502 | | |
503 | | void fx_ArrayBuffer(txMachine* the) |
504 | 843k | { |
505 | 843k | txSlot* instance; |
506 | 843k | txS8 byteLength; |
507 | 843k | txS8 maxByteLength = -1; |
508 | 843k | txSlot* property; |
509 | 843k | if (!mxHasTarget) |
510 | 3 | mxTypeError("call: ArrayBuffer"); |
511 | 843k | byteLength = fxArgToSafeByteLength(the, 0, 0); |
512 | 843k | if ((mxArgc > 1) && mxIsReference(mxArgv(1))) { |
513 | 1.32k | mxPushSlot(mxArgv(1)); |
514 | 1.32k | mxGetID(mxID(_maxByteLength)); |
515 | 1.32k | mxPullSlot(mxArgv(1)); |
516 | 1.32k | maxByteLength = fxArgToSafeByteLength(the, 1, -1); |
517 | 1.32k | } |
518 | 843k | if (maxByteLength >= 0) { |
519 | 542 | if (byteLength > maxByteLength) |
520 | 3 | mxRangeError("byteLength > maxByteLength"); |
521 | 542 | } |
522 | 843k | mxPushSlot(mxTarget); |
523 | 843k | fxGetPrototypeFromConstructor(the, &mxArrayBufferPrototype); |
524 | 843k | instance = fxNewArrayBufferInstance(the); |
525 | 843k | mxPullSlot(mxResult); |
526 | 843k | if (byteLength > 0x7FFFFFFF) |
527 | 3 | mxRangeError("byteLength too big"); |
528 | 843k | if (maxByteLength > 0x7FFFFFFF) |
529 | 5 | mxRangeError("maxByteLength too big"); |
530 | 843k | property = instance->next; |
531 | 843k | property->value.arrayBuffer.address = fxNewChunk(the, (txSize)byteLength); |
532 | 843k | c_memset(property->value.arrayBuffer.address, 0, (txSize)byteLength); |
533 | 843k | property = property->next; |
534 | 843k | property->value.bufferInfo.length = (txSize)byteLength; |
535 | 843k | property->value.bufferInfo.maxLength = (txSize)maxByteLength; |
536 | 843k | } |
537 | | |
538 | | void fx_ArrayBuffer_fromBigInt(txMachine* the) |
539 | 35.0k | { |
540 | 35.0k | txU4 minBytes = 0; |
541 | 35.0k | txBoolean sign = 0; |
542 | 35.0k | int endian = EndianBig; |
543 | 35.0k | if (mxArgc < 1) |
544 | 1 | mxTypeError("no argument"); |
545 | 35.0k | if (mxArgc > 1) |
546 | 35.0k | minBytes = (txU4)fxArgToByteLength(the, 1, 0); |
547 | 35.0k | if ((mxArgc > 2) && fxToBoolean(the, mxArgv(2))) |
548 | 2 | sign = 1; |
549 | 35.0k | if ((mxArgc > 3) && fxToBoolean(the, mxArgv(3))) |
550 | 2 | endian = EndianLittle; |
551 | 35.0k | if (gxTypeBigInt.toArrayBuffer) { |
552 | 35.0k | gxTypeBigInt.toArrayBuffer(the, mxArgv(0), minBytes, sign, endian); |
553 | 35.0k | } |
554 | 0 | else { |
555 | 0 | mxUnknownError("not built-in"); |
556 | 0 | } |
557 | 35.0k | } |
558 | | |
559 | | #ifndef mxCESU8 |
560 | | void fx_ArrayBuffer_fromString(txMachine* the) |
561 | | { |
562 | | txSize length = 0; |
563 | | if (mxArgc < 1) |
564 | | mxTypeError("no argument"); |
565 | | |
566 | | txString c = fxToString(the, mxArgv(0)); |
567 | | txInteger nulls = 0; |
568 | | while (1) { |
569 | | uint8_t b = (uint8_t)c_read8(c++); |
570 | | if (!b) break; |
571 | | |
572 | | length += 1; |
573 | | if ((0xc0 == b) && (0x80 == (uint8_t)c_read8(c))) |
574 | | nulls += 1; |
575 | | } |
576 | | |
577 | | fxConstructArrayBufferResult(the, mxThis, length - nulls); |
578 | | if (!nulls) |
579 | | c_memcpy(mxResult->value.reference->next->value.arrayBuffer.address, mxArgv(0)->value.string, length); |
580 | | else { |
581 | | txString c = mxArgv(0)->value.string, end = c + length; |
582 | | txByte *out = mxResult->value.reference->next->value.arrayBuffer.address; |
583 | | while (c < end) { |
584 | | uint8_t b = (uint8_t)c_read8(c++); |
585 | | if ((0xc0 == (uint8_t)b) && (0x80 == (uint8_t)c_read8(c))) { |
586 | | b = 0; |
587 | | c += 1; |
588 | | } |
589 | | *out++ = b; |
590 | | } |
591 | | } |
592 | | } |
593 | | #endif |
594 | | |
595 | | void fx_ArrayBuffer_isView(txMachine* the) |
596 | 282 | { |
597 | 282 | txSlot* slot; |
598 | 282 | mxResult->kind = XS_BOOLEAN_KIND; |
599 | 282 | mxResult->value.boolean = 0; |
600 | 282 | if (mxArgc > 0) { |
601 | 280 | slot = mxArgv(0); |
602 | 280 | if (slot->kind == XS_REFERENCE_KIND) { |
603 | 8 | slot = slot->value.reference; |
604 | 8 | if (slot->next) { |
605 | 5 | slot = slot->next; |
606 | 5 | if ((slot->kind == XS_DATA_VIEW_KIND) || (slot->kind == XS_TYPED_ARRAY_KIND)) { |
607 | 1 | mxResult->value.boolean = 1; |
608 | 1 | } |
609 | 5 | } |
610 | 8 | } |
611 | 280 | } |
612 | 282 | } |
613 | | |
614 | | void fx_ArrayBuffer_prototype_get_byteLength(txMachine* the) |
615 | 142 | { |
616 | 142 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
617 | 142 | txSlot* arrayBuffer = instance->next; |
618 | 142 | txSlot* bufferInfo = arrayBuffer->next; |
619 | 142 | mxResult->kind = XS_INTEGER_KIND; |
620 | 142 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
621 | 3 | mxResult->value.integer = 0; |
622 | 139 | else |
623 | 139 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
624 | 142 | } |
625 | | |
626 | | void fx_ArrayBuffer_prototype_get_detached(txMachine* the) |
627 | 23.6k | { |
628 | 23.6k | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
629 | 23.6k | txSlot* arrayBuffer = instance->next; |
630 | 23.6k | mxResult->kind = XS_BOOLEAN_KIND; |
631 | 23.6k | mxResult->value.boolean = (arrayBuffer->value.arrayBuffer.address == C_NULL) ? 1 : 0; |
632 | 23.6k | } |
633 | | |
634 | | void fx_ArrayBuffer_prototype_get_immutable(txMachine* the) |
635 | 23.6k | { |
636 | 23.6k | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
637 | 23.6k | txSlot* arrayBuffer = instance->next; |
638 | 23.6k | mxResult->kind = XS_BOOLEAN_KIND; |
639 | 23.6k | mxResult->value.boolean = (arrayBuffer->flag & XS_DONT_SET_FLAG) ? 1 : 0; |
640 | 23.6k | } |
641 | | |
642 | | void fx_ArrayBuffer_prototype_get_maxByteLength(txMachine* the) |
643 | 113 | { |
644 | 113 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
645 | 113 | txSlot* arrayBuffer = instance->next; |
646 | 113 | txSlot* bufferInfo = arrayBuffer->next; |
647 | 113 | mxResult->kind = XS_INTEGER_KIND; |
648 | 113 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
649 | 0 | mxResult->value.integer = 0; |
650 | 113 | else if (bufferInfo->value.bufferInfo.maxLength >= 0) |
651 | 6 | mxResult->value.integer = bufferInfo->value.bufferInfo.maxLength; |
652 | 107 | else |
653 | 107 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
654 | 113 | } |
655 | | |
656 | | void fx_ArrayBuffer_prototype_get_resizable(txMachine* the) |
657 | 77 | { |
658 | 77 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
659 | 77 | txSlot* arrayBuffer = instance->next; |
660 | 77 | txSlot* bufferInfo = arrayBuffer->next; |
661 | 77 | mxResult->kind = XS_BOOLEAN_KIND; |
662 | 77 | mxResult->value.boolean = (bufferInfo->value.bufferInfo.maxLength >= 0) ? 1 : 0; |
663 | 77 | } |
664 | | |
665 | | void fx_ArrayBuffer_prototype_concat(txMachine* the) |
666 | 3.60k | { |
667 | 3.60k | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
668 | 3.60k | txSlot* arrayBuffer = instance->next; |
669 | 3.60k | txSlot* bufferInfo = arrayBuffer->next; |
670 | 3.60k | txInteger length = bufferInfo->value.bufferInfo.length; |
671 | 3.60k | txInteger c = mxArgc, i = 0; |
672 | 3.60k | txByte* address; |
673 | 3.60k | txSlot* slot; |
674 | 3.62k | while (i < c) { |
675 | 18 | arrayBuffer = C_NULL; |
676 | 18 | bufferInfo = C_NULL; |
677 | 18 | slot = mxArgv(i); |
678 | 18 | if (slot->kind == XS_REFERENCE_KIND) { |
679 | 15 | slot = slot->value.reference->next; |
680 | 15 | if (slot) { |
681 | 14 | if (slot->kind == XS_ARRAY_BUFFER_KIND) { |
682 | 13 | bufferInfo = slot->next; |
683 | 13 | } |
684 | 1 | else if ((slot->kind == XS_HOST_KIND) && !(slot->flag & XS_HOST_CHUNK_FLAG)) { |
685 | 0 | slot = slot->next; |
686 | 0 | if (slot && (slot->kind == XS_BUFFER_INFO_KIND)) { |
687 | 0 | bufferInfo = slot; |
688 | 0 | } |
689 | 0 | } |
690 | 14 | } |
691 | 15 | } |
692 | 18 | if (bufferInfo) |
693 | 13 | length = fxAddChunkSizes(the, length, bufferInfo->value.bufferInfo.length); |
694 | 5 | else |
695 | 5 | mxTypeError("arguments[%ld]: not an ArrayBuffer instance", i); |
696 | 13 | i++; |
697 | 13 | } |
698 | 3.60k | fxConstructArrayBufferResult(the, C_NULL, length); |
699 | 3.60k | address = mxResult->value.reference->next->value.arrayBuffer.address; |
700 | 3.60k | slot = instance->next; |
701 | 3.60k | i = -1; |
702 | 3.61k | while (length > 0) { |
703 | 16 | txByte* from; |
704 | 16 | txInteger count; |
705 | 16 | if (slot->kind == XS_ARRAY_BUFFER_KIND) |
706 | 16 | from = slot->value.arrayBuffer.address; |
707 | 0 | else |
708 | 0 | from = slot->value.host.data; |
709 | 16 | count = (from) ? slot->next->value.bufferInfo.length : 0; |
710 | 16 | if (count > length) |
711 | 1 | count = length; |
712 | 16 | if (count > 0) |
713 | 15 | c_memmove(address, from, count); |
714 | 16 | address += count; |
715 | 16 | length -= count; |
716 | 16 | if (++i >= c) |
717 | 5 | break; |
718 | 11 | slot = mxArgv(i)->value.reference->next; |
719 | 11 | } |
720 | 3.60k | } |
721 | | |
722 | | void fx_ArrayBuffer_prototype_resize(txMachine* the) |
723 | 1.00k | { |
724 | 1.00k | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
725 | 1.00k | txSlot* arrayBuffer = instance->next; |
726 | 1.00k | txSlot* bufferInfo = arrayBuffer->next; |
727 | 1.00k | fxCheckArrayBufferMutable(the, mxThis); |
728 | 1.00k | txInteger maxByteLength = bufferInfo->value.bufferInfo.maxLength; |
729 | 1.00k | if (maxByteLength < 0) |
730 | 12 | mxTypeError("not resizable"); |
731 | 991 | txInteger newByteLength = fxArgToByteLength(the, 0, 0); |
732 | 991 | fxCheckArrayBufferDetached(the, mxThis); |
733 | 991 | txInteger oldByteLength; |
734 | 991 | txByte* chunk; |
735 | 991 | oldByteLength = bufferInfo->value.bufferInfo.length; |
736 | 991 | if (newByteLength > maxByteLength) |
737 | 1 | mxRangeError("newLength > maxByteLength"); |
738 | 990 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
739 | 990 | chunk = (txByte*)fxRenewChunk(the, arrayBuffer->value.arrayBuffer.address, newByteLength); |
740 | 990 | if (!chunk) { |
741 | 3 | chunk = (txByte*)fxNewChunk(the, newByteLength); |
742 | 3 | c_memcpy(chunk, arrayBuffer->value.arrayBuffer.address, (newByteLength < oldByteLength) ? newByteLength : oldByteLength); |
743 | 3 | } |
744 | 990 | if (newByteLength > oldByteLength) |
745 | 55 | c_memset(chunk + oldByteLength, 0, newByteLength - oldByteLength); |
746 | 990 | arrayBuffer->value.arrayBuffer.address = chunk; |
747 | 990 | bufferInfo->value.bufferInfo.length = newByteLength; |
748 | 990 | } |
749 | | |
750 | | void fx_ArrayBuffer_prototype_slice(txMachine* the) |
751 | 60 | { |
752 | 60 | /* txSlot* instance = */ fxCheckArrayBufferInstance(the, mxThis); |
753 | 60 | txSlot* arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
754 | 60 | txSlot* bufferInfo = arrayBuffer->next; |
755 | 60 | txInteger length = bufferInfo->value.bufferInfo.length; |
756 | 60 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
757 | 60 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
758 | 60 | txSlot* resultBuffer; |
759 | 60 | if (stop < start) |
760 | 6 | stop = start; |
761 | 60 | fxConstructArrayBufferResult(the, C_NULL, stop - start); |
762 | 60 | resultBuffer = mxResult->value.reference->next; |
763 | 60 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
764 | 60 | bufferInfo = arrayBuffer->next; |
765 | 60 | length = bufferInfo->value.bufferInfo.length; |
766 | 60 | if (start < length) { |
767 | 22 | if (stop > length) |
768 | 1 | stop = length; |
769 | 22 | c_memcpy(resultBuffer->value.arrayBuffer.address, arrayBuffer->value.arrayBuffer.address + start, stop - start); |
770 | 22 | } |
771 | 60 | } |
772 | | |
773 | | void fx_ArrayBuffer_prototype_sliceToImmutable(txMachine* the) |
774 | 14 | { |
775 | 14 | /* txSlot* instance = */ fxCheckArrayBufferInstance(the, mxThis); |
776 | 14 | txSlot* arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
777 | 14 | txSlot* bufferInfo = arrayBuffer->next; |
778 | 14 | txInteger length = bufferInfo->value.bufferInfo.length; |
779 | 14 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
780 | 14 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
781 | 14 | txSlot* resultBuffer; |
782 | 14 | if (stop < start) |
783 | 2 | stop = start; |
784 | 14 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
785 | 14 | bufferInfo = arrayBuffer->next; |
786 | 14 | length = bufferInfo->value.bufferInfo.length; |
787 | 14 | if (length < stop) |
788 | 1 | mxRangeError("resized this"); |
789 | 13 | fxConstructArrayBufferResult(the, &mxArrayBufferConstructor, stop - start); |
790 | 13 | resultBuffer = fxCheckArrayBufferDetached(the, mxResult); |
791 | 13 | c_memcpy(resultBuffer->value.arrayBuffer.address, arrayBuffer->value.arrayBuffer.address + start, stop - start); |
792 | 13 | resultBuffer->flag |= XS_DONT_SET_FLAG; |
793 | 13 | } |
794 | | |
795 | | static void fx_ArrayBuffer_prototype_transferAux(txMachine* the, txFlag flag) |
796 | 23.7k | { |
797 | 23.7k | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
798 | 23.7k | txSlot* arrayBuffer = instance->next; |
799 | 23.7k | txSlot* bufferInfo = arrayBuffer->next; |
800 | 23.7k | txInteger oldByteLength = bufferInfo->value.bufferInfo.length; |
801 | 23.7k | txInteger maxByteLength = bufferInfo->value.bufferInfo.maxLength; |
802 | 23.7k | txInteger newByteLength = fxArgToByteLength(the, 0, oldByteLength); |
803 | 23.7k | txSlot* resultBuffer; |
804 | 23.7k | oldByteLength = bufferInfo->value.bufferInfo.length; // ToIndex may have resized this |
805 | 23.7k | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis); |
806 | 23.7k | fxCheckArrayBufferMutable(the, mxThis); |
807 | 23.7k | if (!(flag & 1) && (maxByteLength >= 0) && (newByteLength > maxByteLength)) |
808 | 1 | mxRangeError("newLength > maxByteLength"); |
809 | 23.7k | fxConstructArrayBufferResult(the, &mxArrayBufferConstructor, newByteLength); |
810 | 23.7k | resultBuffer = mxResult->value.reference->next; |
811 | 23.7k | c_memcpy(resultBuffer->value.arrayBuffer.address, arrayBuffer->value.arrayBuffer.address, (newByteLength < oldByteLength) ? newByteLength : oldByteLength); |
812 | 23.7k | if (newByteLength > oldByteLength) |
813 | 28 | c_memset(resultBuffer->value.arrayBuffer.address + oldByteLength, 0, newByteLength - oldByteLength); |
814 | 23.7k | arrayBuffer->value.arrayBuffer.address = C_NULL; |
815 | 23.7k | bufferInfo->value.bufferInfo.length = 0; |
816 | 23.7k | if (flag & 2) |
817 | 23.6k | resultBuffer->flag |= XS_DONT_SET_FLAG; |
818 | 23.7k | resultBuffer->next->value.bufferInfo.maxLength = (flag & 1) ? -1 : maxByteLength; |
819 | 23.7k | } |
820 | | |
821 | | void fx_ArrayBuffer_prototype_transfer(txMachine* the) |
822 | 24 | { |
823 | 24 | fx_ArrayBuffer_prototype_transferAux(the, 0); |
824 | 24 | } |
825 | | |
826 | | void fx_ArrayBuffer_prototype_transferToFixedLength(txMachine* the) |
827 | 16 | { |
828 | 16 | fx_ArrayBuffer_prototype_transferAux(the, 1); |
829 | 16 | } |
830 | | |
831 | | void fx_ArrayBuffer_prototype_transferToImmutable(txMachine* the) |
832 | 23.6k | { |
833 | 23.6k | fx_ArrayBuffer_prototype_transferAux(the, 3); |
834 | 23.6k | } |
835 | | |
836 | | txSlot* fxCheckDataViewInstance(txMachine* the, txSlot* slot, txBoolean mutable) |
837 | 5.98k | { |
838 | 5.98k | if (slot->kind == XS_REFERENCE_KIND) { |
839 | 5.89k | txSlot* instance = slot->value.reference; |
840 | 5.89k | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_DATA_VIEW_KIND)) { |
841 | 5.73k | if (mutable) { |
842 | 3.67k | txSlot* arrayBuffer = slot->next->value.reference->next; |
843 | 3.67k | if (arrayBuffer->flag & XS_DONT_SET_FLAG) |
844 | 5 | mxTypeError("read-only buffer"); |
845 | 3.67k | } |
846 | 5.72k | return instance; |
847 | 5.73k | } |
848 | 5.89k | } |
849 | 5.98k | mxTypeError("this: not a DataView instance"); |
850 | 0 | return C_NULL; |
851 | 5.98k | } |
852 | | |
853 | | txInteger fxCheckDataViewSize(txMachine* the, txSlot* view, txSlot* buffer, txBoolean mutable) |
854 | 117k | { |
855 | 117k | txInteger size = view->value.dataView.size; |
856 | 117k | txSlot* arrayBuffer = buffer->value.reference->next; |
857 | 117k | txSlot* bufferInfo = arrayBuffer->next; |
858 | 117k | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
859 | 2 | mxTypeError("detached buffer"); |
860 | 117k | if (mutable && (arrayBuffer->flag & XS_DONT_SET_FLAG)) |
861 | 1 | mxTypeError("read-only buffer"); |
862 | 117k | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
863 | 2.28k | txInteger offset = view->value.dataView.offset; |
864 | 2.28k | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
865 | 2.28k | if (offset > byteLength) |
866 | 4 | mxTypeError("out of bounds view"); |
867 | 2.28k | else if (size < 0) |
868 | 2.23k | size = byteLength - offset; |
869 | 51 | else if (offset + size > byteLength) |
870 | 8 | mxTypeError("out of bounds view"); |
871 | 2.28k | } |
872 | 117k | return size; |
873 | 117k | } |
874 | | |
875 | | txSlot* fxGetBufferInfo(txMachine* the, txSlot* buffer) |
876 | 32.6k | { |
877 | 32.6k | txSlot* arrayBuffer = buffer->value.reference->next; |
878 | 32.6k | txSlot* bufferInfo = arrayBuffer->next; |
879 | 32.6k | if (arrayBuffer->kind == XS_ARRAY_BUFFER_KIND) { |
880 | 29.2k | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
881 | 1 | mxTypeError("detached buffer"); |
882 | 29.2k | return bufferInfo; |
883 | 29.2k | } |
884 | 3.46k | if (arrayBuffer->kind == XS_HOST_KIND) { |
885 | 3.46k | if (bufferInfo && (bufferInfo->kind == XS_BUFFER_INFO_KIND)) |
886 | 3.46k | return bufferInfo; |
887 | 3.46k | } |
888 | 3.46k | mxTypeError("invalid buffer"); |
889 | 0 | return C_NULL; |
890 | 3.46k | } |
891 | | |
892 | | txInteger fxGetDataViewSize(txMachine* the, txSlot* view, txSlot* buffer) |
893 | 10.3M | { |
894 | 10.3M | txInteger size = view->value.dataView.size; |
895 | 10.3M | txSlot* arrayBuffer = buffer->value.reference->next; |
896 | 10.3M | txSlot* bufferInfo = arrayBuffer->next; |
897 | 10.3M | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
898 | 17 | return 0; |
899 | 10.3M | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
900 | 6.34k | txInteger offset = view->value.dataView.offset; |
901 | 6.34k | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
902 | 6.34k | if (offset > byteLength) |
903 | 9 | size = 0; |
904 | 6.33k | else if (size < 0) |
905 | 6.32k | size = byteLength - offset; |
906 | 6 | else if (offset + size > byteLength) |
907 | 1 | size = 0; |
908 | 6.34k | } |
909 | 10.3M | return size; |
910 | 10.3M | } |
911 | | |
912 | | txBoolean fxIsDataViewOutOfBound(txMachine* the, txSlot* view, txSlot* buffer) |
913 | 179 | { |
914 | 179 | txInteger size = view->value.dataView.size; |
915 | 179 | txSlot* arrayBuffer = buffer->value.reference->next; |
916 | 179 | txSlot* bufferInfo = arrayBuffer->next; |
917 | 179 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
918 | 0 | return 1; |
919 | 179 | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
920 | 35 | txInteger offset = view->value.dataView.offset; |
921 | 35 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
922 | 35 | if (offset > byteLength) |
923 | 1 | return 1; |
924 | 34 | if ((size > 0) && (offset + size > byteLength)) |
925 | 0 | return 1; |
926 | 34 | } |
927 | 178 | return 0; |
928 | 179 | } |
929 | | |
930 | | txSlot* fxNewDataViewInstance(txMachine* the) |
931 | 791 | { |
932 | 791 | txSlot* instance; |
933 | 791 | txSlot* property; |
934 | 791 | instance = fxNewObjectInstance(the); |
935 | 791 | property = instance->next = fxNewSlot(the); |
936 | 791 | property->flag = XS_INTERNAL_FLAG; |
937 | 791 | property->kind = XS_DATA_VIEW_KIND; |
938 | 791 | property->value.dataView.offset = 0; |
939 | 791 | property->value.dataView.size = 0; |
940 | 791 | property = fxNextNullProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
941 | 791 | return instance; |
942 | 791 | } |
943 | | |
944 | | void fx_DataView(txMachine* the) |
945 | 1.27k | { |
946 | 1.27k | txSlot* slot; |
947 | 1.27k | txBoolean flag = 0; |
948 | 1.27k | txInteger offset, size; |
949 | 1.27k | txSlot* info; |
950 | 1.27k | txSlot* instance; |
951 | 1.27k | txSlot* view; |
952 | 1.27k | txSlot* buffer; |
953 | 1.27k | if (!mxHasTarget) |
954 | 3 | mxTypeError("call: DataView"); |
955 | 1.27k | if ((mxArgc > 0) && (mxArgv(0)->kind == XS_REFERENCE_KIND)) { |
956 | 1.25k | slot = mxArgv(0)->value.reference->next; |
957 | 1.25k | if (slot && ((slot->kind == XS_ARRAY_BUFFER_KIND) || (slot->kind == XS_HOST_KIND))) { |
958 | 1.24k | flag = 1; |
959 | 1.24k | } |
960 | 1.25k | } |
961 | 1.27k | if (!flag) |
962 | 32 | mxTypeError("buffer: not an ArrayBuffer instance"); |
963 | | |
964 | 1.24k | offset = fxArgToByteLength(the, 1, 0); |
965 | 1.24k | info = fxGetBufferInfo(the, mxArgv(0)); |
966 | 1.24k | if (info->value.bufferInfo.length < offset) |
967 | 227 | mxRangeError("invalid byteOffset %ld", offset); |
968 | 1.01k | size = fxArgToByteLength(the, 2, -1); |
969 | 1.01k | if (size >= 0) { |
970 | 193 | txInteger end = offset + size; |
971 | 193 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
972 | 21 | mxRangeError("invalid byteLength %ld", size); |
973 | 193 | } |
974 | 821 | else { |
975 | 821 | if (info->value.bufferInfo.maxLength < 0) |
976 | 610 | size = info->value.bufferInfo.length - offset; |
977 | 821 | } |
978 | 993 | mxPushSlot(mxTarget); |
979 | 993 | fxGetPrototypeFromConstructor(the, &mxDataViewPrototype); |
980 | 993 | instance = fxNewDataViewInstance(the); |
981 | 993 | mxPullSlot(mxResult); |
982 | 993 | view = instance->next; |
983 | 993 | buffer = view->next; |
984 | 993 | buffer->kind = XS_REFERENCE_KIND; |
985 | 993 | buffer->value.reference = mxArgv(0)->value.reference; |
986 | 993 | info = fxGetBufferInfo(the, buffer); |
987 | 993 | if (info->value.bufferInfo.maxLength >= 0) { |
988 | 31 | if (info->value.bufferInfo.length < offset) |
989 | 1 | mxRangeError("invalid byteOffset %ld", offset); |
990 | 30 | else if (size >= 0) { |
991 | 22 | txInteger end = offset + size; |
992 | 22 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
993 | 1 | mxRangeError("invalid byteLength %ld", size); |
994 | 22 | } |
995 | 31 | } |
996 | 991 | view->value.dataView.offset = offset; |
997 | 991 | view->value.dataView.size = size; |
998 | 991 | } |
999 | | |
1000 | | void fx_DataView_prototype_buffer_get(txMachine* the) |
1001 | 64 | { |
1002 | 64 | txSlot* instance = fxCheckDataViewInstance(the, mxThis, XS_IMMUTABLE); |
1003 | 64 | txSlot* view = instance->next; |
1004 | 64 | txSlot* buffer = view->next; |
1005 | 64 | mxResult->kind = buffer->kind; |
1006 | 64 | mxResult->value = buffer->value; |
1007 | 64 | } |
1008 | | |
1009 | | void fx_DataView_prototype_byteLength_get(txMachine* the) |
1010 | 111 | { |
1011 | 111 | txSlot* instance = fxCheckDataViewInstance(the, mxThis, XS_IMMUTABLE); |
1012 | 111 | txSlot* view = instance->next; |
1013 | 111 | txSlot* buffer = view->next; |
1014 | 111 | txInteger size = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1015 | 111 | mxResult->kind = XS_INTEGER_KIND; |
1016 | 111 | mxResult->value.integer = size; |
1017 | 111 | } |
1018 | | |
1019 | | void fx_DataView_prototype_byteOffset_get(txMachine* the) |
1020 | 105 | { |
1021 | 105 | txSlot* instance = fxCheckDataViewInstance(the, mxThis, XS_IMMUTABLE); |
1022 | 105 | txSlot* view = instance->next; |
1023 | 105 | txSlot* buffer = view->next; |
1024 | 105 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1025 | 105 | mxResult->kind = XS_INTEGER_KIND; |
1026 | 105 | mxResult->value.integer = view->value.dataView.offset; |
1027 | 105 | } |
1028 | | |
1029 | | void fx_DataView_prototype_get(txMachine* the, txNumber delta, txTypeCallback getter) |
1030 | 1.95k | { |
1031 | 1.95k | txSlot* instance = fxCheckDataViewInstance(the, mxThis, XS_IMMUTABLE); |
1032 | 1.95k | txSlot* view = instance->next; |
1033 | 1.95k | txSlot* buffer = view->next; |
1034 | 1.95k | txInteger offset = fxArgToByteLength(the, 0, 0); |
1035 | 1.95k | txInteger size; |
1036 | 1.95k | int endian = EndianBig; |
1037 | 1.95k | if ((mxArgc > 1) && fxToBoolean(the, mxArgv(1))) |
1038 | 143 | endian = EndianLittle; |
1039 | 1.95k | size = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1040 | 1.95k | if ((size < delta) || ((size - delta) < offset)) |
1041 | 188 | mxRangeError("invalid byteOffset"); |
1042 | 1.76k | offset += view->value.dataView.offset; |
1043 | 1.76k | (*getter)(the, buffer->value.reference->next, offset, mxResult, endian); |
1044 | 1.76k | } |
1045 | | |
1046 | | void fx_DataView_prototype_getBigInt64(txMachine* the) |
1047 | 230 | { |
1048 | 230 | fx_DataView_prototype_get(the, 8, fxBigInt64Getter); |
1049 | 230 | } |
1050 | | |
1051 | | void fx_DataView_prototype_getBigUint64(txMachine* the) |
1052 | 254 | { |
1053 | 254 | fx_DataView_prototype_get(the, 8, fxBigUint64Getter); |
1054 | 254 | } |
1055 | | |
1056 | | #if mxFloat16 |
1057 | | void fx_DataView_prototype_getFloat16(txMachine* the) |
1058 | 97 | { |
1059 | 97 | fx_DataView_prototype_get(the, 2, fxFloat16Getter); |
1060 | 97 | } |
1061 | | #endif |
1062 | | |
1063 | | void fx_DataView_prototype_getFloat32(txMachine* the) |
1064 | 103 | { |
1065 | 103 | fx_DataView_prototype_get(the, 4, fxFloat32Getter); |
1066 | 103 | } |
1067 | | |
1068 | | void fx_DataView_prototype_getFloat64(txMachine* the) |
1069 | 117 | { |
1070 | 117 | fx_DataView_prototype_get(the, 8, fxFloat64Getter); |
1071 | 117 | } |
1072 | | |
1073 | | void fx_DataView_prototype_getInt8(txMachine* the) |
1074 | 592 | { |
1075 | 592 | fx_DataView_prototype_get(the, 1, fxInt8Getter); |
1076 | 592 | } |
1077 | | |
1078 | | void fx_DataView_prototype_getInt16(txMachine* the) |
1079 | 132 | { |
1080 | 132 | fx_DataView_prototype_get(the, 2, fxInt16Getter); |
1081 | 132 | } |
1082 | | |
1083 | | void fx_DataView_prototype_getInt32(txMachine* the) |
1084 | 119 | { |
1085 | 119 | fx_DataView_prototype_get(the, 4, fxInt32Getter); |
1086 | 119 | } |
1087 | | |
1088 | | void fx_DataView_prototype_getUint8(txMachine* the) |
1089 | 69 | { |
1090 | 69 | fx_DataView_prototype_get(the, 1, fxUint8Getter); |
1091 | 69 | } |
1092 | | |
1093 | | void fx_DataView_prototype_getUint16(txMachine* the) |
1094 | 95 | { |
1095 | 95 | fx_DataView_prototype_get(the, 2, fxUint16Getter); |
1096 | 95 | } |
1097 | | |
1098 | | void fx_DataView_prototype_getUint32(txMachine* the) |
1099 | 147 | { |
1100 | 147 | fx_DataView_prototype_get(the, 4, fxUint32Getter); |
1101 | 147 | } |
1102 | | |
1103 | | void fx_DataView_prototype_set(txMachine* the, txNumber delta, txTypeCoerce coercer, txTypeCallback setter) |
1104 | 3.74k | { |
1105 | 3.74k | txSlot* instance = fxCheckDataViewInstance(the, mxThis, XS_MUTABLE); |
1106 | 3.74k | txSlot* view = instance->next; |
1107 | 3.74k | txSlot* buffer = view->next; |
1108 | 3.74k | txInteger offset = fxArgToByteLength(the, 0, 0); |
1109 | 3.74k | txInteger size; |
1110 | 3.74k | int endian = EndianBig; |
1111 | 3.74k | txSlot* value; |
1112 | 3.74k | if (mxArgc > 1) |
1113 | 3.44k | mxPushSlot(mxArgv(1)); |
1114 | 304 | else |
1115 | 304 | mxPushUndefined(); |
1116 | 3.74k | value = the->stack; |
1117 | 3.74k | (*coercer)(the, value); |
1118 | 3.74k | if ((mxArgc > 2) && fxToBoolean(the, mxArgv(2))) |
1119 | 93 | endian = EndianLittle; |
1120 | 3.74k | size = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
1121 | 3.74k | if ((size < delta) || ((size - delta) < offset)) |
1122 | 81 | mxRangeError("invalid byteOffset"); |
1123 | 3.66k | offset += view->value.dataView.offset; |
1124 | 3.66k | (*setter)(the, buffer->value.reference->next, offset, value, endian); |
1125 | 3.66k | mxPop(); |
1126 | 3.66k | } |
1127 | | |
1128 | | void fx_DataView_prototype_setBigInt64(txMachine* the) |
1129 | 117 | { |
1130 | 117 | fx_DataView_prototype_set(the, 8, fxBigIntCoerce, fxBigInt64Setter); |
1131 | 117 | } |
1132 | | |
1133 | | void fx_DataView_prototype_setBigUint64(txMachine* the) |
1134 | 8 | { |
1135 | 8 | fx_DataView_prototype_set(the, 8, fxBigIntCoerce, fxBigUint64Setter); |
1136 | 8 | } |
1137 | | |
1138 | | #if mxFloat16 |
1139 | | void fx_DataView_prototype_setFloat16(txMachine* the) |
1140 | 143 | { |
1141 | 143 | fx_DataView_prototype_set(the, 2, fxNumberCoerce, fxFloat16Setter); |
1142 | 143 | } |
1143 | | #endif |
1144 | | |
1145 | | void fx_DataView_prototype_setFloat32(txMachine* the) |
1146 | 110 | { |
1147 | 110 | fx_DataView_prototype_set(the, 4, fxNumberCoerce, fxFloat32Setter); |
1148 | 110 | } |
1149 | | |
1150 | | void fx_DataView_prototype_setFloat64(txMachine* the) |
1151 | 125 | { |
1152 | 125 | fx_DataView_prototype_set(the, 8, fxNumberCoerce, fxFloat64Setter); |
1153 | 125 | } |
1154 | | |
1155 | | void fx_DataView_prototype_setInt8(txMachine* the) |
1156 | 100 | { |
1157 | 100 | fx_DataView_prototype_set(the, 1, fxIntCoerce, fxInt8Setter); |
1158 | 100 | } |
1159 | | |
1160 | | void fx_DataView_prototype_setInt16(txMachine* the) |
1161 | 110 | { |
1162 | 110 | fx_DataView_prototype_set(the, 2, fxIntCoerce, fxInt16Setter); |
1163 | 110 | } |
1164 | | |
1165 | | void fx_DataView_prototype_setInt32(txMachine* the) |
1166 | 112 | { |
1167 | 112 | fx_DataView_prototype_set(the, 4, fxIntCoerce, fxInt32Setter); |
1168 | 112 | } |
1169 | | |
1170 | | void fx_DataView_prototype_setUint8(txMachine* the) |
1171 | 2.54k | { |
1172 | 2.54k | fx_DataView_prototype_set(the, 1, fxUintCoerce, fxUint8Setter); |
1173 | 2.54k | } |
1174 | | |
1175 | | void fx_DataView_prototype_setUint16(txMachine* the) |
1176 | 243 | { |
1177 | 243 | fx_DataView_prototype_set(the, 2, fxUintCoerce, fxUint16Setter); |
1178 | 243 | } |
1179 | | |
1180 | | void fx_DataView_prototype_setUint32(txMachine* the) |
1181 | 135 | { |
1182 | 135 | fx_DataView_prototype_set(the, 4, fxUintCoerce, fxUint32Setter); |
1183 | 135 | } |
1184 | | |
1185 | | |
1186 | | #define mxTypedArrayDeclarations \ |
1187 | 64.9k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); \ |
1188 | 64.9k | txSlot* dispatch = instance->next; \ |
1189 | 64.9k | txSlot* view = dispatch->next; \ |
1190 | 64.9k | txSlot* buffer = view->next; \ |
1191 | 64.9k | txInteger length = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE) >> dispatch->value.typedArray.dispatch->shift |
1192 | | |
1193 | | #define mxMutableTypedArrayDeclarations \ |
1194 | 3.68k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); \ |
1195 | 3.68k | txSlot* dispatch = instance->next; \ |
1196 | 3.68k | txSlot* view = dispatch->next; \ |
1197 | 3.68k | txSlot* buffer = view->next; \ |
1198 | 3.68k | txInteger length = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) >> dispatch->value.typedArray.dispatch->shift |
1199 | | |
1200 | | #define mxResultTypedArrayDeclarations \ |
1201 | 23.7k | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
1202 | 23.7k | txSlot* resultDispatch = resultInstance->next; \ |
1203 | 23.7k | txSlot* resultView = resultDispatch->next; \ |
1204 | 23.7k | txSlot* resultBuffer = resultView->next; \ |
1205 | 23.7k | txInteger resultLength = fxCheckDataViewSize(the, resultView, resultBuffer, XS_MUTABLE) >> resultDispatch->value.typedArray.dispatch->shift |
1206 | | |
1207 | | void fxTypedArrayGetter(txMachine* the) |
1208 | 5.27M | { |
1209 | 5.27M | txSlot* instance = fxToInstance(the, mxThis); |
1210 | 5.27M | txSlot* dispatch; |
1211 | 5.27M | while (instance) { |
1212 | 5.27M | if (instance->flag & XS_EXOTIC_FLAG) { |
1213 | 5.27M | dispatch = instance->next; |
1214 | 5.27M | if (dispatch->ID == XS_TYPED_ARRAY_BEHAVIOR) |
1215 | 5.27M | break; |
1216 | 5.27M | } |
1217 | 0 | instance = fxGetPrototype(the, instance); |
1218 | 0 | } |
1219 | 5.27M | if (instance) { |
1220 | 5.27M | txID id = the->scratch.value.at.id; |
1221 | 5.27M | txIndex index = the->scratch.value.at.index; |
1222 | 5.27M | txSlot* view = dispatch->next; |
1223 | 5.27M | txSlot* buffer = view->next; |
1224 | 5.27M | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1225 | 5.27M | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1226 | 5.27M | if ((!id) && (index < length)) { |
1227 | 5.26M | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), mxResult, EndianNative); |
1228 | 5.26M | } |
1229 | 5.27M | } |
1230 | 5.27M | } |
1231 | | |
1232 | | void fxTypedArraySetter(txMachine* the) |
1233 | 501k | { |
1234 | 501k | txSlot* instance = fxToInstance(the, mxThis); |
1235 | 501k | while (instance) { |
1236 | 501k | if (instance->flag & XS_EXOTIC_FLAG) { |
1237 | 501k | if (instance->next->ID == XS_TYPED_ARRAY_BEHAVIOR) |
1238 | 501k | break; |
1239 | 501k | } |
1240 | 0 | instance = fxGetPrototype(the, instance); |
1241 | 0 | } |
1242 | 501k | if (instance) { |
1243 | 501k | txSlot* value = mxArgv(0); |
1244 | 501k | txID id = the->scratch.value.at.id; |
1245 | 501k | txIndex index = the->scratch.value.at.index; |
1246 | 501k | if (!fxTypedArraySetPropertyValue(the, instance, id, index, value, mxThis)) { |
1247 | 0 | if (the->frame->next->flag & XS_STRICT_FLAG) |
1248 | 0 | mxTypeError("not extensible or not writable"); |
1249 | 0 | } |
1250 | 501k | } |
1251 | 501k | } |
1252 | | |
1253 | | txBoolean fxTypedArrayDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask) |
1254 | 19 | { |
1255 | 19 | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1256 | 17 | txSlot* dispatch = instance->next; |
1257 | 17 | txSlot* view = dispatch->next; |
1258 | 17 | txSlot* buffer = view->next; |
1259 | 17 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1260 | 17 | txSlot* arrayBuffer = buffer->value.reference->next; |
1261 | 17 | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1262 | 17 | if (id || (index >= length)) |
1263 | 1 | return 0; |
1264 | 16 | if (arrayBuffer->flag & XS_DONT_SET_FLAG) { |
1265 | 0 | if ((mask & XS_DONT_DELETE_FLAG) && !(slot->flag & XS_DONT_DELETE_FLAG)) |
1266 | 0 | return 0; |
1267 | 0 | if ((mask & XS_DONT_ENUM_FLAG) && (slot->flag & XS_DONT_ENUM_FLAG)) |
1268 | 0 | return 0; |
1269 | 0 | if (mask & XS_ACCESSOR_FLAG) |
1270 | 0 | return 0; |
1271 | 0 | if ((mask & XS_DONT_SET_FLAG) && !(slot->flag & XS_DONT_SET_FLAG)) |
1272 | 0 | return 0; |
1273 | 0 | if (slot->kind != XS_UNINITIALIZED_KIND) { |
1274 | 0 | txSlot* property; |
1275 | 0 | txBoolean result = 1; |
1276 | 0 | mxTemporary(property); |
1277 | 0 | (*dispatch->value.typedArray.dispatch->getter)(the, arrayBuffer, view->value.dataView.offset + (index << shift), property, EndianNative); |
1278 | 0 | result = fxIsSameValue(the, property, slot, 0); |
1279 | 0 | mxPop(); |
1280 | 0 | return result; |
1281 | 0 | } |
1282 | 0 | return 1; |
1283 | 0 | } |
1284 | 16 | if ((mask & XS_DONT_DELETE_FLAG) && (slot->flag & XS_DONT_DELETE_FLAG)) |
1285 | 1 | return 0; |
1286 | 15 | if ((mask & XS_DONT_ENUM_FLAG) && (slot->flag & XS_DONT_ENUM_FLAG)) |
1287 | 0 | return 0; |
1288 | 15 | if (mask & XS_ACCESSOR_FLAG) |
1289 | 0 | return 0; |
1290 | 15 | if ((mask & XS_DONT_SET_FLAG) && (slot->flag & XS_DONT_SET_FLAG)) |
1291 | 0 | return 0; |
1292 | 15 | if (slot->kind != XS_UNINITIALIZED_KIND) { |
1293 | 15 | dispatch->value.typedArray.dispatch->coerce(the, slot); |
1294 | 15 | length = fxGetDataViewSize(the, view, buffer) >> shift; |
1295 | 15 | if (index < length) |
1296 | 15 | (*dispatch->value.typedArray.dispatch->setter)(the, arrayBuffer, view->value.dataView.offset + (index << shift), slot, EndianNative); |
1297 | 15 | } |
1298 | 15 | return 1; |
1299 | 15 | } |
1300 | 2 | return fxOrdinaryDefineOwnProperty(the, instance, id, index, slot, mask); |
1301 | 19 | } |
1302 | | |
1303 | | txBoolean fxTypedArrayDeleteProperty(txMachine* the, txSlot* instance, txID id, txIndex index) |
1304 | 131k | { |
1305 | 131k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1306 | 79 | txSlot* dispatch = instance->next; |
1307 | 79 | txSlot* view = dispatch->next; |
1308 | 79 | txSlot* buffer = view->next; |
1309 | 79 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1310 | 79 | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1311 | 79 | return ((!id) && (index < length)) ? 0 : 1; |
1312 | 79 | } |
1313 | 131k | return fxOrdinaryDeleteProperty(the, instance, id, index); |
1314 | 131k | } |
1315 | | |
1316 | | txBoolean fxTypedArrayGetOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot) |
1317 | 286k | { |
1318 | 286k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1319 | 286k | txSlot* dispatch = instance->next; |
1320 | 286k | txSlot* view = dispatch->next; |
1321 | 286k | txSlot* buffer = view->next; |
1322 | 286k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1323 | 286k | txSlot* arrayBuffer = buffer->value.reference->next; |
1324 | 286k | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1325 | 286k | if ((!id) && (index < length)) { |
1326 | 286k | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), slot, EndianNative); |
1327 | 286k | if (arrayBuffer->flag & XS_DONT_SET_FLAG) |
1328 | 0 | slot->flag |= XS_DONT_DELETE_FLAG | XS_DONT_SET_FLAG; |
1329 | 286k | return 1; |
1330 | 286k | } |
1331 | 0 | slot->kind = XS_UNDEFINED_KIND; |
1332 | 0 | slot->flag = XS_NO_FLAG; |
1333 | 0 | return 0; |
1334 | 286k | } |
1335 | 3 | return fxOrdinaryGetOwnProperty(the, instance, id, index, slot); |
1336 | 286k | } |
1337 | | |
1338 | | txSlot* fxTypedArrayGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) |
1339 | 5.49M | { |
1340 | 5.49M | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1341 | 5.27M | the->scratch.value.at.id = id; |
1342 | 5.27M | the->scratch.value.at.index = index; |
1343 | 5.27M | return &mxTypedArrayAccessor; |
1344 | 5.27M | } |
1345 | 223k | return fxOrdinaryGetProperty(the, instance, id, index, flag); |
1346 | 5.49M | } |
1347 | | |
1348 | | txBoolean fxTypedArrayGetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* receiver, txSlot* value) |
1349 | 0 | { |
1350 | 0 | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1351 | 0 | txSlot* dispatch = instance->next; |
1352 | 0 | txSlot* view = dispatch->next; |
1353 | 0 | txSlot* buffer = view->next; |
1354 | 0 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1355 | 0 | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1356 | 0 | if ((!id) && (index < length)) { |
1357 | 0 | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), value, EndianNative); |
1358 | 0 | return 1; |
1359 | 0 | } |
1360 | 0 | value->kind = XS_UNDEFINED_KIND; |
1361 | 0 | return 0; |
1362 | 0 | } |
1363 | 0 | return fxOrdinaryGetPropertyValue(the, instance, id, index, receiver, value); |
1364 | 0 | } |
1365 | | |
1366 | | txBoolean fxTypedArrayHasProperty(txMachine* the, txSlot* instance, txID id, txIndex index) |
1367 | 4.13M | { |
1368 | 4.13M | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1369 | 4.13M | txSlot* dispatch = instance->next; |
1370 | 4.13M | txSlot* view = dispatch->next; |
1371 | 4.13M | txSlot* buffer = view->next; |
1372 | 4.13M | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1373 | 4.13M | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1374 | 4.13M | return ((!id) && (index < length)) ? 1 : 0; |
1375 | 4.13M | } |
1376 | 356 | return fxOrdinaryHasProperty(the, instance, id, index); |
1377 | 4.13M | } |
1378 | | |
1379 | | void fxTypedArrayOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* keys) |
1380 | 92.8k | { |
1381 | 92.8k | if (flag & XS_EACH_NAME_FLAG) { |
1382 | 92.8k | txSlot* dispatch = instance->next; |
1383 | 92.8k | txSlot* view = dispatch->next; |
1384 | 92.8k | txSlot* buffer = view->next; |
1385 | 92.8k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1386 | 92.8k | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1387 | 92.8k | if (length) { |
1388 | 90.8k | txIndex index; |
1389 | 377k | for (index = 0; index < length; index++) |
1390 | 286k | keys = fxQueueKey(the, 0, index, keys); |
1391 | 90.8k | } |
1392 | 92.8k | } |
1393 | 92.8k | fxOrdinaryOwnKeys(the, instance, flag, keys); |
1394 | 92.8k | } |
1395 | | |
1396 | | txBoolean fxTypedArrayPreventExtensions(txMachine* the, txSlot* instance) |
1397 | 4 | { |
1398 | 4 | txSlot* dispatch = instance->next; |
1399 | 4 | txSlot* view = dispatch->next; |
1400 | 4 | txSlot* buffer = view->next; |
1401 | 4 | txSlot* arrayBuffer = buffer->value.reference->next; |
1402 | 4 | txSlot* bufferInfo = arrayBuffer->next; |
1403 | 4 | if ((arrayBuffer->kind == XS_ARRAY_BUFFER_KIND) && (bufferInfo->value.bufferInfo.maxLength >= 0)) |
1404 | 0 | return 0; |
1405 | 4 | return fxOrdinaryPreventExtensions(the, instance); |
1406 | 4 | } |
1407 | | |
1408 | | txSlot* fxTypedArraySetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) |
1409 | 532k | { |
1410 | 532k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1411 | 501k | the->scratch.value.at.id = id; |
1412 | 501k | the->scratch.value.at.index = index; |
1413 | 501k | return &mxTypedArrayAccessor; |
1414 | 501k | } |
1415 | 31.0k | return fxOrdinarySetProperty(the, instance, id, index, flag); |
1416 | 532k | } |
1417 | | |
1418 | | txBoolean fxTypedArraySetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* value, txSlot* receiver) |
1419 | 501k | { |
1420 | 501k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1421 | 501k | txSlot* dispatch = instance->next; |
1422 | 501k | txSlot* view = dispatch->next; |
1423 | 501k | txSlot* buffer = view->next; |
1424 | 501k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1425 | 501k | txSlot* arrayBuffer = buffer->value.reference->next; |
1426 | 501k | txIndex length; |
1427 | 501k | if (arrayBuffer->flag & XS_DONT_SET_FLAG) |
1428 | 0 | return 0; |
1429 | 501k | if ((receiver->kind == XS_REFERENCE_KIND) && (receiver->value.reference == instance)) { |
1430 | 501k | dispatch->value.typedArray.dispatch->coerce(the, value); |
1431 | 501k | length = fxGetDataViewSize(the, view, buffer) >> shift; |
1432 | 501k | if ((!id) && (index < length)) { |
1433 | 497k | (*dispatch->value.typedArray.dispatch->setter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), value, EndianNative); |
1434 | 497k | } |
1435 | 501k | return 1; |
1436 | 501k | } |
1437 | 3 | length = fxGetDataViewSize(the, view, buffer) >> shift; |
1438 | 3 | if ((id) || (index >= length)) { |
1439 | 2 | return 1; |
1440 | 2 | } |
1441 | 3 | } |
1442 | 3 | return fxOrdinarySetPropertyValue(the, instance, id, index, value, receiver); |
1443 | 501k | } |
1444 | | |
1445 | | void fxCallTypedArrayItem(txMachine* the, txSlot* function, txSlot* dispatch, txSlot* view, txSlot* data, txInteger index, txSlot* item) |
1446 | 3 | { |
1447 | | /* THIS */ |
1448 | 3 | if (mxArgc > 1) |
1449 | 0 | mxPushSlot(mxArgv(1)); |
1450 | 3 | else |
1451 | 3 | mxPushUndefined(); |
1452 | | /* FUNCTION */ |
1453 | 3 | mxPushSlot(function); |
1454 | 3 | mxCall(); |
1455 | | /* ARGUMENTS */ |
1456 | 3 | mxPushSlot(mxThis); |
1457 | 3 | mxGetIndex(index); |
1458 | 3 | if (item) { |
1459 | 0 | item->kind = the->stack->kind; |
1460 | 0 | item->value = the->stack->value; |
1461 | 0 | } |
1462 | 3 | mxPushInteger(index); |
1463 | 3 | mxPushSlot(mxThis); |
1464 | 3 | mxRunCount(3); |
1465 | 3 | } |
1466 | | |
1467 | | void fxCheckTypedArrayContentType(txMachine* the, txSlot* dispatch, txSlot* sourceDispatch) |
1468 | 26.1k | { |
1469 | 26.1k | txBoolean contentType = (dispatch->value.typedArray.dispatch->constructorID == _BigInt64Array) |
1470 | 26.1k | || (dispatch->value.typedArray.dispatch->constructorID == _BigUint64Array); |
1471 | 26.1k | txBoolean sourceContentType = (sourceDispatch->value.typedArray.dispatch->constructorID == _BigInt64Array) |
1472 | 26.1k | || (sourceDispatch->value.typedArray.dispatch->constructorID == _BigUint64Array); |
1473 | 26.1k | if (contentType != sourceContentType) |
1474 | 3 | mxTypeError("incompatible content type"); |
1475 | 26.1k | } |
1476 | | |
1477 | | txSlot* fxCheckTypedArrayInstance(txMachine* the, txSlot* slot) |
1478 | 516k | { |
1479 | 516k | if (slot->kind == XS_REFERENCE_KIND) { |
1480 | 515k | txSlot* instance = slot->value.reference; |
1481 | 515k | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_TYPED_ARRAY_KIND)) |
1482 | 515k | return instance; |
1483 | 515k | } |
1484 | 516k | mxTypeError("this: not a TypedArray instance"); |
1485 | 0 | return C_NULL; |
1486 | 516k | } |
1487 | | |
1488 | | txSlot* fxConstructTypedArray(txMachine* the) |
1489 | 788k | { |
1490 | 788k | txSlot* prototype; |
1491 | 788k | txSlot* dispatch; |
1492 | 788k | txSlot* instance; |
1493 | 788k | dispatch = mxFunctionInstanceHome(mxFunction->value.reference); |
1494 | 788k | dispatch = dispatch->next; |
1495 | 788k | prototype = mxBehaviorGetProperty(the, mxFunction->value.reference, mxID(_prototype), 0, XS_ANY); |
1496 | 788k | if (!dispatch || (dispatch->kind != XS_TYPED_ARRAY_KIND)) |
1497 | 16 | mxTypeError("new: TypedArray"); |
1498 | 788k | mxPushSlot(mxTarget); |
1499 | 788k | fxGetPrototypeFromConstructor(the, prototype); |
1500 | 788k | instance = fxNewTypedArrayInstance(the, dispatch->value.typedArray.dispatch, dispatch->value.typedArray.atomics); |
1501 | 788k | mxPullSlot(mxResult); |
1502 | 788k | return instance; |
1503 | 788k | } |
1504 | | |
1505 | | void fxCreateTypedArraySpecies(txMachine* the) |
1506 | 23.6k | { |
1507 | 23.6k | txSlot* instance = fxToInstance(the, mxThis); |
1508 | 23.6k | txSlot* dispatch = instance->next; |
1509 | 23.6k | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
1510 | 23.6k | mxPushSlot(mxThis); |
1511 | 23.6k | mxGetID(mxID(_constructor)); |
1512 | 23.6k | fxToSpeciesConstructor(the, constructor); |
1513 | 23.6k | mxNew(); |
1514 | 23.6k | } |
1515 | | |
1516 | | void fxReduceTypedArrayItem(txMachine* the, txSlot* function, txSlot* dispatch, txSlot* view, txSlot* data, txInteger index) |
1517 | 1.12M | { |
1518 | | /* THIS */ |
1519 | 1.12M | mxPushUndefined(); |
1520 | | /* FUNCTION */ |
1521 | 1.12M | mxPushSlot(function); |
1522 | 1.12M | mxCall(); |
1523 | | /* ARGUMENTS */ |
1524 | 1.12M | mxPushSlot(mxResult); |
1525 | 1.12M | mxPushSlot(mxThis); |
1526 | 1.12M | mxGetIndex(index); |
1527 | 1.12M | mxPushInteger(index); |
1528 | 1.12M | mxPushSlot(mxThis); |
1529 | 1.12M | mxRunCount(4); |
1530 | 1.12M | mxPullSlot(mxResult); |
1531 | 1.12M | } |
1532 | | |
1533 | | txSlot* fxNewTypedArrayInstance(txMachine* the, txTypeDispatch* dispatch, txTypeAtomics* atomics) |
1534 | 788k | { |
1535 | 788k | txSlot* instance; |
1536 | 788k | txSlot* property; |
1537 | 788k | instance = fxNewObjectInstance(the); |
1538 | 788k | instance->flag |= XS_EXOTIC_FLAG; |
1539 | 788k | property = fxNextTypeDispatchProperty(the, instance, dispatch, atomics, XS_TYPED_ARRAY_BEHAVIOR, XS_INTERNAL_FLAG); |
1540 | 788k | property = property->next = fxNewSlot(the); |
1541 | 788k | property->flag = XS_INTERNAL_FLAG; |
1542 | 788k | property->kind = XS_DATA_VIEW_KIND; |
1543 | 788k | property->value.dataView.offset = 0; |
1544 | 788k | property->value.dataView.size = 0; |
1545 | 788k | property = fxNextNullProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
1546 | 788k | return instance; |
1547 | 788k | } |
1548 | | |
1549 | | void fx_TypedArray(txMachine* the) |
1550 | 789k | { |
1551 | 789k | if (!mxHasTarget) |
1552 | 497 | mxTypeError("call: TypedArray"); |
1553 | 788k | if (mxArgc > 0) { |
1554 | 787k | if (mxArgv(0)->kind == XS_REFERENCE_KIND) { |
1555 | 230k | txSlot* instance = fxConstructTypedArray(the); |
1556 | 230k | txSlot* dispatch = instance->next; |
1557 | 230k | txSlot* view = dispatch->next; |
1558 | 230k | txSlot* buffer = view->next; |
1559 | 230k | txSlot* data = C_NULL; |
1560 | 230k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1561 | 230k | txSlot* slot = mxArgv(0)->value.reference->next; |
1562 | 230k | if (slot && ((slot->kind == XS_ARRAY_BUFFER_KIND) || (slot->kind == XS_HOST_KIND))) { |
1563 | 30.8k | txInteger offset = fxArgToByteLength(the, 1, 0); |
1564 | 30.8k | txInteger size; |
1565 | 30.8k | txSlot* info; |
1566 | 30.8k | if (offset & ((1 << shift) - 1)) |
1567 | 1 | mxRangeError("invalid byteOffset %ld", offset); |
1568 | 30.8k | size = fxArgToByteLength(the, 2, -1); |
1569 | 30.8k | info = fxGetBufferInfo(the, mxArgv(0)); |
1570 | 30.8k | if (size >= 0) { |
1571 | 20 | txInteger delta = (size <= (INT_MAX >> shift)) ? size << shift : -1; |
1572 | 20 | txInteger end = fxAddChunkSizes(the, offset, delta); |
1573 | 20 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
1574 | 1 | mxRangeError("invalid length %ld", size); |
1575 | 19 | size = delta; |
1576 | 19 | } |
1577 | 30.8k | else if (info->value.bufferInfo.maxLength >= 0) { |
1578 | 2.11k | if (info->value.bufferInfo.length < offset) |
1579 | 1 | mxRangeError("invalid offset %ld", offset); |
1580 | 2.11k | size = -1; |
1581 | 2.11k | } |
1582 | 28.6k | else { |
1583 | 28.6k | if (info->value.bufferInfo.length & ((1 << shift) - 1)) |
1584 | 2.60k | mxRangeError("invalid byteLength %ld", info->value.bufferInfo.length); |
1585 | 26.0k | size = info->value.bufferInfo.length - offset; |
1586 | 26.0k | if (size < 0) |
1587 | 1 | mxRangeError("invalid byteLength %ld", size); |
1588 | 26.0k | } |
1589 | 28.2k | view->value.dataView.offset = offset; |
1590 | 28.2k | view->value.dataView.size = size; |
1591 | 28.2k | buffer->kind = XS_REFERENCE_KIND; |
1592 | 28.2k | buffer->value.reference = mxArgv(0)->value.reference; |
1593 | 28.2k | } |
1594 | 199k | else if (slot && (slot->kind == XS_TYPED_ARRAY_KIND)) { |
1595 | 2.51k | txSlot* sourceDispatch = slot; |
1596 | 2.51k | txSlot* sourceView = sourceDispatch->next; |
1597 | 2.51k | txSlot* sourceBuffer = sourceView->next; |
1598 | 2.51k | txU2 sourceShift = sourceDispatch->value.typedArray.dispatch->shift; |
1599 | 2.51k | txInteger sourceLength = fxCheckDataViewSize(the, sourceView, sourceBuffer, XS_IMMUTABLE) >> sourceShift; |
1600 | 2.51k | txSlot* sourceData = sourceBuffer->value.reference->next; |
1601 | 2.51k | txInteger sourceDelta = sourceDispatch->value.typedArray.dispatch->size; |
1602 | 2.51k | txInteger sourceOffset = sourceView->value.dataView.offset; |
1603 | 2.51k | txInteger offset = 0; |
1604 | 2.51k | if (sourceLength > (INT_MAX >> shift)) |
1605 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
1606 | 2.51k | txInteger size = sourceLength << shift; |
1607 | | /* TARGET */ |
1608 | 2.51k | mxPush(mxArrayBufferConstructor); |
1609 | | /* THIS */ |
1610 | 2.51k | mxPushUninitialized(); |
1611 | | /* FUNCTION */ |
1612 | 2.51k | mxPush(mxArrayBufferConstructor); |
1613 | | /* RESULT */ |
1614 | 2.51k | mxPushUndefined(); |
1615 | | /* FRAME */ |
1616 | 2.51k | mxPushUninitialized(); |
1617 | 2.51k | the->stack->flag |= XS_TARGET_FLAG; |
1618 | | /* ARGUMENTS */ |
1619 | 2.51k | sourceLength = fxGetDataViewSize(the, sourceView, sourceBuffer) >> sourceShift; |
1620 | 2.51k | size = sourceLength << shift; |
1621 | 2.51k | mxPushInteger(size); |
1622 | 2.51k | mxRunCount(1); |
1623 | 2.51k | mxPullSlot(buffer); |
1624 | 2.51k | sourceLength = fxCheckDataViewSize(the, sourceView, sourceBuffer, XS_IMMUTABLE) >> sourceShift; |
1625 | 2.51k | size = sourceLength << shift; |
1626 | | |
1627 | 2.51k | data = fxCheckArrayBufferDetached(the, buffer); |
1628 | 2.51k | fxCheckArrayBufferMutable(the, buffer); |
1629 | 2.51k | view->value.dataView.offset = offset; |
1630 | 2.51k | view->value.dataView.size = size; |
1631 | 2.51k | if (dispatch == sourceDispatch) |
1632 | 0 | c_memcpy(data->value.arrayBuffer.address + offset, sourceData->value.arrayBuffer.address + sourceOffset, size); |
1633 | 2.51k | else { |
1634 | 2.51k | fxCheckTypedArrayContentType(the, dispatch, sourceDispatch); |
1635 | 2.51k | mxPushUndefined(); |
1636 | 10.2k | while (offset < size) { |
1637 | 7.71k | (*sourceDispatch->value.typedArray.dispatch->getter)(the, sourceData, sourceOffset, the->stack, EndianNative); |
1638 | 7.71k | (*dispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
1639 | 7.71k | (*dispatch->value.typedArray.dispatch->setter)(the, data, offset, the->stack, EndianNative); |
1640 | 7.71k | sourceOffset += sourceDelta; |
1641 | 7.71k | offset += 1 << shift; |
1642 | 7.71k | } |
1643 | 2.51k | mxPop(); |
1644 | 2.51k | } |
1645 | 2.51k | } |
1646 | 197k | else { |
1647 | 197k | fx_TypedArray_from_object(the, instance, C_NULL, C_NULL); |
1648 | 197k | } |
1649 | 227k | return; |
1650 | 230k | } |
1651 | 556k | fxToNumber(the, mxArgv(0)); |
1652 | 556k | } |
1653 | 558k | { |
1654 | 558k | txInteger length = fxArgToByteLength(the, 0, 0); |
1655 | 558k | txSlot* instance = fxConstructTypedArray(the); |
1656 | 558k | txSlot* dispatch = instance->next; |
1657 | 558k | txSlot* view = dispatch->next; |
1658 | 558k | txSlot* buffer = view->next; |
1659 | 558k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1660 | 558k | if (length > (0x7FFFFFFF >> shift)) |
1661 | 1 | mxRangeError("byteLength too big"); |
1662 | 558k | length <<= shift; |
1663 | 558k | mxPush(mxArrayBufferConstructor); |
1664 | 558k | mxNew(); |
1665 | 558k | mxPushInteger(length); |
1666 | 558k | mxRunCount(1); |
1667 | 558k | mxPullSlot(buffer); |
1668 | 558k | view->value.dataView.offset = 0; |
1669 | 558k | view->value.dataView.size = length; |
1670 | 558k | } |
1671 | 558k | } |
1672 | | |
1673 | | void fx_TypedArray_from(txMachine* the) |
1674 | 33 | { |
1675 | 33 | txSlot* function = C_NULL; |
1676 | 33 | txSlot* _this = C_NULL; |
1677 | 33 | if (!mxIsReference(mxThis) || !(mxIsConstructor(mxThis->value.reference))) |
1678 | 2 | mxTypeError("this: not a constructor"); |
1679 | 31 | if (mxArgc > 1) { |
1680 | 19 | txSlot* slot = mxArgv(1); |
1681 | 19 | if (!mxIsUndefined(slot)) { |
1682 | 18 | function = slot; |
1683 | 18 | if (!fxIsCallable(the, function)) |
1684 | 11 | mxTypeError("map: not a function"); |
1685 | 7 | if (mxArgc > 2) |
1686 | 0 | _this = mxArgv(2); |
1687 | 7 | } |
1688 | 19 | } |
1689 | 20 | fx_TypedArray_from_object(the, C_NULL, function, _this); |
1690 | 20 | } |
1691 | | |
1692 | | void fx_TypedArray_from_object(txMachine* the, txSlot* instance, txSlot* function, txSlot* _this) |
1693 | 197k | { |
1694 | 197k | txSlot* stack = the->stack; |
1695 | 197k | txSlot* iterator; |
1696 | 197k | txSlot* next; |
1697 | 197k | txSlot* value; |
1698 | 197k | txSlot* list = C_NULL; |
1699 | 197k | txSlot* slot; |
1700 | 197k | txSlot* dispatch; |
1701 | 197k | txSlot* view; |
1702 | 197k | txSlot* buffer; |
1703 | 197k | txSlot* data; |
1704 | 197k | txNumber length; |
1705 | 197k | mxTemporary(iterator); |
1706 | 197k | mxTemporary(next); |
1707 | 197k | if (fxGetIterator(the, mxArgv(0), iterator, next, 1)) { |
1708 | 168k | list = fxNewInstance(the); |
1709 | 168k | slot = list; |
1710 | 168k | length = 0; |
1711 | 168k | mxTemporary(value); |
1712 | 520k | while (fxIteratorNext(the, iterator, next, value)) { |
1713 | 352k | slot = fxNextSlotProperty(the, slot, value, XS_NO_ID, XS_NO_FLAG); |
1714 | 352k | length++; |
1715 | 352k | } |
1716 | 168k | } |
1717 | 29.0k | else { |
1718 | 29.0k | mxPushSlot(mxArgv(0)); |
1719 | 29.0k | mxGetID(mxID(_length)); |
1720 | 29.0k | length = fxToLength(the, the->stack); |
1721 | 29.0k | mxPop(); |
1722 | 29.0k | } |
1723 | 197k | if (instance) { |
1724 | 197k | dispatch = instance->next; |
1725 | 197k | view = dispatch->next; |
1726 | 197k | buffer = view->next; |
1727 | 197k | mxPush(mxArrayBufferConstructor); |
1728 | 197k | mxNew(); |
1729 | 197k | mxPushNumber(length * dispatch->value.typedArray.dispatch->size); |
1730 | 197k | mxRunCount(1); |
1731 | 197k | mxPullSlot(buffer); |
1732 | 197k | data = fxCheckArrayBufferDetached(the, buffer); |
1733 | 197k | fxCheckArrayBufferMutable(the, buffer); |
1734 | 197k | view->value.dataView.offset = 0; |
1735 | 197k | view->value.dataView.size = data->next->value.bufferInfo.length; |
1736 | 197k | } |
1737 | 20 | else { |
1738 | 20 | mxPushSlot(mxThis); |
1739 | 20 | mxNew(); |
1740 | 20 | mxPushNumber(length); |
1741 | 20 | mxRunCount(1); |
1742 | 20 | mxPullSlot(mxResult); |
1743 | 20 | instance = fxToInstance(the, mxResult); |
1744 | 20 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_TYPED_ARRAY_KIND)) { |
1745 | 14 | dispatch = instance->next; |
1746 | 14 | view = dispatch->next; |
1747 | 14 | buffer = view->next; |
1748 | 14 | data = fxCheckArrayBufferDetached(the, buffer); |
1749 | 14 | fxCheckArrayBufferMutable(the, buffer); |
1750 | 14 | if (length > (fxGetDataViewSize(the, view, buffer) >> dispatch->value.typedArray.dispatch->shift)) |
1751 | 0 | mxTypeError("result: too small TypedArray instance"); |
1752 | 14 | } |
1753 | 6 | else |
1754 | 6 | mxTypeError("result: not a TypedArray instance"); |
1755 | 20 | } |
1756 | 197k | if (list) { |
1757 | 168k | txInteger index = 0; |
1758 | 168k | slot = list->next; |
1759 | 520k | while (slot) { |
1760 | | /* ARG0 */ |
1761 | 352k | if (function) { |
1762 | | /* THIS */ |
1763 | 12 | if (_this) |
1764 | 0 | mxPushSlot(_this); |
1765 | 12 | else |
1766 | 12 | mxPushUndefined(); |
1767 | | /* FUNCTION */ |
1768 | 12 | mxPushSlot(function); |
1769 | 12 | mxCall(); |
1770 | | /* ARGUMENTS */ |
1771 | 12 | mxPushSlot(slot); |
1772 | 12 | mxPushInteger(index); |
1773 | 12 | mxRunCount(2); |
1774 | 12 | } |
1775 | 352k | else |
1776 | 352k | mxPushSlot(slot); |
1777 | 352k | mxPushSlot(mxResult); |
1778 | 352k | mxSetIndex(index); |
1779 | 352k | mxPop(); |
1780 | 352k | index++; |
1781 | 352k | slot = slot->next; |
1782 | 352k | } |
1783 | 168k | } |
1784 | 29.0k | else { |
1785 | 29.0k | txInteger index = 0; |
1786 | 29.0k | txInteger count = (txInteger)length; |
1787 | 108k | while (index < count) { |
1788 | 79.6k | if (function) { |
1789 | | /* THIS */ |
1790 | 0 | if (_this) |
1791 | 0 | mxPushSlot(_this); |
1792 | 0 | else |
1793 | 0 | mxPushUndefined(); |
1794 | | /* FUNCTION */ |
1795 | 0 | mxPushSlot(function); |
1796 | 0 | mxCall(); |
1797 | | /* ARGUMENTS */ |
1798 | 0 | mxPushSlot(mxArgv(0)); |
1799 | 0 | mxGetIndex(index); |
1800 | 0 | mxPushInteger(index); |
1801 | 0 | mxRunCount(2); |
1802 | 0 | } |
1803 | 79.6k | else { |
1804 | 79.6k | mxPushSlot(mxArgv(0)); |
1805 | 79.6k | mxGetIndex(index); |
1806 | 79.6k | } |
1807 | 79.6k | mxPushSlot(mxResult); |
1808 | 79.6k | mxSetIndex(index); |
1809 | 79.6k | mxPop(); |
1810 | 79.6k | index++; |
1811 | 79.6k | } |
1812 | 29.0k | } |
1813 | 197k | the->stack = stack; |
1814 | 197k | } |
1815 | | |
1816 | | void fx_TypedArray_of(txMachine* the) |
1817 | 6 | { |
1818 | 6 | txInteger count = mxArgc; |
1819 | 6 | txInteger index = 0; |
1820 | 6 | mxPushSlot(mxThis); |
1821 | 6 | mxNew(); |
1822 | 6 | mxPushInteger(count); |
1823 | 6 | mxRunCount(1); |
1824 | 6 | mxPullSlot(mxResult); |
1825 | 6 | { |
1826 | 6 | mxResultTypedArrayDeclarations; |
1827 | 6 | txU2 shift = resultDispatch->value.typedArray.dispatch->shift; |
1828 | 6 | if (resultLength < count) |
1829 | 1 | mxTypeError("result: too small TypedArray instance"); |
1830 | 12 | while (index < count) { |
1831 | 7 | (*resultDispatch->value.typedArray.dispatch->coerce)(the, mxArgv(index)); |
1832 | 7 | if (resultBuffer->value.arrayBuffer.address == C_NULL) |
1833 | 0 | mxTypeError("detached buffer"); |
1834 | 7 | (*resultDispatch->value.typedArray.dispatch->setter)(the, resultBuffer->value.reference->next, resultView->value.dataView.offset + (index << shift), mxArgv(index), EndianNative); |
1835 | 7 | index++; |
1836 | 7 | } |
1837 | 5 | } |
1838 | 5 | } |
1839 | | |
1840 | | void fx_TypedArray_prototype_at(txMachine* the) |
1841 | 3 | { |
1842 | 3 | mxTypedArrayDeclarations; |
1843 | 3 | txInteger index = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
1844 | 3 | if (index < 0) |
1845 | 0 | index = length + index; |
1846 | 3 | if ((0 <= index) && (index < length)) { |
1847 | 0 | mxPushSlot(mxThis); |
1848 | 0 | mxGetIndex(index); |
1849 | 0 | mxPullSlot(mxResult); |
1850 | 0 | } |
1851 | 3 | } |
1852 | | |
1853 | | void fx_TypedArray_prototype_buffer_get(txMachine* the) |
1854 | 54 | { |
1855 | 54 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1856 | 54 | txSlot* dispatch = instance->next; |
1857 | 54 | txSlot* view = dispatch->next; |
1858 | 54 | txSlot* buffer = view->next; |
1859 | 54 | mxResult->kind = buffer->kind; |
1860 | 54 | mxResult->value = buffer->value; |
1861 | 54 | } |
1862 | | |
1863 | | void fx_TypedArray_prototype_byteLength_get(txMachine* the) |
1864 | 44 | { |
1865 | 44 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1866 | 44 | txSlot* dispatch = instance->next; |
1867 | 44 | txSlot* view = dispatch->next; |
1868 | 44 | txSlot* buffer = view->next; |
1869 | 44 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1870 | 44 | mxResult->kind = XS_INTEGER_KIND; |
1871 | 44 | mxResult->value.integer = fxGetDataViewSize(the, view, buffer) & ~((1 << shift) - 1); |
1872 | 44 | } |
1873 | | |
1874 | | void fx_TypedArray_prototype_byteOffset_get(txMachine* the) |
1875 | 48 | { |
1876 | 48 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1877 | 48 | txSlot* dispatch = instance->next; |
1878 | 48 | txSlot* view = dispatch->next; |
1879 | 48 | txSlot* buffer = view->next; |
1880 | 48 | txInteger offset = view->value.dataView.offset; |
1881 | 48 | txInteger size = view->value.dataView.size; |
1882 | 48 | txSlot* arrayBuffer = buffer->value.reference->next; |
1883 | 48 | txSlot* bufferInfo = arrayBuffer->next; |
1884 | 48 | mxResult->kind = XS_INTEGER_KIND; |
1885 | 48 | mxResult->value.integer = 0; |
1886 | 48 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
1887 | 0 | return; |
1888 | 48 | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
1889 | 15 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
1890 | 15 | if (offset > byteLength) |
1891 | 1 | return; |
1892 | 14 | size = (size < 0) ? byteLength : offset + size; |
1893 | 14 | if (size > byteLength) |
1894 | 0 | return; |
1895 | 14 | size -= offset; |
1896 | 14 | } |
1897 | 47 | mxResult->value.integer = offset; |
1898 | 47 | } |
1899 | | |
1900 | | void fx_TypedArray_prototype_copyWithin(txMachine* the) |
1901 | 20 | { |
1902 | 20 | mxMutableTypedArrayDeclarations; |
1903 | 20 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
1904 | 20 | txInteger target = fxArgToIndexInteger(the, 0, 0, length); |
1905 | 20 | txInteger start = fxArgToIndexInteger(the, 1, 0, length); |
1906 | 20 | txInteger end = fxArgToIndexInteger(the, 2, length, length); |
1907 | 20 | txInteger count = end - start; |
1908 | 20 | if (count > length - target) |
1909 | 0 | count = length - target; |
1910 | 20 | if (count > 0) { |
1911 | 0 | txByte* address = buffer->value.reference->next->value.arrayBuffer.address; |
1912 | 0 | txInteger offset = view->value.dataView.offset; |
1913 | 0 | if (fxIsDataViewOutOfBound(the, view, buffer)) |
1914 | 0 | mxTypeError("out of bound buffer"); |
1915 | 0 | txInteger size = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) & ~(delta - 1); |
1916 | 0 | target = offset + (target * delta); |
1917 | 0 | start = offset + (start * delta); |
1918 | 0 | end = offset + size; |
1919 | 0 | count = count * delta; |
1920 | 0 | if (count > end - target) |
1921 | 0 | count = end - target; |
1922 | 0 | if (count > end - start) |
1923 | 0 | count = end - start; |
1924 | 0 | if (count > 0) { |
1925 | 0 | c_memmove(address + target, address + start, count); |
1926 | 0 | mxMeterSome((txU4)count * 2); |
1927 | 0 | } |
1928 | 0 | } |
1929 | 20 | mxResult->kind = mxThis->kind; |
1930 | 20 | mxResult->value = mxThis->value; |
1931 | 20 | } |
1932 | | |
1933 | | void fx_TypedArray_prototype_entries(txMachine* the) |
1934 | 32 | { |
1935 | 32 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1936 | 32 | txSlot* dispatch = instance->next; |
1937 | 32 | txSlot* view = dispatch->next; |
1938 | 32 | txSlot* buffer = view->next; |
1939 | 32 | txSlot* property; |
1940 | 32 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1941 | 32 | mxPush(mxArrayIteratorPrototype); |
1942 | 32 | property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array))); |
1943 | 32 | property = fxNextIntegerProperty(the, property, 2, XS_NO_ID, XS_INTERNAL_FLAG); |
1944 | 32 | mxPullSlot(mxResult); |
1945 | 32 | } |
1946 | | |
1947 | | void fx_TypedArray_prototype_every(txMachine* the) |
1948 | 20 | { |
1949 | 20 | mxTypedArrayDeclarations; |
1950 | 20 | txSlot* function = fxArgToCallback(the, 0); |
1951 | 20 | txInteger index = 0; |
1952 | 20 | mxResult->kind = XS_BOOLEAN_KIND; |
1953 | 20 | mxResult->value.boolean = 1; |
1954 | 23 | while (index < length) { |
1955 | 3 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
1956 | 3 | mxResult->value.boolean = fxToBoolean(the, the->stack++); |
1957 | 3 | if (!mxResult->value.boolean) |
1958 | 0 | break; |
1959 | 3 | index++; |
1960 | 3 | } |
1961 | 20 | } |
1962 | | |
1963 | | void fx_TypedArray_prototype_fill(txMachine* the) |
1964 | 545 | { |
1965 | 545 | mxMutableTypedArrayDeclarations; |
1966 | 545 | txInteger delta, start, end, offset; |
1967 | 545 | if (mxArgc > 0) |
1968 | 132 | mxPushSlot(mxArgv(0)); |
1969 | 413 | else |
1970 | 413 | mxPushUndefined(); |
1971 | 545 | (*dispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
1972 | 545 | delta = dispatch->value.typedArray.dispatch->size; |
1973 | 545 | start = fxArgToIndexInteger(the, 1, 0, length); |
1974 | 545 | end = fxArgToIndexInteger(the, 2, length, length); |
1975 | 545 | offset = view->value.dataView.offset; |
1976 | 545 | start *= delta; |
1977 | 545 | end *= delta; |
1978 | 545 | start += offset; |
1979 | 545 | end += offset; |
1980 | 545 | txInteger size = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) & ~(delta - 1); |
1981 | 545 | if (end > offset + size) |
1982 | 0 | end = offset + size; |
1983 | 1.91k | while (start < end) { |
1984 | 1.36k | (*dispatch->value.typedArray.dispatch->setter)(the, buffer->value.reference->next, start, the->stack, EndianNative); |
1985 | 1.36k | start += delta; |
1986 | 1.36k | } |
1987 | 545 | mxPop(); |
1988 | 545 | mxResult->kind = mxThis->kind; |
1989 | 545 | mxResult->value = mxThis->value; |
1990 | 545 | } |
1991 | | |
1992 | | void fx_TypedArray_prototype_filter(txMachine* the) |
1993 | 20 | { |
1994 | 20 | mxTypedArrayDeclarations; |
1995 | 20 | txSlot* function = fxArgToCallback(the, 0); |
1996 | 20 | txSlot* list = fxNewInstance(the); |
1997 | 20 | txSlot* slot = list; |
1998 | 20 | txInteger count = 0; |
1999 | 20 | txInteger index = 0; |
2000 | 20 | mxPushUndefined(); |
2001 | 20 | while (index < length) { |
2002 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, the->stack); |
2003 | 0 | if (fxToBoolean(the, the->stack++)) { |
2004 | 0 | count++; |
2005 | 0 | slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG); |
2006 | 0 | } |
2007 | 0 | index++; |
2008 | 0 | } |
2009 | 20 | mxPop(); |
2010 | 20 | fxCreateTypedArraySpecies(the); |
2011 | 20 | mxPushNumber(count); |
2012 | 20 | mxRunCount(1); |
2013 | 20 | mxPullSlot(mxResult); |
2014 | 20 | { |
2015 | 20 | mxResultTypedArrayDeclarations; |
2016 | 20 | txInteger resultOffset = 0; |
2017 | 20 | txInteger resultSize = resultDispatch->value.typedArray.dispatch->size; |
2018 | 20 | fxCheckTypedArrayContentType(the, resultDispatch, dispatch); |
2019 | 20 | if (resultLength < count) |
2020 | 0 | mxTypeError("result: too small TypedArray instance"); |
2021 | 20 | slot = list->next; |
2022 | 20 | while (slot) { |
2023 | 0 | (*resultDispatch->value.typedArray.dispatch->coerce)(the, slot); |
2024 | 0 | (*resultDispatch->value.typedArray.dispatch->setter)(the, resultBuffer->value.reference->next, resultOffset, slot, EndianNative); |
2025 | 0 | resultOffset += resultSize; |
2026 | 0 | slot = slot->next; |
2027 | 0 | } |
2028 | 20 | } |
2029 | 20 | mxPop(); |
2030 | 20 | } |
2031 | | |
2032 | | void fx_TypedArray_prototype_find(txMachine* the) |
2033 | 23 | { |
2034 | 23 | mxTypedArrayDeclarations; |
2035 | 23 | txSlot* function = fxArgToCallback(the, 0); |
2036 | 23 | txInteger index = 0; |
2037 | 23 | mxPushUndefined(); |
2038 | 23 | while (index < length) { |
2039 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, the->stack); |
2040 | 0 | if (fxToBoolean(the, the->stack++)) { |
2041 | 0 | mxResult->kind = the->stack->kind; |
2042 | 0 | mxResult->value = the->stack->value; |
2043 | 0 | break; |
2044 | 0 | } |
2045 | 0 | index++; |
2046 | 0 | } |
2047 | 23 | mxPop(); |
2048 | 23 | } |
2049 | | |
2050 | | void fx_TypedArray_prototype_findIndex(txMachine* the) |
2051 | 32 | { |
2052 | 32 | mxTypedArrayDeclarations; |
2053 | 32 | txSlot* function = fxArgToCallback(the, 0); |
2054 | 32 | txInteger index = 0; |
2055 | 32 | mxResult->kind = XS_INTEGER_KIND; |
2056 | 32 | mxResult->value.integer = -1; |
2057 | 32 | while (index < length) { |
2058 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
2059 | 0 | if (fxToBoolean(the, the->stack++)) { |
2060 | 0 | mxResult->value.integer = index; |
2061 | 0 | break; |
2062 | 0 | } |
2063 | 0 | index++; |
2064 | 0 | } |
2065 | 32 | } |
2066 | | |
2067 | | void fx_TypedArray_prototype_findLast(txMachine* the) |
2068 | 11 | { |
2069 | 11 | mxTypedArrayDeclarations; |
2070 | 11 | txSlot* function = fxArgToCallback(the, 0); |
2071 | 11 | txInteger index = length; |
2072 | 11 | mxPushUndefined(); |
2073 | 11 | while (index > 0) { |
2074 | 0 | index--; |
2075 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, the->stack); |
2076 | 0 | if (fxToBoolean(the, the->stack++)) { |
2077 | 0 | mxResult->kind = the->stack->kind; |
2078 | 0 | mxResult->value = the->stack->value; |
2079 | 0 | break; |
2080 | 0 | } |
2081 | 0 | } |
2082 | 11 | mxPop(); |
2083 | 11 | } |
2084 | | |
2085 | | void fx_TypedArray_prototype_findLastIndex(txMachine* the) |
2086 | 32 | { |
2087 | 32 | mxTypedArrayDeclarations; |
2088 | 32 | txSlot* function = fxArgToCallback(the, 0); |
2089 | 32 | txInteger index = length; |
2090 | 32 | mxResult->kind = XS_INTEGER_KIND; |
2091 | 32 | mxResult->value.integer = -1; |
2092 | 32 | while (index > 0) { |
2093 | 0 | index--; |
2094 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
2095 | 0 | if (fxToBoolean(the, the->stack++)) { |
2096 | 0 | mxResult->value.integer = index; |
2097 | 0 | break; |
2098 | 0 | } |
2099 | 0 | } |
2100 | 32 | } |
2101 | | |
2102 | | void fx_TypedArray_prototype_forEach(txMachine* the) |
2103 | 24 | { |
2104 | 24 | mxTypedArrayDeclarations; |
2105 | 24 | txSlot* function = fxArgToCallback(the, 0); |
2106 | 24 | txInteger index = 0; |
2107 | 24 | while (index < length) { |
2108 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
2109 | 0 | mxPop(); |
2110 | 0 | index++; |
2111 | 0 | } |
2112 | 24 | } |
2113 | | |
2114 | | void fx_TypedArray_prototype_includes(txMachine* the) |
2115 | 3.68k | { |
2116 | 3.68k | mxTypedArrayDeclarations; |
2117 | 3.68k | fxBoolean(the, mxResult, 0); |
2118 | 3.68k | if (length) { |
2119 | 3.64k | txInteger index = fxArgToIndexInteger(the, 1, 0, length); |
2120 | 3.64k | txSlot* argument; |
2121 | 3.64k | if (mxArgc > 0) |
2122 | 8 | mxPushSlot(mxArgv(0)); |
2123 | 3.63k | else |
2124 | 3.63k | mxPushUndefined(); |
2125 | 3.64k | argument = the->stack; |
2126 | 3.65k | while (index < length) { |
2127 | 13 | mxPushSlot(mxThis); |
2128 | 13 | mxGetIndex(index); |
2129 | 13 | if (fxIsSameValue(the, the->stack++, argument, 1)) { |
2130 | 0 | mxResult->value.boolean = 1; |
2131 | 0 | break; |
2132 | 0 | } |
2133 | 13 | index++; |
2134 | 13 | mxCheckMetering(); |
2135 | 13 | } |
2136 | 3.64k | mxPop(); |
2137 | 3.64k | } |
2138 | 3.68k | } |
2139 | | |
2140 | | void fx_TypedArray_prototype_indexOf(txMachine* the) |
2141 | 29 | { |
2142 | 29 | mxTypedArrayDeclarations; |
2143 | 29 | fxInteger(the, mxResult, -1); |
2144 | 29 | if (length) { |
2145 | 0 | txInteger index = fxArgToIndexInteger(the, 1, 0, length); |
2146 | 0 | txSlot* argument; |
2147 | 0 | if (mxArgc > 0) |
2148 | 0 | mxPushSlot(mxArgv(0)); |
2149 | 0 | else |
2150 | 0 | mxPushUndefined(); |
2151 | 0 | argument = the->stack; |
2152 | 0 | while (index < length) { |
2153 | 0 | mxPushSlot(mxThis); |
2154 | 0 | if (fxHasIndex(the, index)) { |
2155 | 0 | mxPushSlot(mxThis); |
2156 | 0 | mxGetIndex(index); |
2157 | 0 | if (fxIsSameSlot(the, the->stack++, argument)) { |
2158 | 0 | mxResult->value.integer = index; |
2159 | 0 | break; |
2160 | 0 | } |
2161 | 0 | } |
2162 | 0 | index++; |
2163 | 0 | mxCheckMetering(); |
2164 | 0 | } |
2165 | 0 | mxPop(); |
2166 | 0 | } |
2167 | 29 | } |
2168 | | |
2169 | | void fx_TypedArray_prototype_join(txMachine* the) |
2170 | 30.7k | { |
2171 | 30.7k | mxTypedArrayDeclarations; |
2172 | 30.7k | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2173 | 30.7k | txInteger offset = view->value.dataView.offset; |
2174 | 30.7k | txInteger limit = offset + (length << dispatch->value.typedArray.dispatch->shift); |
2175 | 30.7k | txString string; |
2176 | 30.7k | txSlot* list = fxNewInstance(the); |
2177 | 30.7k | txSlot* slot = list; |
2178 | 30.7k | txBoolean comma = 0; |
2179 | 30.7k | txInteger size = 0; |
2180 | 30.7k | if ((mxArgc > 0) && (mxArgv(0)->kind != XS_UNDEFINED_KIND)) { |
2181 | 4 | mxPushSlot(mxArgv(0)); |
2182 | 4 | string = fxToString(the, the->stack); |
2183 | 4 | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2184 | 4 | the->stack->value.key.sum = mxStringLength(the->stack->value.string); |
2185 | 4 | } |
2186 | 30.7k | else { |
2187 | 30.7k | mxPushStringX(","); |
2188 | 30.7k | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2189 | 30.7k | the->stack->value.key.sum = 1; |
2190 | 30.7k | } |
2191 | 30.7k | length = offset + fxGetDataViewSize(the, view, buffer); |
2192 | 2.58M | while (offset < limit) { |
2193 | 2.55M | if (comma) { |
2194 | 2.52M | slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG); |
2195 | 2.52M | size = fxAddChunkSizes(the, size, slot->value.key.sum); |
2196 | 2.52M | } |
2197 | 28.2k | else |
2198 | 28.2k | comma = 1; |
2199 | 2.55M | if (offset < length) { |
2200 | 2.55M | mxPushUndefined(); |
2201 | 2.55M | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, offset, the->stack, EndianNative); |
2202 | 2.55M | slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG); |
2203 | 2.55M | string = fxToString(the, slot); |
2204 | 2.55M | slot->kind += XS_KEY_KIND - XS_STRING_KIND; |
2205 | 2.55M | slot->value.key.sum = mxStringLength(string); |
2206 | 2.55M | size = fxAddChunkSizes(the, size, slot->value.key.sum); |
2207 | 2.55M | mxPop(); |
2208 | 2.55M | } |
2209 | 2.55M | offset += delta; |
2210 | 2.55M | } |
2211 | 30.7k | mxPop(); |
2212 | 30.7k | string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1)); |
2213 | 30.7k | slot = list->next; |
2214 | 5.11M | while (slot) { |
2215 | 5.08M | c_memcpy(string, slot->value.key.string, slot->value.key.sum); |
2216 | 5.08M | string += slot->value.key.sum; |
2217 | 5.08M | slot = slot->next; |
2218 | 5.08M | } |
2219 | 30.7k | *string = 0; |
2220 | 30.7k | mxResult->kind = XS_STRING_KIND; |
2221 | 30.7k | mxPop(); |
2222 | 30.7k | } |
2223 | | |
2224 | | void fx_TypedArray_prototype_keys(txMachine* the) |
2225 | 22 | { |
2226 | 22 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2227 | 22 | txSlot* dispatch = instance->next; |
2228 | 22 | txSlot* view = dispatch->next; |
2229 | 22 | txSlot* buffer = view->next; |
2230 | 22 | txSlot* property; |
2231 | 22 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
2232 | 22 | mxPush(mxArrayIteratorPrototype); |
2233 | 22 | property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array))); |
2234 | 22 | property = fxNextIntegerProperty(the, property, 1, XS_NO_ID, XS_INTERNAL_FLAG); |
2235 | 22 | mxPullSlot(mxResult); |
2236 | 22 | } |
2237 | | |
2238 | | void fx_TypedArray_prototype_lastIndexOf(txMachine* the) |
2239 | 26 | { |
2240 | 26 | mxTypedArrayDeclarations; |
2241 | 26 | fxInteger(the, mxResult, -1); |
2242 | 26 | if (length) { |
2243 | 0 | txIndex index = (txIndex)fxArgToLastIndex(the, 1, length, length); |
2244 | 0 | txSlot* argument; |
2245 | 0 | if (mxArgc > 0) |
2246 | 0 | mxPushSlot(mxArgv(0)); |
2247 | 0 | else |
2248 | 0 | mxPushUndefined(); |
2249 | 0 | argument = the->stack; |
2250 | 0 | while (index > 0) { |
2251 | 0 | index--; |
2252 | 0 | mxPushSlot(mxThis); |
2253 | 0 | if (fxHasIndex(the, index)) { |
2254 | 0 | mxPushSlot(mxThis); |
2255 | 0 | mxGetIndex(index); |
2256 | 0 | if (fxIsSameSlot(the, the->stack++, argument)) { |
2257 | 0 | mxResult->value.integer = index; |
2258 | 0 | break; |
2259 | 0 | } |
2260 | 0 | } |
2261 | 0 | mxCheckMetering(); |
2262 | 0 | } |
2263 | 0 | mxPop(); |
2264 | 0 | } |
2265 | 26 | } |
2266 | | |
2267 | | void fx_TypedArray_prototype_length_get(txMachine* the) |
2268 | 6.72k | { |
2269 | 6.72k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2270 | 6.72k | txSlot* dispatch = instance->next; |
2271 | 6.72k | txSlot* view = dispatch->next; |
2272 | 6.72k | txSlot* buffer = view->next; |
2273 | 6.72k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
2274 | 6.72k | mxResult->kind = XS_INTEGER_KIND; |
2275 | 6.72k | mxResult->value.integer = fxGetDataViewSize(the, view, buffer) >> shift; |
2276 | 6.72k | } |
2277 | | |
2278 | | void fx_TypedArray_prototype_map(txMachine* the) |
2279 | 25 | { |
2280 | 25 | mxTypedArrayDeclarations; |
2281 | 25 | txSlot* function = fxArgToCallback(the, 0); |
2282 | 25 | fxCreateTypedArraySpecies(the); |
2283 | 25 | mxPushNumber(length); |
2284 | 25 | mxRunCount(1); |
2285 | 25 | mxPullSlot(mxResult); |
2286 | 25 | { |
2287 | 25 | mxResultTypedArrayDeclarations; |
2288 | 25 | txU2 shift = resultDispatch->value.typedArray.dispatch->shift; |
2289 | 25 | txInteger index = 0; |
2290 | 25 | fxCheckTypedArrayContentType(the, resultDispatch, dispatch); |
2291 | 25 | if (resultLength < length) |
2292 | 0 | mxTypeError("result: too small TypedArray instance"); |
2293 | 25 | while (index < length) { |
2294 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
2295 | 0 | if (resultBuffer->value.arrayBuffer.address == C_NULL) |
2296 | 0 | mxTypeError("detached buffer"); |
2297 | 0 | (*resultDispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
2298 | 0 | (*resultDispatch->value.typedArray.dispatch->setter)(the, resultBuffer->value.reference->next, resultView->value.dataView.offset + (index << shift), the->stack, EndianNative); |
2299 | 0 | mxPop(); |
2300 | 0 | index++; |
2301 | 0 | } |
2302 | 25 | } |
2303 | 25 | } |
2304 | | |
2305 | | void fx_TypedArray_prototype_reduce(txMachine* the) |
2306 | 6.42k | { |
2307 | 6.42k | mxTypedArrayDeclarations; |
2308 | 6.42k | txSlot* function = fxArgToCallback(the, 0); |
2309 | 6.42k | txInteger index = 0; |
2310 | 6.42k | if (mxArgc > 1) |
2311 | 1 | *mxResult = *mxArgv(1); |
2312 | 6.42k | else if (index < length) { |
2313 | 6.39k | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset, mxResult, EndianNative); |
2314 | 6.39k | index++; |
2315 | 6.39k | } |
2316 | 25 | else |
2317 | 25 | mxTypeError("no initial value"); |
2318 | 1.13M | while (index < length) { |
2319 | 1.12M | fxReduceTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index); |
2320 | 1.12M | index++; |
2321 | 1.12M | } |
2322 | 6.39k | } |
2323 | | |
2324 | | void fx_TypedArray_prototype_reduceRight(txMachine* the) |
2325 | 28 | { |
2326 | 28 | mxTypedArrayDeclarations; |
2327 | 28 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2328 | 28 | txSlot* function = fxArgToCallback(the, 0); |
2329 | 28 | txInteger index = length - 1; |
2330 | 28 | if (mxArgc > 1) |
2331 | 0 | *mxResult = *mxArgv(1); |
2332 | 28 | else if (index >= 0) { |
2333 | 0 | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index * delta), mxResult, EndianNative); |
2334 | 0 | index--; |
2335 | 0 | } |
2336 | 28 | else |
2337 | 28 | mxTypeError("no initial value"); |
2338 | 0 | while (index >= 0) { |
2339 | 0 | fxReduceTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index); |
2340 | 0 | index--; |
2341 | 0 | } |
2342 | 0 | } |
2343 | | |
2344 | | void fx_TypedArray_prototype_reverse(txMachine* the) |
2345 | 29 | { |
2346 | 29 | mxMutableTypedArrayDeclarations; |
2347 | 29 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2348 | 29 | if (length) { |
2349 | 0 | txByte tmp; |
2350 | 0 | txByte* first = buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
2351 | 0 | txByte* last = first + (length << dispatch->value.typedArray.dispatch->shift) - delta; |
2352 | 0 | txInteger offset; |
2353 | 0 | while (first < last) { |
2354 | 0 | for (offset = 0; offset < delta; offset++) { |
2355 | 0 | tmp = last[offset]; |
2356 | 0 | last[offset] = first[offset]; |
2357 | 0 | first[offset] = tmp; |
2358 | 0 | } |
2359 | 0 | first += delta; |
2360 | 0 | last -= delta; |
2361 | 0 | } |
2362 | 0 | mxMeterSome(length * 4); |
2363 | 0 | } |
2364 | 29 | mxResult->kind = mxThis->kind; |
2365 | 29 | mxResult->value = mxThis->value; |
2366 | 29 | } |
2367 | | |
2368 | | void fx_TypedArray_prototype_set(txMachine* the) |
2369 | 77 | { |
2370 | 77 | mxMutableTypedArrayDeclarations; |
2371 | 77 | txSlot* source = fxArgToInstance(the, 0); |
2372 | 77 | if (source->next && (source->next->kind == XS_TYPED_ARRAY_KIND)) { |
2373 | 0 | txSlot* data = buffer->value.reference->next; |
2374 | 0 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2375 | 0 | txInteger target = fxArgToByteLength(the, 1, 0); |
2376 | 0 | txInteger offset = view->value.dataView.offset + (target * delta); |
2377 | 0 | length = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) >> dispatch->value.typedArray.dispatch->shift; |
2378 | 0 | txSlot* sourceDispatch = source->next; |
2379 | 0 | txSlot* sourceView = sourceDispatch->next; |
2380 | 0 | txSlot* sourceBuffer = sourceView->next; |
2381 | 0 | txU2 shift = sourceDispatch->value.typedArray.dispatch->shift; |
2382 | 0 | txInteger sourceLength = fxCheckDataViewSize(the, sourceView, sourceBuffer, XS_IMMUTABLE) >> shift; |
2383 | 0 | txInteger sourceOffset = sourceView->value.dataView.offset; |
2384 | 0 | txSlot* sourceData = sourceBuffer->value.reference->next; |
2385 | 0 | txInteger limit = offset + (sourceLength * delta); |
2386 | 0 | if ((length - sourceLength < target)) //@@ target can never be negative? |
2387 | 0 | mxRangeError("invalid offset"); |
2388 | 0 | if (data == sourceData) { |
2389 | 0 | txSlot* resultBuffer; |
2390 | 0 | mxPush(mxArrayBufferConstructor); |
2391 | 0 | mxNew(); |
2392 | 0 | mxPushInteger(sourceLength << shift); |
2393 | 0 | mxRunCount(1); |
2394 | 0 | resultBuffer = the->stack->value.reference->next; |
2395 | 0 | c_memcpy(resultBuffer->value.arrayBuffer.address, sourceData->value.arrayBuffer.address + sourceOffset, sourceLength << shift); |
2396 | 0 | sourceData = resultBuffer; |
2397 | 0 | sourceOffset = 0; |
2398 | 0 | } |
2399 | 0 | else |
2400 | 0 | mxPushUndefined(); |
2401 | 0 | if (dispatch->value.typedArray.dispatch == sourceDispatch->value.typedArray.dispatch) { |
2402 | 0 | if (data->value.arrayBuffer.address == C_NULL) |
2403 | 0 | mxTypeError("detached buffer"); |
2404 | 0 | c_memcpy(data->value.arrayBuffer.address + offset, sourceData->value.arrayBuffer.address + sourceOffset, limit - offset); |
2405 | 0 | mxMeterSome(((txU4)(limit - offset)) * 2); |
2406 | 0 | } |
2407 | 0 | else { |
2408 | 0 | txInteger sourceDelta = 1 << shift; |
2409 | 0 | mxPushUndefined(); |
2410 | 0 | while (offset < limit) { |
2411 | 0 | (*sourceDispatch->value.typedArray.dispatch->getter)(the, sourceData, sourceOffset, the->stack, EndianNative); |
2412 | 0 | (*dispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
2413 | 0 | if (data->value.arrayBuffer.address == C_NULL) |
2414 | 0 | mxTypeError("detached buffer"); |
2415 | 0 | (*dispatch->value.typedArray.dispatch->setter)(the, data, offset, the->stack, EndianNative); |
2416 | 0 | sourceOffset += sourceDelta; |
2417 | 0 | offset += delta; |
2418 | 0 | } |
2419 | 0 | mxPop(); |
2420 | 0 | } |
2421 | 0 | mxPop(); |
2422 | 0 | } |
2423 | 77 | else { |
2424 | 77 | txNumber targetOffset = 0, targetLength, sourceLength; |
2425 | 77 | txSlot *arg = mxArgv(1); |
2426 | 77 | if ((mxArgc > 1) && (arg->kind != XS_UNDEFINED_KIND)) { |
2427 | 0 | targetOffset = c_trunc(fxToNumber(the, arg)); |
2428 | 0 | if (c_isnan(targetOffset)) |
2429 | 0 | targetOffset = 0; |
2430 | 0 | if (targetOffset < 0) |
2431 | 0 | mxRangeError("offset < 0"); |
2432 | 0 | } |
2433 | 77 | if (fxIsDataViewOutOfBound(the, view, buffer)) |
2434 | 0 | mxTypeError("out of bound buffer"); |
2435 | 77 | targetLength = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) >> dispatch->value.typedArray.dispatch->shift; |
2436 | 77 | mxPushSlot(mxArgv(0)); |
2437 | 77 | mxGetID(mxID(_length)); |
2438 | 77 | sourceLength = fxToLength(the, the->stack); |
2439 | 77 | mxPop(); |
2440 | 77 | if (sourceLength + targetOffset > targetLength) |
2441 | 1 | mxRangeError("invalid offset"); |
2442 | 76 | txIndex count = (txIndex)sourceLength; |
2443 | 76 | txIndex index = 0; |
2444 | 76 | txIndex delta = (txIndex)targetOffset; |
2445 | 134 | while (index < count) { |
2446 | 58 | mxPushSlot(mxArgv(0)); |
2447 | 58 | mxGetIndex(index); |
2448 | 58 | mxPushSlot(mxThis); |
2449 | 58 | mxPushInteger(delta + index); |
2450 | 58 | mxSetAt(); |
2451 | 58 | mxPop(); |
2452 | 58 | index++; |
2453 | 58 | mxCheckMetering(); |
2454 | 58 | } |
2455 | 76 | } |
2456 | 77 | } |
2457 | | |
2458 | | void fx_TypedArray_prototype_slice(txMachine* the) |
2459 | 23.6k | { |
2460 | 23.6k | mxTypedArrayDeclarations; |
2461 | 23.6k | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2462 | 23.6k | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
2463 | 23.6k | txInteger end = fxArgToIndexInteger(the, 1, length, length); |
2464 | 23.6k | txInteger count = (end > start) ? end - start : 0; |
2465 | 23.6k | txInteger index = 0; |
2466 | 23.6k | fxCreateTypedArraySpecies(the); |
2467 | 23.6k | mxPushNumber(count); |
2468 | 23.6k | mxRunCount(1); |
2469 | 23.6k | mxPullSlot(mxResult); |
2470 | 23.6k | { |
2471 | 23.6k | mxResultTypedArrayDeclarations; |
2472 | 23.6k | fxCheckTypedArrayContentType(the, resultDispatch, dispatch); |
2473 | 23.6k | if (resultLength < count) |
2474 | 0 | mxTypeError("result: too small TypedArray instance"); |
2475 | 23.6k | if (count) { |
2476 | 13.8k | length = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE) >> dispatch->value.typedArray.dispatch->shift; |
2477 | 13.8k | if ((end <= length) && (resultDispatch->value.typedArray.dispatch->constructorID == dispatch->value.typedArray.dispatch->constructorID) && (resultBuffer->value.reference != buffer->value.reference)) { |
2478 | 13.8k | txInteger shift = dispatch->value.typedArray.dispatch->shift; |
2479 | 13.8k | txSlot* data = buffer->value.reference->next; |
2480 | 13.8k | txSlot* resultData = resultBuffer->value.reference->next; |
2481 | 13.8k | txByte* address = data->value.arrayBuffer.address; |
2482 | 13.8k | txByte* resultAddress = resultData->value.arrayBuffer.address; |
2483 | 13.8k | address += view->value.dataView.offset; |
2484 | 13.8k | resultAddress += resultView->value.dataView.offset; |
2485 | 13.8k | c_memmove(resultAddress, address + (start << shift), count << shift); |
2486 | 13.8k | mxMeterSome(((txU4)(count)) * 2); |
2487 | 13.8k | } |
2488 | 0 | else { |
2489 | 0 | mxPushUndefined(); |
2490 | 0 | while ((start < length) && (start < end)) { |
2491 | 0 | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (start * delta), the->stack, EndianNative); |
2492 | 0 | (*resultDispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
2493 | 0 | (*resultDispatch->value.typedArray.dispatch->setter)(the, resultBuffer->value.reference->next, resultView->value.dataView.offset + (index << resultDispatch->value.typedArray.dispatch->shift), the->stack, EndianNative); |
2494 | 0 | start++; |
2495 | 0 | index++; |
2496 | 0 | } |
2497 | 0 | mxPop(); |
2498 | 0 | } |
2499 | 13.8k | } |
2500 | 23.6k | } |
2501 | 23.6k | } |
2502 | | |
2503 | | void fx_TypedArray_prototype_some(txMachine* the) |
2504 | 25 | { |
2505 | 25 | mxTypedArrayDeclarations; |
2506 | 25 | txSlot* function = fxArgToCallback(the, 0); |
2507 | 25 | txInteger index = 0; |
2508 | 25 | mxResult->kind = XS_BOOLEAN_KIND; |
2509 | 25 | mxResult->value.boolean = 0; |
2510 | 25 | while (index < length) { |
2511 | 0 | fxCallTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index, C_NULL); |
2512 | 0 | mxResult->value.boolean = fxToBoolean(the, the->stack++); |
2513 | 0 | if (mxResult->value.boolean) |
2514 | 0 | break; |
2515 | 0 | index++; |
2516 | 0 | } |
2517 | 25 | } |
2518 | | |
2519 | | void fx_TypedArray_prototype_sort(txMachine* the) |
2520 | 3.01k | { |
2521 | 3.01k | mxMutableTypedArrayDeclarations; |
2522 | 3.01k | txSlot* data = buffer->value.reference->next; |
2523 | 3.01k | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2524 | 3.01k | txSlot* function = C_NULL; |
2525 | 3.01k | if (mxArgc > 0) { |
2526 | 2.98k | txSlot* slot = mxArgv(0); |
2527 | 2.98k | if (slot->kind != XS_UNDEFINED_KIND) { |
2528 | 2.98k | if (fxIsCallable(the, slot)) |
2529 | 2.97k | function = slot; |
2530 | 1 | else |
2531 | 1 | mxTypeError("compare: not a function"); |
2532 | 2.98k | } |
2533 | 2.98k | } |
2534 | 3.01k | if (function) |
2535 | 2.97k | fxSortArrayItems(the, function, C_NULL, length, mxThis); |
2536 | 35 | else |
2537 | 35 | c_qsort(data->value.arrayBuffer.address + view->value.dataView.offset, length, delta, dispatch->value.typedArray.dispatch->compare); |
2538 | 3.01k | mxResult->kind = mxThis->kind; |
2539 | 3.01k | mxResult->value = mxThis->value; |
2540 | 3.01k | } |
2541 | | |
2542 | | void fx_TypedArray_prototype_subarray(txMachine* the) |
2543 | 49 | { |
2544 | 49 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2545 | 49 | txSlot* dispatch = instance->next; |
2546 | 49 | txSlot* view = dispatch->next; |
2547 | 49 | txSlot* buffer = view->next; |
2548 | 49 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
2549 | 49 | txInteger length = fxGetDataViewSize(the, view, buffer) >> shift; |
2550 | 49 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
2551 | 49 | if ((view->value.dataView.size < 0) && ((mxArgc < 2) || mxIsUndefined(mxArgv(1)))) { |
2552 | 6 | fxCreateTypedArraySpecies(the); |
2553 | 6 | mxPushSlot(buffer); |
2554 | 6 | mxPushInteger(view->value.dataView.offset + (start << shift)); |
2555 | 6 | mxRunCount(2); |
2556 | 6 | } |
2557 | 43 | else { |
2558 | 43 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
2559 | 43 | if (stop < start) |
2560 | 0 | stop = start; |
2561 | 43 | fxCreateTypedArraySpecies(the); |
2562 | 43 | mxPushSlot(buffer); |
2563 | 43 | mxPushInteger(view->value.dataView.offset + (start << shift)); |
2564 | 43 | mxPushInteger(stop - start); |
2565 | 43 | mxRunCount(3); |
2566 | 43 | } |
2567 | 49 | mxPullSlot(mxResult); |
2568 | 49 | instance = fxCheckTypedArrayInstance(the, mxResult); |
2569 | 49 | fxCheckTypedArrayContentType(the, instance->next, dispatch); |
2570 | 49 | } |
2571 | | |
2572 | | void fx_TypedArray_prototype_toLocaleString(txMachine* the) |
2573 | 21 | { |
2574 | 21 | mxTypedArrayDeclarations; |
2575 | 21 | txInteger index = 0; |
2576 | 21 | txString string; |
2577 | 21 | txSlot* list = fxNewInstance(the); |
2578 | 21 | txSlot* slot = list; |
2579 | 21 | txBoolean comma = 0; |
2580 | 21 | txInteger size = 0; |
2581 | 21 | mxPushStringX(","); |
2582 | 21 | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2583 | 21 | the->stack->value.key.sum = 1; |
2584 | 21 | while (index < length) { |
2585 | 0 | if (comma) { |
2586 | 0 | slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG); |
2587 | 0 | size += slot->value.key.sum; |
2588 | 0 | } |
2589 | 0 | else |
2590 | 0 | comma = 1; |
2591 | 0 | mxPushSlot(mxThis); |
2592 | 0 | mxGetIndex(index); |
2593 | 0 | if ((the->stack->kind != XS_UNDEFINED_KIND) && (the->stack->kind != XS_NULL_KIND)) { |
2594 | 0 | mxDub(); |
2595 | 0 | mxGetID(mxID(_toLocaleString)); |
2596 | 0 | mxCall(); |
2597 | 0 | mxRunCount(0); |
2598 | 0 | slot = fxNextSlotProperty(the, slot, the->stack, XS_NO_ID, XS_NO_FLAG); |
2599 | 0 | string = fxToString(the, slot); |
2600 | 0 | slot->kind += XS_KEY_KIND - XS_STRING_KIND; |
2601 | 0 | slot->value.key.sum = mxStringLength(string); |
2602 | 0 | size = fxAddChunkSizes(the, size, slot->value.key.sum); |
2603 | 0 | } |
2604 | 0 | mxPop(); |
2605 | 0 | index++; |
2606 | 0 | } |
2607 | 21 | string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1)); |
2608 | 21 | slot = list->next; |
2609 | 21 | while (slot) { |
2610 | 0 | c_memcpy(string, slot->value.key.string, slot->value.key.sum); |
2611 | 0 | string += slot->value.key.sum; |
2612 | 0 | slot = slot->next; |
2613 | 0 | } |
2614 | 21 | *string = 0; |
2615 | 21 | mxResult->kind = XS_STRING_KIND; |
2616 | 21 | mxPop(); |
2617 | 21 | } |
2618 | | |
2619 | | void fx_TypedArray_prototype_toReversed(txMachine* the) |
2620 | 59 | { |
2621 | 59 | mxTypedArrayDeclarations; |
2622 | 59 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2623 | 59 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2624 | 59 | mxPushSlot(constructor); |
2625 | 59 | mxNew(); |
2626 | 59 | mxPushInteger(length); |
2627 | 59 | mxRunCount(1); |
2628 | 59 | mxPullSlot(mxResult); |
2629 | 59 | if (length) { |
2630 | 0 | mxResultTypedArrayDeclarations; |
2631 | 0 | txByte* base = buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
2632 | 0 | txByte* from = base + (resultLength << dispatch->value.typedArray.dispatch->shift) - delta; |
2633 | 0 | txByte* to = resultBuffer->value.reference->next->value.arrayBuffer.address; |
2634 | 0 | while (from >= base) { |
2635 | 0 | txInteger offset; |
2636 | 0 | for (offset = 0; offset < delta; offset++) |
2637 | 0 | *to++ = *from++; |
2638 | 0 | from -= delta << 1; |
2639 | 0 | } |
2640 | 0 | mxMeterSome((txU4)length * 4); |
2641 | 0 | } |
2642 | 59 | } |
2643 | | |
2644 | | void fx_TypedArray_prototype_toSorted(txMachine* the) |
2645 | 36 | { |
2646 | 36 | mxTypedArrayDeclarations; |
2647 | 36 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2648 | 36 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2649 | 36 | txSlot* function = C_NULL; |
2650 | 36 | if (mxArgc > 0) { |
2651 | 0 | txSlot* slot = mxArgv(0); |
2652 | 0 | if (slot->kind != XS_UNDEFINED_KIND) { |
2653 | 0 | if (fxIsCallable(the, slot)) |
2654 | 0 | function = slot; |
2655 | 0 | else |
2656 | 0 | mxTypeError("compare: not a function"); |
2657 | 0 | } |
2658 | 0 | } |
2659 | 36 | mxPushSlot(constructor); |
2660 | 36 | mxNew(); |
2661 | 36 | mxPushInteger(length); |
2662 | 36 | mxRunCount(1); |
2663 | 36 | mxPullSlot(mxResult); |
2664 | 36 | if (function) |
2665 | 0 | fxSortArrayItems(the, function, C_NULL, length, mxResult); |
2666 | 36 | else { |
2667 | 36 | mxResultTypedArrayDeclarations; |
2668 | 36 | txByte* from = buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
2669 | 36 | txByte* to = resultBuffer->value.reference->next->value.arrayBuffer.address; |
2670 | 36 | c_memcpy(to, from, resultLength << dispatch->value.typedArray.dispatch->shift); |
2671 | 36 | c_qsort(to, length, delta, dispatch->value.typedArray.dispatch->compare); |
2672 | 36 | } |
2673 | 36 | } |
2674 | | |
2675 | | void fx_TypedArray_prototype_toStringTag_get(txMachine* the) |
2676 | 26 | { |
2677 | 26 | if (mxThis->kind == XS_REFERENCE_KIND) { |
2678 | 18 | txSlot* instance = mxThis->value.reference; |
2679 | 18 | txSlot* slot = instance->next; |
2680 | 18 | if (slot && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_TYPED_ARRAY_KIND)) { |
2681 | 0 | txTypeDispatch *dispatch = instance->next->value.typedArray.dispatch; |
2682 | 0 | txSlot* key = fxGetKey(the, mxID(dispatch->constructorID)); |
2683 | 0 | if (key->kind == XS_KEY_X_KIND) |
2684 | 0 | mxResult->kind = XS_STRING_X_KIND; |
2685 | 0 | else |
2686 | 0 | mxResult->kind = XS_STRING_KIND; |
2687 | 0 | mxResult->value.string = key->value.key.string; |
2688 | 0 | } |
2689 | 18 | } |
2690 | 26 | } |
2691 | | |
2692 | | void fx_TypedArray_prototype_values(txMachine* the) |
2693 | 49 | { |
2694 | 49 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2695 | 49 | txSlot* dispatch = instance->next; |
2696 | 49 | txSlot* view = dispatch->next; |
2697 | 49 | txSlot* buffer = view->next; |
2698 | 49 | txSlot* property; |
2699 | 49 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
2700 | 49 | mxPush(mxArrayIteratorPrototype); |
2701 | 49 | property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array))); |
2702 | 49 | property = fxNextIntegerProperty(the, property, 0, XS_NO_ID, XS_INTERNAL_FLAG); |
2703 | 49 | mxPullSlot(mxResult); |
2704 | 49 | } |
2705 | | |
2706 | | void fx_TypedArray_prototype_with(txMachine* the) |
2707 | 59 | { |
2708 | 59 | mxTypedArrayDeclarations; |
2709 | 59 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2710 | 59 | txInteger index = (txInteger)fxArgToRelativeIndex(the, 0, 0, length), count, i; |
2711 | 59 | txSlot* value; |
2712 | 59 | if (mxArgc > 1) |
2713 | 7 | mxPushSlot(mxArgv(1)); |
2714 | 52 | else |
2715 | 52 | mxPushUndefined(); |
2716 | 59 | value = the->stack; |
2717 | 59 | (*dispatch->value.typedArray.dispatch->coerce)(the, value); |
2718 | 59 | count = fxGetDataViewSize(the, view, buffer) >> dispatch->value.typedArray.dispatch->shift; |
2719 | 59 | if ((index < 0) || (count <= index)) |
2720 | 2 | mxRangeError("invalid index"); |
2721 | 57 | mxPushSlot(constructor); |
2722 | 57 | mxNew(); |
2723 | 57 | mxPushInteger(length); |
2724 | 57 | mxRunCount(1); |
2725 | 57 | mxPullSlot(mxResult); |
2726 | 57 | i = 0; |
2727 | 66 | while (i < index) { |
2728 | 9 | mxPushSlot(mxThis); |
2729 | 9 | mxPushInteger(i); |
2730 | 9 | mxGetAt(); |
2731 | 9 | mxPushSlot(mxResult); |
2732 | 9 | mxPushInteger(i); |
2733 | 9 | mxSetAt(); |
2734 | 9 | mxPop(); |
2735 | 9 | i++; |
2736 | 9 | mxCheckMetering(); |
2737 | 9 | } |
2738 | 57 | mxPushSlot(value); |
2739 | 57 | mxPushSlot(mxResult); |
2740 | 57 | mxPushInteger(i); |
2741 | 57 | mxSetAt(); |
2742 | 57 | mxPop(); |
2743 | 57 | i++; |
2744 | 104 | while (i < length) { |
2745 | 47 | mxPushSlot(mxThis); |
2746 | 47 | mxPushInteger(i); |
2747 | 47 | mxGetAt(); |
2748 | 47 | mxPushSlot(mxResult); |
2749 | 47 | mxPushInteger(i); |
2750 | 47 | mxSetAt(); |
2751 | 47 | mxPop(); |
2752 | 47 | i++; |
2753 | 47 | mxCheckMetering(); |
2754 | 47 | } |
2755 | 57 | mxPop(); |
2756 | 57 | } |
2757 | | |
2758 | | #if mxBigEndian |
2759 | | #define mxEndianFloat16_BtoN(a) (a) |
2760 | | #define mxEndianFloat32_BtoN(a) (a) |
2761 | | #define mxEndianFloat64_BtoN(a) (a) |
2762 | | #define mxEndianS64_BtoN(a) (a) |
2763 | | #define mxEndianU64_BtoN(a) (a) |
2764 | | #define mxEndianS32_BtoN(a) (a) |
2765 | | #define mxEndianU32_BtoN(a) (a) |
2766 | | #define mxEndianS16_BtoN(a) (a) |
2767 | | #define mxEndianU16_BtoN(a) (a) |
2768 | | |
2769 | | #define mxEndianFloat16_NtoB(a) (a) |
2770 | | #define mxEndianFloat32_NtoB(a) (a) |
2771 | | #define mxEndianFloat64_NtoB(a) (a) |
2772 | | #define mxEndianS64_NtoB(a) (a) |
2773 | | #define mxEndianU64_NtoB(a) (a) |
2774 | | #define mxEndianS32_NtoB(a) (a) |
2775 | | #define mxEndianU32_NtoB(a) (a) |
2776 | | #define mxEndianS16_NtoB(a) (a) |
2777 | | #define mxEndianU16_NtoB(a) (a) |
2778 | | #else |
2779 | 19 | #define mxEndianFloat16_LtoN(a) (a) |
2780 | 12 | #define mxEndianFloat32_LtoN(a) (a) |
2781 | 13 | #define mxEndianFloat64_LtoN(a) (a) |
2782 | 60 | #define mxEndianS64_LtoN(a) (a) |
2783 | 34 | #define mxEndianU64_LtoN(a) (a) |
2784 | 17 | #define mxEndianS32_LtoN(a) (a) |
2785 | 32 | #define mxEndianU32_LtoN(a) (a) |
2786 | 22 | #define mxEndianS16_LtoN(a) (a) |
2787 | 13 | #define mxEndianU16_LtoN(a) (a) |
2788 | | |
2789 | | #define mxEndianFloat16_NtoL(a) (a) |
2790 | | #define mxEndianFloat32_NtoL(a) (a) |
2791 | | #define mxEndianFloat64_NtoL(a) (a) |
2792 | | #define mxEndianS64_NtoL(a) (a) |
2793 | | #define mxEndianU64_NtoL(a) (a) |
2794 | | #define mxEndianS32_NtoL(a) (a) |
2795 | | #define mxEndianU32_NtoL(a) (a) |
2796 | | #define mxEndianS16_NtoL(a) (a) |
2797 | | #define mxEndianU16_NtoL(a) (a) |
2798 | | #endif |
2799 | | |
2800 | | #if mxLittleEndian |
2801 | | #define mxEndianFloat16_BtoN(a) (mxEndianFloat16_Swap(a)) |
2802 | 92 | #define mxEndianFloat32_BtoN(a) (mxEndianFloat32_Swap(a)) |
2803 | 81 | #define mxEndianFloat64_BtoN(a) (mxEndianFloat64_Swap(a)) |
2804 | 134 | #define mxEndianS64_BtoN(a) ((txS8) mxEndian64_Swap(a)) |
2805 | 62 | #define mxEndianU64_BtoN(a) ((txU8) mxEndian64_Swap(a)) |
2806 | 86 | #define mxEndianS32_BtoN(a) ((txS4) mxEndian32_Swap(a)) |
2807 | 112 | #define mxEndianU32_BtoN(a) ((txU4) mxEndian32_Swap(a)) |
2808 | 100 | #define mxEndianS16_BtoN(a) ((txS2) mxEndian16_Swap(a)) |
2809 | 80 | #define mxEndianU16_BtoN(a) ((txU2) mxEndian16_Swap(a)) |
2810 | | |
2811 | 111 | #define mxEndianFloat16_NtoB(a) (mxEndianFloat16_Swap(a)) |
2812 | 94 | #define mxEndianFloat32_NtoB(a) (mxEndianFloat32_Swap(a)) |
2813 | 77 | #define mxEndianFloat64_NtoB(a) (mxEndianFloat64_Swap(a)) |
2814 | 85 | #define mxEndianS64_NtoB(a) ((txS8) mxEndian64_Swap(a)) |
2815 | 6 | #define mxEndianU64_NtoB(a) ((txU8) mxEndian64_Swap(a)) |
2816 | 88 | #define mxEndianS32_NtoB(a) ((txS4) mxEndian32_Swap(a)) |
2817 | 81 | #define mxEndianU32_NtoB(a) ((txU4) mxEndian32_Swap(a)) |
2818 | 96 | #define mxEndianS16_NtoB(a) ((txS2) mxEndian16_Swap(a)) |
2819 | 234 | #define mxEndianU16_NtoB(a) ((txU2) mxEndian16_Swap(a)) |
2820 | | #else |
2821 | | #define mxEndianFloat16_LtoN(a) (mxEndianFloat16_Swap(a)) |
2822 | | #define mxEndianFloat32_LtoN(a) (mxEndianFloat32_Swap(a)) |
2823 | | #define mxEndianFloat64_LtoN(a) (mxEndianFloat64_Swap(a)) |
2824 | | #define mxEndianS64_LtoN(a) ((txS8) mxEndian64_Swap(a)) |
2825 | | #define mxEndianU64_LtoN(a) ((txU8) mxEndian64_Swap(a)) |
2826 | | #define mxEndianS32_LtoN(a) ((txS4) mxEndian32_Swap(a)) |
2827 | | #define mxEndianU32_LtoN(a) ((txU4) mxEndian32_Swap(a)) |
2828 | | #define mxEndianS16_LtoN(a) ((txS2) mxEndian16_Swap(a)) |
2829 | | #define mxEndianU16_LtoN(a) ((txU2) mxEndian16_Swap(a)) |
2830 | | |
2831 | | #define mxEndianFloat16_NtoL(a) (mxEndianFloat16_Swap(a)) |
2832 | | #define mxEndianFloat32_NtoL(a) (mxEndianFloat32_Swap(a)) |
2833 | | #define mxEndianFloat64_NtoL(a) (mxEndianFloat64_Swap(a)) |
2834 | | #define mxEndianS64_NtoL(a) ((txS8) mxEndian64_Swap(a)) |
2835 | | #define mxEndianU64_NtoL(a) ((txU8) mxEndian64_Swap(a)) |
2836 | | #define mxEndianS32_NtoL(a) ((txS4) mxEndian32_Swap(a)) |
2837 | | #define mxEndianU32_NtoL(a) ((txU4) mxEndian32_Swap(a)) |
2838 | | #define mxEndianS16_NtoL(a) ((txS2) mxEndian16_Swap(a)) |
2839 | | #define mxEndianU16_NtoL(a) ((txU2) mxEndian16_Swap(a)) |
2840 | | #endif |
2841 | | |
2842 | | #if defined(__GNUC__) || defined(__llvm__) |
2843 | 510 | #define mxEndian16_Swap(a) __builtin_bswap16(a) |
2844 | | #else |
2845 | | static txU2 mxEndian16_Swap(txU2 a) |
2846 | | { |
2847 | | txU2 b; |
2848 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
2849 | | int i; |
2850 | | for (i = 0; i < 2; i++) |
2851 | | p2[i] = p1[1 - i]; |
2852 | | return b; |
2853 | | } |
2854 | | #endif |
2855 | | |
2856 | | #if defined(__GNUC__) || defined(__llvm__) |
2857 | 367 | #define mxEndian32_Swap(a) __builtin_bswap32(a) |
2858 | | #else |
2859 | | static txU4 mxEndian32_Swap(txU4 a) |
2860 | | { |
2861 | | txU4 b; |
2862 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
2863 | | int i; |
2864 | | for (i = 0; i < 4; i++) |
2865 | | p2[i] = p1[3 - i]; |
2866 | | return b; |
2867 | | } |
2868 | | #endif |
2869 | | |
2870 | | #if defined(__GNUC__) || defined(__llvm__) |
2871 | 287 | #define mxEndian64_Swap(a) __builtin_bswap64(a) |
2872 | | #else |
2873 | | static txU8 mxEndian64_Swap(txU8 a) |
2874 | | { |
2875 | | txU8 b; |
2876 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
2877 | | int i; |
2878 | | for (i = 0; i < 8; i++) |
2879 | | p2[i] = p1[7 - i]; |
2880 | | return b; |
2881 | | } |
2882 | | #endif |
2883 | | |
2884 | 969 | #define toNative(size, endian) mxEndian##size##_##endian##toN |
2885 | 872 | #define fromNative(size, endian) mxEndian##size##_Nto##endian |
2886 | 8.12M | #define IMPORT(size) (endian == EndianBig ? toNative(size, B)(value) : endian == EndianLittle ? toNative(size, L)(value) : (value)) |
2887 | 413k | #define EXPORT(size) (endian == EndianBig ? fromNative(size, B)(value) : endian == EndianLittle ? toNative(size, L)(value) : (value)) |
2888 | | |
2889 | | int fxBigInt64Compare(const void* p, const void* q) |
2890 | 0 | { |
2891 | 0 | txS8 a = *((txS8*)p); |
2892 | 0 | txS8 b = *((txS8*)q); |
2893 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
2894 | 0 | } |
2895 | | |
2896 | | void fxBigInt64Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2897 | 230 | { |
2898 | 230 | txS8 value; |
2899 | | #ifdef mxMisalignedSettersCrash |
2900 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
2901 | | #else |
2902 | 230 | value = *((txS8*)(data->value.arrayBuffer.address + offset)); |
2903 | 230 | #endif |
2904 | 230 | value = IMPORT(S64); |
2905 | 230 | fxFromBigInt64(the, slot, value); |
2906 | 230 | mxMeterOne(); |
2907 | 230 | } |
2908 | | |
2909 | | void fxBigInt64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2910 | 175 | { |
2911 | 175 | txS8 value = (txS8)fxToBigInt64(the, slot); |
2912 | | #ifdef mxMisalignedSettersCrash |
2913 | | value = EXPORT(S64); |
2914 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txS8)); |
2915 | | #else |
2916 | 175 | *((txS8*)(data->value.arrayBuffer.address + offset)) = EXPORT(S64); |
2917 | 175 | #endif |
2918 | 175 | mxMeterOne(); |
2919 | 175 | } |
2920 | | |
2921 | | int fxBigUint64Compare(const void* p, const void* q) |
2922 | 0 | { |
2923 | 0 | txU8 a = *((txU8*)p); |
2924 | 0 | txU8 b = *((txU8*)q); |
2925 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
2926 | 0 | } |
2927 | | |
2928 | | void fxBigUint64Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2929 | 121 | { |
2930 | 121 | txU8 value; |
2931 | | #ifdef mxMisalignedSettersCrash |
2932 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
2933 | | #else |
2934 | 121 | value = *((txU8*)(data->value.arrayBuffer.address + offset)); |
2935 | 121 | #endif |
2936 | 121 | value = IMPORT(U64); |
2937 | 121 | fxFromBigUint64(the, slot, value); |
2938 | 121 | mxMeterOne(); |
2939 | 121 | } |
2940 | | |
2941 | | void fxBigUint64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2942 | 107 | { |
2943 | 107 | txU8 value = (txU8)fxToBigUint64(the, slot); |
2944 | | #ifdef mxMisalignedSettersCrash |
2945 | | value = EXPORT(U64); |
2946 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txU8)); |
2947 | | #else |
2948 | 107 | *((txU8*)(data->value.arrayBuffer.address + offset)) = EXPORT(U64); |
2949 | 107 | #endif |
2950 | 107 | mxMeterOne(); |
2951 | 107 | } |
2952 | | |
2953 | | #if mxFloat16 |
2954 | | |
2955 | | #ifdef mxUseFloat16 |
2956 | | typedef _Float16 txFloat16; |
2957 | | #define mxFloat16to64(X) ((double)X) |
2958 | | #define mxFloat64to16(X) ((_Float16)X) |
2959 | | #else |
2960 | | typedef uint16_t txFloat16; |
2961 | 7.32M | #define mxFloat16to64(X) fxFloat16to64(X) |
2962 | 1.45k | #define mxFloat64to16(X) fxFloat64to16(X) |
2963 | | |
2964 | | // adapted from https://half.sourceforge.net |
2965 | | |
2966 | | static double fxFloat16to64(uint16_t value) |
2967 | 7.32M | { |
2968 | 7.32M | uint32_t hi, abs; |
2969 | 7.32M | uint64_t dbits; |
2970 | 7.32M | double out; |
2971 | | |
2972 | 7.32M | hi = (uint32_t)(value & 0x8000) << 16; |
2973 | 7.32M | abs = value & 0x7FFF; |
2974 | 7.32M | if (abs) { |
2975 | 81 | hi |= 0x3F000000 << (abs >= 0x7C00); |
2976 | 116 | for (; abs < 0x400; abs <<= 1, hi -= 0x100000); |
2977 | 81 | hi += abs << 10; |
2978 | 81 | } |
2979 | 7.32M | dbits = (uint64_t)(hi) << 32; |
2980 | 7.32M | c_memcpy(&out, &dbits, sizeof(double)); |
2981 | 7.32M | return out; |
2982 | 7.32M | } |
2983 | | |
2984 | 113 | static uint32_t fxRoundFloat16(uint32_t value, uint32_t g, uint32_t s) { |
2985 | 113 | return value + (g & (s | value)); |
2986 | 113 | } |
2987 | | |
2988 | | static uint16_t fxFloat64to16(double value) |
2989 | 725 | { |
2990 | 725 | uint64_t dbits; |
2991 | 725 | uint32_t hi, lo, sign; |
2992 | | |
2993 | 725 | c_memcpy(&dbits, &value, sizeof(double)); |
2994 | 725 | hi = dbits >> 32; |
2995 | 725 | lo = dbits & 0xFFFFFFFF; |
2996 | 725 | sign = (hi >> 16) & 0x8000; |
2997 | 725 | hi &= 0x7FFFFFFF; |
2998 | 725 | if (hi >= 0x7FF00000) |
2999 | 1 | return sign | 0x7C00 | ((dbits & 0xFFFFFFFFFFFFF) ? (0x200 | ((hi >> 10) & 0x3FF)) : 0); |
3000 | 724 | if (hi >= 0x40F00000) |
3001 | 1 | return sign | 0x7C00; |
3002 | 723 | if (hi >= 0x3F100000) |
3003 | 110 | return fxRoundFloat16(sign | (((hi >> 20) - 1008) << 10) | ((hi >> 10) & 0x3FF), (hi >> 9) & 1, ((hi & 0x1FF) | lo) != 0); |
3004 | 613 | if (hi >= 0x3E600000) { |
3005 | 3 | int i = 1018 - (hi >> 20); |
3006 | 3 | hi = (hi & 0xFFFFF) | 0x100000; |
3007 | 3 | return fxRoundFloat16(sign | (hi >> (i + 1)), (hi >> i) & 1, ((hi & (((uint32_t)(1) << i) - 1)) | lo) != 0); |
3008 | 3 | } |
3009 | 610 | return sign; |
3010 | 613 | } |
3011 | | |
3012 | | #endif |
3013 | | |
3014 | | #if mxCanonicalNaN |
3015 | | #if mxBigEndian |
3016 | | static uint8_t gxCanonicalNaN16Bytes[2] = { 0x7E, 0 }; |
3017 | | #else |
3018 | | static uint8_t gxCanonicalNaN16Bytes[2] = { 0, 0x7E }; |
3019 | | #endif |
3020 | | static txFloat16* gxCanonicalNaN16 = (txFloat16*)gxCanonicalNaN16Bytes; |
3021 | | #endif |
3022 | | |
3023 | | static txFloat16 mxEndianFloat16_Swap(txFloat16 a) |
3024 | 190 | { |
3025 | 190 | #if defined(__GNUC__) || defined(__llvm__) |
3026 | 190 | uint32_t result = __builtin_bswap16(*(uint16_t *)&a); |
3027 | 190 | return *(txFloat16 *)&result; |
3028 | | #else |
3029 | | txFloat16 b; |
3030 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
3031 | | int i; |
3032 | | for (i = 0; i < 2; i++) |
3033 | | p2[i] = p1[1 - i]; |
3034 | | return b; |
3035 | | #endif |
3036 | 190 | } |
3037 | | |
3038 | | int fxFloat16Compare(const void* p, const void* q) |
3039 | 3.66M | { |
3040 | 3.66M | double a = mxFloat16to64(*((txFloat16*)p)); |
3041 | 3.66M | double b = mxFloat16to64(*((txFloat16*)q)); |
3042 | 3.66M | if (c_isnan(a)) { |
3043 | 0 | if (c_isnan(b)) |
3044 | 0 | return 0; |
3045 | 0 | return 1; |
3046 | 0 | } |
3047 | 3.66M | if (c_isnan(b)) |
3048 | 0 | return -1; |
3049 | 3.66M | if (a < b) |
3050 | 0 | return -1; |
3051 | 3.66M | if (a > b) |
3052 | 0 | return 1; |
3053 | 3.66M | if (a == 0) { |
3054 | 3.66M | if (c_signbit(a)) { |
3055 | 0 | if (c_signbit(b)) |
3056 | 0 | return 0; |
3057 | 0 | return -1; |
3058 | 0 | } |
3059 | 3.66M | if (c_signbit(b)) |
3060 | 0 | return 1; |
3061 | 3.66M | } |
3062 | 3.66M | return 0; |
3063 | 3.66M | } |
3064 | | |
3065 | | void fxFloat16Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3066 | 687 | { |
3067 | 687 | txFloat16 value; |
3068 | 687 | slot->kind = XS_NUMBER_KIND; |
3069 | | #ifdef mxMisalignedSettersCrash |
3070 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3071 | | #else |
3072 | 687 | value = *((txFloat16*)(data->value.arrayBuffer.address + offset)); |
3073 | 687 | #endif |
3074 | 687 | slot->value.number = mxFloat16to64(IMPORT(Float16)); |
3075 | 687 | mxMeterOne(); |
3076 | 687 | } |
3077 | | |
3078 | | void fxFloat16Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3079 | 728 | { |
3080 | 728 | #if mxCanonicalNaN |
3081 | 728 | txFloat16 value = (c_isnan(slot->value.number)) ? *gxCanonicalNaN16 : mxFloat64to16(slot->value.number); |
3082 | | #else |
3083 | | txFloat16 value = mxFloat64to16(slot->value.number); |
3084 | | #endif |
3085 | | #ifdef mxMisalignedSettersCrash |
3086 | | value = EXPORT(Float16); |
3087 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(value)); |
3088 | | #else |
3089 | 728 | *((txFloat16*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float16); |
3090 | 728 | #endif |
3091 | 728 | mxMeterOne(); |
3092 | 728 | } |
3093 | | |
3094 | | void fx_Math_f16round(txMachine* the) |
3095 | 0 | { |
3096 | 0 | txFloat16 value = mxFloat64to16((mxArgc < 1) ? C_NAN : fxToNumber(the, mxArgv(0))); |
3097 | 0 | mxResult->kind = XS_NUMBER_KIND; |
3098 | 0 | mxResult->value.number = mxFloat16to64(value); |
3099 | 0 | } |
3100 | | |
3101 | | #endif |
3102 | | |
3103 | | #if mxCanonicalNaN |
3104 | | #if mxBigEndian |
3105 | | static uint8_t gxCanonicalNaN32Bytes[4] = { 0x7F, 0xC0, 0, 0 }; |
3106 | | #else |
3107 | | static uint8_t gxCanonicalNaN32Bytes[4] = { 0, 0, 0xC0, 0x7F }; |
3108 | | #endif |
3109 | | static float* gxCanonicalNaN32 = (float*)gxCanonicalNaN32Bytes; |
3110 | | #endif |
3111 | | |
3112 | | static float mxEndianFloat32_Swap(float a) |
3113 | 186 | { |
3114 | 186 | #if defined(__GNUC__) || defined(__llvm__) |
3115 | 186 | uint32_t result = __builtin_bswap32(*(uint32_t *)&a); |
3116 | 186 | return *(float *)&result; |
3117 | | #else |
3118 | | float b; |
3119 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
3120 | | int i; |
3121 | | for (i = 0; i < 4; i++) |
3122 | | p2[i] = p1[3 - i]; |
3123 | | return b; |
3124 | | #endif |
3125 | 186 | } |
3126 | | |
3127 | | int fxFloat32Compare(const void* p, const void* q) |
3128 | 3.66M | { |
3129 | 3.66M | float a = *((float*)p); |
3130 | 3.66M | float b = *((float*)q); |
3131 | 3.66M | if (c_isnan(a)) { |
3132 | 0 | if (c_isnan(b)) |
3133 | 0 | return 0; |
3134 | 0 | return 1; |
3135 | 0 | } |
3136 | 3.66M | if (c_isnan(b)) |
3137 | 0 | return -1; |
3138 | 3.66M | if (a < b) |
3139 | 0 | return -1; |
3140 | 3.66M | if (a > b) |
3141 | 0 | return 1; |
3142 | 3.66M | if (a == 0) { |
3143 | 3.66M | if (c_signbit(a)) { |
3144 | 0 | if (c_signbit(b)) |
3145 | 0 | return 0; |
3146 | 0 | return -1; |
3147 | 0 | } |
3148 | 3.66M | if (c_signbit(b)) |
3149 | 0 | return 1; |
3150 | 3.66M | } |
3151 | 3.66M | return 0; |
3152 | 3.66M | } |
3153 | | |
3154 | | void fxFloat32Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3155 | 136k | { |
3156 | 136k | float value; |
3157 | 136k | slot->kind = XS_NUMBER_KIND; |
3158 | | #ifdef mxMisalignedSettersCrash |
3159 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3160 | | #else |
3161 | 136k | value = *((float*)(data->value.arrayBuffer.address + offset)); |
3162 | 136k | #endif |
3163 | 136k | slot->value.number = IMPORT(Float32); |
3164 | 136k | mxMeterOne(); |
3165 | 136k | } |
3166 | | |
3167 | | void fxFloat32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3168 | 914 | { |
3169 | 914 | #if mxCanonicalNaN |
3170 | 914 | float value = (c_isnan(slot->value.number)) ? *gxCanonicalNaN32 : (float)slot->value.number; |
3171 | | #else |
3172 | | float value = (float)slot->value.number; |
3173 | | #endif |
3174 | | #ifdef mxMisalignedSettersCrash |
3175 | | value = EXPORT(Float32); |
3176 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(value)); |
3177 | | #else |
3178 | 914 | *((float*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float32); |
3179 | 914 | #endif |
3180 | 914 | mxMeterOne(); |
3181 | 914 | } |
3182 | | |
3183 | | #if mxCanonicalNaN |
3184 | | #if mxBigEndian |
3185 | | static uint8_t gxCanonicalNaN64Bytes[8] = { 0x7F, 0xF8, 0, 0, 0, 0, 0, 0 }; |
3186 | | #else |
3187 | | static uint8_t gxCanonicalNaN64Bytes[8] = { 0, 0, 0, 0, 0, 0, 0xF8, 0x7F }; |
3188 | | #endif |
3189 | | double* gxCanonicalNaN64 = (double*)gxCanonicalNaN64Bytes; |
3190 | | #endif |
3191 | | |
3192 | | static double mxEndianFloat64_Swap(double a) |
3193 | 158 | { |
3194 | 158 | #if defined(__GNUC__) || defined(__llvm__) |
3195 | 158 | uint64_t result = __builtin_bswap64(*(uint64_t *)&a); |
3196 | 158 | return *(double *)&result; |
3197 | | #else |
3198 | | double b; |
3199 | | txU1 *p1 = (txU1 *) &a, *p2 = (txU1 *) &b; |
3200 | | int i; |
3201 | | for (i = 0; i < 8; i++) |
3202 | | p2[i] = p1[7 - i]; |
3203 | | return b; |
3204 | | #endif |
3205 | 158 | } |
3206 | | |
3207 | | int fxFloat64Compare(const void* p, const void* q) |
3208 | 0 | { |
3209 | 0 | double a = *((double*)p); |
3210 | 0 | double b = *((double*)q); |
3211 | 0 | if (c_isnan(a)) { |
3212 | 0 | if (c_isnan(b)) |
3213 | 0 | return 0; |
3214 | 0 | return 1; |
3215 | 0 | } |
3216 | 0 | if (c_isnan(b)) |
3217 | 0 | return -1; |
3218 | 0 | if (a < b) |
3219 | 0 | return -1; |
3220 | 0 | if (a > b) |
3221 | 0 | return 1; |
3222 | 0 | if (a == 0) { |
3223 | 0 | if (c_signbit(a)) { |
3224 | 0 | if (c_signbit(b)) |
3225 | 0 | return 0; |
3226 | 0 | return -1; |
3227 | 0 | } |
3228 | 0 | if (c_signbit(b)) |
3229 | 0 | return 1; |
3230 | 0 | } |
3231 | 0 | return 0; |
3232 | 0 | } |
3233 | | |
3234 | | void fxFloat64Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3235 | 631 | { |
3236 | 631 | double value; |
3237 | 631 | slot->kind = XS_NUMBER_KIND; |
3238 | | #ifdef mxMisalignedSettersCrash |
3239 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3240 | | #else |
3241 | 631 | value = *((double*)(data->value.arrayBuffer.address + offset)); |
3242 | 631 | #endif |
3243 | 631 | slot->value.number = IMPORT(Float64); |
3244 | 631 | mxMeterOne(); |
3245 | 631 | } |
3246 | | |
3247 | | void fxFloat64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3248 | 626 | { |
3249 | 626 | #if mxCanonicalNaN |
3250 | 626 | double value = (c_isnan(slot->value.number)) ? *gxCanonicalNaN32 : slot->value.number; |
3251 | | #else |
3252 | | double value = slot->value.number; |
3253 | | #endif |
3254 | | #ifdef mxMisalignedSettersCrash |
3255 | | value = EXPORT(Float64); |
3256 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(value)); |
3257 | | #else |
3258 | 626 | *((double*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float64); |
3259 | 626 | #endif |
3260 | 626 | mxMeterOne(); |
3261 | 626 | } |
3262 | | |
3263 | | void fxIntCoerce(txMachine* the, txSlot* slot) |
3264 | 23.5k | { |
3265 | 23.5k | fxToInteger(the, slot); |
3266 | 23.5k | } |
3267 | | |
3268 | | void fxUintCoerce(txMachine* the, txSlot* slot) |
3269 | 486k | { |
3270 | 486k | fxToUnsigned(the, slot); |
3271 | 486k | } |
3272 | | |
3273 | | int fxInt8Compare(const void* p, const void* q) |
3274 | 0 | { |
3275 | 0 | txS1 a = *((txS1*)p); |
3276 | 0 | txS1 b = *((txS1*)q); |
3277 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3278 | 0 | } |
3279 | | |
3280 | | void fxInt8Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3281 | 1.56k | { |
3282 | 1.56k | slot->kind = XS_INTEGER_KIND; |
3283 | 1.56k | slot->value.integer = *((txS1*)(data->value.arrayBuffer.address + offset)); |
3284 | 1.56k | mxMeterOne(); |
3285 | 1.56k | } |
3286 | | |
3287 | | void fxInt8Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3288 | 20.6k | { |
3289 | 20.6k | *((txS1*)(data->value.arrayBuffer.address + offset)) = (txS1)slot->value.integer; |
3290 | 20.6k | mxMeterOne(); |
3291 | 20.6k | } |
3292 | | |
3293 | | int fxInt16Compare(const void* p, const void* q) |
3294 | 0 | { |
3295 | 0 | txS2 a = *((txS2*)p); |
3296 | 0 | txS2 b = *((txS2*)q); |
3297 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3298 | 0 | } |
3299 | | |
3300 | | void fxInt16Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3301 | 850k | { |
3302 | 850k | txS2 value; |
3303 | 850k | slot->kind = XS_INTEGER_KIND; |
3304 | | #ifdef mxMisalignedSettersCrash |
3305 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3306 | | #else |
3307 | 850k | value = *((txS2*)(data->value.arrayBuffer.address + offset)); |
3308 | 850k | #endif |
3309 | 850k | slot->value.integer = IMPORT(S16); |
3310 | 850k | mxMeterOne(); |
3311 | 850k | } |
3312 | | |
3313 | | void fxInt16Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3314 | 1.22k | { |
3315 | 1.22k | txS2 value = (txS2)slot->value.integer; |
3316 | | #ifdef mxMisalignedSettersCrash |
3317 | | value = EXPORT(S16); |
3318 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txS2)); |
3319 | | #else |
3320 | 1.22k | *((txS2*)(data->value.arrayBuffer.address + offset)) = EXPORT(S16); |
3321 | 1.22k | #endif |
3322 | 1.22k | mxMeterOne(); |
3323 | 1.22k | } |
3324 | | |
3325 | | int fxInt32Compare(const void* p, const void* q) |
3326 | 0 | { |
3327 | 0 | txS4 a = *((txS4*)p); |
3328 | 0 | txS4 b = *((txS4*)q); |
3329 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3330 | 0 | } |
3331 | | |
3332 | | void fxInt32Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3333 | 2.62M | { |
3334 | 2.62M | txS4 value; |
3335 | 2.62M | slot->kind = XS_INTEGER_KIND; |
3336 | | #ifdef mxMisalignedSettersCrash |
3337 | | value = c_read32(data->value.arrayBuffer.address + offset); |
3338 | | #else |
3339 | 2.62M | value = *((txS4*)(data->value.arrayBuffer.address + offset)); |
3340 | 2.62M | #endif |
3341 | 2.62M | slot->value.integer = IMPORT(S32); |
3342 | 2.62M | mxMeterOne(); |
3343 | 2.62M | } |
3344 | | |
3345 | | void fxInt32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3346 | 373 | { |
3347 | 373 | txS4 value = (txS4)slot->value.integer; |
3348 | | #ifdef mxMisalignedSettersCrash |
3349 | | value = EXPORT(S32); |
3350 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txS4)); |
3351 | | #else |
3352 | 373 | *((txS4*)(data->value.arrayBuffer.address + offset)) = EXPORT(S32); |
3353 | 373 | #endif |
3354 | 373 | mxMeterOne(); |
3355 | 373 | } |
3356 | | |
3357 | | int fxUint8Compare(const void* p, const void* q) |
3358 | 0 | { |
3359 | 0 | txU1 a = c_read8((txU1*)p); |
3360 | 0 | txU1 b = c_read8((txU1*)q); |
3361 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3362 | 0 | } |
3363 | | |
3364 | | void fxUint8Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3365 | 2.90k | { |
3366 | 2.90k | slot->kind = XS_INTEGER_KIND; |
3367 | 2.90k | slot->value.integer = c_read8((txU1*)(data->value.arrayBuffer.address + offset)); |
3368 | 2.90k | mxMeterOne(); |
3369 | 2.90k | } |
3370 | | |
3371 | | void fxUint8Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3372 | 75.1k | { |
3373 | 75.1k | txUnsigned tmp = (slot->kind == XS_INTEGER_KIND) ? (txUnsigned)slot->value.integer : (txUnsigned)slot->value.number; |
3374 | 75.1k | *((txU1*)(data->value.arrayBuffer.address + offset)) = (txU1)tmp; |
3375 | 75.1k | mxMeterOne(); |
3376 | 75.1k | } |
3377 | | |
3378 | | int fxUint16Compare(const void* p, const void* q) |
3379 | 505k | { |
3380 | 505k | txU2 a = *((txU2*)p); |
3381 | 505k | txU2 b = *((txU2*)q); |
3382 | 505k | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3383 | 505k | } |
3384 | | |
3385 | | void fxUint16Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3386 | 4.43M | { |
3387 | 4.43M | txU2 value; |
3388 | 4.43M | slot->kind = XS_INTEGER_KIND; |
3389 | | #ifdef mxMisalignedSettersCrash |
3390 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3391 | | #else |
3392 | 4.43M | value = *((txU2*)(data->value.arrayBuffer.address + offset)); |
3393 | 4.43M | #endif |
3394 | 4.43M | slot->value.integer = IMPORT(U16); |
3395 | 4.43M | mxMeterOne(); |
3396 | 4.43M | } |
3397 | | |
3398 | | void fxUint16Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3399 | 207k | { |
3400 | 207k | txUnsigned tmp = (slot->kind == XS_INTEGER_KIND) ? (txUnsigned)slot->value.integer : (txUnsigned)slot->value.number; |
3401 | 207k | txU2 value = (txU2)tmp; |
3402 | | #ifdef mxMisalignedSettersCrash |
3403 | | value = EXPORT(U16); |
3404 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txU2)); |
3405 | | #else |
3406 | 207k | *((txU2*)(data->value.arrayBuffer.address + offset)) = EXPORT(U16); |
3407 | 207k | #endif |
3408 | 207k | mxMeterOne(); |
3409 | 207k | } |
3410 | | |
3411 | | int fxUint32Compare(const void* p, const void* q) |
3412 | 0 | { |
3413 | 0 | txU4 a = *((txU4*)p); |
3414 | 0 | txU4 b = *((txU4*)q); |
3415 | 0 | return (a < b) ? -1 : (a > b) ? 1 : 0; |
3416 | 0 | } |
3417 | | |
3418 | | void fxUint32Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3419 | 72.4k | { |
3420 | | #ifdef mxMisalignedSettersCrash |
3421 | | txUnsigned value = c_read32(data->value.arrayBuffer.address + offset); |
3422 | | #else |
3423 | 72.4k | txUnsigned value = *((txU4*)(data->value.arrayBuffer.address + offset)); |
3424 | 72.4k | #endif |
3425 | 72.4k | value = IMPORT(U32); |
3426 | 72.4k | if (((txInteger)value) >= 0) { |
3427 | 70.6k | slot->kind = XS_INTEGER_KIND; |
3428 | 70.6k | slot->value.integer = value; |
3429 | 70.6k | } |
3430 | 1.78k | else { |
3431 | 1.78k | slot->kind = XS_NUMBER_KIND; |
3432 | 1.78k | slot->value.number = value; |
3433 | 1.78k | } |
3434 | 72.4k | mxMeterOne(); |
3435 | 72.4k | } |
3436 | | |
3437 | | void fxUint32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3438 | 202k | { |
3439 | 202k | txU4 value = (slot->kind == XS_INTEGER_KIND) ? (txU4)slot->value.integer : (txU4)slot->value.number; |
3440 | | #ifdef mxMisalignedSettersCrash |
3441 | | value = EXPORT(U32); |
3442 | | c_memcpy(data->value.arrayBuffer.address + offset, &value, sizeof(txU4)); |
3443 | | #else |
3444 | 202k | *((txU4*)(data->value.arrayBuffer.address + offset)) = EXPORT(U32); |
3445 | 202k | #endif |
3446 | 202k | mxMeterOne(); |
3447 | 202k | } |
3448 | | |
3449 | | void fxUint8ClampedSetter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3450 | 22 | { |
3451 | 22 | txNumber value = fxToNumber(the, slot); |
3452 | 22 | if (value <= 0) |
3453 | 2 | value = 0; |
3454 | 20 | else if (value >= 255) |
3455 | 11 | value = 255; |
3456 | 9 | else if (c_isnan(value)) |
3457 | 3 | value = 0; |
3458 | 6 | else |
3459 | 6 | value = c_nearbyint(value); |
3460 | 22 | *((txU1*)(data->value.arrayBuffer.address + offset)) = (txU1)value; |
3461 | 22 | mxMeterOne(); |
3462 | 22 | } |
3463 | | |
3464 | | #if mxUint8ArrayBase64 |
3465 | | |
3466 | | static const char gxBase64Alphabet[] ICACHE_FLASH_ATTR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
3467 | | static const char gxBase64URLAlphabet[] ICACHE_FLASH_ATTR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
3468 | | static const char gxHexAlphabet[] ICACHE_FLASH_ATTR = "0123456789abcdef"; |
3469 | | |
3470 | | enum { |
3471 | | mxBase64Loose, |
3472 | | mxBase64StopBeforePartial, |
3473 | | mxBase64Strict, |
3474 | | }; |
3475 | | |
3476 | | static txU1 fxSkipAsciiWhitespace(txU1** src) |
3477 | 1.30M | { |
3478 | 1.30M | txU1* p = *src; |
3479 | 1.30M | txU1 c; |
3480 | 1.99M | while ((c = c_read8(p))) { |
3481 | 1.88M | if ((c != 0x09) && (c != 0x0A) && (c != 0x0C) && (c != 0x0D) && (c != 0x20)) |
3482 | 1.19M | break; |
3483 | 693k | p++; |
3484 | 693k | } |
3485 | 1.30M | *src = p; |
3486 | 1.30M | return c; |
3487 | 1.30M | } |
3488 | | |
3489 | | static void fxUint8ArrayFromBase64(txMachine* the, txU1* srcStart, txU1* dstStart, txSize* read, txSize* written, txU1* alphabet, txInteger lastChunkHandling) |
3490 | 414k | { |
3491 | 414k | txU1* src = srcStart; |
3492 | 414k | txU1* dst = dstStart; |
3493 | 414k | txSize remaining = *written; |
3494 | 414k | txBoolean url = (alphabet == (txU1*)gxBase64URLAlphabet) ? 1 : 0, done = 0; |
3495 | 414k | txU1 byte, buffer[4]; |
3496 | 414k | txSize bufferIndex, bufferLength = 0; |
3497 | | |
3498 | 414k | if (remaining == 0) { |
3499 | 381 | *read = 0; |
3500 | 381 | return; |
3501 | 381 | } |
3502 | 1.26M | for (;;) { |
3503 | 1.26M | byte = fxSkipAsciiWhitespace(&src); |
3504 | 1.26M | if (byte == 0) { |
3505 | 112k | if (bufferLength == 0) |
3506 | 6.05k | break; |
3507 | 106k | if (lastChunkHandling == mxBase64StopBeforePartial) |
3508 | 16 | break; |
3509 | 106k | if ((lastChunkHandling == mxBase64Strict) || (bufferLength == 1)) |
3510 | 103k | mxSyntaxError("invalid string"); |
3511 | 2.48k | if (bufferLength == 2) |
3512 | 1.14k | buffer[2] = 0; |
3513 | 2.48k | buffer[3] = 0; |
3514 | 2.48k | done = 1; |
3515 | 2.48k | } |
3516 | 1.15M | else if (byte == '=') { |
3517 | 74.8k | if (bufferLength < 2) |
3518 | 51.7k | mxSyntaxError("invalid string"); |
3519 | 23.1k | src++; |
3520 | 23.1k | byte = fxSkipAsciiWhitespace(&src); |
3521 | 23.1k | if (bufferLength == 2) { |
3522 | 21.7k | if (byte == 0) { |
3523 | 529 | if (lastChunkHandling == mxBase64StopBeforePartial) |
3524 | 8 | break; |
3525 | 529 | mxSyntaxError("invalid string"); |
3526 | 529 | } |
3527 | 21.2k | if (byte == '=') { |
3528 | 13.7k | src++; |
3529 | 13.7k | byte = fxSkipAsciiWhitespace(&src); |
3530 | 13.7k | } |
3531 | 21.2k | buffer[2] = 0; |
3532 | 21.2k | } |
3533 | 22.6k | if (byte != 0) |
3534 | 22.1k | mxSyntaxError("invalid string"); |
3535 | 454 | buffer[3] = 0; |
3536 | 454 | done = 1; |
3537 | 454 | } |
3538 | 1.08M | else { |
3539 | 1.08M | if (('A' <= byte) && (byte <= 'Z')) |
3540 | 162k | byte = byte - 'A'; |
3541 | 918k | else if (('a' <= byte) && (byte <= 'z')) |
3542 | 246k | byte = byte - 'a' + 26; |
3543 | 672k | else if (('0' <= byte) && (byte <= '9')) |
3544 | 295k | byte = byte - '0' + 52; |
3545 | 376k | else if ((byte == '+') && !url) |
3546 | 107k | byte = 62; |
3547 | 268k | else if ((byte == '-') && url) |
3548 | 1 | byte = 62; |
3549 | 268k | else if ((byte == '/') && !url) |
3550 | 42.2k | byte = 63; |
3551 | 226k | else if ((byte == '_') && url) |
3552 | 1 | byte = 63; |
3553 | 226k | else |
3554 | 226k | mxSyntaxError("invalid string"); |
3555 | 854k | if (((remaining == 1) && (bufferLength == 2)) || ((remaining == 2) && (bufferLength == 3))) |
3556 | 49 | break; |
3557 | 854k | buffer[bufferLength] = byte; |
3558 | 854k | bufferLength++; |
3559 | 854k | src++; |
3560 | 854k | if (bufferLength < 4) |
3561 | 741k | continue; |
3562 | 854k | } |
3563 | 116k | *read = (txSize)(src - srcStart); |
3564 | 116k | buffer[0] = (buffer[0] << 2) | ((buffer[1] & 0x30) >> 4); |
3565 | 116k | buffer[1] = ((buffer[1] & 0x0F) << 4) | ((buffer[2] & 0x3C) >> 2); |
3566 | 116k | buffer[2] = ((buffer[2] & 0x03) << 6) | (buffer[3] & 0x3F); |
3567 | 116k | bufferLength--; |
3568 | 116k | if ((lastChunkHandling == mxBase64Strict) && (bufferLength < 3) && (buffer[bufferLength] != 0)) |
3569 | 0 | mxSyntaxError("invalid string"); |
3570 | 116k | bufferIndex = 0; |
3571 | 463k | while ((bufferIndex < bufferLength) && (remaining > 0)) { |
3572 | 346k | *dst++ = buffer[bufferIndex]; |
3573 | 346k | bufferIndex++; |
3574 | 346k | remaining--; |
3575 | 346k | } |
3576 | 116k | bufferLength = 0; |
3577 | 116k | if ((done) || (remaining == 0)) |
3578 | 3.31k | break; |
3579 | 116k | } |
3580 | 9.44k | *written = (txSize)(dst - dstStart); |
3581 | 9.44k | } |
3582 | | |
3583 | | static void fxUint8ArrayFromHex(txMachine* the, txU1* srcStart, txU1* dstStart, txSize* read, txSize* written) |
3584 | 1.37k | { |
3585 | 1.37k | #define mxFromHex(X) \ |
3586 | 11.9k | if (('0' <= X) && (X <= '9')) X = X - '0'; \ |
3587 | 11.9k | else if (('A' <= X) && (X <= 'F')) X = X - 'A' + 10; \ |
3588 | 11.7k | else if (('a' <= X) && (X <= 'f')) X = X - 'a' + 10; \ |
3589 | 3.33k | else mxSyntaxError("invalid string") |
3590 | | |
3591 | 1.37k | txU1* src = srcStart; |
3592 | 1.37k | txU1* dst = dstStart; |
3593 | 1.37k | txSize srcSize = *read; |
3594 | 1.37k | txSize dstSize = *written; |
3595 | 6.15k | while ((srcSize > 0) && (dstSize > 0)) { |
3596 | 6.13k | txU1 high = c_read8(src++); |
3597 | 6.13k | txU1 low = c_read8(src++); |
3598 | 6.13k | mxFromHex(high); |
3599 | 5.77k | mxFromHex(low); |
3600 | 4.77k | *dst++ = (high << 4) + low; |
3601 | 4.77k | srcSize -= 2; |
3602 | 4.77k | dstSize--; |
3603 | 4.77k | } |
3604 | 21 | *read = (txSize)(src - srcStart); |
3605 | 21 | *written = (txSize)(dst - dstStart); |
3606 | 21 | } |
3607 | | |
3608 | | static void fxUint8ArrayGetBase64Options(txMachine* the, txInteger argi, txU1** alphabet, txInteger* lastChunkHandling, txBoolean* omitPadding) |
3609 | 415k | { |
3610 | 415k | if ((mxArgc > argi) && !mxIsUndefined(mxArgv(argi))) { |
3611 | 1.29k | if (!mxIsReference(mxArgv(argi))) |
3612 | 1 | mxTypeError("options: not an object"); |
3613 | 1.29k | mxPushSlot(mxArgv(argi)); |
3614 | 1.29k | mxGetID(mxID(_alphabet)); |
3615 | 1.29k | if (!mxIsUndefined(the->stack)) { |
3616 | 57 | if (!mxIsStringPrimitive(the->stack)) |
3617 | 7 | mxTypeError("options.alphabet: not a string"); |
3618 | 50 | if (!c_strcmp(the->stack->value.string, "base64url")) |
3619 | 40 | *alphabet = (txU1*)gxBase64URLAlphabet; |
3620 | 10 | else if (c_strcmp(the->stack->value.string, "base64")) |
3621 | 6 | mxTypeError("options.alphabet: neither 'base64' nor 'base64url'"); |
3622 | 50 | } |
3623 | 1.27k | mxPop(); |
3624 | 1.27k | if (lastChunkHandling) { |
3625 | 1.17k | mxPushSlot(mxArgv(argi)); |
3626 | 1.17k | mxGetID(mxID(_lastChunkHandling)); |
3627 | 1.17k | if (!mxIsUndefined(the->stack)) { |
3628 | 504 | if (!mxIsStringPrimitive(the->stack)) |
3629 | 11 | mxTypeError("options.lastChunkHandling: not a string"); |
3630 | 493 | if (!c_strcmp(the->stack->value.string, "stop-before-partial")) |
3631 | 219 | *lastChunkHandling = mxBase64StopBeforePartial; |
3632 | 274 | else if (!c_strcmp(the->stack->value.string, "strict")) |
3633 | 38 | *lastChunkHandling = mxBase64Strict; |
3634 | 236 | else if (c_strcmp(the->stack->value.string, "loose")) |
3635 | 185 | mxTypeError("options.lastChunkHandling: neither 'loose' nor 'strict' nor 'stop-before-partial'"); |
3636 | 493 | } |
3637 | 983 | mxPop(); |
3638 | 983 | } |
3639 | 1.08k | if (omitPadding) { |
3640 | 99 | mxPushSlot(mxArgv(argi)); |
3641 | 99 | mxGetID(mxID(_omitPadding)); |
3642 | 99 | fxToBoolean(the, the->stack); |
3643 | 99 | *omitPadding = the->stack->value.boolean; |
3644 | 99 | mxPop(); |
3645 | 99 | } |
3646 | 1.08k | } |
3647 | 415k | } |
3648 | | |
3649 | | void fx_Uint8Array_fromBase64(txMachine* the) |
3650 | 484k | { |
3651 | 484k | txSize srcSize; |
3652 | 484k | txSize dstSize; |
3653 | 484k | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3654 | 484k | txInteger lastChunkHandling = mxBase64Loose; |
3655 | 484k | txU1* src; |
3656 | 484k | txU1* dst; |
3657 | 484k | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3658 | 70.7k | mxTypeError("string: not a string"); |
3659 | 413k | fxUint8ArrayGetBase64Options(the, 1, &alphabet, &lastChunkHandling, NULL); |
3660 | 413k | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3661 | 413k | dstSize = (((srcSize + 3) / 4) * 3); |
3662 | 413k | mxPush(mxUint8ArrayConstructor); |
3663 | 413k | mxNew(); |
3664 | 413k | mxPushInteger(dstSize); |
3665 | 413k | mxRunCount(1); |
3666 | 413k | mxPullSlot(mxResult); |
3667 | 413k | { |
3668 | 413k | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
3669 | 413k | txSlot* resultDispatch = resultInstance->next; \ |
3670 | 413k | txSlot* resultView = resultDispatch->next; \ |
3671 | 413k | txSlot* resultBuffer = resultView->next; \ |
3672 | 413k | src = (txU1*)(mxArgv(0)->value.string); |
3673 | 413k | dst = (txU1*)(resultBuffer->value.reference->next->value.arrayBuffer.address + resultView->value.dataView.offset); |
3674 | 413k | resultBuffer->value.reference->next->next->value.bufferInfo.maxLength = dstSize; |
3675 | 413k | fxUint8ArrayFromBase64(the, src, dst, &srcSize, &dstSize, alphabet, lastChunkHandling); |
3676 | 413k | fxSetArrayBufferLength(the, resultBuffer, dstSize); |
3677 | 413k | resultBuffer->value.reference->next->next->value.bufferInfo.maxLength = -1; |
3678 | 413k | resultView->value.dataView.size = dstSize; |
3679 | 413k | } |
3680 | 413k | } |
3681 | | |
3682 | | void fx_Uint8Array_fromHex(txMachine* the) |
3683 | 1.69k | { |
3684 | 1.69k | txSize srcSize; |
3685 | 1.69k | txSize dstSize; |
3686 | 1.69k | txU1* src; |
3687 | 1.69k | txU1* dst; |
3688 | 1.69k | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3689 | 11 | mxTypeError("string: not a string"); |
3690 | 1.68k | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3691 | 1.68k | if (srcSize & 1) |
3692 | 333 | mxSyntaxError("string: odd length"); |
3693 | 1.35k | dstSize = srcSize >> 1; |
3694 | 1.35k | mxPush(mxUint8ArrayConstructor); |
3695 | 1.35k | mxNew(); |
3696 | 1.35k | mxPushInteger(dstSize); |
3697 | 1.35k | mxRunCount(1); |
3698 | 1.35k | mxPullSlot(mxResult); |
3699 | 1.35k | { |
3700 | 1.35k | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
3701 | 1.35k | txSlot* resultDispatch = resultInstance->next; \ |
3702 | 1.35k | txSlot* resultView = resultDispatch->next; \ |
3703 | 1.35k | txSlot* resultBuffer = resultView->next; \ |
3704 | 1.35k | src = (txU1*)(mxArgv(0)->value.string); |
3705 | 1.35k | dst = (txU1*)(resultBuffer->value.reference->next->value.arrayBuffer.address + resultView->value.dataView.offset); |
3706 | 1.35k | fxUint8ArrayFromHex(the, src, dst, &srcSize, &dstSize); |
3707 | 1.35k | } |
3708 | 1.35k | } |
3709 | | |
3710 | | void fx_Uint8Array_prototype_setFromBase64(txMachine* the) |
3711 | 1.30k | { |
3712 | 1.30k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3713 | 1.30k | txSlot* dispatch = instance->next; |
3714 | 1.30k | txSlot* view = dispatch->next; |
3715 | 1.30k | txSlot* buffer = view->next; |
3716 | 1.30k | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3717 | 1.30k | txInteger lastChunkHandling = mxBase64Loose; |
3718 | 1.30k | txSize srcSize; |
3719 | 1.30k | txSize dstSize; |
3720 | 1.30k | txU1* src; |
3721 | 1.30k | txU1* dst; |
3722 | 1.30k | txSlot* property; |
3723 | 1.30k | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3724 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3725 | 1.30k | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3726 | 100 | mxTypeError("string: not a string"); |
3727 | 1.20k | fxUint8ArrayGetBase64Options(the, 1, &alphabet, &lastChunkHandling, NULL); |
3728 | 1.20k | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3729 | 1.20k | dstSize = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
3730 | 1.20k | src = (txU1*)(mxArgv(0)->value.string); |
3731 | 1.20k | dst = (txU1*)(buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset); |
3732 | 1.20k | fxUint8ArrayFromBase64(the, src, dst, &srcSize, &dstSize, alphabet, lastChunkHandling); |
3733 | 1.20k | mxPush(mxObjectPrototype); |
3734 | 1.20k | property = fxLastProperty(the, fxNewObjectInstance(the)); |
3735 | 1.20k | property = fxNextIntegerProperty(the, property, srcSize, mxID(_read_), XS_NO_FLAG); |
3736 | 1.20k | property = fxNextIntegerProperty(the, property, dstSize, mxID(_written), XS_NO_FLAG); |
3737 | 1.20k | mxPullSlot(mxResult); |
3738 | 1.20k | } |
3739 | | |
3740 | | void fx_Uint8Array_prototype_setFromHex(txMachine* the) |
3741 | 58 | { |
3742 | 58 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3743 | 58 | txSlot* dispatch = instance->next; |
3744 | 58 | txSlot* view = dispatch->next; |
3745 | 58 | txSlot* buffer = view->next; |
3746 | 58 | txSize srcSize; |
3747 | 58 | txSize dstSize; |
3748 | 58 | txU1* src; |
3749 | 58 | txU1* dst; |
3750 | 58 | txSlot* property; |
3751 | 58 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3752 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3753 | 58 | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3754 | 9 | mxTypeError("string: not a string"); |
3755 | 49 | dstSize = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
3756 | 49 | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3757 | 49 | if (srcSize & 1) |
3758 | 26 | mxSyntaxError("string: odd length"); |
3759 | 23 | src = (txU1*)(mxArgv(0)->value.string); |
3760 | 23 | dst = (txU1*)(buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset); |
3761 | 23 | fxUint8ArrayFromHex(the, src, dst, &srcSize, &dstSize); |
3762 | 23 | mxPush(mxObjectPrototype); |
3763 | 23 | property = fxLastProperty(the, fxNewObjectInstance(the)); |
3764 | 23 | property = fxNextIntegerProperty(the, property, srcSize, mxID(_read_), XS_NO_FLAG); |
3765 | 23 | property = fxNextIntegerProperty(the, property, dstSize, mxID(_written), XS_NO_FLAG); |
3766 | 23 | mxPullSlot(mxResult); |
3767 | 23 | } |
3768 | | |
3769 | | void fx_Uint8Array_prototype_toBase64(txMachine* the) |
3770 | 148 | { |
3771 | 148 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3772 | 148 | txSlot* dispatch = instance->next; |
3773 | 148 | txSlot* view = dispatch->next; |
3774 | 148 | txSlot* buffer = view->next; |
3775 | 148 | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3776 | 148 | txBoolean omitPadding = 0; |
3777 | 148 | txU1* src; |
3778 | 148 | txU1* dst; |
3779 | 148 | txSize srcSize; |
3780 | 148 | txSize dstSize; |
3781 | 148 | txU1 a, b, c; |
3782 | 148 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3783 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3784 | 148 | fxUint8ArrayGetBase64Options(the, 0, &alphabet, C_NULL, &omitPadding); |
3785 | 148 | srcSize = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
3786 | 148 | if (srcSize > (((0x7FFFFFFF >> 2) * 3) - 2)) |
3787 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
3788 | 148 | dstSize = (((srcSize + 2) / 3) << 2); |
3789 | 148 | fxStringBuffer(the, mxResult, C_NULL, dstSize); |
3790 | 148 | src = (txU1*)buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
3791 | 148 | dst = (txU1*)mxResult->value.string; |
3792 | 339 | while (srcSize > 2) { |
3793 | 191 | a = c_read8(src++); |
3794 | 191 | b = c_read8(src++); |
3795 | 191 | c = c_read8(src++); |
3796 | 191 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3797 | 191 | *dst++ = c_read8(alphabet + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
3798 | 191 | *dst++ = c_read8(alphabet + (((b & 0xf) << 2) | ((c & 0xc0) >> 6))); |
3799 | 191 | *dst++ = c_read8(alphabet + (c & 0x3f)); |
3800 | 191 | srcSize -= 3; |
3801 | 191 | } |
3802 | 148 | if (srcSize == 2) { |
3803 | 77 | a = c_read8(src++); |
3804 | 77 | b = c_read8(src++); |
3805 | 77 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3806 | 77 | *dst++ = c_read8(alphabet + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
3807 | 77 | *dst++ = c_read8(alphabet + ((b & 0xf) << 2)); |
3808 | 77 | if (!omitPadding) |
3809 | 51 | *dst++ = '='; |
3810 | 77 | } |
3811 | 71 | else if (srcSize == 1) { |
3812 | 31 | a = c_read8(src++); |
3813 | 31 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3814 | 31 | *dst++ = c_read8(alphabet + ((a & 0x3) << 4)); |
3815 | 31 | if (!omitPadding) { |
3816 | 7 | *dst++ = '='; |
3817 | 7 | *dst++ = '='; |
3818 | 7 | } |
3819 | 31 | } |
3820 | 148 | *dst++ = 0; |
3821 | 148 | } |
3822 | | |
3823 | | void fx_Uint8Array_prototype_toHex(txMachine* the) |
3824 | 206 | { |
3825 | 206 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3826 | 206 | txSlot* dispatch = instance->next; |
3827 | 206 | txSlot* view = dispatch->next; |
3828 | 206 | txSlot* buffer = view->next; |
3829 | 206 | txU1* alphabet = (txU1*)gxHexAlphabet; |
3830 | 206 | txU1* src; |
3831 | 206 | txU1* dst; |
3832 | 206 | txSize srcSize; |
3833 | 206 | txSize dstSize; |
3834 | 206 | txU1 a; |
3835 | 206 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3836 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3837 | 206 | srcSize = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
3838 | 206 | if (srcSize > (0x7FFFFFFF >> 1)) |
3839 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
3840 | 206 | dstSize = (srcSize << 1); |
3841 | 206 | fxStringBuffer(the, mxResult, C_NULL, dstSize); |
3842 | 206 | src = (txU1*)buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
3843 | 206 | dst = (txU1*)mxResult->value.string; |
3844 | 468 | while (srcSize > 0) { |
3845 | 262 | a = c_read8(src++); |
3846 | 262 | *dst++ = c_read8(alphabet + ((a & 0xf0) >> 4)); |
3847 | 262 | *dst++ = c_read8(alphabet + (a & 0x0f)); |
3848 | 262 | srcSize--; |
3849 | 262 | } |
3850 | 206 | *dst++ = 0; |
3851 | 206 | } |
3852 | | |
3853 | | #endif |