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