1 /** 2 * Copyright (c) 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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_TYPES_ETS_ESCOMPAT_ARRAY_H 17 #define PANDA_PLUGINS_ETS_RUNTIME_TYPES_ETS_ESCOMPAT_ARRAY_H 18 19 #include <cstdint> 20 21 #include "libpandabase/macros.h" 22 #include "libpandabase/mem/object_pointer.h" 23 #include "runtime/include/thread.h" 24 #include "runtime/include/managed_thread.h" 25 #include "runtime/coroutines/coroutine.h" 26 #include "runtime/entrypoints/entrypoints.h" 27 #include "plugins/ets/runtime/ets_class_linker_extension.h" 28 #include "plugins/ets/runtime/ets_coroutine.h" 29 #include "plugins/ets/runtime/ets_vm.h" 30 #include "plugins/ets/runtime/types/ets_object.h" 31 #include "plugins/ets/runtime/types/ets_array.h" 32 #include "plugins/ets/runtime/types/ets_box_primitive.h" 33 #include "plugins/ets/runtime/types/ets_method.h" 34 35 namespace ark::ets { 36 37 namespace test { 38 template <class ElementType> 39 class EtsArrayObjectMembers; 40 } // namespace test 41 42 // Mirror class for Array<T> from ETS stdlib 43 template <class ElementType> 44 class EtsArrayObject : public EtsObject { 45 public: 46 EtsArrayObject() = delete; 47 ~EtsArrayObject() = delete; 48 49 NO_COPY_SEMANTIC(EtsArrayObject); 50 NO_MOVE_SEMANTIC(EtsArrayObject); 51 AsObject()52 EtsObject *AsObject() 53 { 54 return this; 55 } 56 AsObject()57 const EtsObject *AsObject() const 58 { 59 return this; 60 } 61 FromEtsObject(EtsObject * etsObj)62 static EtsArrayObject *FromEtsObject(EtsObject *etsObj) 63 { 64 return reinterpret_cast<EtsArrayObject *>(etsObj); 65 } 66 GetData()67 EtsTypedObjectArray<ElementType> *GetData() 68 { 69 return reinterpret_cast<EtsTypedObjectArray<ElementType> *>(GetFieldObject(GetBufferOffset())); 70 } 71 GetActualLength()72 uint32_t GetActualLength() 73 { 74 return helpers::ToUnsigned(GetFieldPrimitive<EtsInt>(GetActualLengthOffset())); 75 } 76 GetBufferOffset()77 static constexpr size_t GetBufferOffset() 78 { 79 return MEMBER_OFFSET(EtsArrayObject, buffer_); 80 } 81 GetActualLengthOffset()82 static constexpr size_t GetActualLengthOffset() 83 { 84 return MEMBER_OFFSET(EtsArrayObject, actualLength_); 85 } 86 Create(size_t length)87 static EtsArrayObject *Create(size_t length) 88 { 89 auto *coro = EtsCoroutine::GetCurrent(); 90 ASSERT(coro->HasPendingException() == false); 91 92 EtsHandleScope scope(coro); 93 94 const EtsPlatformTypes *platformTypes = PlatformTypes(coro->GetPandaVM()); 95 EtsClass *klass = platformTypes->escompatArray; 96 EtsHandle<EtsArrayObject> arrayHandle(coro, FromEtsObject(EtsObject::Create(klass))); 97 98 auto *ctor = klass->GetDirectMethod(coro->GetLanguageContext().GetCtorName(), "I:V"); 99 ASSERT(ctor != nullptr); 100 101 std::array args {Value(arrayHandle->GetCoreType()), Value(length)}; 102 ctor->GetPandaMethod()->InvokeVoid(coro, args.data()); 103 104 if (UNLIKELY(coro->HasPendingException())) { 105 if (coro->GetPandaVM()->GetOOMErrorObject() == nullptr || 106 (coro->GetException()->ClassAddr<Class>() == 107 coro->GetPandaVM()->GetOOMErrorObject()->ClassAddr<Class>())) { 108 coro->ClearException(); 109 return nullptr; 110 } 111 // We do not expect any other exception than OOM 112 UNREACHABLE(); 113 } 114 115 return arrayHandle.GetPtr(); 116 } 117 118 /// @return Returns a status code of bool indicating success or failure. SetRef(size_t index,ElementType * ref)119 bool SetRef(size_t index, ElementType *ref) 120 { 121 if (index >= GetActualLength()) { 122 return false; 123 } 124 125 GetData()->Set(index, ref); 126 return true; 127 } 128 129 /// @return Returns a status code of bool indicating success or failure. GetRef(size_t index,ElementType ** ref)130 bool GetRef(size_t index, ElementType **ref) 131 { 132 ASSERT(ref != nullptr); 133 if (index >= GetActualLength()) { 134 return false; 135 } 136 137 *ref = GetData()->Get(index); 138 return true; 139 } 140 141 private: 142 ObjectPointer<EtsTypedObjectArray<ElementType>> buffer_; 143 EtsInt actualLength_; 144 145 friend class test::EtsArrayObjectMembers<ElementType>; 146 }; 147 148 using EtsBoxedBooleanArray = EtsArrayObject<EtsBoxPrimitive<EtsBoolean>>; 149 using EtsBoxedByteArray = EtsArrayObject<EtsBoxPrimitive<EtsByte>>; 150 using EtsBoxedCharArray = EtsArrayObject<EtsBoxPrimitive<EtsChar>>; 151 using EtsBoxedShortArray = EtsArrayObject<EtsBoxPrimitive<EtsShort>>; 152 using EtsBoxedIntArray = EtsArrayObject<EtsBoxPrimitive<EtsInt>>; 153 using EtsBoxedLongArray = EtsArrayObject<EtsBoxPrimitive<EtsLong>>; 154 using EtsBoxedFloatArray = EtsArrayObject<EtsBoxPrimitive<EtsFloat>>; 155 using EtsBoxedDoubleArray = EtsArrayObject<EtsBoxPrimitive<EtsDouble>>; 156 157 } // namespace ark::ets 158 159 #endif // PANDA_PLUGINS_ETS_RUNTIME_TYPES_ETS_ESCOMPAT_ARRAY_H 160