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