• 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/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