1 /** 2 * Copyright (c) 2021-2024 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_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 17 #define PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 18 19 #include "mark_word.h" 20 #include "runtime/include/object_header-inl.h" 21 #include "plugins/ets/runtime/types/ets_class.h" 22 #include "plugins/ets/runtime/types/ets_field.h" 23 24 namespace ark::ets { 25 26 class EtsCoroutine; 27 28 // Private inheritance, because need to disallow implicit conversion to core type 29 class EtsObject : private ObjectHeader { 30 public: 31 PANDA_PUBLIC_API static EtsObject *Create(EtsCoroutine *etsCoroutine, EtsClass *klass); 32 PANDA_PUBLIC_API static EtsObject *CreateNonMovable(EtsClass *klass); 33 34 PANDA_PUBLIC_API static EtsObject *Create(EtsClass *klass); 35 GetClass()36 PANDA_PUBLIC_API EtsClass *GetClass() const 37 { 38 return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr<Class>()); 39 } 40 SetClass(EtsClass * cls)41 void SetClass(EtsClass *cls) 42 { 43 GetCoreType()->SetClass(UNLIKELY(cls == nullptr) ? nullptr : cls->GetRuntimeClass()); 44 } 45 IsInstanceOf(EtsClass * klass)46 bool IsInstanceOf(EtsClass *klass) const 47 { 48 return klass->IsAssignableFrom(GetClass()); 49 } 50 GetAndSetFieldObject(size_t offset,EtsObject * value,std::memory_order memoryOrder)51 EtsObject *GetAndSetFieldObject(size_t offset, EtsObject *value, std::memory_order memoryOrder) 52 { 53 return FromCoreType(GetCoreType()->GetAndSetFieldObject(offset, value->GetCoreType(), memoryOrder)); 54 } 55 56 template <class T> GetFieldPrimitive(EtsField * field)57 T GetFieldPrimitive(EtsField *field) 58 { 59 return GetCoreType()->GetFieldPrimitive<T>(*field->GetRuntimeField()); 60 } 61 62 template <class T, bool IS_VOLATILE = false> GetFieldPrimitive(size_t offset)63 T GetFieldPrimitive(size_t offset) 64 { 65 return GetCoreType()->GetFieldPrimitive<T, IS_VOLATILE>(offset); 66 } 67 68 template <class T> GetFieldPrimitive(int32_t fieldOffset,bool isVolatile)69 T GetFieldPrimitive(int32_t fieldOffset, bool isVolatile) 70 { 71 if (isVolatile) { 72 return GetCoreType()->GetFieldPrimitive<T, true>(fieldOffset); 73 } 74 return GetCoreType()->GetFieldPrimitive<T, false>(fieldOffset); 75 } 76 77 template <class T> SetFieldPrimitive(EtsField * field,T value)78 void SetFieldPrimitive(EtsField *field, T value) 79 { 80 GetCoreType()->SetFieldPrimitive<T>(*field->GetRuntimeField(), value); 81 } 82 83 template <class T> SetFieldPrimitive(int32_t fieldOffset,bool isVolatile,T value)84 void SetFieldPrimitive(int32_t fieldOffset, bool isVolatile, T value) 85 { 86 if (isVolatile) { 87 GetCoreType()->SetFieldPrimitive<T, true>(fieldOffset, value); 88 } 89 GetCoreType()->SetFieldPrimitive<T, false>(fieldOffset, value); 90 } 91 92 template <class T, bool IS_VOLATILE = false> SetFieldPrimitive(size_t offset,T value)93 void SetFieldPrimitive(size_t offset, T value) 94 { 95 GetCoreType()->SetFieldPrimitive<T, IS_VOLATILE>(offset, value); 96 } 97 98 template <bool NEED_READ_BARRIER = true> GetFieldObject(EtsField * field)99 PANDA_PUBLIC_API EtsObject *GetFieldObject(EtsField *field) const 100 { 101 return reinterpret_cast<EtsObject *>( 102 GetCoreType()->GetFieldObject<NEED_READ_BARRIER>(*field->GetRuntimeField())); 103 } 104 GetFieldObject(int32_t fieldOffset,bool isVolatile)105 EtsObject *GetFieldObject(int32_t fieldOffset, bool isVolatile) const 106 { 107 if (isVolatile) { 108 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<true>(fieldOffset)); 109 } 110 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<false>(fieldOffset)); 111 } 112 113 template <bool IS_VOLATILE = false> GetFieldObject(size_t offset)114 EtsObject *GetFieldObject(size_t offset) 115 { 116 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<IS_VOLATILE>(offset)); 117 } 118 119 template <bool NEED_WRITE_BARRIER = true> SetFieldObject(EtsField * field,EtsObject * value)120 void SetFieldObject(EtsField *field, EtsObject *value) 121 { 122 GetCoreType()->SetFieldObject<NEED_WRITE_BARRIER>(*field->GetRuntimeField(), 123 reinterpret_cast<ObjectHeader *>(value)); 124 } 125 126 template <bool NEED_WRITE_BARRIER = true> SetFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)127 void SetFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value) 128 { 129 if (isVolatile) { 130 GetCoreType()->SetFieldObject<true, NEED_WRITE_BARRIER>(fieldOffset, 131 reinterpret_cast<ObjectHeader *>(value)); 132 } else { 133 GetCoreType()->SetFieldObject<false, NEED_WRITE_BARRIER>(fieldOffset, 134 reinterpret_cast<ObjectHeader *>(value)); 135 } 136 } 137 138 template <bool IS_VOLATILE = false> SetFieldObject(size_t offset,EtsObject * value)139 void SetFieldObject(size_t offset, EtsObject *value) 140 { 141 GetCoreType()->SetFieldObject<IS_VOLATILE>(offset, reinterpret_cast<ObjectHeader *>(value)); 142 } 143 SetFieldObject(size_t offset,EtsObject * value,std::memory_order memoryOrder)144 void SetFieldObject(size_t offset, EtsObject *value, std::memory_order memoryOrder) 145 { 146 GetCoreType()->SetFieldObject(offset, value->GetCoreType(), memoryOrder); 147 } 148 149 template <typename T> CompareAndSetFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)150 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong) 151 { 152 return GetCoreType()->CompareAndSetFieldPrimitive(offset, oldValue, newValue, memoryOrder, strong); 153 } 154 CompareAndSetFieldObject(size_t offset,EtsObject * oldValue,EtsObject * newValue,std::memory_order memoryOrder,bool strong)155 bool CompareAndSetFieldObject(size_t offset, EtsObject *oldValue, EtsObject *newValue, 156 std::memory_order memoryOrder, bool strong) 157 { 158 return GetCoreType()->CompareAndSetFieldObject(offset, reinterpret_cast<ObjectHeader *>(oldValue), 159 reinterpret_cast<ObjectHeader *>(newValue), memoryOrder, strong); 160 } 161 Clone()162 EtsObject *Clone() const 163 { 164 return FromCoreType(ObjectHeader::Clone(GetCoreType())); 165 } 166 GetCoreType()167 ObjectHeader *GetCoreType() const 168 { 169 return static_cast<ObjectHeader *>(const_cast<EtsObject *>(this)); 170 } 171 FromCoreType(ObjectHeader * objectHeader)172 static constexpr EtsObject *FromCoreType(ObjectHeader *objectHeader) 173 { 174 return static_cast<EtsObject *>(objectHeader); 175 } 176 FromCoreType(const ObjectHeader * objectHeader)177 static constexpr const EtsObject *FromCoreType(const ObjectHeader *objectHeader) 178 { 179 return static_cast<const EtsObject *>(objectHeader); 180 } 181 IsStringClass()182 PANDA_PUBLIC_API bool IsStringClass() 183 { 184 return GetClass()->IsStringClass(); 185 } 186 IsArrayClass()187 PANDA_PUBLIC_API bool IsArrayClass() 188 { 189 return GetClass()->IsArrayClass(); 190 } 191 192 // NOTE(ipetrov, #20886): Support separated Interop and Hash states 193 /** 194 * Get hash code if object has been already hashed, 195 * or generate and set hash code in the object header and return it 196 * @return hash code for the object 197 */ 198 uint32_t GetHashCode(); 199 IsHashed()200 inline bool IsHashed() const 201 { 202 return AtomicGetMark().GetState() == MarkWord::STATE_HASHED; 203 } 204 GetInteropHash()205 inline uint32_t GetInteropHash() const 206 { 207 ASSERT(IsHashed()); 208 return GetMark().GetHash(); 209 } 210 SetInteropHash(uint32_t hash)211 inline void SetInteropHash(uint32_t hash) 212 { 213 MarkWord oldMark = AtomicGetMark(); 214 ASSERT(oldMark.GetState() == ark::MarkWord::STATE_UNLOCKED); 215 MarkWord newMark = oldMark.DecodeFromHash(hash); 216 ASSERT(newMark.GetState() == MarkWord::STATE_HASHED); 217 [[maybe_unused]] bool res = AtomicSetMark(oldMark, newMark); 218 ASSERT(res); // NOTE(vpukhov): something went wrong 219 } 220 DropInteropHash()221 inline void DropInteropHash() 222 { 223 ASSERT_MANAGED_CODE(); 224 MarkWord oldMark = AtomicGetMark(); 225 ASSERT(oldMark.GetState() == MarkWord::STATE_HASHED); 226 MarkWord newMark = oldMark.DecodeFromUnlocked(); 227 [[maybe_unused]] bool res = AtomicSetMark(oldMark, newMark); 228 ASSERT(res); // NOTE(vpukhov): something went wrong 229 } 230 231 EtsObject() = delete; 232 ~EtsObject() = delete; 233 234 protected: 235 // Use type alias to allow using into derived classes 236 using ObjectHeader = ::ark::ObjectHeader; 237 238 private: 239 NO_COPY_SEMANTIC(EtsObject); 240 NO_MOVE_SEMANTIC(EtsObject); 241 }; 242 243 // Size of EtsObject must be equal size of ObjectHeader 244 static_assert(sizeof(EtsObject) == sizeof(ObjectHeader)); 245 246 } // namespace ark::ets 247 248 #endif // PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 249