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