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