1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/builtins/builtins_dataview.h"
17 #include "ecmascript/builtins/builtins_arraybuffer.h"
18 #include "ecmascript/js_arraybuffer.h"
19 #include "ecmascript/js_tagged_value-inl.h"
20
21 namespace panda::ecmascript::builtins {
22 // 24.2.2.1
DataViewConstructor(EcmaRuntimeCallInfo * argv)23 JSTaggedValue BuiltinsDataView::DataViewConstructor(EcmaRuntimeCallInfo *argv)
24 {
25 ASSERT(argv);
26 JSThread *thread = argv->GetThread();
27 BUILTINS_API_TRACE(thread, DataView, Constructor);
28 [[maybe_unused]] EcmaHandleScope handleScope(thread);
29 JSHandle<JSTaggedValue> ctor = GetConstructor(argv);
30 JSHandle<JSTaggedValue> newTarget = GetNewTarget(argv);
31 // 1. If NewTarget is undefined, throw a TypeError exception.
32 if (newTarget->IsUndefined()) {
33 THROW_TYPE_ERROR_AND_RETURN(thread, "newtarget is undefined", JSTaggedValue::Exception());
34 }
35 JSHandle<JSTaggedValue> bufferHandle = GetCallArg(argv, 0);
36 // 2. If Type(buffer) is not Object, throw a TypeError exception.
37 if (!bufferHandle->IsECMAObject()) {
38 THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not Object", JSTaggedValue::Exception());
39 }
40 // 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception.
41 if (!bufferHandle->IsArrayBuffer() && !bufferHandle->IsSharedArrayBuffer()) {
42 THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is not ArrayBuffer", JSTaggedValue::Exception());
43 }
44 JSHandle<JSTaggedValue> offsetHandle = GetCallArg(argv, 1);
45 // 4. Let numberOffset be ToIndex(byteOffset).
46 JSTaggedNumber offsetNumber = JSTaggedValue::ToIndex(thread, offsetHandle);
47 // 6. ReturnIfAbrupt(offset).
48 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
49 uint64_t offset = base::NumberHelper::DoubleToUInt64(offsetNumber.GetNumber());
50 // 7. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
51 if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, bufferHandle.GetTaggedValue())) {
52 THROW_TYPE_ERROR_AND_RETURN(thread, "buffer is Detached Buffer", JSTaggedValue::Exception());
53 }
54 // 8. Let bufferByteLength be the value of buffer’s [[ArrayBufferByteLength]] internal slot.
55 JSHandle<JSArrayBuffer> arrBufHandle(bufferHandle);
56 uint32_t bufByteLen = arrBufHandle->GetArrayBufferByteLength();
57 // 9. If offset > bufferByteLength, throw a RangeError exception.
58 if (offset > bufByteLen) {
59 THROW_RANGE_ERROR_AND_RETURN(thread, "offset > bufferByteLength", JSTaggedValue::Exception());
60 }
61 uint64_t viewByteLen = 0;
62 JSHandle<JSTaggedValue> byteLenHandle = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
63 // 10. If byteLength is undefined, then Let viewByteLength be bufferByteLength – offset.
64 if (byteLenHandle->IsUndefined()) {
65 viewByteLen = bufByteLen - offset;
66 } else {
67 // Let viewByteLength be ToIndex(byteLength).
68 JSTaggedNumber byteLen = JSTaggedValue::ToIndex(thread, byteLenHandle);
69 // ReturnIfAbrupt(viewByteLength).
70 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
71 viewByteLen = base::NumberHelper::DoubleToUInt64(byteLen.GetNumber());
72 // If offset+viewByteLength > bufferByteLength, throw a RangeError exception.
73 if (offset + viewByteLen > bufByteLen) {
74 THROW_RANGE_ERROR_AND_RETURN(thread, "offset + viewByteLen > bufByteLen", JSTaggedValue::Exception());
75 }
76 }
77 // 11. Let O be OrdinaryCreateFromConstructor OrdinaryCreateFromConstructor(NewTarget, "%DataViewPrototype%",
78 // «[[DataView]],[[ViewedArrayBuffer]], [[ByteLength]], [[ByteOffset]]» ).
79 ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
80 JSHandle<JSObject> obj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(ctor), newTarget);
81 // 12. ReturnIfAbrupt(O).
82 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
83 JSHandle<JSDataView> dataView(obj);
84 // 13. Set O’s [[DataView]] internal slot to true.
85 dataView->SetDataView(thread, JSTaggedValue::True());
86 // 14. Set O’s [[ViewedArrayBuffer]] internal slot to buffer.
87 dataView->SetViewedArrayBuffer(thread, bufferHandle.GetTaggedValue());
88 // 15. Set O’s [[ByteLength]] internal slot to viewByteLength.
89 dataView->SetByteLength(static_cast<uint32_t>(viewByteLen));
90 // 16. Set O’s [[ByteOffset]] internal slot to offset.
91 dataView->SetByteOffset(static_cast<uint32_t>(offset));
92 // 17. Return O.
93 return JSTaggedValue(dataView.GetTaggedValue());
94 }
95
96 // 24.2.4.1
GetBuffer(EcmaRuntimeCallInfo * argv)97 JSTaggedValue BuiltinsDataView::GetBuffer(EcmaRuntimeCallInfo *argv)
98 {
99 ASSERT(argv);
100 JSThread *thread = argv->GetThread();
101 BUILTINS_API_TRACE(thread, DataView, GetBuffer);
102 [[maybe_unused]] EcmaHandleScope handleScope(thread);
103 // 1. Let O be the this value.
104 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
105 // 2. f Type(O) is not Object, throw a TypeError exception.
106 if (!thisHandle->IsECMAObject()) {
107 THROW_TYPE_ERROR_AND_RETURN(thread, "Type(O) is not Object", JSTaggedValue::Exception());
108 }
109 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
110 if (!thisHandle->IsDataView()) {
111 THROW_TYPE_ERROR_AND_RETURN(thread, "O does not have a [[ViewedArrayBuffer]]", JSTaggedValue::Exception());
112 }
113 JSHandle<JSDataView> dataView(thisHandle);
114 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
115 JSTaggedValue buffer = dataView->GetViewedArrayBuffer(thread);
116 // 5. Return buffer.
117 return JSTaggedValue(buffer);
118 }
119
120 // 24.2.4.2
GetByteLength(EcmaRuntimeCallInfo * argv)121 JSTaggedValue BuiltinsDataView::GetByteLength(EcmaRuntimeCallInfo *argv)
122 {
123 ASSERT(argv);
124 JSThread *thread = argv->GetThread();
125 BUILTINS_API_TRACE(thread, DataView, GetByteLength);
126 [[maybe_unused]] EcmaHandleScope handleScope(thread);
127 // 1. Let O be the this value.
128 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
129 // 2. If Type(O) is not Object, throw a TypeError exception.
130 if (!thisHandle->IsECMAObject()) {
131 THROW_TYPE_ERROR_AND_RETURN(thread, "Type(O) is not Object", JSTaggedValue::Exception());
132 }
133 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
134 if (!thisHandle->IsDataView()) {
135 THROW_TYPE_ERROR_AND_RETURN(thread, "O does not have a [[ViewedArrayBuffer]]", JSTaggedValue::Exception());
136 }
137 JSHandle<JSDataView> dataView(thisHandle);
138 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
139 JSTaggedValue buffer = dataView->GetViewedArrayBuffer(thread);
140 // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
141 if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) {
142 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
143 }
144 // 6. Let size be the value of O’s [[ByteLength]] internal slot.
145 uint32_t size = dataView->GetByteLength();
146 // 7. Return size.
147 return JSTaggedValue(size);
148 }
149
150 // 24.2.4.3
GetOffset(EcmaRuntimeCallInfo * argv)151 JSTaggedValue BuiltinsDataView::GetOffset(EcmaRuntimeCallInfo *argv)
152 {
153 ASSERT(argv);
154 JSThread *thread = argv->GetThread();
155 BUILTINS_API_TRACE(thread, DataView, GetOffset);
156 [[maybe_unused]] EcmaHandleScope handleScope(thread);
157 // 1. Let O be the this value.
158 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
159 // 2. If Type(O) is not Object, throw a TypeError exception.
160 if (!thisHandle->IsECMAObject()) {
161 THROW_TYPE_ERROR_AND_RETURN(thread, "Type(O) is not Object", JSTaggedValue::Exception());
162 }
163 // 3. If O does not have a [[ViewedArrayBuffer]] internal slot, throw a TypeError exception.
164 if (!thisHandle->IsDataView()) {
165 THROW_TYPE_ERROR_AND_RETURN(thread, "O does not have a [[ViewedArrayBuffer]]", JSTaggedValue::Exception());
166 }
167 JSHandle<JSDataView> dataView(thisHandle);
168 // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot.
169 JSTaggedValue buffer = dataView->GetViewedArrayBuffer(thread);
170 // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
171 if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) {
172 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
173 }
174 // 6. Let offset be the value of O’s [[ByteOffset]] internal slot.
175 uint32_t offset = dataView->GetByteOffset();
176 // 7. Return offset.
177 return JSTaggedValue(offset);
178 }
179
180 // 24.2.4.5
GetFloat32(EcmaRuntimeCallInfo * argv)181 JSTaggedValue BuiltinsDataView::GetFloat32(EcmaRuntimeCallInfo *argv)
182 {
183 ASSERT(argv);
184 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetFloat32);
185 return GetTypedValue(argv, DataViewType::FLOAT32);
186 }
187
188 // 24.2.4.6
GetFloat64(EcmaRuntimeCallInfo * argv)189 JSTaggedValue BuiltinsDataView::GetFloat64(EcmaRuntimeCallInfo *argv)
190 {
191 ASSERT(argv);
192 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetFloat64);
193 return GetTypedValue(argv, DataViewType::FLOAT64);
194 }
195
196 // 24.2.4.7
GetInt8(EcmaRuntimeCallInfo * argv)197 JSTaggedValue BuiltinsDataView::GetInt8(EcmaRuntimeCallInfo *argv)
198 {
199 ASSERT(argv);
200 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetInt8);
201 return GetTypedValue(argv, DataViewType::INT8);
202 }
203
204 // 24.2.4.8
GetInt16(EcmaRuntimeCallInfo * argv)205 JSTaggedValue BuiltinsDataView::GetInt16(EcmaRuntimeCallInfo *argv)
206 {
207 ASSERT(argv);
208 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetInt16);
209 return GetTypedValue(argv, DataViewType::INT16);
210 }
211
212 // 24.2.4.9
GetInt32(EcmaRuntimeCallInfo * argv)213 JSTaggedValue BuiltinsDataView::GetInt32(EcmaRuntimeCallInfo *argv)
214 {
215 ASSERT(argv);
216 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetInt32);
217 return GetTypedValue(argv, DataViewType::INT32);
218 }
219
220 // 24.2.4.10
GetUint8(EcmaRuntimeCallInfo * argv)221 JSTaggedValue BuiltinsDataView::GetUint8(EcmaRuntimeCallInfo *argv)
222 {
223 ASSERT(argv);
224 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetUint8);
225 return GetTypedValue(argv, DataViewType::UINT8);
226 }
227
228 // 24.2.4.11
GetUint16(EcmaRuntimeCallInfo * argv)229 JSTaggedValue BuiltinsDataView::GetUint16(EcmaRuntimeCallInfo *argv)
230 {
231 ASSERT(argv);
232 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetUint16);
233 return GetTypedValue(argv, DataViewType::UINT16);
234 }
235
236 // 24.2.4.12
GetUint32(EcmaRuntimeCallInfo * argv)237 JSTaggedValue BuiltinsDataView::GetUint32(EcmaRuntimeCallInfo *argv)
238 {
239 ASSERT(argv);
240 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetUint32);
241 return GetTypedValue(argv, DataViewType::UINT32);
242 }
243 // 25.3.4.5
GetBigInt64(EcmaRuntimeCallInfo * argv)244 JSTaggedValue BuiltinsDataView::GetBigInt64(EcmaRuntimeCallInfo *argv)
245 {
246 ASSERT(argv);
247 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetBigInt64);
248 return GetTypedValue(argv, DataViewType::BIGINT64);
249 }
250 // 25.3.4.6
GetBigUint64(EcmaRuntimeCallInfo * argv)251 JSTaggedValue BuiltinsDataView::GetBigUint64(EcmaRuntimeCallInfo *argv)
252 {
253 ASSERT(argv);
254 BUILTINS_API_TRACE(argv->GetThread(), DataView, GetBigUint64);
255 return GetTypedValue(argv, DataViewType::BIGUINT64);
256 }
257 // 24.2.4.13
SetFloat32(EcmaRuntimeCallInfo * argv)258 JSTaggedValue BuiltinsDataView::SetFloat32(EcmaRuntimeCallInfo *argv)
259 {
260 ASSERT(argv);
261 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetFloat32);
262 return SetTypedValue(argv, DataViewType::FLOAT32);
263 }
264
265 // 24.2.4.14
SetFloat64(EcmaRuntimeCallInfo * argv)266 JSTaggedValue BuiltinsDataView::SetFloat64(EcmaRuntimeCallInfo *argv)
267 {
268 ASSERT(argv);
269 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetFloat64);
270 return SetTypedValue(argv, DataViewType::FLOAT64);
271 }
272
273 // 24.2.4.15
SetInt8(EcmaRuntimeCallInfo * argv)274 JSTaggedValue BuiltinsDataView::SetInt8(EcmaRuntimeCallInfo *argv)
275 {
276 ASSERT(argv);
277 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetInt8);
278 return SetTypedValue(argv, DataViewType::INT8);
279 }
280
281 // 24.2.4.16
SetInt16(EcmaRuntimeCallInfo * argv)282 JSTaggedValue BuiltinsDataView::SetInt16(EcmaRuntimeCallInfo *argv)
283 {
284 ASSERT(argv);
285 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetInt16);
286 return SetTypedValue(argv, DataViewType::INT16);
287 }
288
289 // 24.2.4.17
SetInt32(EcmaRuntimeCallInfo * argv)290 JSTaggedValue BuiltinsDataView::SetInt32(EcmaRuntimeCallInfo *argv)
291 {
292 ASSERT(argv);
293 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetInt32);
294 return SetTypedValue(argv, DataViewType::INT32);
295 }
296
297 // 24.2.4.18
SetUint8(EcmaRuntimeCallInfo * argv)298 JSTaggedValue BuiltinsDataView::SetUint8(EcmaRuntimeCallInfo *argv)
299 {
300 ASSERT(argv);
301 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetUint8);
302 return SetTypedValue(argv, DataViewType::UINT8);
303 }
304
305 // 24.2.4.19
SetUint16(EcmaRuntimeCallInfo * argv)306 JSTaggedValue BuiltinsDataView::SetUint16(EcmaRuntimeCallInfo *argv)
307 {
308 ASSERT(argv);
309 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetUint16);
310 return SetTypedValue(argv, DataViewType::UINT16);
311 }
312
313 // 24.2.4.20
SetUint32(EcmaRuntimeCallInfo * argv)314 JSTaggedValue BuiltinsDataView::SetUint32(EcmaRuntimeCallInfo *argv)
315 {
316 ASSERT(argv);
317 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetUint32);
318 return SetTypedValue(argv, DataViewType::UINT32);
319 }
320
321 // 25.3.4.15
SetBigInt64(EcmaRuntimeCallInfo * argv)322 JSTaggedValue BuiltinsDataView::SetBigInt64(EcmaRuntimeCallInfo *argv)
323 {
324 ASSERT(argv);
325 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetBigInt64);
326 return SetTypedValue(argv, DataViewType::BIGINT64);
327 }
328
329 // 25.3.4.16
SetBigUint64(EcmaRuntimeCallInfo * argv)330 JSTaggedValue BuiltinsDataView::SetBigUint64(EcmaRuntimeCallInfo *argv)
331 {
332 ASSERT(argv);
333 BUILTINS_API_TRACE(argv->GetThread(), DataView, SetBigUint64);
334 return SetTypedValue(argv, DataViewType::BIGUINT64);
335 }
336
337 // 24.2.1.1
GetViewValue(JSThread * thread,const JSHandle<JSTaggedValue> & view,const JSHandle<JSTaggedValue> & requestIndex,const JSHandle<JSTaggedValue> & littleEndian,DataViewType type)338 JSTaggedValue BuiltinsDataView::GetViewValue(JSThread *thread, const JSHandle<JSTaggedValue> &view,
339 const JSHandle<JSTaggedValue> &requestIndex,
340 const JSHandle<JSTaggedValue> &littleEndian,
341 DataViewType type)
342 {
343 BUILTINS_API_TRACE(thread, DataView, GetViewValue);
344 // 1. If Type(view) is not Object, throw a TypeError exception.
345 if (!view->IsECMAObject()) {
346 THROW_TYPE_ERROR_AND_RETURN(thread, "Type(O) is not Object", JSTaggedValue::Exception());
347 }
348 // 2. If view does not have a [[DataView]] internal slot, throw a TypeError exception.
349 if (!view->IsDataView()) {
350 THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception());
351 }
352
353 uint64_t index = 0;
354 if (requestIndex->IsInt()) {
355 // fast get index if requestIndex is int
356 auto indexInt = requestIndex->GetInt();
357 if (indexInt < 0) {
358 THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception());
359 }
360 index = static_cast<uint64_t>(indexInt);
361 } else {
362 // 3. Let numberIndex be ToIndex(requestIndex).
363 JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex);
364 // 5. ReturnIfAbrupt(getIndex).
365 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
366 index = base::NumberHelper::DoubleToUInt64(numberIndex.GetNumber());
367 }
368 // 7. Let isLittleEndian be ToBoolean(isLittleEndian).
369 bool isLittleEndian = false;
370 if (littleEndian->IsUndefined()) {
371 isLittleEndian = false;
372 } else {
373 isLittleEndian = littleEndian->ToBoolean();
374 }
375 // 8. Let buffer be the value of view’s [[ViewedArrayBuffer]] internal slot.
376 JSHandle<JSDataView> dataView(view);
377 JSTaggedValue buffer = dataView->GetViewedArrayBuffer(thread);
378 // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
379 if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) {
380 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
381 }
382 // 10. Let viewOffset be the value of view’s [[ByteOffset]] internal slot.
383 uint32_t offset = dataView->GetByteOffset();
384 // 11. Let viewSize be the value of view’s [[ByteLength]] internal slot.
385 uint32_t size = dataView->GetByteLength();
386 // 12. Let elementSize be the Number value of the Element Size value specified in Table 49 for Element Type type.
387 uint32_t elementSize = JSDataView::GetElementSize(type);
388 // 13. If getIndex +elementSize > viewSize, throw a RangeError exception.
389 if (index + elementSize > size) {
390 THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex +elementSize > viewSize", JSTaggedValue::Exception());
391 }
392 // 14. Let bufferIndex be getIndex + viewOffset.
393 uint32_t bufferIndex = static_cast<uint32_t>(index + offset);
394 // 15. Return GetValueFromBuffer(buffer, bufferIndex, type, isLittleEndian).
395 return BuiltinsArrayBuffer::GetValueFromBuffer(thread, buffer, bufferIndex, type, isLittleEndian);
396 }
397
398 // 24.2.1.2
SetViewValue(JSThread * thread,const JSHandle<JSTaggedValue> & view,const JSHandle<JSTaggedValue> & requestIndex,const JSHandle<JSTaggedValue> & littleEndian,DataViewType type,const JSHandle<JSTaggedValue> & value)399 JSTaggedValue BuiltinsDataView::SetViewValue(JSThread *thread, const JSHandle<JSTaggedValue> &view,
400 const JSHandle<JSTaggedValue> &requestIndex,
401 const JSHandle<JSTaggedValue> &littleEndian,
402 DataViewType type, const JSHandle<JSTaggedValue> &value)
403 {
404 // 1. If Type(view) is not Object, throw a TypeError exception.
405 BUILTINS_API_TRACE(thread, DataView, SetViewValue);
406 if (!view->IsECMAObject()) {
407 THROW_TYPE_ERROR_AND_RETURN(thread, "Type(O) is not Object", JSTaggedValue::Exception());
408 }
409 // 2. If view does not have a [[DataView]] internal slot, throw a TypeError exception.
410 if (!view->IsDataView()) {
411 THROW_TYPE_ERROR_AND_RETURN(thread, "view is not dataview", JSTaggedValue::Exception());
412 }
413 uint64_t index = 0;
414 if (requestIndex->IsInt()) {
415 // fast get index if requestIndex is int
416 auto indexInt = requestIndex->GetInt();
417 // If numberIndex ≠ getIndex or getIndex < 0, throw a RangeError exception.
418 if (indexInt < 0) {
419 THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex < 0", JSTaggedValue::Exception());
420 }
421 index = static_cast<uint64_t>(indexInt);
422 } else {
423 // 3. Let numberIndex be ToNumber(requestIndex).
424 JSTaggedNumber numberIndex = JSTaggedValue::ToIndex(thread, requestIndex);
425 // 5. ReturnIfAbrupt(getIndex).
426 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
427 index = base::NumberHelper::DoubleToUInt64(numberIndex.GetNumber());
428 }
429 JSMutableHandle<JSTaggedValue> numValueHandle = JSMutableHandle<JSTaggedValue>(thread, value);
430 if (!value->IsNumber()) {
431 numValueHandle.Update(JSTaggedValue::ToNumeric(thread, value));
432 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
433 }
434 // 7. Let isLittleEndian be ToBoolean(isLittleEndian).
435 bool isLittleEndian = false;
436 if (littleEndian->IsUndefined()) {
437 isLittleEndian = false;
438 } else {
439 isLittleEndian = littleEndian->ToBoolean();
440 }
441 // 8. Let buffer be the value of view’s [[ViewedArrayBuffer]] internal slot.
442 JSHandle<JSDataView> dataView(view);
443 JSTaggedValue buffer = dataView->GetViewedArrayBuffer(thread);
444 // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
445 if (BuiltinsArrayBuffer::IsDetachedBuffer(thread, buffer)) {
446 THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception());
447 }
448 // 10. Let viewOffset be the value of view’s [[ByteOffset]] internal slot.
449 uint32_t offset = dataView->GetByteOffset();
450 // 11. Let viewSize be the value of view’s [[ByteLength]] internal slot.
451 uint32_t size = dataView->GetByteLength();
452 // 12. Let elementSize be the Number value of the Element Size value specified in Table 49 for Element Type type.
453 uint32_t elementSize = JSDataView::GetElementSize(type);
454 // 13. If getIndex +elementSize > viewSize, throw a RangeError exception.
455 if (index + elementSize > size) {
456 THROW_RANGE_ERROR_AND_RETURN(thread, "getIndex +elementSize > viewSize", JSTaggedValue::Exception());
457 }
458 // 14. Let bufferIndex be getIndex + viewOffset.
459 uint32_t bufferIndex = static_cast<uint32_t>(index + offset);
460 // 15. Return SetValueFromBuffer(buffer, bufferIndex, type, value, isLittleEndian).
461 return BuiltinsArrayBuffer::SetValueInBuffer(thread, buffer, bufferIndex, type, numValueHandle, isLittleEndian);
462 }
463
GetTypedValue(EcmaRuntimeCallInfo * argv,DataViewType type)464 JSTaggedValue BuiltinsDataView::GetTypedValue(EcmaRuntimeCallInfo *argv, DataViewType type)
465 {
466 JSThread *thread = argv->GetThread();
467 BUILTINS_API_TRACE(thread, DataView, GetTypedValue);
468 [[maybe_unused]] EcmaHandleScope handleScope(thread);
469 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
470 JSHandle<JSTaggedValue> offsetHandle = GetCallArg(argv, 0);
471 JSHandle<JSTaggedValue> trueHandle(thread, JSTaggedValue::True());
472 if (type == DataViewType::UINT8 || type == DataViewType::INT8) {
473 return GetViewValue(thread, thisHandle, offsetHandle, trueHandle, type);
474 }
475 JSHandle<JSTaggedValue> littleEndianHandle = GetCallArg(argv, 1);
476 return GetViewValue(thread, thisHandle, offsetHandle, littleEndianHandle, type);
477 }
478
SetTypedValue(EcmaRuntimeCallInfo * argv,DataViewType type)479 JSTaggedValue BuiltinsDataView::SetTypedValue(EcmaRuntimeCallInfo *argv, DataViewType type)
480 {
481 JSThread *thread = argv->GetThread();
482 BUILTINS_API_TRACE(thread, DataView, SetTypedValue);
483 [[maybe_unused]] EcmaHandleScope handleScope(thread);
484 JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
485 JSHandle<JSTaggedValue> offsetHandle = GetCallArg(argv, 0);
486 JSHandle<JSTaggedValue> value = GetCallArg(argv, 1);
487 JSHandle<JSTaggedValue> trueHandle(thread, JSTaggedValue::True());
488 if (type == DataViewType::UINT8 || type == DataViewType::INT8) {
489 return SetViewValue(thread, thisHandle, offsetHandle, trueHandle, type, value);
490 }
491 JSHandle<JSTaggedValue> littleEndianHandle = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
492 return SetViewValue(thread, thisHandle, offsetHandle, littleEndianHandle, type, value);
493 }
494 } // namespace panda::ecmascript::builtins
495