1 /**
2 * Copyright (c) 2021-2025 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 "ets_coroutine.h"
17 #include "ets_vm.h"
18 #include "intrinsics.h"
19 #include "mem/vm_handle.h"
20 #include "plugins/ets/runtime/types/ets_object.h"
21 #include "plugins/ets/runtime/types/ets_string.h"
22 #include "plugins/ets/runtime/types/ets_box_primitive-inl.h"
23 #include "plugins/ets/runtime/ets_panda_file_items.h"
24 #include "plugins/ets/runtime/ets_utils.h"
25 #include "types/ets_array.h"
26 #include "types/ets_box_primitive.h"
27 #include "types/ets_class.h"
28 #include "types/ets_method.h"
29 #include "types/ets_primitives.h"
30 #include "types/ets_type.h"
31 #include "types/ets_type_comptime_traits.h"
32 #include "types/ets_typeapi.h"
33 #include "types/ets_typeapi_field.h"
34
35 namespace ark::ets::intrinsics {
36
ValueAPISetFieldObject(EtsObject * obj,EtsLong i,EtsObject * val)37 void ValueAPISetFieldObject(EtsObject *obj, EtsLong i, EtsObject *val)
38 {
39 auto coroutine = EtsCoroutine::GetCurrent();
40 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
41 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
42 VMHandle<EtsObject> valHandle(coroutine, val->GetCoreType());
43 ASSERT(objHandle.GetPtr() != nullptr);
44 auto typeClass = objHandle->GetClass();
45 auto fieldObject = typeClass->GetFieldByIndex(i);
46 objHandle->SetFieldObject(fieldObject, valHandle.GetPtr());
47 }
48
49 template <typename T>
SetFieldValue(EtsObject * obj,EtsLong i,T val)50 void SetFieldValue(EtsObject *obj, EtsLong i, T val)
51 {
52 auto coroutine = EtsCoroutine::GetCurrent();
53 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
54 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
55 ASSERT(objHandle.GetPtr() != nullptr);
56 auto typeClass = objHandle->GetClass();
57 auto fieldObject = typeClass->GetFieldByIndex(i);
58 if (fieldObject->GetType()->IsBoxed()) {
59 auto *boxedVal = EtsBoxPrimitive<T>::Create(coroutine, val);
60 objHandle->SetFieldObject(fieldObject, boxedVal);
61 return;
62 }
63 objHandle->SetFieldPrimitive<T>(fieldObject, val);
64 }
65
ValueAPISetFieldBoolean(EtsObject * obj,EtsLong i,EtsBoolean val)66 void ValueAPISetFieldBoolean(EtsObject *obj, EtsLong i, EtsBoolean val)
67 {
68 SetFieldValue(obj, i, val);
69 }
70
ValueAPISetFieldByte(EtsObject * obj,EtsLong i,EtsByte val)71 void ValueAPISetFieldByte(EtsObject *obj, EtsLong i, EtsByte val)
72 {
73 SetFieldValue(obj, i, val);
74 }
75
ValueAPISetFieldShort(EtsObject * obj,EtsLong i,EtsShort val)76 void ValueAPISetFieldShort(EtsObject *obj, EtsLong i, EtsShort val)
77 {
78 SetFieldValue(obj, i, val);
79 }
80
ValueAPISetFieldChar(EtsObject * obj,EtsLong i,EtsChar val)81 void ValueAPISetFieldChar(EtsObject *obj, EtsLong i, EtsChar val)
82 {
83 SetFieldValue(obj, i, val);
84 }
85
ValueAPISetFieldInt(EtsObject * obj,EtsLong i,EtsInt val)86 void ValueAPISetFieldInt(EtsObject *obj, EtsLong i, EtsInt val)
87 {
88 SetFieldValue(obj, i, val);
89 }
90
ValueAPISetFieldLong(EtsObject * obj,EtsLong i,EtsLong val)91 void ValueAPISetFieldLong(EtsObject *obj, EtsLong i, EtsLong val)
92 {
93 SetFieldValue(obj, i, val);
94 }
95
ValueAPISetFieldFloat(EtsObject * obj,EtsLong i,EtsFloat val)96 void ValueAPISetFieldFloat(EtsObject *obj, EtsLong i, EtsFloat val)
97 {
98 SetFieldValue(obj, i, val);
99 }
100
ValueAPISetFieldDouble(EtsObject * obj,EtsLong i,EtsDouble val)101 void ValueAPISetFieldDouble(EtsObject *obj, EtsLong i, EtsDouble val)
102 {
103 SetFieldValue(obj, i, val);
104 }
105
ValueAPISetFieldByNameObject(EtsObject * obj,EtsString * name,EtsObject * val)106 void ValueAPISetFieldByNameObject(EtsObject *obj, EtsString *name, EtsObject *val)
107 {
108 auto coroutine = EtsCoroutine::GetCurrent();
109 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
110 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
111 VMHandle<EtsString> nameHandle(coroutine, name->GetCoreType());
112 VMHandle<EtsObject> valHandle(coroutine, val->GetCoreType());
113 ASSERT(objHandle.GetPtr() != nullptr);
114 ASSERT(nameHandle.GetPtr() != nullptr);
115 auto typeClass = objHandle->GetClass();
116 auto fieldObject = ManglingUtils::GetFieldIDByDisplayName(typeClass, nameHandle->GetMutf8());
117 objHandle->SetFieldObject(fieldObject, valHandle.GetPtr());
118 }
119
120 template <typename T>
SetFieldByNameValue(EtsObject * obj,EtsString * name,T val)121 void SetFieldByNameValue(EtsObject *obj, EtsString *name, T val)
122 {
123 auto coroutine = EtsCoroutine::GetCurrent();
124 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
125 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
126 VMHandle<EtsString> nameHandle(coroutine, name->GetCoreType());
127 ASSERT(objHandle.GetPtr() != nullptr);
128 ASSERT(nameHandle.GetPtr() != nullptr);
129 auto typeClass = objHandle->GetClass();
130 auto fieldObject = ManglingUtils::GetFieldIDByDisplayName(typeClass, nameHandle->GetMutf8());
131 if (fieldObject->GetType()->IsBoxed()) {
132 auto *boxedVal = EtsBoxPrimitive<T>::Create(coroutine, val);
133 objHandle->SetFieldObject(fieldObject, boxedVal);
134 return;
135 }
136 objHandle->SetFieldPrimitive<T>(fieldObject, val);
137 }
138
ValueAPISetFieldByNameBoolean(EtsObject * obj,EtsString * name,EtsBoolean val)139 void ValueAPISetFieldByNameBoolean(EtsObject *obj, EtsString *name, EtsBoolean val)
140 {
141 SetFieldByNameValue(obj, name, val);
142 }
143
ValueAPISetFieldByNameByte(EtsObject * obj,EtsString * name,EtsByte val)144 void ValueAPISetFieldByNameByte(EtsObject *obj, EtsString *name, EtsByte val)
145 {
146 SetFieldByNameValue(obj, name, val);
147 }
148
ValueAPISetFieldByNameShort(EtsObject * obj,EtsString * name,EtsShort val)149 void ValueAPISetFieldByNameShort(EtsObject *obj, EtsString *name, EtsShort val)
150 {
151 SetFieldByNameValue(obj, name, val);
152 }
153
ValueAPISetFieldByNameChar(EtsObject * obj,EtsString * name,EtsChar val)154 void ValueAPISetFieldByNameChar(EtsObject *obj, EtsString *name, EtsChar val)
155 {
156 SetFieldByNameValue(obj, name, val);
157 }
158
ValueAPISetFieldByNameInt(EtsObject * obj,EtsString * name,EtsInt val)159 void ValueAPISetFieldByNameInt(EtsObject *obj, EtsString *name, EtsInt val)
160 {
161 SetFieldByNameValue(obj, name, val);
162 }
163
ValueAPISetFieldByNameLong(EtsObject * obj,EtsString * name,EtsLong val)164 void ValueAPISetFieldByNameLong(EtsObject *obj, EtsString *name, EtsLong val)
165 {
166 SetFieldByNameValue(obj, name, val);
167 }
168
ValueAPISetFieldByNameFloat(EtsObject * obj,EtsString * name,EtsFloat val)169 void ValueAPISetFieldByNameFloat(EtsObject *obj, EtsString *name, EtsFloat val)
170 {
171 SetFieldByNameValue(obj, name, val);
172 }
173
ValueAPISetFieldByNameDouble(EtsObject * obj,EtsString * name,EtsDouble val)174 void ValueAPISetFieldByNameDouble(EtsObject *obj, EtsString *name, EtsDouble val)
175 {
176 SetFieldByNameValue(obj, name, val);
177 }
178
ValueAPIGetFieldObject(EtsObject * obj,EtsLong i)179 EtsObject *ValueAPIGetFieldObject(EtsObject *obj, EtsLong i)
180 {
181 auto coroutine = EtsCoroutine::GetCurrent();
182 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
183 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
184 ASSERT(objHandle.GetPtr() != nullptr);
185 auto typeClass = objHandle->GetClass();
186 auto fieldObject = typeClass->GetFieldByIndex(i);
187 return objHandle->GetFieldObject(fieldObject);
188 }
189
190 template <typename T>
GetFieldValue(EtsObject * obj,EtsLong i)191 T GetFieldValue(EtsObject *obj, EtsLong i)
192 {
193 auto coroutine = EtsCoroutine::GetCurrent();
194 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
195 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
196 ASSERT(objHandle.GetPtr() != nullptr);
197 auto typeClass = objHandle->GetClass();
198 auto fieldObject = typeClass->GetFieldByIndex(i);
199 if (fieldObject->GetType()->IsBoxed()) {
200 return EtsBoxPrimitive<T>::FromCoreType(objHandle->GetFieldObject(fieldObject))->GetValue();
201 }
202 return objHandle->GetFieldPrimitive<T>(fieldObject);
203 }
204
ValueAPIGetFieldBoolean(EtsObject * obj,EtsLong i)205 EtsBoolean ValueAPIGetFieldBoolean(EtsObject *obj, EtsLong i)
206 {
207 return GetFieldValue<EtsBoolean>(obj, i);
208 }
209
ValueAPIGetFieldByte(EtsObject * obj,EtsLong i)210 EtsByte ValueAPIGetFieldByte(EtsObject *obj, EtsLong i)
211 {
212 return GetFieldValue<EtsByte>(obj, i);
213 }
214
ValueAPIGetFieldShort(EtsObject * obj,EtsLong i)215 EtsShort ValueAPIGetFieldShort(EtsObject *obj, EtsLong i)
216 {
217 return GetFieldValue<EtsShort>(obj, i);
218 }
219
ValueAPIGetFieldChar(EtsObject * obj,EtsLong i)220 EtsChar ValueAPIGetFieldChar(EtsObject *obj, EtsLong i)
221 {
222 return GetFieldValue<EtsChar>(obj, i);
223 }
224
ValueAPIGetFieldInt(EtsObject * obj,EtsLong i)225 EtsInt ValueAPIGetFieldInt(EtsObject *obj, EtsLong i)
226 {
227 return GetFieldValue<EtsInt>(obj, i);
228 }
229
ValueAPIGetFieldLong(EtsObject * obj,EtsLong i)230 EtsLong ValueAPIGetFieldLong(EtsObject *obj, EtsLong i)
231 {
232 return GetFieldValue<EtsLong>(obj, i);
233 }
234
ValueAPIGetFieldFloat(EtsObject * obj,EtsLong i)235 EtsFloat ValueAPIGetFieldFloat(EtsObject *obj, EtsLong i)
236 {
237 return GetFieldValue<EtsFloat>(obj, i);
238 }
239
ValueAPIGetFieldDouble(EtsObject * obj,EtsLong i)240 EtsDouble ValueAPIGetFieldDouble(EtsObject *obj, EtsLong i)
241 {
242 return GetFieldValue<EtsDouble>(obj, i);
243 }
244
ValueAPIGetFieldByNameObject(EtsObject * obj,EtsString * name)245 EtsObject *ValueAPIGetFieldByNameObject(EtsObject *obj, EtsString *name)
246 {
247 auto coroutine = EtsCoroutine::GetCurrent();
248 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
249 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
250 ASSERT(objHandle.GetPtr() != nullptr);
251 auto typeClass = objHandle->GetClass();
252 auto fieldObject = ManglingUtils::GetFieldIDByDisplayName(typeClass, name->GetMutf8());
253 return objHandle->GetFieldObject(fieldObject);
254 }
255
256 template <typename T>
GetFieldByNameValue(EtsObject * obj,EtsString * name)257 T GetFieldByNameValue(EtsObject *obj, EtsString *name)
258 {
259 auto coroutine = EtsCoroutine::GetCurrent();
260 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
261 VMHandle<EtsObject> objHandle(coroutine, obj->GetCoreType());
262 ASSERT(objHandle.GetPtr() != nullptr);
263 auto typeClass = objHandle->GetClass();
264 auto fieldObject = ManglingUtils::GetFieldIDByDisplayName(typeClass, name->GetMutf8());
265 if (fieldObject->GetType()->IsBoxed()) {
266 return EtsBoxPrimitive<T>::FromCoreType(objHandle->GetFieldObject(fieldObject))->GetValue();
267 }
268 return objHandle->GetFieldPrimitive<T>(fieldObject);
269 }
270
ValueAPIGetFieldByNameBoolean(EtsObject * obj,EtsString * name)271 EtsBoolean ValueAPIGetFieldByNameBoolean(EtsObject *obj, EtsString *name)
272 {
273 return GetFieldByNameValue<EtsBoolean>(obj, name);
274 }
275
ValueAPIGetFieldByNameByte(EtsObject * obj,EtsString * name)276 EtsByte ValueAPIGetFieldByNameByte(EtsObject *obj, EtsString *name)
277 {
278 return GetFieldByNameValue<EtsByte>(obj, name);
279 }
280
ValueAPIGetFieldByNameShort(EtsObject * obj,EtsString * name)281 EtsShort ValueAPIGetFieldByNameShort(EtsObject *obj, EtsString *name)
282 {
283 return GetFieldByNameValue<EtsShort>(obj, name);
284 }
285
ValueAPIGetFieldByNameChar(EtsObject * obj,EtsString * name)286 EtsChar ValueAPIGetFieldByNameChar(EtsObject *obj, EtsString *name)
287 {
288 return GetFieldByNameValue<EtsChar>(obj, name);
289 }
290
ValueAPIGetFieldByNameInt(EtsObject * obj,EtsString * name)291 EtsInt ValueAPIGetFieldByNameInt(EtsObject *obj, EtsString *name)
292 {
293 return GetFieldByNameValue<EtsInt>(obj, name);
294 }
295
ValueAPIGetFieldByNameLong(EtsObject * obj,EtsString * name)296 EtsLong ValueAPIGetFieldByNameLong(EtsObject *obj, EtsString *name)
297 {
298 return GetFieldByNameValue<EtsLong>(obj, name);
299 }
300
ValueAPIGetFieldByNameFloat(EtsObject * obj,EtsString * name)301 EtsFloat ValueAPIGetFieldByNameFloat(EtsObject *obj, EtsString *name)
302 {
303 return GetFieldByNameValue<EtsFloat>(obj, name);
304 }
305
ValueAPIGetFieldByNameDouble(EtsObject * obj,EtsString * name)306 EtsDouble ValueAPIGetFieldByNameDouble(EtsObject *obj, EtsString *name)
307 {
308 return GetFieldByNameValue<EtsDouble>(obj, name);
309 }
310
ValueAPIGetArrayLength(EtsObject * obj)311 EtsLong ValueAPIGetArrayLength(EtsObject *obj)
312 {
313 auto coroutine = EtsCoroutine::GetCurrent();
314 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
315 VMHandle<EtsArray> arrHandle(coroutine, obj->GetCoreType());
316 ASSERT(arrHandle.GetPtr() != nullptr);
317 return arrHandle->GetLength();
318 }
319
ValueAPISetElementObject(EtsObject * obj,EtsLong i,EtsObject * val)320 void ValueAPISetElementObject(EtsObject *obj, EtsLong i, EtsObject *val)
321 {
322 auto coroutine = EtsCoroutine::GetCurrent();
323 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
324 VMHandle<EtsObjectArray> arrHandle(coroutine, obj->GetCoreType());
325 VMHandle<EtsObject> valHandle(coroutine, val->GetCoreType());
326 ASSERT(arrHandle.GetPtr() != nullptr);
327 arrHandle->Set(i, valHandle.GetPtr());
328 }
329
330 template <typename P, typename T>
SetElement(EtsObject * obj,EtsLong i,T val)331 void SetElement(EtsObject *obj, EtsLong i, T val)
332 {
333 auto coroutine = EtsCoroutine::GetCurrent();
334 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
335 auto typeClass = obj->GetClass();
336 if (!typeClass->GetComponentType()->IsBoxed()) {
337 VMHandle<P> arrHandle(coroutine, obj->GetCoreType());
338 ASSERT(arrHandle.GetPtr() != nullptr);
339 arrHandle->Set(i, val);
340 } else {
341 VMHandle<EtsObjectArray> arrHandle(coroutine, obj->GetCoreType());
342 ASSERT(arrHandle.GetPtr() != nullptr);
343 // Don't inline boxedVal.
344 // In case it is inlined, the handle may be dereferenced before
345 // call Create which leads to invalid raw pointer to the managed object.
346 auto *boxedVal = EtsBoxPrimitive<T>::Create(coroutine, val);
347 arrHandle->Set(i, boxedVal);
348 }
349 }
350
ValueAPISetElementBoolean(EtsObject * obj,EtsLong i,EtsBoolean val)351 void ValueAPISetElementBoolean(EtsObject *obj, EtsLong i, EtsBoolean val)
352 {
353 SetElement<EtsBooleanArray>(obj, i, val);
354 }
355
ValueAPISetElementByte(EtsObject * obj,EtsLong i,EtsByte val)356 void ValueAPISetElementByte(EtsObject *obj, EtsLong i, EtsByte val)
357 {
358 SetElement<EtsByteArray>(obj, i, val);
359 }
360
ValueAPISetElementShort(EtsObject * obj,EtsLong i,EtsShort val)361 void ValueAPISetElementShort(EtsObject *obj, EtsLong i, EtsShort val)
362 {
363 SetElement<EtsShortArray>(obj, i, val);
364 }
365
ValueAPISetElementChar(EtsObject * obj,EtsLong i,EtsChar val)366 void ValueAPISetElementChar(EtsObject *obj, EtsLong i, EtsChar val)
367 {
368 SetElement<EtsCharArray>(obj, i, val);
369 }
370
ValueAPISetElementInt(EtsObject * obj,EtsLong i,EtsInt val)371 void ValueAPISetElementInt(EtsObject *obj, EtsLong i, EtsInt val)
372 {
373 SetElement<EtsIntArray>(obj, i, val);
374 }
375
ValueAPISetElementLong(EtsObject * obj,EtsLong i,EtsLong val)376 void ValueAPISetElementLong(EtsObject *obj, EtsLong i, EtsLong val)
377 {
378 SetElement<EtsLongArray>(obj, i, val);
379 }
380
ValueAPISetElementFloat(EtsObject * obj,EtsLong i,EtsFloat val)381 void ValueAPISetElementFloat(EtsObject *obj, EtsLong i, EtsFloat val)
382 {
383 SetElement<EtsFloatArray>(obj, i, val);
384 }
385
ValueAPISetElementDouble(EtsObject * obj,EtsLong i,EtsDouble val)386 void ValueAPISetElementDouble(EtsObject *obj, EtsLong i, EtsDouble val)
387 {
388 SetElement<EtsDoubleArray>(obj, i, val);
389 }
390
ValueAPIGetElementObject(EtsObject * obj,EtsLong i)391 EtsObject *ValueAPIGetElementObject(EtsObject *obj, EtsLong i)
392 {
393 auto coroutine = EtsCoroutine::GetCurrent();
394 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
395 VMHandle<EtsObjectArray> arrHandle(coroutine, obj->GetCoreType());
396 ASSERT(arrHandle.GetPtr() != nullptr);
397 return arrHandle->Get(i);
398 }
399
400 template <typename P>
GetElement(EtsObject * obj,EtsLong i)401 typename P::ValueType GetElement(EtsObject *obj, EtsLong i)
402 {
403 auto coroutine = EtsCoroutine::GetCurrent();
404 [[maybe_unused]] HandleScope<ObjectHeader *> scope(coroutine);
405 auto typeClass = obj->GetClass();
406 ASSERT(typeClass != nullptr);
407 if (!typeClass->GetComponentType()->IsBoxed()) {
408 VMHandle<P> arrHandle(coroutine, obj->GetCoreType());
409 ASSERT(arrHandle.GetPtr() != nullptr);
410 return arrHandle->Get(i);
411 }
412 VMHandle<EtsObjectArray> arrHandle(coroutine, obj->GetCoreType());
413 ASSERT(arrHandle.GetPtr() != nullptr);
414 auto value = EtsBoxPrimitive<typename P::ValueType>::FromCoreType(arrHandle->Get(i));
415 return value->GetValue();
416 }
417
ValueAPIGetElementBoolean(EtsObject * obj,EtsLong i)418 EtsBoolean ValueAPIGetElementBoolean(EtsObject *obj, EtsLong i)
419 {
420 return GetElement<EtsBooleanArray>(obj, i);
421 }
422
ValueAPIGetElementByte(EtsObject * obj,EtsLong i)423 EtsByte ValueAPIGetElementByte(EtsObject *obj, EtsLong i)
424 {
425 return GetElement<EtsByteArray>(obj, i);
426 }
427
ValueAPIGetElementShort(EtsObject * obj,EtsLong i)428 EtsShort ValueAPIGetElementShort(EtsObject *obj, EtsLong i)
429 {
430 return GetElement<EtsShortArray>(obj, i);
431 }
432
ValueAPIGetElementChar(EtsObject * obj,EtsLong i)433 EtsChar ValueAPIGetElementChar(EtsObject *obj, EtsLong i)
434 {
435 return GetElement<EtsCharArray>(obj, i);
436 }
437
ValueAPIGetElementInt(EtsObject * obj,EtsLong i)438 EtsInt ValueAPIGetElementInt(EtsObject *obj, EtsLong i)
439 {
440 return GetElement<EtsIntArray>(obj, i);
441 }
442
ValueAPIGetElementLong(EtsObject * obj,EtsLong i)443 EtsLong ValueAPIGetElementLong(EtsObject *obj, EtsLong i)
444 {
445 return GetElement<EtsLongArray>(obj, i);
446 }
447
ValueAPIGetElementFloat(EtsObject * obj,EtsLong i)448 EtsFloat ValueAPIGetElementFloat(EtsObject *obj, EtsLong i)
449 {
450 return GetElement<EtsFloatArray>(obj, i);
451 }
452
ValueAPIGetElementDouble(EtsObject * obj,EtsLong i)453 EtsDouble ValueAPIGetElementDouble(EtsObject *obj, EtsLong i)
454 {
455 return GetElement<EtsDoubleArray>(obj, i);
456 }
457
458 } // namespace ark::ets::intrinsics
459