• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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