/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 | 589k | { |
90 | 589k | txSlot* instance; |
91 | 589k | txSlot* arrayBuffer; |
92 | 589k | txSlot* bufferInfo; |
93 | 589k | if (byteLength < 0) |
94 | 0 | mxRangeError("invalid byteLength %ld", byteLength); |
95 | 589k | mxPush(mxArrayBufferPrototype); |
96 | 589k | instance = fxNewArrayBufferInstance(the); |
97 | 589k | arrayBuffer = instance->next; |
98 | 589k | arrayBuffer->value.arrayBuffer.address = fxNewChunk(the, byteLength); |
99 | 589k | bufferInfo = arrayBuffer->next; |
100 | 589k | bufferInfo->value.bufferInfo.length = byteLength; |
101 | 589k | bufferInfo->value.bufferInfo.maxLength = maxByteLength; |
102 | 589k | if (data != NULL) |
103 | 24.8k | c_memcpy(arrayBuffer->value.arrayBuffer.address, data, byteLength); |
104 | 564k | else |
105 | 564k | c_memset(arrayBuffer->value.arrayBuffer.address, 0, byteLength); |
106 | 589k | mxPullSlot(slot); |
107 | 589k | return arrayBuffer->value.arrayBuffer.address; |
108 | 589k | } |
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 | 35.6M | { |
125 | 35.6M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
126 | 35.6M | txSlot* arrayBuffer = instance->next; |
127 | 35.6M | txSlot* bufferInfo = arrayBuffer->next; |
128 | 35.6M | return bufferInfo->value.bufferInfo.length; |
129 | 35.6M | } |
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 | 2.14M | { |
154 | 2.14M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
155 | 2.14M | txSlot* arrayBuffer = instance->next; |
156 | 2.14M | txSlot* bufferInfo = arrayBuffer->next; |
157 | 2.14M | txInteger length = bufferInfo->value.bufferInfo.length; |
158 | 2.14M | txByte* address = arrayBuffer->value.arrayBuffer.address; |
159 | 2.14M | if (bufferInfo->value.bufferInfo.maxLength < 0) |
160 | 0 | fxReport(the, "# Use xsArrayBufferResizable instead of xsArrayBuffer\n"); |
161 | 2.14M | if (length != target) { |
162 | 2.12M | if (address) |
163 | 2.12M | address = (txByte*)fxRenewChunk(the, address, target); |
164 | 2.12M | if (address) { |
165 | 2.12M | if (length < target) |
166 | 2.08M | c_memset(address + length, 0, target - length); |
167 | 2.12M | } |
168 | 326 | else { |
169 | 326 | address = (txByte*)fxNewChunk(the, target); |
170 | 326 | if (length < target) { |
171 | 326 | c_memcpy(address, arrayBuffer->value.arrayBuffer.address, length); |
172 | 326 | c_memset(address + length, 0, target - length); |
173 | 326 | } |
174 | 0 | else |
175 | 0 | c_memcpy(address, arrayBuffer->value.arrayBuffer.address, target); |
176 | 326 | } |
177 | 2.12M | arrayBuffer->value.arrayBuffer.address = address; |
178 | 2.12M | bufferInfo->value.bufferInfo.length = target; |
179 | 2.12M | } |
180 | 2.14M | } |
181 | | |
182 | | void* fxToArrayBuffer(txMachine* the, txSlot* slot) |
183 | 2.64M | { |
184 | 2.64M | txSlot* instance = fxCheckArrayBufferInstance(the, slot); |
185 | 2.64M | txSlot* arrayBuffer = instance->next; |
186 | 2.64M | return arrayBuffer->value.arrayBuffer.address; |
187 | 2.64M | } |
188 | | |
189 | | void fxBuildDataView(txMachine* the) |
190 | 24.8k | { |
191 | 24.8k | txSlot* instance; |
192 | 24.8k | txSlot* slot; |
193 | 24.8k | txInteger index; |
194 | 24.8k | const txTypeDispatch *dispatch; |
195 | 24.8k | const txTypeAtomics *atomics; |
196 | 24.8k | txSlot* property; |
197 | 24.8k | txSlot* constructor; |
198 | | |
199 | 24.8k | mxPush(mxObjectPrototype); |
200 | 24.8k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
201 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_byteLength), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
202 | 24.8k | #if mxECMAScript2023 |
203 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_detached), C_NULL, mxID(_detached), XS_DONT_ENUM_FLAG); |
204 | 24.8k | #endif |
205 | 24.8k | #if mxImmutableArrayBuffers |
206 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_immutable), C_NULL, mxID(_immutable), XS_DONT_ENUM_FLAG); |
207 | 24.8k | #endif |
208 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_maxByteLength), C_NULL, mxID(_maxByteLength), XS_DONT_ENUM_FLAG); |
209 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_get_resizable), C_NULL, mxID(_resizable), XS_DONT_ENUM_FLAG); |
210 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_concat), 1, mxID(_concat), XS_DONT_ENUM_FLAG); |
211 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_resize), 1, mxID(_resize), XS_DONT_ENUM_FLAG); |
212 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG); |
213 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transfer), 0, mxID(_transfer), XS_DONT_ENUM_FLAG); |
214 | 24.8k | #if mxECMAScript2024 |
215 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transferToFixedLength), 0, mxID(_transferToFixedLength), XS_DONT_ENUM_FLAG); |
216 | 24.8k | #endif |
217 | 24.8k | #if mxImmutableArrayBuffers |
218 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_prototype_transferToImmutable), 0, mxID(_transferToImmutable), XS_DONT_ENUM_FLAG); |
219 | 24.8k | #endif |
220 | 24.8k | slot = fxNextStringXProperty(the, slot, "ArrayBuffer", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
221 | 24.8k | mxArrayBufferPrototype = *the->stack; |
222 | 24.8k | slot = fxBuildHostConstructor(the, mxCallback(fx_ArrayBuffer), 1, mxID(_ArrayBuffer)); |
223 | 24.8k | mxArrayBufferConstructor = *the->stack; |
224 | 24.8k | slot = fxLastProperty(the, slot); |
225 | 24.8k | 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 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_ArrayBuffer_isView), 1, mxID(_isView), XS_DONT_ENUM_FLAG); |
230 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG); |
231 | 24.8k | mxPop(); |
232 | | |
233 | 24.8k | mxPush(mxObjectPrototype); |
234 | 24.8k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
235 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getBigInt64), 1, mxID(_getBigInt64), XS_DONT_ENUM_FLAG); |
236 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setBigInt64), 2, mxID(_setBigInt64), XS_DONT_ENUM_FLAG); |
237 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getBigUint64), 1, mxID(_getBigUint64), XS_DONT_ENUM_FLAG); |
238 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setBigUint64), 2, mxID(_setBigUint64), XS_DONT_ENUM_FLAG); |
239 | 24.8k | #if mxFloat16 |
240 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat16), 1, mxID(_getFloat16), XS_DONT_ENUM_FLAG); |
241 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat16), 2, mxID(_setFloat16), XS_DONT_ENUM_FLAG); |
242 | 24.8k | #endif |
243 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat32), 1, mxID(_getFloat32), XS_DONT_ENUM_FLAG); |
244 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat32), 2, mxID(_setFloat32), XS_DONT_ENUM_FLAG); |
245 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getFloat64), 1, mxID(_getFloat64), XS_DONT_ENUM_FLAG); |
246 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setFloat64), 2, mxID(_setFloat64), XS_DONT_ENUM_FLAG); |
247 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt8), 1, mxID(_getInt8), XS_DONT_ENUM_FLAG); |
248 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt8), 2, mxID(_setInt8), XS_DONT_ENUM_FLAG); |
249 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt16), 1, mxID(_getInt16), XS_DONT_ENUM_FLAG); |
250 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt16), 2, mxID(_setInt16), XS_DONT_ENUM_FLAG); |
251 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getInt32), 1, mxID(_getInt32), XS_DONT_ENUM_FLAG); |
252 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setInt32), 2, mxID(_setInt32), XS_DONT_ENUM_FLAG); |
253 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint8), 1, mxID(_getUint8), XS_DONT_ENUM_FLAG); |
254 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint8), 2, mxID(_setUint8), XS_DONT_ENUM_FLAG); |
255 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint16), 1, mxID(_getUint16), XS_DONT_ENUM_FLAG); |
256 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint16), 2, mxID(_setUint16), XS_DONT_ENUM_FLAG); |
257 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_getUint32), 1, mxID(_getUint32), XS_DONT_ENUM_FLAG); |
258 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_DataView_prototype_setUint32), 2, mxID(_setUint32), XS_DONT_ENUM_FLAG); |
259 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_buffer_get), C_NULL, mxID(_buffer), XS_DONT_ENUM_FLAG); |
260 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_byteLength_get), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
261 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_DataView_prototype_byteOffset_get), C_NULL, mxID(_byteOffset), XS_DONT_ENUM_FLAG); |
262 | 24.8k | slot = fxNextStringXProperty(the, slot, "DataView", mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG | XS_DONT_SET_FLAG); |
263 | 24.8k | mxDataViewPrototype = *the->stack; |
264 | 24.8k | slot = fxBuildHostConstructor(the, mxCallback(fx_DataView), 1, mxID(_DataView)); |
265 | 24.8k | mxDataViewConstructor = *the->stack; |
266 | 24.8k | mxPop(); |
267 | | |
268 | 24.8k | mxPush(mxObjectPrototype); |
269 | 24.8k | instance = fxNewObjectInstance(the); |
270 | | |
271 | 24.8k | fxNewHostFunction(the, mxCallback(fxTypedArrayGetter), 0, XS_NO_ID, XS_NO_ID); |
272 | 24.8k | property = mxFunctionInstanceHome(the->stack->value.reference); |
273 | 24.8k | property->value.home.object = instance; |
274 | 24.8k | fxNewHostFunction(the, mxCallback(fxTypedArraySetter), 1, XS_NO_ID, XS_NO_ID); |
275 | 24.8k | property = mxFunctionInstanceHome(the->stack->value.reference); |
276 | 24.8k | property->value.home.object = instance; |
277 | 24.8k | mxPushUndefined(); |
278 | 24.8k | the->stack->flag = XS_DONT_DELETE_FLAG; |
279 | 24.8k | the->stack->kind = XS_ACCESSOR_KIND; |
280 | 24.8k | the->stack->value.accessor.getter = (the->stack + 2)->value.reference; |
281 | 24.8k | the->stack->value.accessor.setter = (the->stack + 1)->value.reference; |
282 | 24.8k | mxPull(mxTypedArrayAccessor); |
283 | 24.8k | mxPop(); |
284 | 24.8k | mxPop(); |
285 | | |
286 | 24.8k | slot = fxLastProperty(the, instance); |
287 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_at), 1, mxID(_at), XS_DONT_ENUM_FLAG); |
288 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_buffer_get), C_NULL, mxID(_buffer), XS_DONT_ENUM_FLAG); |
289 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_byteLength_get), C_NULL, mxID(_byteLength), XS_DONT_ENUM_FLAG); |
290 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_byteOffset_get), C_NULL, mxID(_byteOffset), XS_DONT_ENUM_FLAG); |
291 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_length_get), C_NULL, mxID(_length), XS_DONT_ENUM_FLAG); |
292 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_TypedArray_prototype_toStringTag_get), C_NULL, mxID(_Symbol_toStringTag), XS_DONT_ENUM_FLAG); |
293 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_copyWithin), 2, mxID(_copyWithin), XS_DONT_ENUM_FLAG); |
294 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_entries), 0, mxID(_entries), XS_DONT_ENUM_FLAG); |
295 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_every), 1, mxID(_every), XS_DONT_ENUM_FLAG); |
296 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_fill), 1, mxID(_fill), XS_DONT_ENUM_FLAG); |
297 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_filter), 1, mxID(_filter), XS_DONT_ENUM_FLAG); |
298 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_find), 1, mxID(_find), XS_DONT_ENUM_FLAG); |
299 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findIndex), 1, mxID(_findIndex), XS_DONT_ENUM_FLAG); |
300 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findLast), 1, mxID(_findLast), XS_DONT_ENUM_FLAG); |
301 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_findLastIndex), 1, mxID(_findLastIndex), XS_DONT_ENUM_FLAG); |
302 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_forEach), 1, mxID(_forEach), XS_DONT_ENUM_FLAG); |
303 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_includes), 1, mxID(_includes), XS_DONT_ENUM_FLAG); |
304 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_indexOf), 1, mxID(_indexOf), XS_DONT_ENUM_FLAG); |
305 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_join), 1, mxID(_join), XS_DONT_ENUM_FLAG); |
306 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_keys), 0, mxID(_keys), XS_DONT_ENUM_FLAG); |
307 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_lastIndexOf), 1, mxID(_lastIndexOf), XS_DONT_ENUM_FLAG); |
308 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_map), 1, mxID(_map), XS_DONT_ENUM_FLAG); |
309 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reduce), 1, mxID(_reduce), XS_DONT_ENUM_FLAG); |
310 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reduceRight), 1, mxID(_reduceRight), XS_DONT_ENUM_FLAG); |
311 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_reverse), 0, mxID(_reverse), XS_DONT_ENUM_FLAG); |
312 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_set), 1, mxID(_set), XS_DONT_ENUM_FLAG); |
313 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_slice), 2, mxID(_slice), XS_DONT_ENUM_FLAG); |
314 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_some), 1, mxID(_some), XS_DONT_ENUM_FLAG); |
315 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_sort), 1, mxID(_sort), XS_DONT_ENUM_FLAG); |
316 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_subarray), 2, mxID(_subarray), XS_DONT_ENUM_FLAG); |
317 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toLocaleString), 0, mxID(_toLocaleString), XS_DONT_ENUM_FLAG); |
318 | 24.8k | property = mxBehaviorGetProperty(the, mxArrayPrototype.value.reference, mxID(_toString), 0, XS_OWN); |
319 | 24.8k | slot = fxNextSlotProperty(the, slot, property, mxID(_toString), XS_DONT_ENUM_FLAG); |
320 | 24.8k | property = slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_values), 0, mxID(_values), XS_DONT_ENUM_FLAG); |
321 | 24.8k | slot = fxNextSlotProperty(the, slot, property, mxID(_Symbol_iterator), XS_DONT_ENUM_FLAG); |
322 | 24.8k | #if mxECMAScript2023 |
323 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toReversed), 0, mxID(_toReversed), XS_DONT_ENUM_FLAG); |
324 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_toSorted), 1, mxID(_toSorted), XS_DONT_ENUM_FLAG); |
325 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_prototype_with), 2, mxID(_with), XS_DONT_ENUM_FLAG); |
326 | 24.8k | #endif |
327 | 24.8k | mxTypedArrayPrototype = *the->stack; |
328 | 24.8k | constructor = fxBuildHostConstructor(the, mxCallback(fx_TypedArray), 0, mxID(_TypedArray)); |
329 | 24.8k | mxTypedArrayConstructor = *the->stack; |
330 | 24.8k | slot = fxLastProperty(the, constructor); |
331 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_from), 1, mxID(_from), XS_DONT_ENUM_FLAG); |
332 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_TypedArray_of), 0, mxID(_of), XS_DONT_ENUM_FLAG); |
333 | 24.8k | slot = fxNextHostAccessorProperty(the, slot, mxCallback(fx_species_get), C_NULL, mxID(_Symbol_species), XS_DONT_ENUM_FLAG); |
334 | 323k | for (index = 0, dispatch = &gxTypeDispatches[0], atomics = &gxTypeAtomics[0]; index < mxTypeArrayCount; index++, dispatch++, atomics++) { |
335 | 298k | mxPush(mxTypedArrayPrototype); |
336 | 298k | slot = fxLastProperty(the, fxNewObjectInstance(the)); |
337 | 298k | slot = fxNextIntegerProperty(the, slot, dispatch->size, mxID(_BYTES_PER_ELEMENT), XS_GET_ONLY); |
338 | 298k | slot = fxBuildHostConstructor(the, mxCallback(fx_TypedArray), 3, mxID(dispatch->constructorID)); |
339 | 298k | the->stackIntrinsics[-1 - (txInteger)dispatch->constructorID] = *the->stack; //@@ |
340 | 298k | slot->value.instance.prototype = constructor; |
341 | 298k | property = mxFunctionInstanceHome(slot); |
342 | 298k | slot = property->next; |
343 | 298k | property = fxNextTypeDispatchProperty(the, property, (txTypeDispatch*)dispatch, (txTypeAtomics*)atomics, XS_NO_ID, XS_INTERNAL_FLAG); |
344 | 298k | property->next = slot; |
345 | 298k | slot = fxLastProperty(the, slot); |
346 | 298k | slot = fxNextIntegerProperty(the, slot, dispatch->size, mxID(_BYTES_PER_ELEMENT), XS_GET_ONLY); |
347 | 298k | mxPop(); |
348 | 298k | } |
349 | 24.8k | mxPop(); |
350 | | |
351 | 24.8k | #if mxUint8ArrayBase64 |
352 | 24.8k | mxPush(mxUint8ArrayConstructor); |
353 | 24.8k | instance = fxToInstance(the, the->stack); |
354 | 24.8k | slot = fxLastProperty(the, instance); |
355 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_fromBase64), 1, mxID(_fromBase64), XS_DONT_ENUM_FLAG); |
356 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_fromHex), 1, mxID(_fromHex), XS_DONT_ENUM_FLAG); |
357 | 24.8k | mxGetID(mxID(_prototype)); |
358 | 24.8k | instance = fxToInstance(the, the->stack); |
359 | 24.8k | slot = fxLastProperty(the, instance); |
360 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_setFromBase64), 1, mxID(_setFromBase64), XS_DONT_ENUM_FLAG); |
361 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_setFromHex), 1, mxID(_setFromHex), XS_DONT_ENUM_FLAG); |
362 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_toBase64), 0, mxID(_toBase64), XS_DONT_ENUM_FLAG); |
363 | 24.8k | slot = fxNextHostFunctionProperty(the, slot, mxCallback(fx_Uint8Array_prototype_toHex), 0, mxID(_toHex), XS_DONT_ENUM_FLAG); |
364 | 24.8k | mxPop(); |
365 | 24.8k | #endif |
366 | 24.8k | } |
367 | | |
368 | | txInteger fxArgToByteLength(txMachine* the, txInteger argi, txInteger length) |
369 | 336k | { |
370 | 336k | txSlot *arg = mxArgv(argi); |
371 | 336k | if ((mxArgc > argi) && (arg->kind != XS_UNDEFINED_KIND)) { |
372 | 334k | txNumber value; |
373 | 334k | if (XS_INTEGER_KIND == arg->kind) { |
374 | 311k | txInteger value = arg->value.integer; |
375 | 311k | if (value < 0) |
376 | 27 | mxRangeError("byteLength < 0"); |
377 | 311k | return value; |
378 | 311k | } |
379 | 22.4k | value = c_trunc(fxToNumber(the, arg)); |
380 | 22.4k | if (c_isnan(value)) |
381 | 834 | return 0; |
382 | 21.6k | if (value < 0) |
383 | 27 | mxRangeError("byteLength < 0"); |
384 | 21.6k | if (0x7FFFFFFF < value) |
385 | 31 | mxRangeError("byteLength too big"); |
386 | 21.5k | return (txInteger)value; |
387 | 21.6k | } |
388 | 1.90k | return length; |
389 | 336k | } |
390 | | |
391 | | txS8 fxArgToSafeByteLength(txMachine* the, txInteger argi, txInteger length) |
392 | 413k | { |
393 | 413k | txSlot *arg = mxArgv(argi); |
394 | 413k | if ((mxArgc > argi) && (arg->kind != XS_UNDEFINED_KIND)) { |
395 | 412k | txNumber value; |
396 | 412k | if (XS_INTEGER_KIND == arg->kind) { |
397 | 334k | txS8 value = arg->value.integer; |
398 | 334k | if (value < 0) |
399 | 6 | mxRangeError("byteLength < 0"); |
400 | 334k | return value; |
401 | 334k | } |
402 | 78.4k | value = c_trunc(fxToNumber(the, arg)); |
403 | 78.4k | if (c_isnan(value)) |
404 | 12 | return 0; |
405 | 78.4k | if (value < 0) |
406 | 6 | mxRangeError("byteLength < 0"); |
407 | 78.4k | if (C_MAX_SAFE_INTEGER < value) |
408 | 3 | mxRangeError("byteLength too big"); |
409 | 78.4k | return (txS8)value; |
410 | 78.4k | } |
411 | 112 | return length; |
412 | 413k | } |
413 | | |
414 | | txSlot* fxArgToInstance(txMachine* the, txInteger i) |
415 | 8 | { |
416 | 8 | if (mxArgc > i) |
417 | 8 | return fxToInstance(the, mxArgv(i)); |
418 | 8 | mxTypeError("cannot coerce undefined to object"); |
419 | 0 | return C_NULL; |
420 | 8 | } |
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 | 78.9k | { |
435 | 78.9k | slot = slot->value.reference->next; |
436 | 78.9k | if (slot->value.arrayBuffer.address == C_NULL) |
437 | 5 | mxTypeError("detached buffer"); |
438 | 78.9k | if (mutable && (slot->flag & XS_DONT_SET_FLAG)) |
439 | 0 | mxTypeError("ArrayBuffer instance is read-only"); |
440 | 78.9k | return slot; |
441 | 78.9k | } |
442 | | |
443 | | txSlot* fxCheckArrayBufferInstance(txMachine* the, txSlot* slot) |
444 | 40.4M | { |
445 | 40.4M | if (slot->kind == XS_REFERENCE_KIND) { |
446 | 40.4M | txSlot* instance = slot->value.reference; |
447 | 40.4M | txSlot* arrayBuffer = instance->next; |
448 | 40.4M | if (arrayBuffer && (arrayBuffer->flag & XS_INTERNAL_FLAG) && (arrayBuffer->kind == XS_ARRAY_BUFFER_KIND)) |
449 | 40.4M | return instance; |
450 | 40.4M | } |
451 | 173 | if (slot == mxThis) |
452 | 173 | mxTypeError("this: not an ArrayBuffer instance"); |
453 | 173 | mxTypeError("not an ArrayBuffer instance"); |
454 | 0 | return C_NULL; |
455 | 173 | } |
456 | | |
457 | | void fxConstructArrayBufferResult(txMachine* the, txSlot* constructor, txInteger length) |
458 | 21.1k | { |
459 | 21.1k | txSlot* instance; |
460 | 21.1k | if (constructor) |
461 | 21.0k | mxPushSlot(constructor); |
462 | 53 | else { |
463 | 53 | mxPushSlot(mxThis); |
464 | 53 | mxGetID(mxID(_constructor)); |
465 | 53 | } |
466 | 21.1k | fxToSpeciesConstructor(the, &mxArrayBufferConstructor); |
467 | 21.1k | mxNew(); |
468 | 21.1k | mxPushInteger(length); |
469 | 21.1k | mxRunCount(1); |
470 | 21.1k | if (the->stack->kind != XS_REFERENCE_KIND) |
471 | 0 | mxTypeError("not an object"); |
472 | 21.1k | instance = the->stack->value.reference; |
473 | 21.1k | if (!(instance->next) || (instance->next->kind != XS_ARRAY_BUFFER_KIND)) |
474 | 2 | mxTypeError("not an ArrayBuffer instance"); |
475 | 21.1k | if (!constructor && (mxThis->value.reference == instance)) |
476 | 1 | mxTypeError("same ArrayBuffer instance"); |
477 | 21.1k | if (instance->next->next->value.bufferInfo.length < length) |
478 | 1 | mxTypeError("smaller ArrayBuffer instance"); |
479 | 21.1k | mxPullSlot(mxResult); |
480 | 21.1k | } |
481 | | |
482 | | txSlot* fxNewArrayBufferInstance(txMachine* the) |
483 | 1.00M | { |
484 | 1.00M | txSlot* instance; |
485 | 1.00M | txSlot* property; |
486 | 1.00M | instance = fxNewObjectInstance(the); |
487 | 1.00M | property = instance->next = fxNewSlot(the); |
488 | 1.00M | property->flag = XS_INTERNAL_FLAG; |
489 | 1.00M | property->kind = XS_ARRAY_BUFFER_KIND; |
490 | 1.00M | property->value.arrayBuffer.address = C_NULL; |
491 | 1.00M | property->value.arrayBuffer.detachKey = C_NULL; |
492 | 1.00M | property = property->next = fxNewSlot(the); |
493 | 1.00M | property->flag = XS_INTERNAL_FLAG; |
494 | 1.00M | property->kind = XS_BUFFER_INFO_KIND; |
495 | 1.00M | property->value.bufferInfo.length = 0; |
496 | 1.00M | property->value.bufferInfo.maxLength = -1; |
497 | 1.00M | return instance; |
498 | 1.00M | } |
499 | | |
500 | | void fx_ArrayBuffer(txMachine* the) |
501 | 410k | { |
502 | 410k | txSlot* instance; |
503 | 410k | txS8 byteLength; |
504 | 410k | txS8 maxByteLength = -1; |
505 | 410k | txSlot* property; |
506 | 410k | if (mxIsUndefined(mxTarget)) |
507 | 3 | mxTypeError("call: ArrayBuffer"); |
508 | 410k | byteLength = fxArgToSafeByteLength(the, 0, 0); |
509 | 410k | if ((mxArgc > 1) && mxIsReference(mxArgv(1))) { |
510 | 186 | mxPushSlot(mxArgv(1)); |
511 | 186 | mxGetID(mxID(_maxByteLength)); |
512 | 186 | mxPullSlot(mxArgv(1)); |
513 | 186 | maxByteLength = fxArgToSafeByteLength(the, 1, -1); |
514 | 186 | } |
515 | 410k | if (maxByteLength >= 0) { |
516 | 97 | if (byteLength > maxByteLength) |
517 | 2 | mxRangeError("byteLength > maxByteLength"); |
518 | 97 | } |
519 | 410k | mxPushSlot(mxTarget); |
520 | 410k | fxGetPrototypeFromConstructor(the, &mxArrayBufferPrototype); |
521 | 410k | instance = fxNewArrayBufferInstance(the); |
522 | 410k | mxPullSlot(mxResult); |
523 | 410k | if (byteLength > 0x7FFFFFFF) |
524 | 6 | mxRangeError("byteLength too big"); |
525 | 410k | if (maxByteLength > 0x7FFFFFFF) |
526 | 8 | mxRangeError("maxByteLength too big"); |
527 | 410k | property = instance->next; |
528 | 410k | property->value.arrayBuffer.address = fxNewChunk(the, (txSize)byteLength); |
529 | 410k | c_memset(property->value.arrayBuffer.address, 0, (txSize)byteLength); |
530 | 410k | property = property->next; |
531 | 410k | property->value.bufferInfo.length = (txSize)byteLength; |
532 | 410k | property->value.bufferInfo.maxLength = (txSize)maxByteLength; |
533 | 410k | } |
534 | | |
535 | | void fx_ArrayBuffer_fromBigInt(txMachine* the) |
536 | 21.0k | { |
537 | 21.0k | txU4 minBytes = 0; |
538 | 21.0k | txBoolean sign = 0; |
539 | 21.0k | int endian = EndianBig; |
540 | 21.0k | if (mxArgc < 1) |
541 | 0 | mxTypeError("no argument"); |
542 | 21.0k | if (mxArgc > 1) |
543 | 21.0k | minBytes = (txU4)fxArgToByteLength(the, 1, 0); |
544 | 21.0k | if ((mxArgc > 2) && fxToBoolean(the, mxArgv(2))) |
545 | 2 | sign = 1; |
546 | 21.0k | if ((mxArgc > 3) && fxToBoolean(the, mxArgv(3))) |
547 | 1 | endian = EndianLittle; |
548 | 21.0k | if (gxTypeBigInt.toArrayBuffer) { |
549 | 21.0k | gxTypeBigInt.toArrayBuffer(the, mxArgv(0), minBytes, sign, endian); |
550 | 21.0k | } |
551 | 0 | else { |
552 | 0 | mxUnknownError("not built-in"); |
553 | 0 | } |
554 | 21.0k | } |
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 | 52 | { |
594 | 52 | txSlot* slot; |
595 | 52 | mxResult->kind = XS_BOOLEAN_KIND; |
596 | 52 | mxResult->value.boolean = 0; |
597 | 52 | if (mxArgc > 0) { |
598 | 51 | slot = mxArgv(0); |
599 | 51 | 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 | 51 | } |
609 | 52 | } |
610 | | |
611 | | void fx_ArrayBuffer_prototype_get_byteLength(txMachine* the) |
612 | 81 | { |
613 | 81 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
614 | 81 | txSlot* arrayBuffer = instance->next; |
615 | 81 | txSlot* bufferInfo = arrayBuffer->next; |
616 | 81 | mxResult->kind = XS_INTEGER_KIND; |
617 | 81 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
618 | 8 | mxResult->value.integer = 0; |
619 | 73 | else |
620 | 73 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
621 | 81 | } |
622 | | |
623 | | void fx_ArrayBuffer_prototype_get_detached(txMachine* the) |
624 | 19 | { |
625 | 19 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
626 | 19 | txSlot* arrayBuffer = instance->next; |
627 | 19 | mxResult->kind = XS_BOOLEAN_KIND; |
628 | 19 | mxResult->value.boolean = (arrayBuffer->value.arrayBuffer.address == C_NULL) ? 1 : 0; |
629 | 19 | } |
630 | | |
631 | | void fx_ArrayBuffer_prototype_get_immutable(txMachine* the) |
632 | 26 | { |
633 | 26 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
634 | 26 | txSlot* arrayBuffer = instance->next; |
635 | 26 | mxResult->kind = XS_BOOLEAN_KIND; |
636 | 26 | mxResult->value.boolean = (arrayBuffer->flag & XS_DONT_SET_FLAG) ? 1 : 0; |
637 | 26 | } |
638 | | |
639 | | void fx_ArrayBuffer_prototype_get_maxByteLength(txMachine* the) |
640 | 33 | { |
641 | 33 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
642 | 33 | txSlot* arrayBuffer = instance->next; |
643 | 33 | txSlot* bufferInfo = arrayBuffer->next; |
644 | 33 | mxResult->kind = XS_INTEGER_KIND; |
645 | 33 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
646 | 0 | mxResult->value.integer = 0; |
647 | 33 | else if (bufferInfo->value.bufferInfo.maxLength >= 0) |
648 | 6 | mxResult->value.integer = bufferInfo->value.bufferInfo.maxLength; |
649 | 27 | else |
650 | 27 | mxResult->value.integer = bufferInfo->value.bufferInfo.length; |
651 | 33 | } |
652 | | |
653 | | void fx_ArrayBuffer_prototype_get_resizable(txMachine* the) |
654 | 55 | { |
655 | 55 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
656 | 55 | txSlot* arrayBuffer = instance->next; |
657 | 55 | txSlot* bufferInfo = arrayBuffer->next; |
658 | 55 | mxResult->kind = XS_BOOLEAN_KIND; |
659 | 55 | mxResult->value.boolean = (bufferInfo->value.bufferInfo.maxLength >= 0) ? 1 : 0; |
660 | 55 | } |
661 | | |
662 | | void fx_ArrayBuffer_prototype_concat(txMachine* the) |
663 | 2 | { |
664 | 2 | txSlot* instance = fxCheckArrayBufferInstance(the, mxThis); |
665 | 2 | txSlot* arrayBuffer = instance->next; |
666 | 2 | txSlot* bufferInfo = arrayBuffer->next; |
667 | 2 | txInteger length = bufferInfo->value.bufferInfo.length; |
668 | 2 | txInteger c = mxArgc, i = 0; |
669 | 2 | txByte* address; |
670 | 2 | txSlot* slot; |
671 | 2 | while (i < c) { |
672 | 2 | arrayBuffer = C_NULL; |
673 | 2 | bufferInfo = C_NULL; |
674 | 2 | slot = mxArgv(i); |
675 | 2 | if (slot->kind == XS_REFERENCE_KIND) { |
676 | 2 | slot = slot->value.reference->next; |
677 | 2 | 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 | 2 | } |
689 | 2 | if (bufferInfo) |
690 | 0 | length = fxAddChunkSizes(the, length, bufferInfo->value.bufferInfo.length); |
691 | 2 | else |
692 | 2 | mxTypeError("arguments[%ld]: not an ArrayBuffer instance", i); |
693 | 0 | i++; |
694 | 0 | } |
695 | 0 | fxConstructArrayBufferResult(the, C_NULL, length); |
696 | 0 | arrayBuffer = instance->next; |
697 | 0 | bufferInfo = arrayBuffer->next; |
698 | 0 | address = mxResult->value.reference->next->value.arrayBuffer.address; |
699 | 0 | length = bufferInfo->value.bufferInfo.length; |
700 | 0 | c_memcpy(address, arrayBuffer->value.arrayBuffer.address, length); |
701 | 0 | address += length; |
702 | 0 | i = 0; |
703 | 0 | 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 | 0 | } |
715 | | |
716 | | void fx_ArrayBuffer_prototype_resize(txMachine* the) |
717 | 146 | { |
718 | 146 | /* txSlot* instance = */ fxCheckArrayBufferInstance(the, mxThis); |
719 | 146 | txInteger newByteLength = fxArgToByteLength(the, 0, 0); |
720 | 146 | txSlot* arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_MUTABLE); |
721 | 146 | txSlot* bufferInfo = arrayBuffer->next; |
722 | 146 | txInteger maxByteLength, oldByteLength; |
723 | 146 | txByte* chunk; |
724 | 146 | maxByteLength = bufferInfo->value.bufferInfo.maxLength; |
725 | 146 | if (maxByteLength < 0) |
726 | 13 | mxTypeError("not resizable"); |
727 | 133 | oldByteLength = bufferInfo->value.bufferInfo.length; |
728 | 133 | if (newByteLength > maxByteLength) |
729 | 1 | mxRangeError("newLength > maxByteLength"); |
730 | 132 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_MUTABLE); |
731 | 132 | chunk = (txByte*)fxRenewChunk(the, arrayBuffer->value.arrayBuffer.address, newByteLength); |
732 | 132 | if (!chunk) { |
733 | 2 | chunk = (txByte*)fxNewChunk(the, newByteLength); |
734 | 2 | c_memcpy(chunk, arrayBuffer->value.arrayBuffer.address, (newByteLength < oldByteLength) ? newByteLength : oldByteLength); |
735 | 2 | } |
736 | 132 | if (newByteLength > oldByteLength) |
737 | 43 | c_memset(chunk + oldByteLength, 0, newByteLength - oldByteLength); |
738 | 132 | arrayBuffer->value.arrayBuffer.address = chunk; |
739 | 132 | bufferInfo->value.bufferInfo.length = newByteLength; |
740 | 132 | } |
741 | | |
742 | | void fx_ArrayBuffer_prototype_slice(txMachine* the) |
743 | 59 | { |
744 | 59 | /* txSlot* instance = */ fxCheckArrayBufferInstance(the, mxThis); |
745 | 59 | txSlot* arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_IMMUTABLE); |
746 | 59 | txSlot* bufferInfo = arrayBuffer->next; |
747 | 59 | txInteger length = bufferInfo->value.bufferInfo.length; |
748 | 59 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
749 | 59 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
750 | 59 | txSlot* resultBuffer; |
751 | 59 | if (stop < start) |
752 | 6 | stop = start; |
753 | 59 | fxConstructArrayBufferResult(the, C_NULL, stop - start); |
754 | 59 | resultBuffer = fxCheckArrayBufferDetached(the, mxResult, XS_MUTABLE); |
755 | 59 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_IMMUTABLE); |
756 | 59 | bufferInfo = arrayBuffer->next; |
757 | 59 | if (bufferInfo->value.bufferInfo.length < stop) |
758 | 0 | mxTypeError("resized this"); |
759 | 59 | c_memcpy(resultBuffer->value.arrayBuffer.address, arrayBuffer->value.arrayBuffer.address + start, stop - start); |
760 | 59 | } |
761 | | |
762 | | static void fx_ArrayBuffer_prototype_transferAux(txMachine* the, txFlag flag) |
763 | 62 | { |
764 | 62 | /* txSlot* instance = */ fxCheckArrayBufferInstance(the, mxThis); |
765 | 62 | txSlot* arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_MUTABLE); |
766 | 62 | txSlot* bufferInfo = arrayBuffer->next; |
767 | 62 | txInteger oldByteLength = bufferInfo->value.bufferInfo.length; |
768 | 62 | txInteger maxByteLength = bufferInfo->value.bufferInfo.maxLength; |
769 | 62 | txInteger newByteLength = fxArgToByteLength(the, 0, oldByteLength); |
770 | 62 | txSlot* resultBuffer; |
771 | 62 | if ((maxByteLength >= 0) && (newByteLength > maxByteLength)) |
772 | 0 | mxRangeError("newLength > maxByteLength"); |
773 | 62 | fxConstructArrayBufferResult(the, C_NULL, newByteLength); |
774 | 62 | resultBuffer = fxCheckArrayBufferDetached(the, mxResult, XS_MUTABLE); |
775 | 62 | arrayBuffer = fxCheckArrayBufferDetached(the, mxThis, XS_MUTABLE); |
776 | 62 | c_memcpy(resultBuffer->value.arrayBuffer.address, arrayBuffer->value.arrayBuffer.address, (newByteLength < oldByteLength) ? newByteLength : oldByteLength); |
777 | 62 | if (newByteLength > oldByteLength) |
778 | 1 | c_memset(resultBuffer->value.arrayBuffer.address + oldByteLength, 0, newByteLength - oldByteLength); |
779 | 62 | arrayBuffer->value.arrayBuffer.address = C_NULL; |
780 | 62 | bufferInfo->value.bufferInfo.length = 0; |
781 | 62 | if (flag & 2) |
782 | 11 | resultBuffer->flag |= XS_DONT_SET_FLAG; |
783 | 62 | resultBuffer->next->value.bufferInfo.maxLength = (flag & 1) ? -1 : maxByteLength; |
784 | 62 | } |
785 | | |
786 | | void fx_ArrayBuffer_prototype_transfer(txMachine* the) |
787 | 29 | { |
788 | 29 | fx_ArrayBuffer_prototype_transferAux(the, 0); |
789 | 29 | } |
790 | | |
791 | | void fx_ArrayBuffer_prototype_transferToFixedLength(txMachine* the) |
792 | 12 | { |
793 | 12 | fx_ArrayBuffer_prototype_transferAux(the, 1); |
794 | 12 | } |
795 | | |
796 | | void fx_ArrayBuffer_prototype_transferToImmutable(txMachine* the) |
797 | 21 | { |
798 | 21 | fx_ArrayBuffer_prototype_transferAux(the, 3); |
799 | 21 | } |
800 | | |
801 | | txSlot* fxCheckDataViewInstance(txMachine* the, txSlot* slot) |
802 | 3.38k | { |
803 | 3.38k | if (slot->kind == XS_REFERENCE_KIND) { |
804 | 3.30k | txSlot* instance = slot->value.reference; |
805 | 3.30k | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_DATA_VIEW_KIND)) |
806 | 3.17k | return instance; |
807 | 3.30k | } |
808 | 3.38k | mxTypeError("this: not a DataView instance"); |
809 | 0 | return C_NULL; |
810 | 3.38k | } |
811 | | |
812 | | txInteger fxCheckDataViewSize(txMachine* the, txSlot* view, txSlot* buffer, txBoolean mutable) |
813 | 16.2k | { |
814 | 16.2k | txInteger size = view->value.dataView.size; |
815 | 16.2k | txSlot* arrayBuffer = buffer->value.reference->next; |
816 | 16.2k | txSlot* bufferInfo = arrayBuffer->next; |
817 | 16.2k | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
818 | 0 | mxTypeError("detached buffer"); |
819 | 16.2k | if (mutable && (arrayBuffer->flag & XS_DONT_SET_FLAG)) |
820 | 2 | mxTypeError("read-only buffer"); |
821 | 16.2k | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
822 | 108 | txInteger offset = view->value.dataView.offset; |
823 | 108 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
824 | 108 | if (offset > byteLength) |
825 | 3 | mxTypeError("out of bounds view"); |
826 | 105 | else if (size < 0) |
827 | 52 | size = byteLength - offset; |
828 | 53 | else if (offset + size > byteLength) |
829 | 12 | mxTypeError("out of bounds view"); |
830 | 108 | } |
831 | 16.2k | return size; |
832 | 16.2k | } |
833 | | |
834 | | txSlot* fxGetBufferInfo(txMachine* the, txSlot* buffer) |
835 | 1.28k | { |
836 | 1.28k | txSlot* arrayBuffer = buffer->value.reference->next; |
837 | 1.28k | txSlot* bufferInfo = arrayBuffer->next; |
838 | 1.28k | if (arrayBuffer->kind == XS_ARRAY_BUFFER_KIND) { |
839 | 1.11k | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
840 | 0 | mxTypeError("detached buffer"); |
841 | 1.11k | return bufferInfo; |
842 | 1.11k | } |
843 | 173 | if (arrayBuffer->kind == XS_HOST_KIND) { |
844 | 173 | txInteger byteLength; |
845 | 173 | if (bufferInfo && (bufferInfo->kind == XS_BUFFER_INFO_KIND)) |
846 | 173 | 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 | 173 | mxTypeError("invalid buffer"); |
863 | 0 | return C_NULL; |
864 | 173 | } |
865 | | |
866 | | txInteger fxGetDataViewSize(txMachine* the, txSlot* view, txSlot* buffer) |
867 | 5.26M | { |
868 | 5.26M | txInteger size = view->value.dataView.size; |
869 | 5.26M | txSlot* arrayBuffer = buffer->value.reference->next; |
870 | 5.26M | txSlot* bufferInfo = arrayBuffer->next; |
871 | 5.26M | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
872 | 0 | return 0; |
873 | 5.26M | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
874 | 187 | txInteger offset = view->value.dataView.offset; |
875 | 187 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
876 | 187 | if (offset > byteLength) |
877 | 5 | size = 0; |
878 | 182 | else if (size < 0) |
879 | 179 | size = byteLength - offset; |
880 | 3 | else if (offset + size > byteLength) |
881 | 1 | size = 0; |
882 | 187 | } |
883 | 5.26M | return size; |
884 | 5.26M | } |
885 | | |
886 | | txBoolean fxIsDataViewOutOfBound(txMachine* the, txSlot* view, txSlot* buffer) |
887 | 65 | { |
888 | 65 | txInteger size = view->value.dataView.size; |
889 | 65 | txSlot* arrayBuffer = buffer->value.reference->next; |
890 | 65 | txSlot* bufferInfo = arrayBuffer->next; |
891 | 65 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
892 | 0 | return 1; |
893 | 65 | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
894 | 18 | txInteger offset = view->value.dataView.offset; |
895 | 18 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
896 | 18 | if (offset > byteLength) |
897 | 0 | return 1; |
898 | 18 | if ((size > 0) && (offset + size > byteLength)) |
899 | 0 | return 1; |
900 | 18 | } |
901 | 65 | return 0; |
902 | 65 | } |
903 | | |
904 | | txSlot* fxNewDataViewInstance(txMachine* the) |
905 | 536 | { |
906 | 536 | txSlot* instance; |
907 | 536 | txSlot* property; |
908 | 536 | instance = fxNewObjectInstance(the); |
909 | 536 | property = instance->next = fxNewSlot(the); |
910 | 536 | property->flag = XS_INTERNAL_FLAG; |
911 | 536 | property->kind = XS_DATA_VIEW_KIND; |
912 | 536 | property->value.dataView.offset = 0; |
913 | 536 | property->value.dataView.size = 0; |
914 | 536 | property = fxNextNullProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
915 | 536 | return instance; |
916 | 536 | } |
917 | | |
918 | | void fx_DataView(txMachine* the) |
919 | 610 | { |
920 | 610 | txSlot* slot; |
921 | 610 | txBoolean flag = 0; |
922 | 610 | txInteger offset, size; |
923 | 610 | txSlot* info; |
924 | 610 | txSlot* instance; |
925 | 610 | txSlot* view; |
926 | 610 | txSlot* buffer; |
927 | 610 | if (mxIsUndefined(mxTarget)) |
928 | 4 | mxTypeError("call: DataView"); |
929 | 606 | if ((mxArgc > 0) && (mxArgv(0)->kind == XS_REFERENCE_KIND)) { |
930 | 587 | slot = mxArgv(0)->value.reference->next; |
931 | 587 | if (slot && ((slot->kind == XS_ARRAY_BUFFER_KIND) || (slot->kind == XS_HOST_KIND))) { |
932 | 578 | flag = 1; |
933 | 578 | } |
934 | 587 | } |
935 | 606 | if (!flag) |
936 | 28 | mxTypeError("buffer: not an ArrayBuffer instance"); |
937 | | |
938 | 578 | offset = fxArgToByteLength(the, 1, 0); |
939 | 578 | info = fxGetBufferInfo(the, mxArgv(0)); |
940 | 578 | if (info->value.bufferInfo.length < offset) |
941 | 13 | mxRangeError("invalid byteOffset %ld", offset); |
942 | 565 | size = fxArgToByteLength(the, 2, -1); |
943 | 565 | if (size >= 0) { |
944 | 202 | txInteger end = offset + size; |
945 | 202 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
946 | 17 | mxRangeError("invalid byteLength %ld", size); |
947 | 202 | } |
948 | 363 | else { |
949 | 363 | if (info->value.bufferInfo.maxLength < 0) |
950 | 340 | size = info->value.bufferInfo.length - offset; |
951 | 363 | } |
952 | 548 | mxPushSlot(mxTarget); |
953 | 548 | fxGetPrototypeFromConstructor(the, &mxDataViewPrototype); |
954 | 548 | instance = fxNewDataViewInstance(the); |
955 | 548 | mxPullSlot(mxResult); |
956 | 548 | view = instance->next; |
957 | 548 | buffer = view->next; |
958 | 548 | buffer->kind = XS_REFERENCE_KIND; |
959 | 548 | buffer->value.reference = mxArgv(0)->value.reference; |
960 | 548 | info = fxGetBufferInfo(the, buffer); |
961 | 548 | if (info->value.bufferInfo.maxLength >= 0) { |
962 | 32 | if (info->value.bufferInfo.length < offset) |
963 | 1 | mxRangeError("invalid byteOffset %ld", offset); |
964 | 31 | else if (size >= 0) { |
965 | 21 | txInteger end = offset + size; |
966 | 21 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
967 | 1 | mxRangeError("invalid byteLength %ld", size); |
968 | 21 | } |
969 | 32 | } |
970 | 546 | view->value.dataView.offset = offset; |
971 | 546 | view->value.dataView.size = size; |
972 | 546 | } |
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 | 99 | { |
985 | 99 | txSlot* instance = fxCheckDataViewInstance(the, mxThis); |
986 | 99 | txSlot* view = instance->next; |
987 | 99 | txSlot* buffer = view->next; |
988 | 99 | txInteger size = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
989 | 99 | mxResult->kind = XS_INTEGER_KIND; |
990 | 99 | mxResult->value.integer = size; |
991 | 99 | } |
992 | | |
993 | | void fx_DataView_prototype_byteOffset_get(txMachine* the) |
994 | 85 | { |
995 | 85 | txSlot* instance = fxCheckDataViewInstance(the, mxThis); |
996 | 85 | txSlot* view = instance->next; |
997 | 85 | txSlot* buffer = view->next; |
998 | 85 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
999 | 85 | mxResult->kind = XS_INTEGER_KIND; |
1000 | 85 | mxResult->value.integer = view->value.dataView.offset; |
1001 | 85 | } |
1002 | | |
1003 | | void fx_DataView_prototype_get(txMachine* the, txNumber delta, txTypeCallback getter) |
1004 | 1.74k | { |
1005 | 1.74k | txSlot* instance = fxCheckDataViewInstance(the, mxThis); |
1006 | 1.74k | txSlot* view = instance->next; |
1007 | 1.74k | txSlot* buffer = view->next; |
1008 | 1.74k | txInteger offset = fxArgToByteLength(the, 0, 0); |
1009 | 1.74k | txInteger size; |
1010 | 1.74k | int endian = EndianBig; |
1011 | 1.74k | if ((mxArgc > 1) && fxToBoolean(the, mxArgv(1))) |
1012 | 201 | endian = EndianLittle; |
1013 | 1.74k | size = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1014 | 1.74k | if ((size < delta) || ((size - delta) < offset)) |
1015 | 84 | mxRangeError("invalid byteOffset"); |
1016 | 1.66k | offset += view->value.dataView.offset; |
1017 | 1.66k | (*getter)(the, buffer->value.reference->next, offset, mxResult, endian); |
1018 | 1.66k | } |
1019 | | |
1020 | | void fx_DataView_prototype_getBigInt64(txMachine* the) |
1021 | 220 | { |
1022 | 220 | fx_DataView_prototype_get(the, 8, fxBigInt64Getter); |
1023 | 220 | } |
1024 | | |
1025 | | void fx_DataView_prototype_getBigUint64(txMachine* the) |
1026 | 154 | { |
1027 | 154 | fx_DataView_prototype_get(the, 8, fxBigUint64Getter); |
1028 | 154 | } |
1029 | | |
1030 | | #if mxFloat16 |
1031 | | void fx_DataView_prototype_getFloat16(txMachine* the) |
1032 | 160 | { |
1033 | 160 | fx_DataView_prototype_get(the, 2, fxFloat16Getter); |
1034 | 160 | } |
1035 | | #endif |
1036 | | |
1037 | | void fx_DataView_prototype_getFloat32(txMachine* the) |
1038 | 138 | { |
1039 | 138 | fx_DataView_prototype_get(the, 4, fxFloat32Getter); |
1040 | 138 | } |
1041 | | |
1042 | | void fx_DataView_prototype_getFloat64(txMachine* the) |
1043 | 125 | { |
1044 | 125 | fx_DataView_prototype_get(the, 8, fxFloat64Getter); |
1045 | 125 | } |
1046 | | |
1047 | | void fx_DataView_prototype_getInt8(txMachine* the) |
1048 | 471 | { |
1049 | 471 | fx_DataView_prototype_get(the, 1, fxInt8Getter); |
1050 | 471 | } |
1051 | | |
1052 | | void fx_DataView_prototype_getInt16(txMachine* the) |
1053 | 104 | { |
1054 | 104 | fx_DataView_prototype_get(the, 2, fxInt16Getter); |
1055 | 104 | } |
1056 | | |
1057 | | void fx_DataView_prototype_getInt32(txMachine* the) |
1058 | 120 | { |
1059 | 120 | fx_DataView_prototype_get(the, 4, fxInt32Getter); |
1060 | 120 | } |
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 | 93 | { |
1069 | 93 | fx_DataView_prototype_get(the, 2, fxUint16Getter); |
1070 | 93 | } |
1071 | | |
1072 | | void fx_DataView_prototype_getUint32(txMachine* the) |
1073 | 125 | { |
1074 | 125 | fx_DataView_prototype_get(the, 4, fxUint32Getter); |
1075 | 125 | } |
1076 | | |
1077 | | void fx_DataView_prototype_set(txMachine* the, txNumber delta, txTypeCoerce coercer, txTypeCallback setter) |
1078 | 1.41k | { |
1079 | 1.41k | txSlot* instance = fxCheckDataViewInstance(the, mxThis); |
1080 | 1.41k | txSlot* view = instance->next; |
1081 | 1.41k | txSlot* buffer = view->next; |
1082 | 1.41k | txInteger offset = fxArgToByteLength(the, 0, 0); |
1083 | 1.41k | txInteger size; |
1084 | 1.41k | int endian = EndianBig; |
1085 | 1.41k | txSlot* value; |
1086 | 1.41k | if (mxArgc > 1) |
1087 | 1.28k | mxPushSlot(mxArgv(1)); |
1088 | 132 | else |
1089 | 132 | mxPushUndefined(); |
1090 | 1.41k | value = the->stack; |
1091 | 1.41k | (*coercer)(the, value); |
1092 | 1.41k | if ((mxArgc > 2) && fxToBoolean(the, mxArgv(2))) |
1093 | 90 | endian = EndianLittle; |
1094 | 1.41k | size = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
1095 | 1.41k | if ((size < delta) || ((size - delta) < offset)) |
1096 | 112 | mxRangeError("invalid byteOffset"); |
1097 | 1.30k | offset += view->value.dataView.offset; |
1098 | 1.30k | (*setter)(the, buffer->value.reference->next, offset, value, endian); |
1099 | 1.30k | mxPop(); |
1100 | 1.30k | } |
1101 | | |
1102 | | void fx_DataView_prototype_setBigInt64(txMachine* the) |
1103 | 124 | { |
1104 | 124 | fx_DataView_prototype_set(the, 8, fxBigIntCoerce, fxBigInt64Setter); |
1105 | 124 | } |
1106 | | |
1107 | | void fx_DataView_prototype_setBigUint64(txMachine* the) |
1108 | 9 | { |
1109 | 9 | fx_DataView_prototype_set(the, 8, fxBigIntCoerce, fxBigUint64Setter); |
1110 | 9 | } |
1111 | | |
1112 | | #if mxFloat16 |
1113 | | void fx_DataView_prototype_setFloat16(txMachine* the) |
1114 | 163 | { |
1115 | 163 | fx_DataView_prototype_set(the, 2, fxNumberCoerce, fxFloat16Setter); |
1116 | 163 | } |
1117 | | #endif |
1118 | | |
1119 | | void fx_DataView_prototype_setFloat32(txMachine* the) |
1120 | 132 | { |
1121 | 132 | fx_DataView_prototype_set(the, 4, fxNumberCoerce, fxFloat32Setter); |
1122 | 132 | } |
1123 | | |
1124 | | void fx_DataView_prototype_setFloat64(txMachine* the) |
1125 | 139 | { |
1126 | 139 | fx_DataView_prototype_set(the, 8, fxNumberCoerce, fxFloat64Setter); |
1127 | 139 | } |
1128 | | |
1129 | | void fx_DataView_prototype_setInt8(txMachine* the) |
1130 | 78 | { |
1131 | 78 | fx_DataView_prototype_set(the, 1, fxIntCoerce, fxInt8Setter); |
1132 | 78 | } |
1133 | | |
1134 | | void fx_DataView_prototype_setInt16(txMachine* the) |
1135 | 86 | { |
1136 | 86 | fx_DataView_prototype_set(the, 2, fxIntCoerce, fxInt16Setter); |
1137 | 86 | } |
1138 | | |
1139 | | void fx_DataView_prototype_setInt32(txMachine* the) |
1140 | 86 | { |
1141 | 86 | fx_DataView_prototype_set(the, 4, fxIntCoerce, fxInt32Setter); |
1142 | 86 | } |
1143 | | |
1144 | | void fx_DataView_prototype_setUint8(txMachine* the) |
1145 | 437 | { |
1146 | 437 | fx_DataView_prototype_set(the, 1, fxUintCoerce, fxUint8Setter); |
1147 | 437 | } |
1148 | | |
1149 | | void fx_DataView_prototype_setUint16(txMachine* the) |
1150 | 95 | { |
1151 | 95 | fx_DataView_prototype_set(the, 2, fxUintCoerce, fxUint16Setter); |
1152 | 95 | } |
1153 | | |
1154 | | void fx_DataView_prototype_setUint32(txMachine* the) |
1155 | 68 | { |
1156 | 68 | fx_DataView_prototype_set(the, 4, fxUintCoerce, fxUint32Setter); |
1157 | 68 | } |
1158 | | |
1159 | | |
1160 | | #define mxTypedArrayDeclarations \ |
1161 | 9.85k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); \ |
1162 | 9.85k | txSlot* dispatch = instance->next; \ |
1163 | 9.85k | txSlot* view = dispatch->next; \ |
1164 | 9.85k | txSlot* buffer = view->next; \ |
1165 | 9.85k | txInteger length = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE) >> dispatch->value.typedArray.dispatch->shift |
1166 | | |
1167 | | #define mxMutableTypedArrayDeclarations \ |
1168 | 1.97k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); \ |
1169 | 1.97k | txSlot* dispatch = instance->next; \ |
1170 | 1.97k | txSlot* view = dispatch->next; \ |
1171 | 1.97k | txSlot* buffer = view->next; \ |
1172 | 1.97k | txInteger length = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE) >> dispatch->value.typedArray.dispatch->shift |
1173 | | |
1174 | | #define mxResultTypedArrayDeclarations \ |
1175 | 91 | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
1176 | 91 | txSlot* resultDispatch = resultInstance->next; \ |
1177 | 91 | txSlot* resultView = resultDispatch->next; \ |
1178 | 91 | txSlot* resultBuffer = resultView->next; \ |
1179 | 91 | txInteger resultLength = fxCheckDataViewSize(the, resultView, resultBuffer, XS_MUTABLE) >> resultDispatch->value.typedArray.dispatch->shift |
1180 | | |
1181 | | void fxTypedArrayGetter(txMachine* the) |
1182 | 3.01M | { |
1183 | 3.01M | txSlot* instance = fxToInstance(the, mxThis); |
1184 | 3.01M | txSlot* dispatch; |
1185 | 3.01M | while (instance) { |
1186 | 3.01M | if (instance->flag & XS_EXOTIC_FLAG) { |
1187 | 3.01M | dispatch = instance->next; |
1188 | 3.01M | if (dispatch->ID == XS_TYPED_ARRAY_BEHAVIOR) |
1189 | 3.01M | break; |
1190 | 3.01M | } |
1191 | 0 | instance = fxGetPrototype(the, instance); |
1192 | 0 | } |
1193 | 3.01M | if (instance) { |
1194 | 3.01M | txID id = the->scratch.value.at.id; |
1195 | 3.01M | txIndex index = the->scratch.value.at.index; |
1196 | 3.01M | txSlot* view = dispatch->next; |
1197 | 3.01M | txSlot* buffer = view->next; |
1198 | 3.01M | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1199 | 3.01M | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1200 | 3.01M | if ((!id) && (index < length)) { |
1201 | 3.01M | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), mxResult, EndianNative); |
1202 | 3.01M | } |
1203 | 3.01M | } |
1204 | 3.01M | } |
1205 | | |
1206 | | void fxTypedArraySetter(txMachine* the) |
1207 | 144k | { |
1208 | 144k | txSlot* instance = fxToInstance(the, mxThis); |
1209 | 144k | while (instance) { |
1210 | 144k | if (instance->flag & XS_EXOTIC_FLAG) { |
1211 | 144k | if (instance->next->ID == XS_TYPED_ARRAY_BEHAVIOR) |
1212 | 144k | break; |
1213 | 144k | } |
1214 | 0 | instance = fxGetPrototype(the, instance); |
1215 | 0 | } |
1216 | 144k | if (instance) { |
1217 | 144k | txSlot* value = mxArgv(0); |
1218 | 144k | txID id = the->scratch.value.at.id; |
1219 | 144k | txIndex index = the->scratch.value.at.index; |
1220 | 144k | 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 | 144k | } |
1225 | 144k | } |
1226 | | |
1227 | | txBoolean fxTypedArrayDefineOwnProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* slot, txFlag mask) |
1228 | 3 | { |
1229 | 3 | 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 | 2 | return fxOrdinaryDefineOwnProperty(the, instance, id, index, slot, mask); |
1257 | 3 | } |
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 | 3.33k | { |
1274 | 3.33k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1275 | 3.33k | txSlot* dispatch = instance->next; |
1276 | 3.33k | txSlot* view = dispatch->next; |
1277 | 3.33k | txSlot* buffer = view->next; |
1278 | 3.33k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1279 | 3.33k | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1280 | 3.33k | if ((!id) && (index < length)) { |
1281 | 3.33k | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), slot, EndianNative); |
1282 | 3.33k | return 1; |
1283 | 3.33k | } |
1284 | 0 | slot->kind = XS_UNDEFINED_KIND; |
1285 | 0 | slot->flag = XS_NO_FLAG; |
1286 | 0 | return 0; |
1287 | 3.33k | } |
1288 | 1 | return fxOrdinaryGetOwnProperty(the, instance, id, index, slot); |
1289 | 3.33k | } |
1290 | | |
1291 | | txSlot* fxTypedArrayGetProperty(txMachine* the, txSlot* instance, txID id, txIndex index, txFlag flag) |
1292 | 3.07M | { |
1293 | 3.07M | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1294 | 3.01M | the->scratch.value.at.id = id; |
1295 | 3.01M | the->scratch.value.at.index = index; |
1296 | 3.01M | return &mxTypedArrayAccessor; |
1297 | 3.01M | } |
1298 | 56.8k | return fxOrdinaryGetProperty(the, instance, id, index, flag); |
1299 | 3.07M | } |
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.08M | { |
1321 | 2.08M | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1322 | 2.08M | txSlot* dispatch = instance->next; |
1323 | 2.08M | txSlot* view = dispatch->next; |
1324 | 2.08M | txSlot* buffer = view->next; |
1325 | 2.08M | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1326 | 2.08M | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1327 | 2.08M | return ((!id) && (index < length)) ? 1 : 0; |
1328 | 2.08M | } |
1329 | 60 | return fxOrdinaryHasProperty(the, instance, id, index); |
1330 | 2.08M | } |
1331 | | |
1332 | | void fxTypedArrayOwnKeys(txMachine* the, txSlot* instance, txFlag flag, txSlot* keys) |
1333 | 1.65k | { |
1334 | 1.65k | if (flag & XS_EACH_NAME_FLAG) { |
1335 | 1.65k | txSlot* dispatch = instance->next; |
1336 | 1.65k | txSlot* view = dispatch->next; |
1337 | 1.65k | txSlot* buffer = view->next; |
1338 | 1.65k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1339 | 1.65k | txIndex length = fxGetDataViewSize(the, view, buffer) >> shift; |
1340 | 1.65k | if (length) { |
1341 | 1.11k | txIndex index; |
1342 | 4.44k | for (index = 0; index < length; index++) |
1343 | 3.33k | keys = fxQueueKey(the, 0, index, keys); |
1344 | 1.11k | } |
1345 | 1.65k | } |
1346 | 1.65k | fxOrdinaryOwnKeys(the, instance, flag, keys); |
1347 | 1.65k | } |
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 | 144k | { |
1364 | 144k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1365 | 144k | the->scratch.value.at.id = id; |
1366 | 144k | the->scratch.value.at.index = index; |
1367 | 144k | return &mxTypedArrayAccessor; |
1368 | 144k | } |
1369 | 115 | return fxOrdinarySetProperty(the, instance, id, index, flag); |
1370 | 144k | } |
1371 | | |
1372 | | txBoolean fxTypedArraySetPropertyValue(txMachine* the, txSlot* instance, txID id, txIndex index, txSlot* value, txSlot* receiver) |
1373 | 144k | { |
1374 | 144k | if ((!id) || fxIsCanonicalIndex(the, id)) { |
1375 | 144k | txSlot* dispatch = instance->next; |
1376 | 144k | txSlot* view = dispatch->next; |
1377 | 144k | txSlot* buffer = view->next; |
1378 | 144k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1379 | 144k | txSlot* arrayBuffer = buffer->value.reference->next; |
1380 | 144k | txIndex length; |
1381 | 144k | if ((receiver->kind == XS_REFERENCE_KIND) && (receiver->value.reference == instance)) { |
1382 | 144k | dispatch->value.typedArray.dispatch->coerce(the, value); |
1383 | 144k | 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 | 144k | length = fxGetDataViewSize(the, view, buffer) >> shift; |
1390 | 144k | if ((!id) && (index < length)) { |
1391 | 144k | (*dispatch->value.typedArray.dispatch->setter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), value, EndianNative); |
1392 | 144k | } |
1393 | 144k | return 1; |
1394 | 144k | } |
1395 | 4 | length = fxGetDataViewSize(the, view, buffer) >> shift; |
1396 | 4 | if ((id) || (index >= length)) { |
1397 | 3 | return 1; |
1398 | 3 | } |
1399 | 4 | } |
1400 | 2 | return fxOrdinarySetPropertyValue(the, instance, id, index, value, receiver); |
1401 | 144k | } |
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 | 317k | { |
1427 | 317k | if (slot->kind == XS_REFERENCE_KIND) { |
1428 | 317k | txSlot* instance = slot->value.reference; |
1429 | 317k | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_TYPED_ARRAY_KIND)) |
1430 | 316k | return instance; |
1431 | 317k | } |
1432 | 317k | mxTypeError("this: not a TypedArray instance"); |
1433 | 0 | return C_NULL; |
1434 | 317k | } |
1435 | | |
1436 | | txSlot* fxConstructTypedArray(txMachine* the) |
1437 | 389k | { |
1438 | 389k | txSlot* prototype; |
1439 | 389k | txSlot* dispatch; |
1440 | 389k | txSlot* instance; |
1441 | 389k | if (mxIsUndefined(mxTarget)) |
1442 | 434 | mxTypeError("call: TypedArray"); |
1443 | 389k | dispatch = mxFunctionInstanceHome(mxFunction->value.reference); |
1444 | 389k | dispatch = dispatch->next; |
1445 | 389k | prototype = mxBehaviorGetProperty(the, mxFunction->value.reference, mxID(_prototype), 0, XS_ANY); |
1446 | 389k | if (!dispatch || (dispatch->kind != XS_TYPED_ARRAY_KIND)) |
1447 | 10 | mxTypeError("new: TypedArray"); |
1448 | 389k | mxPushSlot(mxTarget); |
1449 | 389k | fxGetPrototypeFromConstructor(the, prototype); |
1450 | 389k | instance = fxNewTypedArrayInstance(the, dispatch->value.typedArray.dispatch, dispatch->value.typedArray.atomics); |
1451 | 389k | mxPullSlot(mxResult); |
1452 | 389k | return instance; |
1453 | 389k | } |
1454 | | |
1455 | | void fxCreateTypedArraySpecies(txMachine* the) |
1456 | 7 | { |
1457 | 7 | txSlot* instance = fxToInstance(the, mxThis); |
1458 | 7 | txSlot* dispatch = instance->next; |
1459 | 7 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
1460 | 7 | mxPushSlot(mxThis); |
1461 | 7 | mxGetID(mxID(_constructor)); |
1462 | 7 | fxToSpeciesConstructor(the, constructor); |
1463 | 7 | mxNew(); |
1464 | 7 | } |
1465 | | |
1466 | | void fxReduceTypedArrayItem(txMachine* the, txSlot* function, txSlot* dispatch, txSlot* view, txSlot* data, txInteger index) |
1467 | 927k | { |
1468 | | /* THIS */ |
1469 | 927k | mxPushUndefined(); |
1470 | | /* FUNCTION */ |
1471 | 927k | mxPushSlot(function); |
1472 | 927k | mxCall(); |
1473 | | /* ARGUMENTS */ |
1474 | 927k | mxPushSlot(mxResult); |
1475 | 927k | mxPushSlot(mxThis); |
1476 | 927k | mxGetIndex(index); |
1477 | 927k | mxPushInteger(index); |
1478 | 927k | mxPushSlot(mxThis); |
1479 | 927k | mxRunCount(4); |
1480 | 927k | mxPullSlot(mxResult); |
1481 | 927k | } |
1482 | | |
1483 | | txSlot* fxNewTypedArrayInstance(txMachine* the, txTypeDispatch* dispatch, txTypeAtomics* atomics) |
1484 | 389k | { |
1485 | 389k | txSlot* instance; |
1486 | 389k | txSlot* property; |
1487 | 389k | instance = fxNewObjectInstance(the); |
1488 | 389k | instance->flag |= XS_EXOTIC_FLAG; |
1489 | 389k | property = fxNextTypeDispatchProperty(the, instance, dispatch, atomics, XS_TYPED_ARRAY_BEHAVIOR, XS_INTERNAL_FLAG); |
1490 | 389k | property = property->next = fxNewSlot(the); |
1491 | 389k | property->flag = XS_INTERNAL_FLAG; |
1492 | 389k | property->kind = XS_DATA_VIEW_KIND; |
1493 | 389k | property->value.dataView.offset = 0; |
1494 | 389k | property->value.dataView.size = 0; |
1495 | 389k | property = fxNextNullProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG); |
1496 | 389k | return instance; |
1497 | 389k | } |
1498 | | |
1499 | | void fx_TypedArray(txMachine* the) |
1500 | 389k | { |
1501 | 389k | txSlot* instance = fxConstructTypedArray(the); |
1502 | 389k | txSlot* dispatch = instance->next; |
1503 | 389k | txSlot* view = dispatch->next; |
1504 | 389k | txSlot* buffer = view->next; |
1505 | 389k | txSlot* data = C_NULL; |
1506 | 389k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1507 | 389k | txSlot* slot; |
1508 | 389k | if ((mxArgc > 0) && (mxArgv(0)->kind == XS_REFERENCE_KIND)) { |
1509 | 78.7k | slot = mxArgv(0)->value.reference->next; |
1510 | 78.7k | if (slot && ((slot->kind == XS_ARRAY_BUFFER_KIND) || (slot->kind == XS_HOST_KIND))) { |
1511 | 171 | txInteger offset = fxArgToByteLength(the, 1, 0); |
1512 | 171 | txInteger size; |
1513 | 171 | txSlot* info; |
1514 | 171 | if (offset & ((1 << shift) - 1)) |
1515 | 0 | mxRangeError("invalid byteOffset %ld", offset); |
1516 | 171 | size = fxArgToByteLength(the, 2, -1); |
1517 | 171 | info = fxGetBufferInfo(the, mxArgv(0)); |
1518 | 171 | if (size >= 0) { |
1519 | 11 | txInteger delta = size << shift; //@@ overflow |
1520 | 11 | txInteger end = fxAddChunkSizes(the, offset, delta); |
1521 | 11 | if ((info->value.bufferInfo.length < end) || (end < offset)) |
1522 | 1 | mxRangeError("invalid length %ld", size); |
1523 | 10 | size = delta; |
1524 | 10 | } |
1525 | 160 | else if (info->value.bufferInfo.maxLength >= 0) { |
1526 | 37 | if (info->value.bufferInfo.length < offset) |
1527 | 0 | mxRangeError("invalid offset %ld", offset); |
1528 | 37 | size = -1; |
1529 | 37 | } |
1530 | 123 | else { |
1531 | 123 | if (info->value.bufferInfo.length & ((1 << shift) - 1)) |
1532 | 3 | mxRangeError("invalid byteLength %ld", info->value.bufferInfo.length); |
1533 | 120 | size = info->value.bufferInfo.length - offset; |
1534 | 120 | if (size < 0) |
1535 | 1 | mxRangeError("invalid byteLength %ld", size); |
1536 | 120 | } |
1537 | 166 | view->value.dataView.offset = offset; |
1538 | 166 | view->value.dataView.size = size; |
1539 | 166 | buffer->kind = XS_REFERENCE_KIND; |
1540 | 166 | buffer->value.reference = mxArgv(0)->value.reference; |
1541 | 166 | } |
1542 | 78.5k | else if (slot && (slot->kind == XS_TYPED_ARRAY_KIND)) { |
1543 | 220 | txSlot* sourceDispatch = slot; |
1544 | 220 | txSlot* sourceView = sourceDispatch->next; |
1545 | 220 | txSlot* sourceBuffer = sourceView->next; |
1546 | 220 | txU2 sourceShift = sourceDispatch->value.typedArray.dispatch->shift; |
1547 | 220 | txInteger sourceLength = fxCheckDataViewSize(the, sourceView, sourceBuffer, XS_IMMUTABLE) >> sourceShift; |
1548 | 220 | txSlot* sourceData = sourceBuffer->value.reference->next; |
1549 | 220 | txInteger sourceDelta = sourceDispatch->value.typedArray.dispatch->size; |
1550 | 220 | txInteger sourceOffset = sourceView->value.dataView.offset; |
1551 | 220 | txInteger offset = 0; |
1552 | 220 | txInteger size = sourceLength << shift; |
1553 | | /* THIS */ |
1554 | 220 | mxPushUninitialized(); |
1555 | | /* FUNCTION */ |
1556 | 220 | mxPush(mxArrayBufferConstructor); |
1557 | | /* TARGET */ |
1558 | 220 | mxPush(mxArrayBufferConstructor); |
1559 | | /* RESULT */ |
1560 | 220 | mxPushUndefined(); |
1561 | 220 | mxPushUninitialized(); |
1562 | 220 | mxPushUninitialized(); |
1563 | | /* ARGUMENTS */ |
1564 | 220 | sourceLength = fxGetDataViewSize(the, sourceView, sourceBuffer) >> sourceShift; |
1565 | 220 | size = sourceLength << shift; |
1566 | 220 | mxPushInteger(size); |
1567 | 220 | mxRunCount(1); |
1568 | 220 | mxPullSlot(buffer); |
1569 | 220 | sourceLength = fxCheckDataViewSize(the, sourceView, sourceBuffer, XS_IMMUTABLE) >> sourceShift; |
1570 | 220 | size = sourceLength << shift; |
1571 | | |
1572 | 220 | data = fxCheckArrayBufferDetached(the, buffer, XS_MUTABLE); |
1573 | 220 | view->value.dataView.offset = offset; |
1574 | 220 | view->value.dataView.size = size; |
1575 | 220 | if (dispatch == sourceDispatch) |
1576 | 0 | c_memcpy(data->value.arrayBuffer.address + offset, sourceData->value.arrayBuffer.address + sourceOffset, size); |
1577 | 220 | else { |
1578 | 220 | txBoolean contentType = (dispatch->value.typedArray.dispatch->constructorID == _BigInt64Array) |
1579 | 220 | || (dispatch->value.typedArray.dispatch->constructorID == _BigUint64Array); |
1580 | 220 | txBoolean sourceContentType = (sourceDispatch->value.typedArray.dispatch->constructorID == _BigInt64Array) |
1581 | 220 | || (sourceDispatch->value.typedArray.dispatch->constructorID == _BigUint64Array); |
1582 | 220 | if (contentType != sourceContentType) |
1583 | 3 | mxTypeError("incompatible content type"); |
1584 | 217 | mxPushUndefined(); |
1585 | 1.76k | while (offset < size) { |
1586 | 1.54k | (*sourceDispatch->value.typedArray.dispatch->getter)(the, sourceData, sourceOffset, the->stack, EndianNative); |
1587 | 1.54k | (*dispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
1588 | 1.54k | (*dispatch->value.typedArray.dispatch->setter)(the, data, offset, the->stack, EndianNative); |
1589 | 1.54k | sourceOffset += sourceDelta; |
1590 | 1.54k | offset += 1 << shift; |
1591 | 1.54k | } |
1592 | 217 | mxPop(); |
1593 | 217 | } |
1594 | 220 | } |
1595 | 78.3k | else { |
1596 | 78.3k | fx_TypedArray_from_object(the, instance, C_NULL, C_NULL); |
1597 | 78.3k | } |
1598 | 78.7k | } |
1599 | 311k | else { |
1600 | 311k | txInteger length = fxArgToByteLength(the, 0, 0); |
1601 | 311k | if (length > (0x7FFFFFFF >> shift)) |
1602 | 0 | mxRangeError("byteLength too big"); |
1603 | 311k | length <<= shift; |
1604 | 311k | mxPush(mxArrayBufferConstructor); |
1605 | 311k | mxNew(); |
1606 | 311k | mxPushInteger(length); |
1607 | 311k | mxRunCount(1); |
1608 | 311k | mxPullSlot(buffer); |
1609 | 311k | view->value.dataView.offset = 0; |
1610 | 311k | view->value.dataView.size = length; |
1611 | 311k | } |
1612 | 389k | } |
1613 | | |
1614 | | void fx_TypedArray_from(txMachine* the) |
1615 | 23 | { |
1616 | 23 | txSlot* function = C_NULL; |
1617 | 23 | txSlot* _this = C_NULL; |
1618 | 23 | if (!mxIsReference(mxThis) || !(mxIsConstructor(mxThis->value.reference))) |
1619 | 2 | mxTypeError("this: not a constructor"); |
1620 | 21 | if (mxArgc > 1) { |
1621 | 18 | txSlot* slot = mxArgv(1); |
1622 | 18 | if (!mxIsUndefined(slot)) { |
1623 | 18 | function = slot; |
1624 | 18 | if (!fxIsCallable(the, function)) |
1625 | 13 | mxTypeError("map: not a function"); |
1626 | 5 | if (mxArgc > 2) |
1627 | 0 | _this = mxArgv(2); |
1628 | 5 | } |
1629 | 18 | } |
1630 | 8 | fx_TypedArray_from_object(the, C_NULL, function, _this); |
1631 | 8 | } |
1632 | | |
1633 | | void fx_TypedArray_from_object(txMachine* the, txSlot* instance, txSlot* function, txSlot* _this) |
1634 | 78.3k | { |
1635 | 78.3k | txSlot* stack = the->stack; |
1636 | 78.3k | txSlot* iterator; |
1637 | 78.3k | txSlot* next; |
1638 | 78.3k | txSlot* value; |
1639 | 78.3k | txSlot* list = C_NULL; |
1640 | 78.3k | txSlot* slot; |
1641 | 78.3k | txSlot* dispatch; |
1642 | 78.3k | txSlot* view; |
1643 | 78.3k | txSlot* buffer; |
1644 | 78.3k | txSlot* data; |
1645 | 78.3k | txNumber length; |
1646 | 78.3k | mxTemporary(iterator); |
1647 | 78.3k | mxTemporary(next); |
1648 | 78.3k | if (fxGetIterator(the, mxArgv(0), iterator, next, 1)) { |
1649 | 68.8k | list = fxNewInstance(the); |
1650 | 68.8k | slot = list; |
1651 | 68.8k | length = 0; |
1652 | 68.8k | mxTemporary(value); |
1653 | 211k | while (fxIteratorNext(the, iterator, next, value)) { |
1654 | 142k | slot = fxNextSlotProperty(the, slot, value, XS_NO_ID, XS_NO_FLAG); |
1655 | 142k | length++; |
1656 | 142k | } |
1657 | 68.8k | } |
1658 | 9.51k | else { |
1659 | 9.51k | mxPushSlot(mxArgv(0)); |
1660 | 9.51k | mxGetID(mxID(_length)); |
1661 | 9.51k | length = fxToLength(the, the->stack); |
1662 | 9.51k | mxPop(); |
1663 | 9.51k | } |
1664 | 78.3k | if (instance) { |
1665 | 78.3k | dispatch = instance->next; |
1666 | 78.3k | view = dispatch->next; |
1667 | 78.3k | buffer = view->next; |
1668 | 78.3k | mxPush(mxArrayBufferConstructor); |
1669 | 78.3k | mxNew(); |
1670 | 78.3k | mxPushNumber(length * dispatch->value.typedArray.dispatch->size); |
1671 | 78.3k | mxRunCount(1); |
1672 | 78.3k | mxPullSlot(buffer); |
1673 | 78.3k | data = fxCheckArrayBufferDetached(the, buffer, XS_MUTABLE); |
1674 | 78.3k | view->value.dataView.offset = 0; |
1675 | 78.3k | view->value.dataView.size = data->next->value.bufferInfo.length; |
1676 | 78.3k | } |
1677 | 8 | else { |
1678 | 8 | mxPushSlot(mxThis); |
1679 | 8 | mxNew(); |
1680 | 8 | mxPushNumber(length); |
1681 | 8 | mxRunCount(1); |
1682 | 8 | mxPullSlot(mxResult); |
1683 | 8 | instance = fxToInstance(the, mxResult); |
1684 | 8 | if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_TYPED_ARRAY_KIND)) { |
1685 | 6 | dispatch = instance->next; |
1686 | 6 | view = dispatch->next; |
1687 | 6 | buffer = view->next; |
1688 | 6 | data = fxCheckArrayBufferDetached(the, buffer, XS_MUTABLE); |
1689 | 6 | if (length > (fxGetDataViewSize(the, view, buffer) >> dispatch->value.typedArray.dispatch->shift)) |
1690 | 1 | mxTypeError("result: too small TypedArray instance"); |
1691 | 6 | } |
1692 | 2 | else |
1693 | 2 | mxTypeError("result: not a TypedArray instance"); |
1694 | 8 | } |
1695 | 78.3k | if (list) { |
1696 | 68.8k | txInteger index = 0; |
1697 | 68.8k | slot = list->next; |
1698 | 211k | while (slot) { |
1699 | | /* ARG0 */ |
1700 | 142k | if (function) { |
1701 | | /* THIS */ |
1702 | 8 | if (_this) |
1703 | 0 | mxPushSlot(_this); |
1704 | 8 | else |
1705 | 8 | mxPushUndefined(); |
1706 | | /* FUNCTION */ |
1707 | 8 | mxPushSlot(function); |
1708 | 8 | mxCall(); |
1709 | | /* ARGUMENTS */ |
1710 | 8 | mxPushSlot(slot); |
1711 | 8 | mxPushInteger(index); |
1712 | 8 | mxRunCount(2); |
1713 | 8 | } |
1714 | 142k | else |
1715 | 142k | mxPushSlot(slot); |
1716 | 142k | mxPushSlot(mxResult); |
1717 | 142k | mxSetIndex(index); |
1718 | 142k | mxPop(); |
1719 | 142k | index++; |
1720 | 142k | slot = slot->next; |
1721 | 142k | } |
1722 | 68.8k | } |
1723 | 9.51k | else { |
1724 | 9.51k | txInteger index = 0; |
1725 | 9.51k | txInteger count = (txInteger)length; |
1726 | 9.87k | while (index < count) { |
1727 | 356 | 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 | 356 | else { |
1743 | 356 | mxPushSlot(mxArgv(0)); |
1744 | 356 | mxGetIndex(index); |
1745 | 356 | } |
1746 | 356 | mxPushSlot(mxResult); |
1747 | 356 | mxSetIndex(index); |
1748 | 356 | mxPop(); |
1749 | 356 | index++; |
1750 | 356 | } |
1751 | 9.51k | } |
1752 | 78.3k | the->stack = stack; |
1753 | 78.3k | } |
1754 | | |
1755 | | void fx_TypedArray_of(txMachine* the) |
1756 | 4 | { |
1757 | 4 | txInteger count = mxArgc; |
1758 | 4 | txInteger index = 0; |
1759 | 4 | mxPushSlot(mxThis); |
1760 | 4 | mxNew(); |
1761 | 4 | mxPushInteger(count); |
1762 | 4 | mxRunCount(1); |
1763 | 4 | mxPullSlot(mxResult); |
1764 | 4 | { |
1765 | 4 | mxResultTypedArrayDeclarations; |
1766 | 4 | txU2 shift = resultDispatch->value.typedArray.dispatch->shift; |
1767 | 4 | if (resultLength < count) |
1768 | 0 | mxTypeError("result: too small TypedArray instance"); |
1769 | 9 | 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 | 4 | } |
1777 | 4 | } |
1778 | | |
1779 | | void fx_TypedArray_prototype_at(txMachine* the) |
1780 | 2 | { |
1781 | 2 | mxTypedArrayDeclarations; |
1782 | 2 | txInteger index = (mxArgc > 0) ? fxToInteger(the, mxArgv(0)) : 0; |
1783 | 2 | if (index < 0) |
1784 | 0 | index = length + index; |
1785 | 2 | if ((0 <= index) && (index < length)) { |
1786 | 0 | mxPushSlot(mxThis); |
1787 | 0 | mxGetIndex(index); |
1788 | 0 | mxPullSlot(mxResult); |
1789 | 0 | } |
1790 | 2 | } |
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 | 25 | { |
1804 | 25 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1805 | 25 | txSlot* dispatch = instance->next; |
1806 | 25 | txSlot* view = dispatch->next; |
1807 | 25 | txSlot* buffer = view->next; |
1808 | 25 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
1809 | 25 | mxResult->kind = XS_INTEGER_KIND; |
1810 | 25 | mxResult->value.integer = fxGetDataViewSize(the, view, buffer) & ~((1 << shift) - 1); |
1811 | 25 | } |
1812 | | |
1813 | | void fx_TypedArray_prototype_byteOffset_get(txMachine* the) |
1814 | 35 | { |
1815 | 35 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1816 | 35 | txSlot* dispatch = instance->next; |
1817 | 35 | txSlot* view = dispatch->next; |
1818 | 35 | txSlot* buffer = view->next; |
1819 | 35 | txInteger offset = view->value.dataView.offset; |
1820 | 35 | txInteger size = view->value.dataView.size; |
1821 | 35 | txSlot* arrayBuffer = buffer->value.reference->next; |
1822 | 35 | txSlot* bufferInfo = arrayBuffer->next; |
1823 | 35 | mxResult->kind = XS_INTEGER_KIND; |
1824 | 35 | mxResult->value.integer = 0; |
1825 | 35 | if (arrayBuffer->value.arrayBuffer.address == C_NULL) |
1826 | 0 | return; |
1827 | 35 | if (bufferInfo->value.bufferInfo.maxLength >= 0) { |
1828 | 13 | txInteger byteLength = bufferInfo->value.bufferInfo.length; |
1829 | 13 | if (offset > byteLength) |
1830 | 1 | return; |
1831 | 12 | size = (size < 0) ? byteLength : offset + size; |
1832 | 12 | if (size > byteLength) |
1833 | 0 | return; |
1834 | 12 | size -= offset; |
1835 | 12 | } |
1836 | 34 | mxResult->value.integer = offset; |
1837 | 34 | } |
1838 | | |
1839 | | void fx_TypedArray_prototype_copyWithin(txMachine* the) |
1840 | 24 | { |
1841 | 24 | mxMutableTypedArrayDeclarations; |
1842 | 24 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
1843 | 24 | txInteger target = fxArgToIndexInteger(the, 0, 0, length); |
1844 | 24 | txInteger start = fxArgToIndexInteger(the, 1, 0, length); |
1845 | 24 | txInteger end = fxArgToIndexInteger(the, 2, length, length); |
1846 | 24 | txInteger count = end - start; |
1847 | 24 | if (count > length - target) |
1848 | 0 | count = length - target; |
1849 | 24 | 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 | 24 | mxResult->kind = mxThis->kind; |
1868 | 24 | mxResult->value = mxThis->value; |
1869 | 24 | } |
1870 | | |
1871 | | void fx_TypedArray_prototype_entries(txMachine* the) |
1872 | 28 | { |
1873 | 28 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
1874 | 28 | txSlot* dispatch = instance->next; |
1875 | 28 | txSlot* view = dispatch->next; |
1876 | 28 | txSlot* buffer = view->next; |
1877 | 28 | txSlot* property; |
1878 | 28 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
1879 | 28 | mxPush(mxArrayIteratorPrototype); |
1880 | 28 | property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array))); |
1881 | 28 | property = fxNextIntegerProperty(the, property, 2, XS_NO_ID, XS_INTERNAL_FLAG); |
1882 | 28 | mxPullSlot(mxResult); |
1883 | 28 | } |
1884 | | |
1885 | | void fx_TypedArray_prototype_every(txMachine* the) |
1886 | 20 | { |
1887 | 20 | mxTypedArrayDeclarations; |
1888 | 20 | txSlot* function = fxArgToCallback(the, 0); |
1889 | 20 | txInteger index = 0; |
1890 | 20 | mxResult->kind = XS_BOOLEAN_KIND; |
1891 | 20 | mxResult->value.boolean = 1; |
1892 | 20 | 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 | 20 | } |
1900 | | |
1901 | | void fx_TypedArray_prototype_fill(txMachine* the) |
1902 | 308 | { |
1903 | 308 | mxMutableTypedArrayDeclarations; |
1904 | 308 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
1905 | 308 | txInteger start = fxArgToIndexInteger(the, 1, 0, length); |
1906 | 308 | txInteger end = fxArgToIndexInteger(the, 2, length, length); |
1907 | 308 | start *= delta; |
1908 | 308 | end *= delta; |
1909 | 308 | start += view->value.dataView.offset; |
1910 | 308 | end += view->value.dataView.offset; |
1911 | 308 | if (mxArgc > 0) |
1912 | 2 | mxPushSlot(mxArgv(0)); |
1913 | 306 | else |
1914 | 306 | mxPushUndefined(); |
1915 | 308 | (*dispatch->value.typedArray.dispatch->coerce)(the, the->stack); |
1916 | 308 | fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
1917 | 312 | while (start < end) { |
1918 | 4 | (*dispatch->value.typedArray.dispatch->setter)(the, buffer->value.reference->next, start, the->stack, EndianNative); |
1919 | 4 | start += delta; |
1920 | 4 | } |
1921 | 308 | mxPop(); |
1922 | 308 | mxResult->kind = mxThis->kind; |
1923 | 308 | mxResult->value = mxThis->value; |
1924 | 308 | } |
1925 | | |
1926 | | void fx_TypedArray_prototype_filter(txMachine* the) |
1927 | 16 | { |
1928 | 16 | mxTypedArrayDeclarations; |
1929 | 16 | txSlot* function = fxArgToCallback(the, 0); |
1930 | 16 | txSlot* list = fxNewInstance(the); |
1931 | 16 | txSlot* slot = list; |
1932 | 16 | txInteger count = 0; |
1933 | 16 | txInteger index = 0; |
1934 | 16 | mxPushUndefined(); |
1935 | 16 | 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 | 16 | mxPop(); |
1944 | 16 | fxCreateTypedArraySpecies(the); |
1945 | 16 | mxPushNumber(count); |
1946 | 16 | mxRunCount(1); |
1947 | 16 | mxPullSlot(mxResult); |
1948 | 16 | { |
1949 | 16 | mxResultTypedArrayDeclarations; |
1950 | 16 | txInteger resultOffset = 0; |
1951 | 16 | txInteger resultSize = resultDispatch->value.typedArray.dispatch->size; |
1952 | 16 | if (resultLength < count) |
1953 | 0 | mxTypeError("result: too small TypedArray instance"); |
1954 | 16 | slot = list->next; |
1955 | 16 | 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 | 16 | } |
1962 | 16 | mxPop(); |
1963 | 16 | } |
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 | 28 | { |
1985 | 28 | mxTypedArrayDeclarations; |
1986 | 28 | txSlot* function = fxArgToCallback(the, 0); |
1987 | 28 | txInteger index = 0; |
1988 | 28 | mxResult->kind = XS_INTEGER_KIND; |
1989 | 28 | mxResult->value.integer = -1; |
1990 | 28 | 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 | 28 | } |
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 | 32 | { |
2020 | 32 | mxTypedArrayDeclarations; |
2021 | 32 | txSlot* function = fxArgToCallback(the, 0); |
2022 | 32 | txInteger index = length; |
2023 | 32 | mxResult->kind = XS_INTEGER_KIND; |
2024 | 32 | mxResult->value.integer = -1; |
2025 | 32 | 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 | 32 | } |
2034 | | |
2035 | | void fx_TypedArray_prototype_forEach(txMachine* the) |
2036 | 18 | { |
2037 | 18 | mxTypedArrayDeclarations; |
2038 | 18 | txSlot* function = fxArgToCallback(the, 0); |
2039 | 18 | txInteger index = 0; |
2040 | 18 | 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 | 18 | } |
2046 | | |
2047 | | void fx_TypedArray_prototype_includes(txMachine* the) |
2048 | 25 | { |
2049 | 25 | mxTypedArrayDeclarations; |
2050 | 25 | fxBoolean(the, mxResult, 0); |
2051 | 25 | if (length) { |
2052 | 6 | txInteger index = fxArgToIndexInteger(the, 1, 0, length); |
2053 | 6 | txSlot* argument; |
2054 | 6 | if (mxArgc > 0) |
2055 | 6 | mxPushSlot(mxArgv(0)); |
2056 | 0 | else |
2057 | 0 | mxPushUndefined(); |
2058 | 6 | argument = the->stack; |
2059 | 28 | while (index < length) { |
2060 | 22 | mxPushSlot(mxThis); |
2061 | 22 | mxGetIndex(index); |
2062 | 22 | if (fxIsSameValue(the, the->stack++, argument, 1)) { |
2063 | 0 | mxResult->value.boolean = 1; |
2064 | 0 | break; |
2065 | 0 | } |
2066 | 22 | index++; |
2067 | 22 | mxCheckMetering(); |
2068 | 22 | } |
2069 | 6 | mxPop(); |
2070 | 6 | } |
2071 | 25 | } |
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 | 4.75k | { |
2104 | 4.75k | mxTypedArrayDeclarations; |
2105 | 4.75k | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2106 | 4.75k | txInteger offset = view->value.dataView.offset; |
2107 | 4.75k | txInteger limit = offset + (length << dispatch->value.typedArray.dispatch->shift); |
2108 | 4.75k | txString string; |
2109 | 4.75k | txSlot* list = fxNewInstance(the); |
2110 | 4.75k | txSlot* slot = list; |
2111 | 4.75k | txBoolean comma = 0; |
2112 | 4.75k | txInteger size = 0; |
2113 | 4.75k | if ((mxArgc > 0) && (mxArgv(0)->kind != XS_UNDEFINED_KIND)) { |
2114 | 1 | mxPushSlot(mxArgv(0)); |
2115 | 1 | string = fxToString(the, the->stack); |
2116 | 1 | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2117 | 1 | the->stack->value.key.sum = mxStringLength(the->stack->value.string); |
2118 | 1 | } |
2119 | 4.74k | else { |
2120 | 4.74k | mxPushStringX(","); |
2121 | 4.74k | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2122 | 4.74k | the->stack->value.key.sum = 1; |
2123 | 4.74k | } |
2124 | 4.75k | length = offset + fxGetDataViewSize(the, view, buffer); |
2125 | 1.98M | 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 | 1.39k | else |
2131 | 1.39k | 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 | 4.75k | mxPop(); |
2145 | 4.75k | string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1)); |
2146 | 4.75k | slot = list->next; |
2147 | 3.97M | while (slot) { |
2148 | 3.96M | c_memcpy(string, slot->value.key.string, slot->value.key.sum); |
2149 | 3.96M | string += slot->value.key.sum; |
2150 | 3.96M | slot = slot->next; |
2151 | 3.96M | } |
2152 | 4.75k | *string = 0; |
2153 | 4.75k | mxResult->kind = XS_STRING_KIND; |
2154 | 4.75k | mxPop(); |
2155 | 4.75k | } |
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.58k | { |
2202 | 1.58k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2203 | 1.58k | txSlot* dispatch = instance->next; |
2204 | 1.58k | txSlot* view = dispatch->next; |
2205 | 1.58k | txSlot* buffer = view->next; |
2206 | 1.58k | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
2207 | 1.58k | mxResult->kind = XS_INTEGER_KIND; |
2208 | 1.58k | mxResult->value.integer = fxGetDataViewSize(the, view, buffer) >> shift; |
2209 | 1.58k | } |
2210 | | |
2211 | | void fx_TypedArray_prototype_map(txMachine* the) |
2212 | 19 | { |
2213 | 19 | mxTypedArrayDeclarations; |
2214 | 19 | txSlot* function = fxArgToCallback(the, 0); |
2215 | 19 | fxCreateTypedArraySpecies(the); |
2216 | 19 | mxPushNumber(length); |
2217 | 19 | mxRunCount(1); |
2218 | 19 | mxPullSlot(mxResult); |
2219 | 19 | { |
2220 | 19 | mxResultTypedArrayDeclarations; |
2221 | 19 | txU2 shift = resultDispatch->value.typedArray.dispatch->shift; |
2222 | 19 | txInteger index = 0; |
2223 | 19 | if (resultLength < length) |
2224 | 0 | mxTypeError("result: too small TypedArray instance"); |
2225 | 19 | 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 | 19 | } |
2235 | 19 | } |
2236 | | |
2237 | | void fx_TypedArray_prototype_reduce(txMachine* the) |
2238 | 4.72k | { |
2239 | 4.72k | mxTypedArrayDeclarations; |
2240 | 4.72k | txSlot* function = fxArgToCallback(the, 0); |
2241 | 4.72k | txInteger index = 0; |
2242 | 4.72k | if (mxArgc > 1) |
2243 | 0 | *mxResult = *mxArgv(1); |
2244 | 4.72k | else if (index < length) { |
2245 | 31 | (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset, mxResult, EndianNative); |
2246 | 31 | index++; |
2247 | 31 | } |
2248 | 4.68k | else |
2249 | 4.68k | mxTypeError("no initial value"); |
2250 | 927k | while (index < length) { |
2251 | 927k | fxReduceTypedArrayItem(the, function, dispatch, view, buffer->value.reference->next, index); |
2252 | 927k | index++; |
2253 | 927k | } |
2254 | 31 | } |
2255 | | |
2256 | | void fx_TypedArray_prototype_reduceRight(txMachine* the) |
2257 | 28 | { |
2258 | 28 | mxTypedArrayDeclarations; |
2259 | 28 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2260 | 28 | txSlot* function = fxArgToCallback(the, 0); |
2261 | 28 | txInteger index = length - 1; |
2262 | 28 | if (mxArgc > 1) |
2263 | 0 | *mxResult = *mxArgv(1); |
2264 | 28 | 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 | 28 | else |
2269 | 28 | 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 | 24 | { |
2278 | 24 | mxMutableTypedArrayDeclarations; |
2279 | 24 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2280 | 24 | 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 | 24 | mxResult->kind = mxThis->kind; |
2297 | 24 | mxResult->value = mxThis->value; |
2298 | 24 | } |
2299 | | |
2300 | | void fx_TypedArray_prototype_set(txMachine* the) |
2301 | 43 | { |
2302 | 43 | mxMutableTypedArrayDeclarations; |
2303 | 43 | txSlot* data = buffer->value.reference->next; |
2304 | 43 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2305 | 43 | txSlot* source = fxArgToInstance(the, 0); |
2306 | 43 | txInteger target = fxArgToByteLength(the, 1, 0); |
2307 | 43 | txInteger offset = view->value.dataView.offset + (target * delta); |
2308 | 43 | 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 | 43 | else { |
2355 | 43 | txInteger count, index; |
2356 | 43 | if (fxIsDataViewOutOfBound(the, view, buffer)) |
2357 | 0 | mxTypeError("out of bound buffer"); |
2358 | 43 | mxPushSlot(mxArgv(0)); |
2359 | 43 | mxGetID(mxID(_length)); |
2360 | 43 | count = fxToInteger(the, the->stack); |
2361 | 43 | mxPop(); |
2362 | 43 | if (length - count < target) |
2363 | 1 | mxRangeError("invalid offset"); |
2364 | 42 | index = 0; |
2365 | 60 | while (index < count) { |
2366 | 18 | mxPushSlot(mxArgv(0)); |
2367 | 18 | mxGetIndex(index); |
2368 | 18 | mxPushSlot(mxThis); |
2369 | 18 | mxPushInteger(target + index); |
2370 | 18 | mxSetAt(); |
2371 | 18 | mxPop(); |
2372 | 18 | index++; |
2373 | 18 | mxCheckMetering(); |
2374 | 18 | } |
2375 | 42 | } |
2376 | 43 | } |
2377 | | |
2378 | | void fx_TypedArray_prototype_slice(txMachine* the) |
2379 | 21 | { |
2380 | 21 | mxTypedArrayDeclarations; |
2381 | 21 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2382 | 21 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
2383 | 21 | txInteger end = fxArgToIndexInteger(the, 1, length, length); |
2384 | 21 | txInteger count = (end > start) ? end - start : 0; |
2385 | 21 | txInteger index = 0; |
2386 | 21 | fxCreateTypedArraySpecies(the); |
2387 | 21 | mxPushNumber(count); |
2388 | 21 | mxRunCount(1); |
2389 | 21 | mxPullSlot(mxResult); |
2390 | 21 | { |
2391 | 21 | mxResultTypedArrayDeclarations; |
2392 | 21 | if (resultLength < count) |
2393 | 0 | mxTypeError("result: too small TypedArray instance"); |
2394 | 21 | 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 | 21 | } |
2420 | 21 | } |
2421 | | |
2422 | | void fx_TypedArray_prototype_some(txMachine* the) |
2423 | 21 | { |
2424 | 21 | mxTypedArrayDeclarations; |
2425 | 21 | txSlot* function = fxArgToCallback(the, 0); |
2426 | 21 | txInteger index = 0; |
2427 | 21 | mxResult->kind = XS_BOOLEAN_KIND; |
2428 | 21 | mxResult->value.boolean = 0; |
2429 | 21 | 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 | 21 | } |
2437 | | |
2438 | | void fx_TypedArray_prototype_sort(txMachine* the) |
2439 | 1.54k | { |
2440 | 1.54k | mxMutableTypedArrayDeclarations; |
2441 | 1.54k | txSlot* data = buffer->value.reference->next; |
2442 | 1.54k | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2443 | 1.54k | txSlot* function = C_NULL; |
2444 | 1.54k | 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 | 33 | else |
2456 | 33 | 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 | 32 | { |
2463 | 32 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2464 | 32 | txSlot* dispatch = instance->next; |
2465 | 32 | txSlot* view = dispatch->next; |
2466 | 32 | txSlot* buffer = view->next; |
2467 | 32 | txU2 shift = dispatch->value.typedArray.dispatch->shift; |
2468 | 32 | txInteger length = fxGetDataViewSize(the, view, buffer) >> shift; |
2469 | 32 | txInteger start = fxArgToIndexInteger(the, 0, 0, length); |
2470 | 32 | if ((view->value.dataView.size < 0) && ((mxArgc < 2) || mxIsUndefined(mxArgv(1)))) { |
2471 | 3 | fxCreateTypedArraySpecies(the); |
2472 | 3 | mxPushSlot(buffer); |
2473 | 3 | mxPushInteger(view->value.dataView.offset + (start << shift)); |
2474 | 3 | mxRunCount(2); |
2475 | 3 | } |
2476 | 29 | else { |
2477 | 29 | txInteger stop = fxArgToIndexInteger(the, 1, length, length); |
2478 | 29 | if (stop < start) |
2479 | 0 | stop = start; |
2480 | 29 | fxCreateTypedArraySpecies(the); |
2481 | 29 | mxPushSlot(buffer); |
2482 | 29 | mxPushInteger(view->value.dataView.offset + (start << shift)); |
2483 | 29 | mxPushInteger(stop - start); |
2484 | 29 | mxRunCount(3); |
2485 | 29 | } |
2486 | 32 | mxPullSlot(mxResult); |
2487 | 32 | fxCheckTypedArrayInstance(the, mxResult); |
2488 | 32 | } |
2489 | | |
2490 | | void fx_TypedArray_prototype_toLocaleString(txMachine* the) |
2491 | 22 | { |
2492 | 22 | mxTypedArrayDeclarations; |
2493 | 22 | txInteger index = 0; |
2494 | 22 | txString string; |
2495 | 22 | txSlot* list = fxNewInstance(the); |
2496 | 22 | txSlot* slot = list; |
2497 | 22 | txBoolean comma = 0; |
2498 | 22 | txInteger size = 0; |
2499 | 22 | mxPushStringX(","); |
2500 | 22 | the->stack->kind += XS_KEY_KIND - XS_STRING_KIND; |
2501 | 22 | the->stack->value.key.sum = 1; |
2502 | 22 | 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 | 22 | string = mxResult->value.string = fxNewChunk(the, fxAddChunkSizes(the, size, 1)); |
2526 | 22 | slot = list->next; |
2527 | 22 | 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 | 22 | *string = 0; |
2533 | 22 | mxResult->kind = XS_STRING_KIND; |
2534 | 22 | mxPop(); |
2535 | 22 | } |
2536 | | |
2537 | | void fx_TypedArray_prototype_toReversed(txMachine* the) |
2538 | 19 | { |
2539 | 19 | mxTypedArrayDeclarations; |
2540 | 19 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2541 | 19 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2542 | 19 | mxPushSlot(constructor); |
2543 | 19 | mxNew(); |
2544 | 19 | mxPushInteger(length); |
2545 | 19 | mxRunCount(1); |
2546 | 19 | mxPullSlot(mxResult); |
2547 | 19 | 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 | 19 | } |
2561 | | |
2562 | | void fx_TypedArray_prototype_toSorted(txMachine* the) |
2563 | 31 | { |
2564 | 31 | mxMutableTypedArrayDeclarations; |
2565 | 31 | txInteger delta = dispatch->value.typedArray.dispatch->size; |
2566 | 31 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2567 | 31 | txSlot* function = C_NULL; |
2568 | 31 | 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 | 31 | mxPushSlot(constructor); |
2578 | 31 | mxNew(); |
2579 | 31 | mxPushInteger(length); |
2580 | 31 | mxRunCount(1); |
2581 | 31 | mxPullSlot(mxResult); |
2582 | 31 | if (function) |
2583 | 0 | fxSortArrayItems(the, function, C_NULL, length, mxResult); |
2584 | 31 | else { |
2585 | 31 | mxResultTypedArrayDeclarations; |
2586 | 31 | txByte* from = buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
2587 | 31 | txByte* to = resultBuffer->value.reference->next->value.arrayBuffer.address; |
2588 | 31 | c_memcpy(to, from, resultLength << dispatch->value.typedArray.dispatch->shift); |
2589 | 31 | c_qsort(to, length, delta, dispatch->value.typedArray.dispatch->compare); |
2590 | 31 | } |
2591 | 31 | } |
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 | 40 | { |
2612 | 40 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
2613 | 40 | txSlot* dispatch = instance->next; |
2614 | 40 | txSlot* view = dispatch->next; |
2615 | 40 | txSlot* buffer = view->next; |
2616 | 40 | txSlot* property; |
2617 | 40 | fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
2618 | 40 | mxPush(mxArrayIteratorPrototype); |
2619 | 40 | property = fxLastProperty(the, fxNewIteratorInstance(the, mxThis, mxID(_Array))); |
2620 | 40 | property = fxNextIntegerProperty(the, property, 0, XS_NO_ID, XS_INTERNAL_FLAG); |
2621 | 40 | mxPullSlot(mxResult); |
2622 | 40 | } |
2623 | | |
2624 | | void fx_TypedArray_prototype_with(txMachine* the) |
2625 | 29 | { |
2626 | 29 | mxTypedArrayDeclarations; |
2627 | 29 | txSlot* constructor = &the->stackIntrinsics[-1 - (txInteger)dispatch->value.typedArray.dispatch->constructorID]; |
2628 | 29 | txInteger index = (txInteger)fxArgToRelativeIndex(the, 0, 0, length), count, i; |
2629 | 29 | txSlot* value; |
2630 | 29 | if (mxArgc > 1) |
2631 | 7 | mxPushSlot(mxArgv(1)); |
2632 | 22 | else |
2633 | 22 | mxPushUndefined(); |
2634 | 29 | value = the->stack; |
2635 | 29 | (*dispatch->value.typedArray.dispatch->coerce)(the, value); |
2636 | 29 | count = fxGetDataViewSize(the, view, buffer) >> dispatch->value.typedArray.dispatch->shift; |
2637 | 29 | if ((index < 0) || (count <= index)) |
2638 | 1 | mxRangeError("invalid index"); |
2639 | 28 | mxPushSlot(constructor); |
2640 | 28 | mxNew(); |
2641 | 28 | mxPushInteger(length); |
2642 | 28 | mxRunCount(1); |
2643 | 28 | mxPullSlot(mxResult); |
2644 | 28 | i = 0; |
2645 | 37 | 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 | 28 | mxPushSlot(value); |
2657 | 28 | mxPushSlot(mxResult); |
2658 | 28 | mxPushInteger(i); |
2659 | 28 | mxSetAt(); |
2660 | 28 | mxPop(); |
2661 | 28 | i++; |
2662 | 38 | while (i < length) { |
2663 | 10 | mxPushSlot(mxThis); |
2664 | 10 | mxPushInteger(i); |
2665 | 10 | mxGetAt(); |
2666 | 10 | mxPushSlot(mxResult); |
2667 | 10 | mxPushInteger(i); |
2668 | 10 | mxSetAt(); |
2669 | 10 | mxPop(); |
2670 | 10 | i++; |
2671 | 10 | mxCheckMetering(); |
2672 | 10 | } |
2673 | 28 | mxPop(); |
2674 | 28 | } |
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 | 30 | #define mxEndianFloat32_LtoN(a) (a) |
2699 | 24 | #define mxEndianFloat64_LtoN(a) (a) |
2700 | 66 | #define mxEndianS64_LtoN(a) (a) |
2701 | 51 | #define mxEndianU64_LtoN(a) (a) |
2702 | 24 | #define mxEndianS32_LtoN(a) (a) |
2703 | 30 | #define mxEndianU32_LtoN(a) (a) |
2704 | 17 | #define mxEndianS16_LtoN(a) (a) |
2705 | 13 | #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 | 112 | #define mxEndianFloat32_BtoN(a) (mxEndianFloat32_Swap(a)) |
2721 | 81 | #define mxEndianFloat64_BtoN(a) (mxEndianFloat64_Swap(a)) |
2722 | 99 | #define mxEndianS64_BtoN(a) ((txS8) mxEndian64_Swap(a)) |
2723 | 70 | #define mxEndianU64_BtoN(a) ((txU8) mxEndian64_Swap(a)) |
2724 | 80 | #define mxEndianS32_BtoN(a) ((txS4) mxEndian32_Swap(a)) |
2725 | 87 | #define mxEndianU32_BtoN(a) ((txU4) mxEndian32_Swap(a)) |
2726 | 84 | #define mxEndianS16_BtoN(a) ((txS2) mxEndian16_Swap(a)) |
2727 | 78 | #define mxEndianU16_BtoN(a) ((txU2) mxEndian16_Swap(a)) |
2728 | | |
2729 | 125 | #define mxEndianFloat16_NtoB(a) (mxEndianFloat16_Swap(a)) |
2730 | 90 | #define mxEndianFloat32_NtoB(a) (mxEndianFloat32_Swap(a)) |
2731 | 54 | #define mxEndianFloat64_NtoB(a) (mxEndianFloat64_Swap(a)) |
2732 | 71 | #define mxEndianS64_NtoB(a) ((txS8) mxEndian64_Swap(a)) |
2733 | 7 | #define mxEndianU64_NtoB(a) ((txU8) mxEndian64_Swap(a)) |
2734 | 62 | #define mxEndianS32_NtoB(a) ((txS4) mxEndian32_Swap(a)) |
2735 | 48 | #define mxEndianU32_NtoB(a) ((txU4) mxEndian32_Swap(a)) |
2736 | 73 | #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 | 318 | #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 | 277 | #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 | 247 | #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.1M | #define toNative(size, endian) mxEndian##size##_##endian##toN |
2803 | 125k | #define fromNative(size, endian) mxEndian##size##_Nto##endian |
2804 | 5.00M | #define IMPORT(size) (endian == EndianBig ? toNative(size, B)(value) : endian == EndianLittle ? toNative(size, L)(value) : (value)) |
2805 | 125k | #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 | 145 | { |
2816 | 145 | txS8 value; |
2817 | | #ifdef mxMisalignedSettersCrash |
2818 | | value = c_read32(data->value.arrayBuffer.address + offset); |
2819 | | #else |
2820 | 145 | value = *((txS8*)(data->value.arrayBuffer.address + offset)); |
2821 | 145 | #endif |
2822 | 145 | value = IMPORT(S64); |
2823 | 145 | fxFromBigInt64(the, slot, value); |
2824 | 145 | mxMeterOne(); |
2825 | 145 | } |
2826 | | |
2827 | | void fxBigInt64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2828 | 144 | { |
2829 | 144 | 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 | 144 | *((txS8*)(data->value.arrayBuffer.address + offset)) = EXPORT(S64); |
2835 | 144 | #endif |
2836 | 144 | mxMeterOne(); |
2837 | 144 | } |
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 | 131 | { |
2848 | 131 | txU8 value; |
2849 | | #ifdef mxMisalignedSettersCrash |
2850 | | value = c_read32(data->value.arrayBuffer.address + offset); |
2851 | | #else |
2852 | 131 | value = *((txU8*)(data->value.arrayBuffer.address + offset)); |
2853 | 131 | #endif |
2854 | 131 | value = IMPORT(U64); |
2855 | 131 | fxFromBigUint64(the, slot, value); |
2856 | 131 | mxMeterOne(); |
2857 | 131 | } |
2858 | | |
2859 | | void fxBigUint64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2860 | 48 | { |
2861 | 48 | 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 | 48 | *((txU8*)(data->value.arrayBuffer.address + offset)) = EXPORT(U64); |
2867 | 48 | #endif |
2868 | 48 | mxMeterOne(); |
2869 | 48 | } |
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 | 925 | #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 | 128 | hi |= 0x3F000000 << (abs >= 0x7C00); |
2894 | 162 | for (; abs < 0x400; abs <<= 1, hi -= 0x100000); |
2895 | 128 | hi += abs << 10; |
2896 | 128 | } |
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 | 99 | static uint32_t fxRoundFloat16(uint32_t value, uint32_t g, uint32_t s) { |
2903 | 99 | return value + (g & (s | value)); |
2904 | 99 | } |
2905 | | |
2906 | | static uint16_t fxFloat64to16(double value) |
2907 | 460 | { |
2908 | 460 | uint64_t dbits; |
2909 | 460 | uint32_t hi, lo, sign; |
2910 | | |
2911 | 460 | c_memcpy(&dbits, &value, sizeof(double)); |
2912 | 460 | hi = dbits >> 32; |
2913 | 460 | lo = dbits & 0xFFFFFFFF; |
2914 | 460 | sign = (hi >> 16) & 0x8000; |
2915 | 460 | hi &= 0x7FFFFFFF; |
2916 | 460 | if (hi >= 0x7FF00000) |
2917 | 0 | return sign | 0x7C00 | ((dbits & 0xFFFFFFFFFFFFF) ? (0x200 | ((hi >> 10) & 0x3FF)) : 0); |
2918 | 460 | if (hi >= 0x40F00000) |
2919 | 1 | return sign | 0x7C00; |
2920 | 459 | if (hi >= 0x3F100000) |
2921 | 98 | return fxRoundFloat16(sign | (((hi >> 20) - 1008) << 10) | ((hi >> 10) & 0x3FF), (hi >> 9) & 1, ((hi & 0x1FF) | lo) != 0); |
2922 | 361 | 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 | 360 | return sign; |
2928 | 361 | } |
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 | 253 | { |
2943 | 253 | #if defined(__GNUC__) || defined(__llvm__) |
2944 | 253 | uint32_t result = __builtin_bswap16(*(uint16_t *)&a); |
2945 | 253 | 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 | 253 | } |
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 | 478 | { |
2985 | 478 | txFloat16 value; |
2986 | 478 | slot->kind = XS_NUMBER_KIND; |
2987 | | #ifdef mxMisalignedSettersCrash |
2988 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
2989 | | #else |
2990 | 478 | value = *((txFloat16*)(data->value.arrayBuffer.address + offset)); |
2991 | 478 | #endif |
2992 | 478 | slot->value.number = mxFloat16to64(IMPORT(Float16)); |
2993 | 478 | mxMeterOne(); |
2994 | 478 | } |
2995 | | |
2996 | | void fxFloat16Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
2997 | 465 | { |
2998 | 465 | #if mxCanonicalNaN |
2999 | 465 | 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 | 465 | *((txFloat16*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float16); |
3008 | 465 | #endif |
3009 | 465 | mxMeterOne(); |
3010 | 465 | } |
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 | 202 | { |
3032 | 202 | #if defined(__GNUC__) || defined(__llvm__) |
3033 | 202 | uint32_t result = __builtin_bswap32(*(uint32_t *)&a); |
3034 | 202 | 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 | 202 | } |
3044 | | |
3045 | | int fxFloat32Compare(const void* p, const void* q) |
3046 | 10 | { |
3047 | 10 | float a = *((float*)p); |
3048 | 10 | float b = *((float*)q); |
3049 | 10 | if (c_isnan(a)) { |
3050 | 0 | if (c_isnan(b)) |
3051 | 0 | return 0; |
3052 | 0 | return 1; |
3053 | 0 | } |
3054 | 10 | if (c_isnan(b)) |
3055 | 0 | return -1; |
3056 | 10 | if (a < b) |
3057 | 0 | return -1; |
3058 | 10 | if (a > b) |
3059 | 0 | return 1; |
3060 | 10 | if (a == 0) { |
3061 | 10 | if (c_signbit(a)) { |
3062 | 0 | if (c_signbit(b)) |
3063 | 0 | return 0; |
3064 | 0 | return -1; |
3065 | 0 | } |
3066 | 10 | if (c_signbit(b)) |
3067 | 0 | return 1; |
3068 | 10 | } |
3069 | 10 | return 0; |
3070 | 10 | } |
3071 | | |
3072 | | void fxFloat32Getter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3073 | 66.3k | { |
3074 | 66.3k | float value; |
3075 | 66.3k | slot->kind = XS_NUMBER_KIND; |
3076 | | #ifdef mxMisalignedSettersCrash |
3077 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3078 | | #else |
3079 | 66.3k | value = *((float*)(data->value.arrayBuffer.address + offset)); |
3080 | 66.3k | #endif |
3081 | 66.3k | slot->value.number = IMPORT(Float32); |
3082 | 66.3k | mxMeterOne(); |
3083 | 66.3k | } |
3084 | | |
3085 | | void fxFloat32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3086 | 472 | { |
3087 | 472 | #if mxCanonicalNaN |
3088 | 472 | 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 | 472 | *((float*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float32); |
3097 | 472 | #endif |
3098 | 472 | mxMeterOne(); |
3099 | 472 | } |
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 | 135 | { |
3112 | 135 | #if defined(__GNUC__) || defined(__llvm__) |
3113 | 135 | uint64_t result = __builtin_bswap64(*(uint64_t *)&a); |
3114 | 135 | 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 | 135 | } |
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 | 527 | { |
3154 | 527 | double value; |
3155 | 527 | slot->kind = XS_NUMBER_KIND; |
3156 | | #ifdef mxMisalignedSettersCrash |
3157 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3158 | | #else |
3159 | 527 | value = *((double*)(data->value.arrayBuffer.address + offset)); |
3160 | 527 | #endif |
3161 | 527 | slot->value.number = IMPORT(Float64); |
3162 | 527 | mxMeterOne(); |
3163 | 527 | } |
3164 | | |
3165 | | void fxFloat64Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3166 | 490 | { |
3167 | 490 | #if mxCanonicalNaN |
3168 | 490 | 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 | 490 | *((double*)(data->value.arrayBuffer.address + offset)) = EXPORT(Float64); |
3177 | 490 | #endif |
3178 | 490 | mxMeterOne(); |
3179 | 490 | } |
3180 | | |
3181 | | void fxIntCoerce(txMachine* the, txSlot* slot) |
3182 | 16.5k | { |
3183 | 16.5k | fxToInteger(the, slot); |
3184 | 16.5k | } |
3185 | | |
3186 | | void fxUintCoerce(txMachine* the, txSlot* slot) |
3187 | 129k | { |
3188 | 129k | fxToUnsigned(the, slot); |
3189 | 129k | } |
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 | 574 | { |
3200 | 574 | slot->kind = XS_INTEGER_KIND; |
3201 | 574 | slot->value.integer = *((txS1*)(data->value.arrayBuffer.address + offset)); |
3202 | 574 | mxMeterOne(); |
3203 | 574 | } |
3204 | | |
3205 | | void fxInt8Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3206 | 15.9k | { |
3207 | 15.9k | *((txS1*)(data->value.arrayBuffer.address + offset)) = (txS1)slot->value.integer; |
3208 | 15.9k | mxMeterOne(); |
3209 | 15.9k | } |
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 | 849k | { |
3220 | 849k | txS2 value; |
3221 | 849k | slot->kind = XS_INTEGER_KIND; |
3222 | | #ifdef mxMisalignedSettersCrash |
3223 | | c_memcpy(&value, data->value.arrayBuffer.address + offset, sizeof(value)); |
3224 | | #else |
3225 | 849k | value = *((txS2*)(data->value.arrayBuffer.address + offset)); |
3226 | 849k | #endif |
3227 | 849k | slot->value.integer = IMPORT(S16); |
3228 | 849k | mxMeterOne(); |
3229 | 849k | } |
3230 | | |
3231 | | void fxInt16Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3232 | 245 | { |
3233 | 245 | 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 | 245 | *((txS2*)(data->value.arrayBuffer.address + offset)) = EXPORT(S16); |
3239 | 245 | #endif |
3240 | 245 | mxMeterOne(); |
3241 | 245 | } |
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 | 1.99M | { |
3252 | 1.99M | txS4 value; |
3253 | 1.99M | slot->kind = XS_INTEGER_KIND; |
3254 | | #ifdef mxMisalignedSettersCrash |
3255 | | value = c_read32(data->value.arrayBuffer.address + offset); |
3256 | | #else |
3257 | 1.99M | value = *((txS4*)(data->value.arrayBuffer.address + offset)); |
3258 | 1.99M | #endif |
3259 | 1.99M | slot->value.integer = IMPORT(S32); |
3260 | 1.99M | mxMeterOne(); |
3261 | 1.99M | } |
3262 | | |
3263 | | void fxInt32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3264 | 182 | { |
3265 | 182 | 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 | 182 | *((txS4*)(data->value.arrayBuffer.address + offset)) = EXPORT(S32); |
3271 | 182 | #endif |
3272 | 182 | mxMeterOne(); |
3273 | 182 | } |
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.30k | { |
3284 | 1.30k | slot->kind = XS_INTEGER_KIND; |
3285 | 1.30k | slot->value.integer = c_read8((txU1*)(data->value.arrayBuffer.address + offset)); |
3286 | 1.30k | mxMeterOne(); |
3287 | 1.30k | } |
3288 | | |
3289 | | void fxUint8Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3290 | 5.38k | { |
3291 | 5.38k | txUnsigned tmp = (slot->kind == XS_INTEGER_KIND) ? (txUnsigned)slot->value.integer : (txUnsigned)slot->value.number; |
3292 | 5.38k | *((txU1*)(data->value.arrayBuffer.address + offset)) = (txU1)tmp; |
3293 | 5.38k | mxMeterOne(); |
3294 | 5.38k | } |
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 | 3.75k | { |
3318 | 3.75k | txUnsigned tmp = (slot->kind == XS_INTEGER_KIND) ? (txUnsigned)slot->value.integer : (txUnsigned)slot->value.number; |
3319 | 3.75k | 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 | 3.75k | *((txU2*)(data->value.arrayBuffer.address + offset)) = EXPORT(U16); |
3325 | 3.75k | #endif |
3326 | 3.75k | mxMeterOne(); |
3327 | 3.75k | } |
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.35k | { |
3338 | | #ifdef mxMisalignedSettersCrash |
3339 | | txUnsigned value = c_read32(data->value.arrayBuffer.address + offset); |
3340 | | #else |
3341 | 1.35k | txUnsigned value = *((txU4*)(data->value.arrayBuffer.address + offset)); |
3342 | 1.35k | #endif |
3343 | 1.35k | value = IMPORT(U32); |
3344 | 1.35k | if (((txInteger)value) >= 0) { |
3345 | 1.10k | slot->kind = XS_INTEGER_KIND; |
3346 | 1.10k | slot->value.integer = value; |
3347 | 1.10k | } |
3348 | 246 | else { |
3349 | 246 | slot->kind = XS_NUMBER_KIND; |
3350 | 246 | slot->value.number = value; |
3351 | 246 | } |
3352 | 1.35k | mxMeterOne(); |
3353 | 1.35k | } |
3354 | | |
3355 | | void fxUint32Setter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3356 | 120k | { |
3357 | 120k | 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 | 120k | *((txU4*)(data->value.arrayBuffer.address + offset)) = EXPORT(U32); |
3363 | 120k | #endif |
3364 | 120k | mxMeterOne(); |
3365 | 120k | } |
3366 | | |
3367 | | void fxUint8ClampedSetter(txMachine* the, txSlot* data, txInteger offset, txSlot* slot, int endian) |
3368 | 8 | { |
3369 | 8 | txNumber value = fxToNumber(the, slot); |
3370 | 8 | if (value <= 0) |
3371 | 2 | value = 0; |
3372 | 6 | else if (value >= 255) |
3373 | 0 | value = 255; |
3374 | 6 | else if (c_isnan(value)) |
3375 | 2 | value = 0; |
3376 | 4 | else |
3377 | 4 | value = c_nearbyint(value); |
3378 | 8 | *((txU1*)(data->value.arrayBuffer.address + offset)) = (txU1)value; |
3379 | 8 | mxMeterOne(); |
3380 | 8 | } |
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 | 3.19M | { |
3396 | 3.19M | txU1* p = *src; |
3397 | 3.19M | txU1 c; |
3398 | 4.29M | while ((c = c_read8(p))) { |
3399 | 4.24M | if ((c != 0x09) && (c != 0x0A) && (c != 0x0C) && (c != 0x0D) && (c != 0x20)) |
3400 | 3.15M | break; |
3401 | 1.09M | p++; |
3402 | 1.09M | } |
3403 | 3.19M | *src = p; |
3404 | 3.19M | return c; |
3405 | 3.19M | } |
3406 | | |
3407 | | static void fxUint8ArrayFromBase64(txMachine* the, txU1* srcStart, txU1* dstStart, txSize* read, txSize* written, txU1* alphabet, txInteger lastChunkHandling) |
3408 | 302k | { |
3409 | 302k | txU1* src = srcStart; |
3410 | 302k | txU1* dst = dstStart; |
3411 | 302k | txSize remaining = *written; |
3412 | 302k | txBoolean url = (alphabet == (txU1*)gxBase64URLAlphabet) ? 1 : 0, done = 0; |
3413 | 302k | txU1 byte, buffer[4]; |
3414 | 302k | txSize bufferIndex, bufferLength = 0; |
3415 | | |
3416 | 302k | if (remaining == 0) { |
3417 | 1 | *read = 0; |
3418 | 1 | return; |
3419 | 1 | } |
3420 | 3.04M | for (;;) { |
3421 | 3.04M | byte = fxSkipAsciiWhitespace(&src); |
3422 | 3.04M | if (byte == 0) { |
3423 | 48.2k | if (bufferLength == 0) |
3424 | 43.8k | break; |
3425 | 4.37k | if (lastChunkHandling == mxBase64StopBeforePartial) |
3426 | 3 | break; |
3427 | 4.37k | if ((lastChunkHandling == mxBase64Strict) || (bufferLength == 1)) |
3428 | 4.24k | mxSyntaxError("invalid string"); |
3429 | 123 | if (bufferLength == 2) |
3430 | 120 | buffer[2] = 0; |
3431 | 123 | buffer[3] = 0; |
3432 | 123 | done = 1; |
3433 | 123 | } |
3434 | 3.00M | else if (byte == '=') { |
3435 | 200k | if (bufferLength < 2) |
3436 | 50.5k | mxSyntaxError("invalid string"); |
3437 | 150k | src++; |
3438 | 150k | byte = fxSkipAsciiWhitespace(&src); |
3439 | 150k | if (bufferLength == 2) { |
3440 | 99.4k | if (byte == 0) { |
3441 | 6 | if (lastChunkHandling == mxBase64StopBeforePartial) |
3442 | 0 | break; |
3443 | 6 | mxSyntaxError("invalid string"); |
3444 | 6 | } |
3445 | 99.4k | if (byte == '=') { |
3446 | 20 | src++; |
3447 | 20 | byte = fxSkipAsciiWhitespace(&src); |
3448 | 20 | } |
3449 | 99.4k | buffer[2] = 0; |
3450 | 99.4k | } |
3451 | 150k | if (byte != 0) |
3452 | 150k | mxSyntaxError("invalid string"); |
3453 | 25 | buffer[3] = 0; |
3454 | 25 | done = 1; |
3455 | 25 | } |
3456 | 2.79M | else { |
3457 | 2.79M | if (('A' <= byte) && (byte <= 'Z')) |
3458 | 330k | byte = byte - 'A'; |
3459 | 2.46M | else if (('a' <= byte) && (byte <= 'z')) |
3460 | 697k | byte = byte - 'a' + 26; |
3461 | 1.77M | else if (('0' <= byte) && (byte <= '9')) |
3462 | 1.12M | byte = byte - '0' + 52; |
3463 | 645k | else if ((byte == '+') && !url) |
3464 | 140 | byte = 62; |
3465 | 645k | else if ((byte == '-') && url) |
3466 | 1 | byte = 62; |
3467 | 645k | else if ((byte == '/') && !url) |
3468 | 609k | byte = 63; |
3469 | 35.5k | else if ((byte == '_') && url) |
3470 | 1 | byte = 63; |
3471 | 35.5k | else |
3472 | 35.5k | mxSyntaxError("invalid string"); |
3473 | 2.76M | if (((remaining == 1) && (bufferLength == 2)) || ((remaining == 2) && (bufferLength == 3))) |
3474 | 7 | break; |
3475 | 2.76M | buffer[bufferLength] = byte; |
3476 | 2.76M | bufferLength++; |
3477 | 2.76M | src++; |
3478 | 2.76M | if (bufferLength < 4) |
3479 | 2.18M | continue; |
3480 | 2.76M | } |
3481 | 581k | *read = (txSize)(src - srcStart); |
3482 | 581k | buffer[0] = (buffer[0] << 2) | ((buffer[1] & 0x30) >> 4); |
3483 | 581k | buffer[1] = ((buffer[1] & 0x0F) << 4) | ((buffer[2] & 0x3C) >> 2); |
3484 | 581k | buffer[2] = ((buffer[2] & 0x03) << 6) | (buffer[3] & 0x3F); |
3485 | 581k | bufferLength--; |
3486 | 581k | if ((lastChunkHandling == mxBase64Strict) && (bufferLength < 3) && (buffer[bufferLength] != 0)) |
3487 | 0 | mxSyntaxError("invalid string"); |
3488 | 581k | bufferIndex = 0; |
3489 | 2.32M | while ((bufferIndex < bufferLength) && (remaining > 0)) { |
3490 | 1.74M | *dst++ = buffer[bufferIndex]; |
3491 | 1.74M | bufferIndex++; |
3492 | 1.74M | remaining--; |
3493 | 1.74M | } |
3494 | 581k | bufferLength = 0; |
3495 | 581k | if ((done) || (remaining == 0)) |
3496 | 18.0k | break; |
3497 | 581k | } |
3498 | 61.9k | *written = (txSize)(dst - dstStart); |
3499 | 61.9k | } |
3500 | | |
3501 | | static void fxUint8ArrayFromHex(txMachine* the, txU1* srcStart, txU1* dstStart, txSize* read, txSize* written) |
3502 | 29 | { |
3503 | 29 | #define mxFromHex(X) \ |
3504 | 156 | if (('0' <= X) && (X <= '9')) X = X - '0'; \ |
3505 | 156 | else if (('A' <= X) && (X <= 'F')) X = X - 'A' + 10; \ |
3506 | 109 | else if (('a' <= X) && (X <= 'f')) X = X - 'a' + 10; \ |
3507 | 89 | else mxSyntaxError("invalid string") |
3508 | | |
3509 | 29 | txU1* src = srcStart; |
3510 | 29 | txU1* dst = dstStart; |
3511 | 29 | txSize srcSize = *read; |
3512 | 29 | txSize dstSize = *written; |
3513 | 92 | while ((srcSize > 0) && (dstSize > 0)) { |
3514 | 80 | txU1 high = c_read8(src++); |
3515 | 80 | txU1 low = c_read8(src++); |
3516 | 80 | mxFromHex(high); |
3517 | 76 | mxFromHex(low); |
3518 | 63 | *dst++ = (high << 4) + low; |
3519 | 63 | srcSize -= 2; |
3520 | 63 | dstSize--; |
3521 | 63 | } |
3522 | 12 | *read = (txSize)(src - srcStart); |
3523 | 12 | *written = (txSize)(dst - dstStart); |
3524 | 12 | } |
3525 | | |
3526 | | static void fxUint8ArrayGetBase64Options(txMachine* the, txInteger argi, txU1** alphabet, txInteger* lastChunkHandling, txBoolean* omitPadding) |
3527 | 302k | { |
3528 | 302k | if ((mxArgc > argi) && !mxIsUndefined(mxArgv(argi))) { |
3529 | 90 | if (!mxIsReference(mxArgv(argi))) |
3530 | 1 | mxTypeError("options: not an object"); |
3531 | 89 | mxPushSlot(mxArgv(argi)); |
3532 | 89 | mxGetID(mxID(_alphabet)); |
3533 | 89 | if (!mxIsUndefined(the->stack)) { |
3534 | 35 | if (!mxIsStringPrimitive(the->stack)) |
3535 | 8 | mxTypeError("options.alphabet: not a string"); |
3536 | 27 | if (!c_strcmp(the->stack->value.string, "base64url")) |
3537 | 20 | *alphabet = (txU1*)gxBase64URLAlphabet; |
3538 | 7 | else if (c_strcmp(the->stack->value.string, "base64")) |
3539 | 4 | mxTypeError("options.alphabet: neither 'base64' nor 'base64url'"); |
3540 | 27 | } |
3541 | 77 | mxPop(); |
3542 | 77 | if (lastChunkHandling) { |
3543 | 19 | mxPushSlot(mxArgv(argi)); |
3544 | 19 | mxGetID(mxID(_lastChunkHandling)); |
3545 | 19 | if (!mxIsUndefined(the->stack)) { |
3546 | 13 | if (!mxIsStringPrimitive(the->stack)) |
3547 | 3 | mxTypeError("options.lastChunkHandling: not a string"); |
3548 | 10 | if (!c_strcmp(the->stack->value.string, "stop-before-partial")) |
3549 | 3 | *lastChunkHandling = mxBase64StopBeforePartial; |
3550 | 7 | else if (!c_strcmp(the->stack->value.string, "strict")) |
3551 | 3 | *lastChunkHandling = mxBase64Strict; |
3552 | 4 | else if (c_strcmp(the->stack->value.string, "loose")) |
3553 | 1 | mxTypeError("options.lastChunkHandling: neither 'loose' nor 'strict' nor 'stop-before-partial'"); |
3554 | 10 | } |
3555 | 15 | mxPop(); |
3556 | 15 | } |
3557 | 73 | if (omitPadding) { |
3558 | 58 | mxPushSlot(mxArgv(argi)); |
3559 | 58 | mxGetID(mxID(_omitPadding)); |
3560 | 58 | fxToBoolean(the, the->stack); |
3561 | 58 | *omitPadding = the->stack->value.boolean; |
3562 | 58 | mxPop(); |
3563 | 58 | } |
3564 | 73 | } |
3565 | 302k | } |
3566 | | |
3567 | | void fx_Uint8Array_fromBase64(txMachine* the) |
3568 | 302k | { |
3569 | 302k | txSize srcSize; |
3570 | 302k | txSize dstSize; |
3571 | 302k | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3572 | 302k | txInteger lastChunkHandling = mxBase64Loose; |
3573 | 302k | txU1* src; |
3574 | 302k | txU1* dst; |
3575 | 302k | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3576 | 13 | mxTypeError("string: not a string"); |
3577 | 302k | fxUint8ArrayGetBase64Options(the, 1, &alphabet, &lastChunkHandling, NULL); |
3578 | 302k | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3579 | 302k | dstSize = (((srcSize + 3) / 4) * 3); |
3580 | 302k | mxPush(mxUint8ArrayConstructor); |
3581 | 302k | mxNew(); |
3582 | 302k | mxPushInteger(dstSize); |
3583 | 302k | mxRunCount(1); |
3584 | 302k | mxPullSlot(mxResult); |
3585 | 302k | { |
3586 | 302k | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
3587 | 302k | txSlot* resultDispatch = resultInstance->next; \ |
3588 | 302k | txSlot* resultView = resultDispatch->next; \ |
3589 | 302k | txSlot* resultBuffer = resultView->next; \ |
3590 | 302k | src = (txU1*)(mxArgv(0)->value.string); |
3591 | 302k | dst = (txU1*)(resultBuffer->value.reference->next->value.arrayBuffer.address + resultView->value.dataView.offset); |
3592 | 302k | resultBuffer->value.reference->next->next->value.bufferInfo.maxLength = dstSize; |
3593 | 302k | fxUint8ArrayFromBase64(the, src, dst, &srcSize, &dstSize, alphabet, lastChunkHandling); |
3594 | 302k | fxSetArrayBufferLength(the, resultBuffer, dstSize); |
3595 | 302k | resultBuffer->value.reference->next->next->value.bufferInfo.maxLength = -1; |
3596 | 302k | resultView->value.dataView.size = dstSize; |
3597 | 302k | } |
3598 | 302k | } |
3599 | | |
3600 | | void fx_Uint8Array_fromHex(txMachine* the) |
3601 | 53 | { |
3602 | 53 | txSize srcSize; |
3603 | 53 | txSize dstSize; |
3604 | 53 | txU1* src; |
3605 | 53 | txU1* dst; |
3606 | 53 | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3607 | 5 | mxTypeError("string: not a string"); |
3608 | 48 | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3609 | 48 | if (srcSize & 1) |
3610 | 26 | mxSyntaxError("string: odd length"); |
3611 | 22 | dstSize = srcSize >> 1; |
3612 | 22 | mxPush(mxUint8ArrayConstructor); |
3613 | 22 | mxNew(); |
3614 | 22 | mxPushInteger(dstSize); |
3615 | 22 | mxRunCount(1); |
3616 | 22 | mxPullSlot(mxResult); |
3617 | 22 | { |
3618 | 22 | txSlot* resultInstance = fxCheckTypedArrayInstance(the, mxResult); \ |
3619 | 22 | txSlot* resultDispatch = resultInstance->next; \ |
3620 | 22 | txSlot* resultView = resultDispatch->next; \ |
3621 | 22 | txSlot* resultBuffer = resultView->next; \ |
3622 | 22 | src = (txU1*)(mxArgv(0)->value.string); |
3623 | 22 | dst = (txU1*)(resultBuffer->value.reference->next->value.arrayBuffer.address + resultView->value.dataView.offset); |
3624 | 22 | fxUint8ArrayFromHex(the, src, dst, &srcSize, &dstSize); |
3625 | 22 | } |
3626 | 22 | } |
3627 | | |
3628 | | void fx_Uint8Array_prototype_setFromBase64(txMachine* the) |
3629 | 41 | { |
3630 | 41 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3631 | 41 | txSlot* dispatch = instance->next; |
3632 | 41 | txSlot* view = dispatch->next; |
3633 | 41 | txSlot* buffer = view->next; |
3634 | 41 | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3635 | 41 | txInteger lastChunkHandling = mxBase64Loose; |
3636 | 41 | txSize srcSize; |
3637 | 41 | txSize dstSize; |
3638 | 41 | txU1* src; |
3639 | 41 | txU1* dst; |
3640 | 41 | txSlot* property; |
3641 | 41 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3642 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3643 | 41 | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3644 | 9 | mxTypeError("string: not a string"); |
3645 | 32 | fxUint8ArrayGetBase64Options(the, 1, &alphabet, &lastChunkHandling, NULL); |
3646 | 32 | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3647 | 32 | dstSize = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
3648 | 32 | src = (txU1*)(mxArgv(0)->value.string); |
3649 | 32 | dst = (txU1*)(buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset); |
3650 | 32 | fxUint8ArrayFromBase64(the, src, dst, &srcSize, &dstSize, alphabet, lastChunkHandling); |
3651 | 32 | mxPush(mxObjectPrototype); |
3652 | 32 | property = fxLastProperty(the, fxNewObjectInstance(the)); |
3653 | 32 | property = fxNextIntegerProperty(the, property, srcSize, mxID(_read_), XS_NO_FLAG); |
3654 | 32 | property = fxNextIntegerProperty(the, property, dstSize, mxID(_written), XS_NO_FLAG); |
3655 | 32 | mxPullSlot(mxResult); |
3656 | 32 | } |
3657 | | |
3658 | | void fx_Uint8Array_prototype_setFromHex(txMachine* the) |
3659 | 29 | { |
3660 | 29 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3661 | 29 | txSlot* dispatch = instance->next; |
3662 | 29 | txSlot* view = dispatch->next; |
3663 | 29 | txSlot* buffer = view->next; |
3664 | 29 | txSize srcSize; |
3665 | 29 | txSize dstSize; |
3666 | 29 | txU1* src; |
3667 | 29 | txU1* dst; |
3668 | 29 | txSlot* property; |
3669 | 29 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3670 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3671 | 29 | if ((mxArgc < 1) || !mxIsStringPrimitive(mxArgv(0))) |
3672 | 2 | mxTypeError("string: not a string"); |
3673 | 27 | srcSize = (txSize)c_strlen(mxArgv(0)->value.string); |
3674 | 27 | if (srcSize & 1) |
3675 | 20 | mxSyntaxError("string: odd length"); |
3676 | 7 | dstSize = fxCheckDataViewSize(the, view, buffer, XS_MUTABLE); |
3677 | 7 | src = (txU1*)(mxArgv(0)->value.string); |
3678 | 7 | dst = (txU1*)(buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset); |
3679 | 7 | fxUint8ArrayFromHex(the, src, dst, &srcSize, &dstSize); |
3680 | 7 | mxPush(mxObjectPrototype); |
3681 | 7 | property = fxLastProperty(the, fxNewObjectInstance(the)); |
3682 | 7 | property = fxNextIntegerProperty(the, property, srcSize, mxID(_read_), XS_NO_FLAG); |
3683 | 7 | property = fxNextIntegerProperty(the, property, dstSize, mxID(_written), XS_NO_FLAG); |
3684 | 7 | mxPullSlot(mxResult); |
3685 | 7 | } |
3686 | | |
3687 | | void fx_Uint8Array_prototype_toBase64(txMachine* the) |
3688 | 101 | { |
3689 | 101 | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3690 | 101 | txSlot* dispatch = instance->next; |
3691 | 101 | txSlot* view = dispatch->next; |
3692 | 101 | txSlot* buffer = view->next; |
3693 | 101 | txU1* alphabet = (txU1*)gxBase64Alphabet; |
3694 | 101 | txBoolean omitPadding = 0; |
3695 | 101 | txU1* src; |
3696 | 101 | txU1* dst; |
3697 | 101 | txSize srcSize; |
3698 | 101 | txSize dstSize; |
3699 | 101 | txU1 a, b, c; |
3700 | 101 | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3701 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3702 | 101 | fxUint8ArrayGetBase64Options(the, 0, &alphabet, C_NULL, &omitPadding); |
3703 | 101 | srcSize = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
3704 | 101 | if (srcSize > (((0x7FFFFFFF >> 2) * 3) - 2)) |
3705 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
3706 | 101 | dstSize = (((srcSize + 2) / 3) << 2); |
3707 | 101 | fxStringBuffer(the, mxResult, C_NULL, dstSize); |
3708 | 101 | src = (txU1*)buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
3709 | 101 | dst = (txU1*)mxResult->value.string; |
3710 | 147 | while (srcSize > 2) { |
3711 | 46 | a = c_read8(src++); |
3712 | 46 | b = c_read8(src++); |
3713 | 46 | c = c_read8(src++); |
3714 | 46 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3715 | 46 | *dst++ = c_read8(alphabet + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
3716 | 46 | *dst++ = c_read8(alphabet + (((b & 0xf) << 2) | ((c & 0xc0) >> 6))); |
3717 | 46 | *dst++ = c_read8(alphabet + (c & 0x3f)); |
3718 | 46 | srcSize -= 3; |
3719 | 46 | } |
3720 | 101 | if (srcSize == 2) { |
3721 | 45 | a = c_read8(src++); |
3722 | 45 | b = c_read8(src++); |
3723 | 45 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3724 | 45 | *dst++ = c_read8(alphabet + (((a & 0x3) << 4) | ((b & 0xf0) >> 4))); |
3725 | 45 | *dst++ = c_read8(alphabet + ((b & 0xf) << 2)); |
3726 | 45 | if (!omitPadding) |
3727 | 32 | *dst++ = '='; |
3728 | 45 | } |
3729 | 56 | else if (srcSize == 1) { |
3730 | 21 | a = c_read8(src++); |
3731 | 21 | *dst++ = c_read8(alphabet + ((a & 0xfc) >> 2)); |
3732 | 21 | *dst++ = c_read8(alphabet + ((a & 0x3) << 4)); |
3733 | 21 | if (!omitPadding) { |
3734 | 6 | *dst++ = '='; |
3735 | 6 | *dst++ = '='; |
3736 | 6 | } |
3737 | 21 | } |
3738 | 101 | *dst++ = 0; |
3739 | 101 | } |
3740 | | |
3741 | | void fx_Uint8Array_prototype_toHex(txMachine* the) |
3742 | 1.62k | { |
3743 | 1.62k | txSlot* instance = fxCheckTypedArrayInstance(the, mxThis); |
3744 | 1.62k | txSlot* dispatch = instance->next; |
3745 | 1.62k | txSlot* view = dispatch->next; |
3746 | 1.62k | txSlot* buffer = view->next; |
3747 | 1.62k | txU1* alphabet = (txU1*)gxHexAlphabet; |
3748 | 1.62k | txU1* src; |
3749 | 1.62k | txU1* dst; |
3750 | 1.62k | txSize srcSize; |
3751 | 1.62k | txSize dstSize; |
3752 | 1.62k | txU1 a; |
3753 | 1.62k | if (dispatch->value.typedArray.dispatch->constructorID != mxID(_Uint8Array)) |
3754 | 0 | mxTypeError("this: not a Uint8Array instance"); |
3755 | 1.62k | srcSize = fxCheckDataViewSize(the, view, buffer, XS_IMMUTABLE); |
3756 | 1.62k | if (srcSize > (0x7FFFFFFF >> 1)) |
3757 | 0 | fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT); |
3758 | 1.62k | dstSize = (srcSize << 1); |
3759 | 1.62k | fxStringBuffer(the, mxResult, C_NULL, dstSize); |
3760 | 1.62k | src = (txU1*)buffer->value.reference->next->value.arrayBuffer.address + view->value.dataView.offset; |
3761 | 1.62k | dst = (txU1*)mxResult->value.string; |
3762 | 5.41k | while (srcSize > 0) { |
3763 | 3.78k | a = c_read8(src++); |
3764 | 3.78k | *dst++ = c_read8(alphabet + ((a & 0xf0) >> 4)); |
3765 | 3.78k | *dst++ = c_read8(alphabet + (a & 0x0f)); |
3766 | 3.78k | srcSize--; |
3767 | 3.78k | } |
3768 | 1.62k | *dst++ = 0; |
3769 | 1.62k | } |
3770 | | |
3771 | | #endif |