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