• 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 #include "runtime/core/core_class_linker_extension.h"
17 
18 #include "runtime/include/coretypes/class.h"
19 #include "runtime/include/exceptions.h"
20 #include "runtime/include/panda_vm.h"
21 
22 namespace ark {
23 
24 using SourceLang = panda_file::SourceLang;
25 using Type = panda_file::Type;
26 
OnError(ClassLinker::Error error,const PandaString & message)27 void CoreClassLinkerExtension::ErrorHandler::OnError(ClassLinker::Error error, const PandaString &message)
28 {
29     auto *thread = ManagedThread::GetCurrent();
30     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(panda_file::SourceLang::PANDA_ASSEMBLY);
31 
32     switch (error) {
33         case ClassLinker::Error::CLASS_NOT_FOUND: {
34             ThrowException(ctx, thread, ctx.GetClassNotFoundExceptionDescriptor(),
35                            utf::CStringAsMutf8(message.c_str()));
36             break;
37         }
38         case ClassLinker::Error::FIELD_NOT_FOUND: {
39             ThrowException(ctx, thread, ctx.GetNoSuchFieldErrorDescriptor(), utf::CStringAsMutf8(message.c_str()));
40             break;
41         }
42         case ClassLinker::Error::METHOD_NOT_FOUND: {
43             ThrowException(ctx, thread, ctx.GetNoSuchMethodErrorDescriptor(), utf::CStringAsMutf8(message.c_str()));
44             break;
45         }
46         case ClassLinker::Error::NO_CLASS_DEF: {
47             ThrowException(ctx, thread, ctx.GetNoClassDefFoundErrorDescriptor(), utf::CStringAsMutf8(message.c_str()));
48             break;
49         }
50         case ClassLinker::Error::CLASS_CIRCULARITY: {
51             ThrowException(ctx, thread, ctx.GetClassCircularityErrorDescriptor(), utf::CStringAsMutf8(message.c_str()));
52             break;
53         }
54         default:
55             LOG(FATAL, CLASS_LINKER) << "Unhandled error (" << static_cast<size_t>(error) << "): " << message;
56             break;
57     }
58 }
59 
InitializeClassRoots(const LanguageContext & ctx)60 void CoreClassLinkerExtension::InitializeClassRoots(const LanguageContext &ctx)
61 {
62     InitializePrimitiveClassRoot(ClassRoot::U1, Type::TypeId::U1, "Z");
63     InitializePrimitiveClassRoot(ClassRoot::I8, Type::TypeId::I8, "B");
64     InitializePrimitiveClassRoot(ClassRoot::U8, Type::TypeId::U8, "H");
65     InitializePrimitiveClassRoot(ClassRoot::I16, Type::TypeId::I16, "S");
66     InitializePrimitiveClassRoot(ClassRoot::U16, Type::TypeId::U16, "C");
67     InitializePrimitiveClassRoot(ClassRoot::I32, Type::TypeId::I32, "I");
68     InitializePrimitiveClassRoot(ClassRoot::U32, Type::TypeId::U32, "U");
69     InitializePrimitiveClassRoot(ClassRoot::I64, Type::TypeId::I64, "J");
70     InitializePrimitiveClassRoot(ClassRoot::U64, Type::TypeId::U64, "Q");
71     InitializePrimitiveClassRoot(ClassRoot::F32, Type::TypeId::F32, "F");
72     InitializePrimitiveClassRoot(ClassRoot::F64, Type::TypeId::F64, "D");
73     InitializePrimitiveClassRoot(ClassRoot::TAGGED, Type::TypeId::TAGGED, "A");
74 
75     InitializeArrayClassRoot(ClassRoot::ARRAY_U1, ClassRoot::U1, "[Z");
76     InitializeArrayClassRoot(ClassRoot::ARRAY_I8, ClassRoot::I8, "[B");
77     InitializeArrayClassRoot(ClassRoot::ARRAY_U8, ClassRoot::U8, "[H");
78     InitializeArrayClassRoot(ClassRoot::ARRAY_I16, ClassRoot::I16, "[S");
79     InitializeArrayClassRoot(ClassRoot::ARRAY_U16, ClassRoot::U16, "[C");
80     InitializeArrayClassRoot(ClassRoot::ARRAY_I32, ClassRoot::I32, "[I");
81     InitializeArrayClassRoot(ClassRoot::ARRAY_U32, ClassRoot::U32, "[U");
82     InitializeArrayClassRoot(ClassRoot::ARRAY_I64, ClassRoot::I64, "[J");
83     InitializeArrayClassRoot(ClassRoot::ARRAY_U64, ClassRoot::U64, "[Q");
84     InitializeArrayClassRoot(ClassRoot::ARRAY_F32, ClassRoot::F32, "[F");
85     InitializeArrayClassRoot(ClassRoot::ARRAY_F64, ClassRoot::F64, "[D");
86     InitializeArrayClassRoot(ClassRoot::ARRAY_TAGGED, ClassRoot::TAGGED, "[A");
87     InitializeArrayClassRoot(ClassRoot::ARRAY_STRING, ClassRoot::STRING,
88                              utf::Mutf8AsCString(ctx.GetStringArrayClassDescriptor()));
89 }
90 
InitializeImpl(bool compressedStringEnabled)91 bool CoreClassLinkerExtension::InitializeImpl(bool compressedStringEnabled)
92 {
93     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(GetLanguage());
94 
95     auto *classClass = CreateClass(ctx.GetClassClassDescriptor(), GetClassVTableSize(ClassRoot::CLASS),
96                                    GetClassIMTSize(ClassRoot::CLASS), GetClassSize(ClassRoot::CLASS));
97     coretypes::Class::FromRuntimeClass(classClass)->SetClass(classClass);
98     classClass->SetState(Class::State::LOADED);
99     classClass->SetLoadContext(GetBootContext());
100     GetClassLinker()->AddClassRoot(ClassRoot::CLASS, classClass);
101 
102     auto *objClass = GetClassLinker()->GetClass(ctx.GetObjectClassDescriptor(), false, GetBootContext());
103     if (objClass == nullptr) {  // Happens when we work without pandastdlib
104         objClass = CreateClass(ctx.GetObjectClassDescriptor(), GetClassVTableSize(ClassRoot::OBJECT),
105                                GetClassIMTSize(ClassRoot::OBJECT), GetClassSize(ClassRoot::OBJECT));
106         objClass->SetObjectSize(ObjectHeader::ObjectHeaderSize());
107         objClass->SetState(Class::State::LOADED);
108         objClass->SetLoadContext(GetBootContext());
109         GetClassLinker()->AddClassRoot(ClassRoot::OBJECT, objClass);
110     } else {
111         SetClassRoot(ClassRoot::OBJECT, objClass);
112     }
113     classClass->SetBase(objClass);
114 
115     auto *stringClass = CreateClass(ctx.GetStringClassDescriptor(), GetClassVTableSize(ClassRoot::STRING),
116                                     GetClassIMTSize(ClassRoot::STRING), GetClassSize(ClassRoot::STRING));
117     stringClass->SetBase(objClass);
118     stringClass->SetStringClass();
119     coretypes::String::SetCompressedStringsEnabled(compressedStringEnabled);
120     stringClass->SetState(Class::State::LOADED);
121     stringClass->SetLoadContext(GetBootContext());
122     GetClassLinker()->AddClassRoot(ClassRoot::STRING, stringClass);
123 
124     InitializeArrayClassRoot(ClassRoot::ARRAY_CLASS, ClassRoot::CLASS,
125                              utf::Mutf8AsCString(ctx.GetClassArrayClassDescriptor()));
126 
127     InitializeClassRoots(ctx);
128     return true;
129 }
130 
InitializeArrayClass(Class * arrayClass,Class * componentClass)131 bool CoreClassLinkerExtension::InitializeArrayClass(Class *arrayClass, Class *componentClass)
132 {
133     ASSERT(IsInitialized());
134 
135     auto *objectClass = GetClassRoot(ClassRoot::OBJECT);
136     arrayClass->SetBase(objectClass);
137     arrayClass->SetComponentType(componentClass);
138     uint32_t accessFlags = componentClass->GetAccessFlags() & ACC_FILE_MASK;
139     accessFlags &= ~ACC_INTERFACE;
140     accessFlags |= ACC_FINAL | ACC_ABSTRACT;
141     arrayClass->SetAccessFlags(accessFlags);
142     arrayClass->SetState(Class::State::INITIALIZED);
143     return true;
144 }
145 
InitializePrimitiveClass(Class * primitiveClass)146 void CoreClassLinkerExtension::InitializePrimitiveClass(Class *primitiveClass)
147 {
148     ASSERT(IsInitialized());
149 
150     primitiveClass->SetAccessFlags(ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT);
151     primitiveClass->SetState(Class::State::INITIALIZED);
152 }
153 
GetClassVTableSize(ClassRoot root)154 size_t CoreClassLinkerExtension::GetClassVTableSize(ClassRoot root)
155 {
156     ASSERT(IsInitialized());
157 
158     switch (root) {
159         case ClassRoot::U1:
160         case ClassRoot::I8:
161         case ClassRoot::U8:
162         case ClassRoot::I16:
163         case ClassRoot::U16:
164         case ClassRoot::I32:
165         case ClassRoot::U32:
166         case ClassRoot::I64:
167         case ClassRoot::U64:
168         case ClassRoot::F32:
169         case ClassRoot::F64:
170         case ClassRoot::TAGGED:
171             return 0;
172         case ClassRoot::ARRAY_U1:
173         case ClassRoot::ARRAY_I8:
174         case ClassRoot::ARRAY_U8:
175         case ClassRoot::ARRAY_I16:
176         case ClassRoot::ARRAY_U16:
177         case ClassRoot::ARRAY_I32:
178         case ClassRoot::ARRAY_U32:
179         case ClassRoot::ARRAY_I64:
180         case ClassRoot::ARRAY_U64:
181         case ClassRoot::ARRAY_F32:
182         case ClassRoot::ARRAY_F64:
183         case ClassRoot::ARRAY_TAGGED:
184         case ClassRoot::ARRAY_CLASS:
185         case ClassRoot::ARRAY_STRING:
186             return GetArrayClassVTableSize();
187         case ClassRoot::OBJECT:
188         case ClassRoot::CLASS:
189         case ClassRoot::STRING:
190             return 0;
191         default: {
192             break;
193         }
194     }
195 
196     UNREACHABLE();
197 }
198 
GetClassIMTSize(ClassRoot root)199 size_t CoreClassLinkerExtension::GetClassIMTSize(ClassRoot root)
200 {
201     ASSERT(IsInitialized());
202 
203     switch (root) {
204         case ClassRoot::U1:
205         case ClassRoot::I8:
206         case ClassRoot::U8:
207         case ClassRoot::I16:
208         case ClassRoot::U16:
209         case ClassRoot::I32:
210         case ClassRoot::U32:
211         case ClassRoot::I64:
212         case ClassRoot::U64:
213         case ClassRoot::F32:
214         case ClassRoot::F64:
215         case ClassRoot::TAGGED:
216             return 0;
217         case ClassRoot::ARRAY_U1:
218         case ClassRoot::ARRAY_I8:
219         case ClassRoot::ARRAY_U8:
220         case ClassRoot::ARRAY_I16:
221         case ClassRoot::ARRAY_U16:
222         case ClassRoot::ARRAY_I32:
223         case ClassRoot::ARRAY_U32:
224         case ClassRoot::ARRAY_I64:
225         case ClassRoot::ARRAY_U64:
226         case ClassRoot::ARRAY_F32:
227         case ClassRoot::ARRAY_F64:
228         case ClassRoot::ARRAY_TAGGED:
229         case ClassRoot::ARRAY_CLASS:
230         case ClassRoot::ARRAY_STRING:
231             return GetArrayClassIMTSize();
232         case ClassRoot::OBJECT:
233         case ClassRoot::CLASS:
234         case ClassRoot::STRING:
235             return 0;
236         default: {
237             break;
238         }
239     }
240 
241     UNREACHABLE();
242 }
243 
GetClassSize(ClassRoot root)244 size_t CoreClassLinkerExtension::GetClassSize(ClassRoot root)
245 {
246     ASSERT(IsInitialized());
247 
248     switch (root) {
249         case ClassRoot::U1:
250         case ClassRoot::I8:
251         case ClassRoot::U8:
252         case ClassRoot::I16:
253         case ClassRoot::U16:
254         case ClassRoot::I32:
255         case ClassRoot::U32:
256         case ClassRoot::I64:
257         case ClassRoot::U64:
258         case ClassRoot::F32:
259         case ClassRoot::F64:
260         case ClassRoot::TAGGED:
261             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
262         case ClassRoot::ARRAY_U1:
263         case ClassRoot::ARRAY_I8:
264         case ClassRoot::ARRAY_U8:
265         case ClassRoot::ARRAY_I16:
266         case ClassRoot::ARRAY_U16:
267         case ClassRoot::ARRAY_I32:
268         case ClassRoot::ARRAY_U32:
269         case ClassRoot::ARRAY_I64:
270         case ClassRoot::ARRAY_U64:
271         case ClassRoot::ARRAY_F32:
272         case ClassRoot::ARRAY_F64:
273         case ClassRoot::ARRAY_TAGGED:
274         case ClassRoot::ARRAY_CLASS:
275         case ClassRoot::ARRAY_STRING:
276             return GetArrayClassSize();
277         case ClassRoot::OBJECT:
278         case ClassRoot::CLASS:
279         case ClassRoot::STRING:
280             return Class::ComputeClassSize(GetClassVTableSize(root), GetClassIMTSize(root), 0, 0, 0, 0, 0, 0);
281         default: {
282             break;
283         }
284     }
285 
286     UNREACHABLE();
287 }
288 
GetArrayClassVTableSize()289 size_t CoreClassLinkerExtension::GetArrayClassVTableSize()
290 {
291     ASSERT(IsInitialized());
292 
293     return GetClassVTableSize(ClassRoot::OBJECT);
294 }
295 
GetArrayClassIMTSize()296 size_t CoreClassLinkerExtension::GetArrayClassIMTSize()
297 {
298     ASSERT(IsInitialized());
299 
300     return GetClassIMTSize(ClassRoot::OBJECT);
301 }
302 
GetArrayClassSize()303 size_t CoreClassLinkerExtension::GetArrayClassSize()
304 {
305     ASSERT(IsInitialized());
306 
307     return GetClassSize(ClassRoot::OBJECT);
308 }
309 
CreateClass(const uint8_t * descriptor,size_t vtableSize,size_t imtSize,size_t size)310 Class *CoreClassLinkerExtension::CreateClass(const uint8_t *descriptor, size_t vtableSize, size_t imtSize, size_t size)
311 {
312     ASSERT(IsInitialized());
313 
314     auto vm = Thread::GetCurrent()->GetVM();
315     auto *heapManager = vm->GetHeapManager();
316 
317     auto *classRoot = GetClassRoot(ClassRoot::CLASS);
318     ObjectHeader *objectHeader;
319     if (classRoot == nullptr) {
320         objectHeader = heapManager->AllocateNonMovableObject<true>(classRoot, coretypes::Class::GetSize(size));
321     } else {
322         objectHeader = heapManager->AllocateNonMovableObject<false>(classRoot, coretypes::Class::GetSize(size));
323     }
324 
325     if (UNLIKELY(objectHeader == nullptr)) {
326         return nullptr;
327     }
328 
329     auto *res = reinterpret_cast<coretypes::Class *>(objectHeader);
330     res->InitClass(descriptor, vtableSize, imtSize, size);
331     auto *klass = res->GetRuntimeClass();
332     klass->SetManagedObject(res);
333     AddCreatedClass(klass);
334     return klass;
335 }
336 
FreeClass(Class * klass)337 void CoreClassLinkerExtension::FreeClass(Class *klass)
338 {
339     ASSERT(IsInitialized());
340 
341     RemoveCreatedClass(klass);
342 }
343 
~CoreClassLinkerExtension()344 CoreClassLinkerExtension::~CoreClassLinkerExtension()
345 {
346     if (!IsInitialized()) {
347         return;
348     }
349 
350     FreeLoadedClasses();
351 }
352 
353 }  // namespace ark
354