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/class_initializer.h"
17
18 #include "include/object_header.h"
19 #include "libpandafile/file_items.h"
20 #include "macros.h"
21 #include "runtime/include/class_linker.h"
22 #include "runtime/include/coretypes/tagged_value.h"
23 #include "runtime/include/runtime.h"
24 #include "runtime/handle_scope-inl.h"
25 #include "runtime/monitor.h"
26 #include "runtime/monitor_object_lock.h"
27 #include "runtime/global_object_lock.h"
28 #include "verification/util/is_system.h"
29 #include "verify_app_install.h"
30
31 namespace panda {
32
33 template <MTModeT mode>
34 class ObjectLockConfig {
35 };
36
37 template <>
38 class ObjectLockConfig<MT_MODE_MULTI> {
39 public:
40 using LockT = ObjectLock;
41 };
42
43 template <>
44 class ObjectLockConfig<MT_MODE_TASK> {
45 public:
46 // TODO(xuliang): it is fast solution which we can reconsider later if we will face some perf issues with it.
47 using LockT = GlobalObjectLock;
48 };
49
50 template <>
51 class ObjectLockConfig<MT_MODE_SINGLE> {
52 public:
53 class DummyObjectLock {
54 public:
DummyObjectLock(ObjectHeader * header)55 explicit DummyObjectLock(ObjectHeader *header [[maybe_unused]]) {}
56 ~DummyObjectLock() = default;
Wait(bool ignore_interruption=false)57 void Wait([[maybe_unused]] bool ignore_interruption = false) {}
TimedWait(uint64_t timeout)58 void TimedWait([[maybe_unused]] uint64_t timeout) {}
Notify()59 void Notify() {}
NotifyAll()60 void NotifyAll() {}
61 NO_COPY_SEMANTIC(DummyObjectLock);
62 NO_MOVE_SEMANTIC(DummyObjectLock);
63 };
64
65 using LockT = DummyObjectLock;
66 };
67
WrapException(ClassLinker * class_linker,ManagedThread * thread)68 static void WrapException(ClassLinker *class_linker, ManagedThread *thread)
69 {
70 ASSERT(thread->HasPendingException());
71
72 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*thread->GetException()->ClassAddr<Class>());
73
74 auto *error_class = class_linker->GetExtension(ctx)->GetClass(ctx.GetErrorClassDescriptor(), false);
75 ASSERT(error_class != nullptr);
76
77 auto *cause = thread->GetException();
78 if (cause->IsInstanceOf(error_class)) {
79 return;
80 }
81
82 ThrowException(ctx, thread, ctx.GetExceptionInInitializerErrorDescriptor(), nullptr);
83 }
84
ThrowNoClassDefFoundError(ManagedThread * thread,const Class * klass)85 static void ThrowNoClassDefFoundError(ManagedThread *thread, const Class *klass)
86 {
87 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
88 auto name = klass->GetName();
89 ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(name.c_str()));
90 }
91
ThrowEarlierInitializationException(ManagedThread * thread,const Class * klass)92 static void ThrowEarlierInitializationException(ManagedThread *thread, const Class *klass)
93 {
94 ASSERT(klass->IsErroneous());
95
96 ThrowNoClassDefFoundError(thread, klass);
97 }
98
ThrowIncompatibleClassChangeError(ManagedThread * thread,const Class * klass)99 static void ThrowIncompatibleClassChangeError(ManagedThread *thread, const Class *klass)
100 {
101 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
102 auto name = klass->GetName();
103 ThrowException(ctx, thread, ctx.GetIncompatibleClassChangeErrorDescriptor(), utf::CStringAsMutf8(name.c_str()));
104 }
105
ThrowVerifyError(ManagedThread * thread,const Class * klass)106 static void ThrowVerifyError(ManagedThread *thread, const Class *klass)
107 {
108 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
109 auto name = klass->GetName();
110 ThrowException(ctx, thread, ctx.GetVerifyErrorClassDescriptor(), utf::CStringAsMutf8(name.c_str()));
111 }
112
isBadSuperClass(const Class * base,ManagedThread * thread,const Class * klass)113 static bool isBadSuperClass(const Class *base, ManagedThread *thread, const Class *klass)
114 {
115 if (base->IsInterface()) {
116 ThrowIncompatibleClassChangeError(thread, klass);
117 return true;
118 }
119
120 if (base->IsFinal()) {
121 ThrowVerifyError(thread, klass);
122 return true;
123 }
124
125 return false;
126 }
127
128 template <class ObjectLockT>
WaitInitialization(ObjectLockT * lock,ClassLinker * class_linker,ManagedThread * thread,Class * klass)129 static bool WaitInitialization(ObjectLockT *lock, ClassLinker *class_linker, ManagedThread *thread, Class *klass)
130 {
131 while (true) {
132 lock->Wait(true);
133
134 if (thread->HasPendingException()) {
135 WrapException(class_linker, thread);
136 klass->SetState(Class::State::ERRONEOUS);
137 return false;
138 }
139
140 if (klass->IsInitializing()) {
141 continue;
142 }
143
144 if (klass->IsErroneous()) {
145 ThrowNoClassDefFoundError(thread, klass);
146 return false;
147 }
148
149 if (klass->IsInitialized()) {
150 return true;
151 }
152
153 UNREACHABLE();
154 }
155 }
156
157 /* static */
158 template <MTModeT mode>
Initialize(ClassLinker * class_linker,ManagedThread * thread,Class * klass)159 bool ClassInitializer<mode>::Initialize(ClassLinker *class_linker, ManagedThread *thread, Class *klass)
160 {
161 if (klass->IsInitialized()) {
162 return true;
163 }
164
165 using ObjectLockT = typename ObjectLockConfig<mode>::LockT;
166
167 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
168 VMHandle<ObjectHeader> managed_class_obj_handle(thread, klass->GetManagedObject());
169 {
170 ObjectLockT lock(managed_class_obj_handle.GetPtr());
171
172 if (klass->IsInitialized()) {
173 return true;
174 }
175
176 if (klass->IsErroneous()) {
177 ThrowEarlierInitializationException(thread, klass);
178 return false;
179 }
180
181 if (!klass->IsVerified()) {
182 if (!VerifyClass(klass)) {
183 klass->SetState(Class::State::ERRONEOUS);
184 panda::ThrowVerificationException(utf::Mutf8AsCString(klass->GetDescriptor()));
185 return false;
186 }
187 }
188
189 if (klass->IsInitializing()) {
190 if (klass->GetInitTid() == thread->GetId()) {
191 return true;
192 }
193
194 if (mode == MT_MODE_MULTI) {
195 return WaitInitialization(&lock, class_linker, thread, klass);
196 }
197
198 UNREACHABLE();
199 }
200
201 klass->SetInitTid(thread->GetId());
202 klass->SetState(Class::State::INITIALIZING);
203 if (!ClassInitializer::InitializeFields(klass)) {
204 LOG(ERROR, CLASS_LINKER) << "Cannot initialize fields of class '" << klass->GetName() << "'";
205 return false;
206 }
207 }
208
209 LOG(DEBUG, CLASS_LINKER) << "Initializing class " << klass->GetName();
210
211 return InitializeClass(class_linker, thread, klass, managed_class_obj_handle);
212 }
213
214 /* static */
215 template <MTModeT mode>
InitializeClass(ClassLinker * class_linker,ManagedThread * thread,Class * klass,const VMHandle<ObjectHeader> & managed_class_obj_handle)216 bool ClassInitializer<mode>::InitializeClass(ClassLinker *class_linker, ManagedThread *thread, Class *klass,
217 const VMHandle<ObjectHeader> &managed_class_obj_handle)
218 {
219 using ObjectLockT = typename ObjectLockConfig<mode>::LockT;
220
221 if (!klass->IsInterface()) {
222 auto *base = klass->GetBase();
223
224 if (base != nullptr) {
225 if (isBadSuperClass(base, thread, klass)) {
226 return false;
227 }
228
229 if (!Initialize(class_linker, thread, base)) {
230 ObjectLockT lock(managed_class_obj_handle.GetPtr());
231 klass->SetState(Class::State::ERRONEOUS);
232 lock.NotifyAll();
233 return false;
234 }
235 }
236
237 for (auto *iface : klass->GetInterfaces()) {
238 if (iface->IsInitialized()) {
239 continue;
240 }
241
242 if (!InitializeInterface(class_linker, thread, iface, klass)) {
243 ObjectLockT lock(managed_class_obj_handle.GetPtr());
244 klass->SetState(Class::State::ERRONEOUS);
245 lock.NotifyAll();
246 return false;
247 }
248 }
249 }
250
251 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
252 Method::Proto proto(Method::Proto::ShortyVector {panda_file::Type(panda_file::Type::TypeId::VOID)},
253 Method::Proto::RefTypeVector {});
254 auto *cctor_name = ctx.GetCctorName();
255 auto *cctor = klass->GetDirectMethod(cctor_name, proto);
256 if (cctor != nullptr) {
257 cctor->InvokeVoid(thread, nullptr);
258 }
259
260 {
261 ObjectLockT lock(managed_class_obj_handle.GetPtr());
262
263 if (thread->HasPendingException()) {
264 WrapException(class_linker, thread);
265 klass->SetState(Class::State::ERRONEOUS);
266 lock.NotifyAll();
267 return false;
268 }
269
270 klass->SetState(Class::State::INITIALIZED);
271
272 lock.NotifyAll();
273 }
274
275 return true;
276 }
277
278 /* static */
279 template <MTModeT mode>
InitializeInterface(ClassLinker * class_linker,ManagedThread * thread,Class * iface,Class * klass)280 bool ClassInitializer<mode>::InitializeInterface(ClassLinker *class_linker, ManagedThread *thread, Class *iface,
281 Class *klass)
282 {
283 if (!iface->IsInterface()) {
284 ThrowIncompatibleClassChangeError(thread, klass);
285 return false;
286 }
287
288 for (auto *base_iface : iface->GetInterfaces()) {
289 if (base_iface->IsInitialized()) {
290 continue;
291 }
292
293 if (!InitializeInterface(class_linker, thread, base_iface, klass)) {
294 return false;
295 }
296 }
297
298 if (!iface->HasDefaultMethods()) {
299 return true;
300 }
301
302 return Initialize(class_linker, thread, iface);
303 }
304
305 /* static */
306 template <MTModeT mode>
VerifyClass(Class * klass)307 bool ClassInitializer<mode>::VerifyClass(Class *klass)
308 {
309 ASSERT(!klass->IsVerified());
310
311 auto &verif_opts = Runtime::GetCurrent()->GetVerificationOptions();
312
313 if (!IsVerifySuccInAppInstall(klass->GetPandaFile())) {
314 LOG(ERROR, CLASS_LINKER) << "verify fail";
315 return false;
316 }
317 if (!verif_opts.IsEnabled()) {
318 klass->SetState(Class::State::VERIFIED);
319 return true;
320 }
321
322 bool skip_verification = !verif_opts.VerifyRuntimeLibraries && verifier::IsSystemOrSyntheticClass(*klass);
323 if (skip_verification) {
324 for (auto &method : klass->GetMethods()) {
325 method.SetVerified(true);
326 }
327 klass->SetState(Class::State::VERIFIED);
328 return true;
329 }
330
331 LOG(INFO, VERIFIER) << "Verification of class '" << klass->GetName() << "'";
332 for (auto &method : klass->GetMethods()) {
333 method.EnqueueForVerification();
334 }
335
336 // sync point
337 if (!verif_opts.SyncOnClassInitialization) {
338 klass->SetState(Class::State::VERIFIED);
339 return true;
340 }
341
342 for (auto &method : klass->GetMethods()) {
343 if (!method.Verify()) {
344 return false;
345 }
346 }
347
348 klass->SetState(Class::State::VERIFIED);
349 return true;
350 }
351
352 template <class T>
InitializePrimitiveField(Class * klass,const Field & field)353 static void InitializePrimitiveField(Class *klass, const Field &field)
354 {
355 panda_file::FieldDataAccessor fda(*field.GetPandaFile(), field.GetFileId());
356 auto value = fda.GetValue<T>();
357 klass->SetFieldPrimitive<T>(field, value ? value.value() : 0);
358 }
359
InitializeTaggedField(Class * klass,const Field & field)360 static void InitializeTaggedField(Class *klass, const Field &field)
361 {
362 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
363 klass->SetFieldPrimitive<coretypes::TaggedValue>(field, ctx.GetInitialTaggedValue());
364 }
365
InitializeStringField(Class * klass,const Field & field)366 static void InitializeStringField(Class *klass, const Field &field)
367 {
368 panda_file::FieldDataAccessor fda(*field.GetPandaFile(), field.GetFileId());
369 auto value = fda.GetValue<uint32_t>();
370 if (value) {
371 panda_file::File::EntityId id(value.value());
372 coretypes::String *str = Runtime::GetCurrent()->GetPandaVM()->ResolveString(*klass->GetPandaFile(), id);
373 if (LIKELY(str != nullptr)) {
374 klass->SetFieldObject(field, str);
375 return;
376 }
377 }
378 // Should nullptr be set?
379 klass->SetFieldObject(field, nullptr);
380 }
381
382 /* static */
383 template <MTModeT mode>
InitializeFields(Class * klass)384 bool ClassInitializer<mode>::InitializeFields(Class *klass)
385 {
386 using Type = panda_file::Type;
387
388 for (const auto &field : klass->GetStaticFields()) {
389 switch (field.GetTypeId()) {
390 case Type::TypeId::U1:
391 case Type::TypeId::U8:
392 InitializePrimitiveField<uint8_t>(klass, field);
393 break;
394 case Type::TypeId::I8:
395 InitializePrimitiveField<int8_t>(klass, field);
396 break;
397 case Type::TypeId::I16:
398 InitializePrimitiveField<int16_t>(klass, field);
399 break;
400 case Type::TypeId::U16:
401 InitializePrimitiveField<uint16_t>(klass, field);
402 break;
403 case Type::TypeId::I32:
404 InitializePrimitiveField<int32_t>(klass, field);
405 break;
406 case Type::TypeId::U32:
407 InitializePrimitiveField<uint32_t>(klass, field);
408 break;
409 case Type::TypeId::I64:
410 InitializePrimitiveField<int64_t>(klass, field);
411 break;
412 case Type::TypeId::U64:
413 InitializePrimitiveField<uint64_t>(klass, field);
414 break;
415 case Type::TypeId::F32:
416 InitializePrimitiveField<float>(klass, field);
417 break;
418 case Type::TypeId::F64:
419 InitializePrimitiveField<double>(klass, field);
420 break;
421 case Type::TypeId::TAGGED:
422 InitializeTaggedField(klass, field);
423 break;
424 case Type::TypeId::REFERENCE:
425 InitializeStringField(klass, field);
426 break;
427 default: {
428 UNREACHABLE();
429 break;
430 }
431 }
432 }
433
434 return true;
435 }
436
437 template class ClassInitializer<MT_MODE_SINGLE>;
438 template class ClassInitializer<MT_MODE_MULTI>;
439 template class ClassInitializer<MT_MODE_TASK>;
440
441 } // namespace panda
442