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 #ifndef PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 17 #define PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 18 19 #include <cstdint> 20 #include "plugins/ets/runtime/ets_mark_word.h" 21 #include "mark_word.h" 22 #include "mem/mem.h" 23 #include "runtime/include/object_header-inl.h" 24 #include "plugins/ets/runtime/types/ets_class.h" 25 #include "plugins/ets/runtime/types/ets_field.h" 26 27 namespace ark::ets { 28 29 class EtsCoroutine; 30 31 // Private inheritance, because need to disallow implicit conversion to core type 32 class EtsObject : private ObjectHeader { 33 public: 34 PANDA_PUBLIC_API static EtsObject *Create(EtsCoroutine *etsCoroutine, EtsClass *klass); 35 PANDA_PUBLIC_API static EtsObject *CreateNonMovable(EtsClass *klass); 36 37 PANDA_PUBLIC_API static EtsObject *Create(EtsClass *klass); 38 GetClass()39 PANDA_PUBLIC_API EtsClass *GetClass() const 40 { 41 return EtsClass::FromRuntimeClass(GetCoreType()->ClassAddr<Class>()); 42 } 43 SetClass(EtsClass * cls)44 void SetClass(EtsClass *cls) 45 { 46 GetCoreType()->SetClass(UNLIKELY(cls == nullptr) ? nullptr : cls->GetRuntimeClass()); 47 } 48 IsInstanceOf(EtsClass * klass)49 bool IsInstanceOf(EtsClass *klass) const 50 { 51 ASSERT(klass != nullptr); 52 return klass->IsAssignableFrom(GetClass()); 53 } 54 HasField(EtsField * field)55 bool HasField(EtsField *field) const 56 { 57 ASSERT(field != nullptr); 58 return field->GetDeclaringClass()->IsAssignableFrom(field->GetDeclaringClass()); 59 } 60 GetAndSetFieldObject(size_t offset,EtsObject * value,std::memory_order memoryOrder)61 EtsObject *GetAndSetFieldObject(size_t offset, EtsObject *value, std::memory_order memoryOrder) 62 { 63 ASSERT(value != nullptr); 64 return FromCoreType(GetCoreType()->GetAndSetFieldObject(offset, value->GetCoreType(), memoryOrder)); 65 } 66 67 template <class T> GetFieldPrimitive(EtsField * field)68 T GetFieldPrimitive(EtsField *field) 69 { 70 ASSERT(field != nullptr); 71 ASSERT(field->GetEtsType() == GetEtsTypeByPrimitive<T>()); 72 ASSERT(HasField(field)); 73 return GetCoreType()->GetFieldPrimitive<T>(*field->GetRuntimeField()); 74 } 75 76 template <class T, bool IS_VOLATILE = false> GetFieldPrimitive(size_t offset)77 T GetFieldPrimitive(size_t offset) 78 { 79 return GetCoreType()->GetFieldPrimitive<T, IS_VOLATILE>(offset); 80 } 81 82 template <class T> GetFieldPrimitive(int32_t fieldOffset,bool isVolatile)83 T GetFieldPrimitive(int32_t fieldOffset, bool isVolatile) 84 { 85 if (isVolatile) { 86 return GetCoreType()->GetFieldPrimitive<T, true>(fieldOffset); 87 } 88 return GetCoreType()->GetFieldPrimitive<T, false>(fieldOffset); 89 } 90 91 template <class T> SetFieldPrimitive(EtsField * field,T value)92 void SetFieldPrimitive(EtsField *field, T value) 93 { 94 ASSERT(field != nullptr); 95 ASSERT(field->GetEtsType() == GetEtsTypeByPrimitive<T>()); 96 ASSERT(HasField(field)); 97 GetCoreType()->SetFieldPrimitive<T>(*field->GetRuntimeField(), value); 98 } 99 100 template <class T> SetFieldPrimitive(int32_t fieldOffset,bool isVolatile,T value)101 void SetFieldPrimitive(int32_t fieldOffset, bool isVolatile, T value) 102 { 103 if (isVolatile) { 104 GetCoreType()->SetFieldPrimitive<T, true>(fieldOffset, value); 105 } 106 GetCoreType()->SetFieldPrimitive<T, false>(fieldOffset, value); 107 } 108 109 template <class T, bool IS_VOLATILE = false> SetFieldPrimitive(size_t offset,T value)110 void SetFieldPrimitive(size_t offset, T value) 111 { 112 GetCoreType()->SetFieldPrimitive<T, IS_VOLATILE>(offset, value); 113 } 114 115 template <bool NEED_READ_BARRIER = true> GetFieldObject(EtsField * field)116 PANDA_PUBLIC_API EtsObject *GetFieldObject(EtsField *field) const 117 { 118 ASSERT(field != nullptr); 119 ASSERT(field->GetEtsType() == EtsType::OBJECT); 120 ASSERT(HasField(field)); 121 return reinterpret_cast<EtsObject *>( 122 GetCoreType()->GetFieldObject<NEED_READ_BARRIER>(*field->GetRuntimeField())); 123 } 124 GetFieldObject(int32_t fieldOffset,bool isVolatile)125 EtsObject *GetFieldObject(int32_t fieldOffset, bool isVolatile) const 126 { 127 if (isVolatile) { 128 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<true>(fieldOffset)); 129 } 130 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<false>(fieldOffset)); 131 } 132 133 template <bool IS_VOLATILE = false> GetFieldObject(size_t offset)134 EtsObject *GetFieldObject(size_t offset) 135 { 136 return reinterpret_cast<EtsObject *>(GetCoreType()->GetFieldObject<IS_VOLATILE>(offset)); 137 } 138 139 template <bool NEED_WRITE_BARRIER = true> SetFieldObject(EtsField * field,EtsObject * value)140 void SetFieldObject(EtsField *field, EtsObject *value) 141 { 142 ASSERT(field != nullptr); 143 ASSERT(field->GetEtsType() == EtsType::OBJECT); 144 ASSERT(HasField(field)); 145 GetCoreType()->SetFieldObject<NEED_WRITE_BARRIER>(*field->GetRuntimeField(), 146 reinterpret_cast<ObjectHeader *>(value)); 147 } 148 149 template <bool NEED_WRITE_BARRIER = true> SetFieldObject(int32_t fieldOffset,bool isVolatile,EtsObject * value)150 void SetFieldObject(int32_t fieldOffset, bool isVolatile, EtsObject *value) 151 { 152 if (isVolatile) { 153 GetCoreType()->SetFieldObject<true, NEED_WRITE_BARRIER>(fieldOffset, 154 reinterpret_cast<ObjectHeader *>(value)); 155 } else { 156 GetCoreType()->SetFieldObject<false, NEED_WRITE_BARRIER>(fieldOffset, 157 reinterpret_cast<ObjectHeader *>(value)); 158 } 159 } 160 161 template <bool IS_VOLATILE = false> SetFieldObject(size_t offset,EtsObject * value)162 void SetFieldObject(size_t offset, EtsObject *value) 163 { 164 GetCoreType()->SetFieldObject<IS_VOLATILE>(offset, reinterpret_cast<ObjectHeader *>(value)); 165 } 166 SetFieldObject(size_t offset,EtsObject * value,std::memory_order memoryOrder)167 void SetFieldObject(size_t offset, EtsObject *value, std::memory_order memoryOrder) 168 { 169 GetCoreType()->SetFieldObject(offset, value->GetCoreType(), memoryOrder); 170 } 171 172 template <typename T> CompareAndSetFieldPrimitive(size_t offset,T oldValue,T newValue,std::memory_order memoryOrder,bool strong)173 bool CompareAndSetFieldPrimitive(size_t offset, T oldValue, T newValue, std::memory_order memoryOrder, bool strong) 174 { 175 return GetCoreType()->CompareAndSetFieldPrimitive(offset, oldValue, newValue, memoryOrder, strong); 176 } 177 CompareAndSetFieldObject(size_t offset,EtsObject * oldValue,EtsObject * newValue,std::memory_order memoryOrder,bool strong)178 bool CompareAndSetFieldObject(size_t offset, EtsObject *oldValue, EtsObject *newValue, 179 std::memory_order memoryOrder, bool strong) 180 { 181 return GetCoreType()->CompareAndSetFieldObject(offset, reinterpret_cast<ObjectHeader *>(oldValue), 182 reinterpret_cast<ObjectHeader *>(newValue), memoryOrder, strong); 183 } 184 Clone()185 EtsObject *Clone() const 186 { 187 return FromCoreType(ObjectHeader::Clone(GetCoreType())); 188 } 189 GetCoreType()190 ObjectHeader *GetCoreType() const 191 { 192 return static_cast<ObjectHeader *>(const_cast<EtsObject *>(this)); 193 } 194 FromCoreType(ObjectHeader * objectHeader)195 static constexpr EtsObject *FromCoreType(ObjectHeader *objectHeader) 196 { 197 return static_cast<EtsObject *>(objectHeader); 198 } 199 FromCoreType(const ObjectHeader * objectHeader)200 static constexpr const EtsObject *FromCoreType(const ObjectHeader *objectHeader) 201 { 202 return static_cast<const EtsObject *>(objectHeader); 203 } 204 IsStringClass()205 PANDA_PUBLIC_API bool IsStringClass() 206 { 207 return GetClass()->IsStringClass(); 208 } 209 IsArrayClass()210 PANDA_PUBLIC_API bool IsArrayClass() 211 { 212 return GetClass()->IsArrayClass(); 213 } 214 215 // NOTE(ipetrov, #20886): Support separated Interop and Hash states 216 /** 217 * Get hash code if object has been already hashed, 218 * or generate and set hash code in the object header and return it 219 * @return hash code for the object 220 */ 221 uint32_t GetHashCode(); 222 223 /** 224 * @brief Get interop index of object. It should be setted. You can check if it's setted by 225 * HasInteropIndexed method. 226 * This method is thread safe to GetHashCode, HasInteropIndexed methods. Also it's thread safe to itself. 227 * @see HasInteropIndexed, GetHashCode. 228 * @return interop index of object. 229 */ 230 uint32_t GetInteropIndex() const; 231 232 /** 233 * @brief This method sets interop index of the object. Object must not have it. You can check if it's setted by 234 * HasInteropIndexed method. 235 * This method is thread safe to GetHashCode, HasInteropIndexed methods. IT IN NOT THREAD SAFE TO ITSELF! 236 * @see HasInteropIndexed, GetHashCode. 237 */ 238 void SetInteropIndex(uint32_t index); 239 240 /** 241 * @brief This method drops interop index of the object. Object must have it. You can check if it's setted by 242 * HasInteropIndexed method. If object is in USE_INFO state, it will no be changed until Deflate method is called. 243 * This method is thread safe to GetHashCode, HasInteropIndexed methods. IT IN NOT THREAD SAFE TO ITSELF! 244 * @see HasInteropIndexed, GetHashCode, Deflate 245 */ 246 void DropInteropIndex(); 247 HasInteropIndex()248 bool HasInteropIndex() const 249 { 250 bool hasInteropIndex = false; 251 while (!TryCheckIfHasInteropIndex(&hasInteropIndex)) { 252 } 253 return hasInteropIndex; 254 } 255 IsHashed()256 bool IsHashed() const 257 { 258 auto mark = AtomicGetMark(std::memory_order_relaxed); 259 auto markState = mark.GetState(); 260 return markState == EtsMarkWord::STATE_USE_INFO || markState == EtsMarkWord::STATE_HASHED; 261 } 262 IsUsedInfo()263 bool IsUsedInfo() const 264 { 265 auto mark = AtomicGetMark(std::memory_order_relaxed); 266 auto markState = mark.GetState(); 267 return markState == EtsMarkWord::STATE_USE_INFO; 268 } 269 SetMark(EtsMarkWord word)270 ALWAYS_INLINE void SetMark(EtsMarkWord word) 271 { 272 ObjectHeader::SetMark(word.ToMark()); 273 } 274 275 ALWAYS_INLINE EtsMarkWord AtomicGetMark(std::memory_order memoryOrder = std::memory_order_seq_cst) const 276 { 277 return EtsMarkWord::FromMarkWord(ObjectHeader::AtomicGetMark(memoryOrder)); 278 } 279 GetMark()280 ALWAYS_INLINE EtsMarkWord GetMark() const 281 { 282 return EtsMarkWord::FromMarkWord(ObjectHeader::GetMark()); 283 } 284 285 template <bool STRONG = true> 286 ALWAYS_INLINE bool AtomicSetMark(EtsMarkWord &oldMarkWord, EtsMarkWord newMarkWord, 287 std::memory_order memoryOrder = std::memory_order_seq_cst) 288 { 289 return ObjectHeader::AtomicSetMark<STRONG>(oldMarkWord, newMarkWord.ToMark(), memoryOrder); 290 } 291 292 EtsObject() = delete; 293 ~EtsObject() = delete; 294 295 protected: 296 // Use type alias to allow using into derived classes 297 using ObjectHeader = ::ark::ObjectHeader; 298 299 private: 300 static inline uint32_t GenerateHashCode(); 301 302 [[nodiscard]] bool TryGetHashCode(uint32_t *hash); 303 [[nodiscard]] bool TryGetInteropIndex(uint32_t *index) const; 304 [[nodiscard]] bool TrySetInteropIndex(uint32_t index); 305 [[nodiscard]] bool TryDropInteropIndex(); 306 [[nodiscard]] bool TryDeflate(); 307 [[nodiscard]] PANDA_PUBLIC_API bool TryCheckIfHasInteropIndex(bool *hasInteropIndexed) const; 308 309 NO_COPY_SEMANTIC(EtsObject); 310 NO_MOVE_SEMANTIC(EtsObject); 311 }; 312 313 // Size of EtsObject must be equal size of ObjectHeader 314 static_assert(sizeof(EtsObject) == sizeof(ObjectHeader)); 315 316 } // namespace ark::ets 317 318 #endif // PANDA_RUNTIME_ETS_FFI_CLASSES_ETS_OBJECT_H_ 319