• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 "runtime/include/object_header.h"
17 
18 #include "runtime/include/coretypes/array.h"
19 #include "runtime/include/coretypes/class.h"
20 #include "runtime/include/hclass.h"
21 #include "runtime/include/runtime.h"
22 #include "runtime/include/thread.h"
23 #include "runtime/include/panda_vm.h"
24 #include "runtime/mem/free_object.h"
25 #include "runtime/mem/vm_handle.h"
26 #include "runtime/monitor_pool.h"
27 #include "runtime/handle_base-inl.h"
28 
29 namespace panda {
30 
31 /* static */
CreateObject(panda::BaseClass * klass,bool non_movable)32 ObjectHeader *ObjectHeader::CreateObject(panda::BaseClass *klass, bool non_movable)
33 {
34     ASSERT(klass != nullptr);
35 #ifndef NDEBUG
36     if (!klass->IsDynamicClass()) {
37         auto cls = static_cast<panda::Class *>(klass);
38         ASSERT(cls->IsInstantiable());
39         ASSERT(!cls->IsArrayClass());
40         ASSERT(!cls->IsStringClass());
41     }
42 #endif
43 
44     size_t size = klass->GetObjectSize();
45     ASSERT(size != 0);
46     mem::HeapManager *heap_manager = Thread::GetCurrent()->GetVM()->GetHeapManager();
47     ObjectHeader *obj {nullptr};
48     if (LIKELY(!non_movable)) {
49         obj = heap_manager->AllocateObject(klass, size);
50     } else {
51         obj = heap_manager->AllocateNonMovableObject(klass, size);
52     }
53     return obj;
54 }
55 
56 /* static */
Create(BaseClass * klass)57 ObjectHeader *ObjectHeader::Create(BaseClass *klass)
58 {
59     return CreateObject(klass, false);
60 }
61 
62 /* static */
CreateNonMovable(BaseClass * klass)63 ObjectHeader *ObjectHeader::CreateNonMovable(BaseClass *klass)
64 {
65     return CreateObject(klass, true);
66 }
67 
GetHashCodeFromMonitor(Monitor * monitor_p)68 uint32_t ObjectHeader::GetHashCodeFromMonitor(Monitor *monitor_p)
69 {
70     return monitor_p->GetHashCode();
71 }
72 
GetHashCodeMTSingle()73 uint32_t ObjectHeader::GetHashCodeMTSingle()
74 {
75     auto mark = GetMark();
76 
77     switch (mark.GetState()) {
78         case MarkWord::STATE_UNLOCKED: {
79             mark = mark.DecodeFromHash(GenerateHashCode());
80             ASSERT(mark.GetState() == MarkWord::STATE_HASHED);
81             SetMark(mark);
82             return mark.GetHash();
83         }
84         case MarkWord::STATE_HASHED:
85             return mark.GetHash();
86         default:
87             LOG(FATAL, RUNTIME) << "Error on GetHashCode(): invalid state";
88             return 0;
89     }
90 }
91 
GetHashCodeMTMulti()92 uint32_t ObjectHeader::GetHashCodeMTMulti()
93 {
94     ObjectHeader *current_obj = this;
95     while (true) {
96         auto mark = current_obj->AtomicGetMark();
97         auto *thread = MTManagedThread::GetCurrent();
98         ASSERT(thread != nullptr);
99         [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
100         VMHandle<ObjectHeader> handle_obj(thread, current_obj);
101 
102         switch (mark.GetState()) {
103             case MarkWord::STATE_UNLOCKED: {
104                 auto hash_mark = mark.DecodeFromHash(GenerateHashCode());
105                 ASSERT(hash_mark.GetState() == MarkWord::STATE_HASHED);
106                 current_obj->AtomicSetMark(mark, hash_mark);
107                 break;
108             }
109             case MarkWord::STATE_LIGHT_LOCKED: {
110                 os::thread::ThreadId owner_thread_id = mark.GetThreadId();
111                 if (owner_thread_id == thread->GetInternalId()) {
112                     Monitor::Inflate(this, thread);
113                 } else {
114                     Monitor::InflateThinLock(thread, handle_obj);
115                     current_obj = handle_obj.GetPtr();
116                 }
117                 break;
118             }
119             case MarkWord::STATE_HEAVY_LOCKED: {
120                 auto monitor_id = mark.GetMonitorId();
121                 auto monitor_p = MTManagedThread::GetCurrent()->GetMonitorPool()->LookupMonitor(monitor_id);
122                 if (monitor_p != nullptr) {
123                     return GetHashCodeFromMonitor(monitor_p);
124                 }
125                 LOG(FATAL, RUNTIME) << "Error on GetHashCode(): no monitor on heavy locked state";
126                 break;
127             }
128             case MarkWord::STATE_HASHED: {
129                 return mark.GetHash();
130             }
131             default: {
132                 LOG(FATAL, RUNTIME) << "Error on GetHashCode(): invalid state";
133             }
134         }
135     }
136 }
137 
Clone(ObjectHeader * src)138 ObjectHeader *ObjectHeader::Clone(ObjectHeader *src)
139 {
140     LOG_IF(src->ClassAddr<Class>()->GetManagedObject() == src, FATAL, RUNTIME) << "Can't clone a class";
141     return ObjectHeader::ShallowCopy(src);
142 }
143 
ShallowCopy(ObjectHeader * src)144 ObjectHeader *ObjectHeader::ShallowCopy(ObjectHeader *src)
145 {
146     /*
147      TODO(d.trubenkov):
148         use bariers for possible copied reference fields
149     */
150     auto object_class = src->ClassAddr<Class>();
151     std::size_t obj_size = src->ObjectSize();
152 
153     // AllocateObject can trigger gc, use handle for src.
154     auto *thread = ManagedThread::GetCurrent();
155     ASSERT(thread != nullptr);
156     mem::HeapManager *heap_manager = thread->GetVM()->GetHeapManager();
157     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
158     VMHandle<ObjectHeader> src_handle(thread, src);
159 
160     ObjectHeader *dst = nullptr;
161     // Determine whether object is non-movable
162     if (PoolManager::GetMmapMemPool()->GetSpaceTypeForAddr(src) == SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT) {
163         dst = heap_manager->AllocateNonMovableObject(object_class, obj_size);
164     } else {
165         dst = heap_manager->AllocateObject(object_class, obj_size);
166     }
167     if (dst == nullptr) {
168         return nullptr;
169     }
170     ASSERT(PoolManager::GetMmapMemPool()->GetSpaceTypeForAddr(src_handle.GetPtr()) ==
171            PoolManager::GetMmapMemPool()->GetSpaceTypeForAddr(dst));
172 
173     Span<uint8_t> src_sp(reinterpret_cast<uint8_t *>(src_handle.GetPtr()), obj_size);
174     Span<uint8_t> dst_sp(reinterpret_cast<uint8_t *>(dst), obj_size);
175     constexpr const std::size_t WORD_SIZE = sizeof(uintptr_t);
176     std::size_t bytes_to_copy = obj_size - ObjectHeader::ObjectHeaderSize();
177     std::size_t words_to_copy = bytes_to_copy / WORD_SIZE;
178     std::size_t remaining_offset = ObjectHeader::ObjectHeaderSize() + WORD_SIZE * words_to_copy;
179     // copy words
180     for (std::size_t i = ObjectHeader::ObjectHeaderSize(); i < remaining_offset; i += WORD_SIZE) {
181         // Atomic with relaxed order reason: data race with src_handle with no synchronization or ordering constraints
182         // imposed on other reads or writes
183         reinterpret_cast<std::atomic<uintptr_t> *>(&dst_sp[i])
184             ->store(reinterpret_cast<std::atomic<uintptr_t> *>(&src_sp[i])->load(std::memory_order_relaxed),
185                     std::memory_order_relaxed);
186     }
187     // copy remaining bytes
188     for (std::size_t i = remaining_offset; i < obj_size; i++) {
189         // Atomic with relaxed order reason: data race with src_handle with no synchronization or ordering constraints
190         // imposed on other reads or writes
191         reinterpret_cast<std::atomic<uint8_t> *>(&dst_sp[i])
192             ->store(reinterpret_cast<std::atomic<uint8_t> *>(&src_sp[i])->load(std::memory_order_relaxed),
193                     std::memory_order_relaxed);
194     }
195 
196     // Call barriers here.
197     auto *barrier_set = thread->GetBarrierSet();
198     // We don't need pre barrier here because we don't change any links inside main object
199     // Post barrier
200     auto gc_post_barrier_type = barrier_set->GetPostType();
201     if (!mem::IsEmptyBarrier(gc_post_barrier_type)) {
202         if (object_class->IsArrayClass()) {
203             if (object_class->IsObjectArrayClass()) {
204                 barrier_set->PostBarrierArrayWrite(dst, obj_size);
205             }
206         } else {
207             barrier_set->PostBarrierEveryObjectFieldWrite(dst, obj_size);
208         }
209     }
210     return dst;
211 }
212 
ObjectSize() const213 size_t ObjectHeader::ObjectSize() const
214 {
215     auto *base_klass = ClassAddr<BaseClass>();
216     if (base_klass->IsDynamicClass()) {
217         auto *klass = ClassAddr<HClass>();
218 
219         if (klass->IsArray()) {
220             return static_cast<const coretypes::Array *>(this)->ObjectSize(TaggedValue::TaggedTypeSize());
221         }
222         if (klass->IsString()) {
223             LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(klass->GetSourceLang());
224             return ctx.GetStringSize(this);
225         }
226         if (klass->IsFreeObject()) {
227             return static_cast<const mem::FreeObject *>(this)->GetSize();
228         }
229     } else {
230         auto *klass = ClassAddr<Class>();
231 
232         if (klass->IsArrayClass()) {
233             return static_cast<const coretypes::Array *>(this)->ObjectSize(klass->GetComponentSize());
234         }
235 
236         if (klass->IsStringClass()) {
237             return static_cast<const coretypes::String *>(this)->ObjectSize();
238         }
239 
240         if (klass->IsClassClass()) {
241             auto cls = panda::Class::FromClassObject(const_cast<ObjectHeader *>(this));
242             if (cls != nullptr) {
243                 return panda::Class::GetClassObjectSizeFromClass(cls);
244             }
245         }
246     }
247     return base_klass->GetObjectSize();
248 }
249 
250 }  // namespace panda
251