1 /**
2 * Copyright (c) 2021-2025 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/class_linker.h"
17 #include "runtime/bridge/bridge.h"
18 #include "runtime/cha.h"
19 #include "runtime/class_initializer.h"
20 #include "runtime/include/coretypes/array.h"
21 #include "runtime/include/coretypes/string.h"
22 #include "runtime/include/field.h"
23 #include "runtime/include/itable_builder.h"
24 #include "runtime/include/method.h"
25 #include "runtime/include/panda_vm.h"
26 #include "runtime/include/runtime.h"
27 #include "runtime/include/runtime_notification.h"
28 #include "libpandabase/macros.h"
29 #include "libpandabase/mem/mem.h"
30 #include "libpandabase/utils/bit_utils.h"
31 #include "libpandabase/utils/span.h"
32 #include "libpandabase/utils/utf.h"
33 #include "libpandafile/class_data_accessor-inl.h"
34 #include "libpandafile/code_data_accessor-inl.h"
35 #include "libpandafile/field_data_accessor-inl.h"
36 #include "libpandafile/method_data_accessor-inl.h"
37 #include "libpandafile/modifiers.h"
38 #include "libpandafile/panda_cache.h"
39 #include "libpandafile/proto_data_accessor-inl.h"
40 #include "runtime/include/tooling/debug_inf.h"
41 #include "trace/trace.h"
42
43 namespace ark {
44
45 using Type = panda_file::Type;
46 using SourceLang = panda_file::SourceLang;
47
AddPandaFile(std::unique_ptr<const panda_file::File> && pf,ClassLinkerContext * context)48 void ClassLinker::AddPandaFile(std::unique_ptr<const panda_file::File> &&pf, ClassLinkerContext *context)
49 {
50 ASSERT(pf != nullptr);
51
52 const panda_file::File *file = pf.get();
53
54 SCOPED_TRACE_STREAM << __FUNCTION__ << " " << file->GetFilename();
55
56 {
57 os::memory::LockHolder lock {pandaFilesLock_};
58 pandaFiles_.push_back({context, std::forward<std::unique_ptr<const panda_file::File>>(pf)});
59 }
60
61 if (context == nullptr || context->IsBootContext()) {
62 os::memory::LockHolder lock {bootPandaFilesLock_};
63 bootPandaFiles_.push_back(file);
64 }
65
66 if (Runtime::GetCurrent()->IsInitialized()) {
67 // LoadModule for initial boot files is called in runtime
68 Runtime::GetCurrent()->GetNotificationManager()->LoadModuleEvent(file->GetFilename());
69 }
70
71 tooling::DebugInf::AddCodeMetaInfo(file);
72 }
73
FreeClassData(Class * classPtr)74 void ClassLinker::FreeClassData(Class *classPtr)
75 {
76 Span<Field> fields = classPtr->GetFields();
77 if (fields.Size() > 0) {
78 allocator_->Free(fields.begin());
79 classPtr->SetFields(Span<Field>(), 0);
80 }
81 Span<Method> methods = classPtr->GetMethods();
82 size_t n = methods.Size() + classPtr->GetNumCopiedMethods();
83 if (n > 0) {
84 mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
85 for (auto &method : methods) {
86 // We create Profiling data in method class via InternalAllocator.
87 // Therefore, we should delete it via InternalAllocator too.
88 allocator->Free(method.GetProfilingData());
89 }
90
91 // Free copied method's ProfileData if it is necessary.
92 for (auto &method : classPtr->GetCopiedMethods()) {
93 auto id = method.GetFileId();
94 auto pf = method.GetPandaFile();
95
96 // There is a possibility that ProfilingData can be borrowed from the original method. Example:
97 // 1. create a base interface class with a default method,
98 // 2. call StartProfiling(),
99 // 3. create a derived class and do not override the default method from the base interface,
100 // 4. call StartProfiling() for the derived class.
101 // Currently this example is impossible (the default method cannot be called from the interface) because
102 // there is no such a language where #2 step will be executed.
103 // Need more investigations to eliminate this extra check.
104 Span<Method> originalMethods = method.GetClass()->GetMethods();
105 auto it = std::find_if(originalMethods.begin(), originalMethods.end(),
106 [id, pf](const auto &m) { return m.GetFileId() == id && m.GetPandaFile() == pf; });
107
108 // Free method's ProfileData if it was set after copying of the original method.
109 auto ptr = method.GetProfilingData();
110 if (it == originalMethods.end() || it->GetProfilingDataWithoutCheck() != ptr) {
111 allocator->Free(ptr);
112 }
113 }
114
115 allocator_->Free(methods.begin());
116 classPtr->SetMethods(Span<Method>(), 0, 0);
117 }
118 bool hasOwnItable = !classPtr->IsArrayClass();
119 auto itable = classPtr->GetITable().Get();
120 if (hasOwnItable && !itable.Empty()) {
121 for (size_t i = 0; i < itable.Size(); i++) {
122 Span<Method *> imethods = itable[i].GetMethods();
123 if (!imethods.Empty()) {
124 allocator_->Free(imethods.begin());
125 }
126 }
127 allocator_->Free(itable.begin());
128 classPtr->SetITable(ITable());
129 }
130 Span<Class *> interfaces = classPtr->GetInterfaces();
131 if (!interfaces.Empty()) {
132 allocator_->Free(interfaces.begin());
133 classPtr->SetInterfaces(Span<Class *>());
134 }
135 }
136
FreeClass(Class * classPtr)137 void ClassLinker::FreeClass(Class *classPtr)
138 {
139 FreeClassData(classPtr);
140 GetExtension(classPtr->GetSourceLang())->FreeClass(classPtr);
141 }
142
~ClassLinker()143 ClassLinker::~ClassLinker()
144 {
145 for (auto &copiedName : copiedNames_) {
146 allocator_->Free(reinterpret_cast<void *>(const_cast<uint8_t *>(copiedName)));
147 }
148 }
149
ClassLinker(mem::InternalAllocatorPtr allocator,std::vector<std::unique_ptr<ClassLinkerExtension>> && extensions)150 ClassLinker::ClassLinker(mem::InternalAllocatorPtr allocator,
151 std::vector<std::unique_ptr<ClassLinkerExtension>> &&extensions)
152 : allocator_(allocator), aotManager_(MakePandaUnique<AotManager>()), copiedNames_(allocator->Adapter())
153 {
154 for (auto &ext : extensions) {
155 extensions_[ark::panda_file::GetLangArrIndex(ext->GetLanguage())] = std::move(ext);
156 }
157 }
158
ResetExtension(panda_file::SourceLang lang)159 void ClassLinker::ResetExtension(panda_file::SourceLang lang)
160 {
161 extensions_[ark::panda_file::GetLangArrIndex(lang)] =
162 Runtime::GetCurrent()->GetLanguageContext(lang).CreateClassLinkerExtension();
163 }
164
165 template <class T, class... Args>
InitializeMemory(T * mem,Args...args)166 static T *InitializeMemory(T *mem, Args... args)
167 {
168 return new (mem) T(std::forward<Args>(args)...);
169 }
170
Initialize(bool compressedStringEnabled)171 bool ClassLinker::Initialize(bool compressedStringEnabled)
172 {
173 if (isInitialized_) {
174 return true;
175 }
176
177 for (auto &ext : extensions_) {
178 if (ext == nullptr) {
179 continue;
180 }
181
182 if (!ext->Initialize(this, compressedStringEnabled)) {
183 return false;
184 }
185 }
186
187 isInitialized_ = true;
188
189 return true;
190 }
191
InitializeRoots(ManagedThread * thread)192 bool ClassLinker::InitializeRoots(ManagedThread *thread)
193 {
194 for (auto &ext : extensions_) {
195 if (ext == nullptr) {
196 continue;
197 }
198
199 if (!ext->InitializeRoots(thread)) {
200 return false;
201 }
202 }
203
204 return true;
205 }
206
207 using ClassEntry = std::pair<panda_file::File::EntityId, const panda_file::File *>;
208 using PandaFiles = PandaVector<const panda_file::File *>;
209
FindClassInPandaFiles(const uint8_t * descriptor,const PandaFiles & pandaFiles)210 static ClassEntry FindClassInPandaFiles(const uint8_t *descriptor, const PandaFiles &pandaFiles)
211 {
212 for (auto *pf : pandaFiles) {
213 auto classId = pf->GetClassId(descriptor);
214 if (classId.IsValid() && !pf->IsExternal(classId)) {
215 return {classId, pf};
216 }
217 }
218
219 return {};
220 }
221
FindLoadedClass(const uint8_t * descriptor,ClassLinkerContext * context)222 Class *ClassLinker::FindLoadedClass(const uint8_t *descriptor, ClassLinkerContext *context)
223 {
224 ASSERT(context != nullptr);
225 return context->FindClass(descriptor);
226 }
227
228 template <class ClassDataAccessorT>
GetClassSize(ClassDataAccessorT dataAccessor,size_t vtableSize,size_t imtSize,size_t * outNumSfields)229 static size_t GetClassSize(ClassDataAccessorT dataAccessor, size_t vtableSize, size_t imtSize, size_t *outNumSfields)
230 {
231 size_t num8bitSfields = 0;
232 size_t num16bitSfields = 0;
233 size_t num32bitSfields = 0;
234 size_t num64bitSfields = 0;
235 size_t numRefSfields = 0;
236 size_t numTaggedSfields = 0;
237
238 size_t numSfields = 0;
239
240 dataAccessor.template EnumerateStaticFieldTypes([&num8bitSfields, &num16bitSfields, &num32bitSfields,
241 &num64bitSfields, &numRefSfields, &numTaggedSfields,
242 &numSfields](Type fieldType) {
243 ++numSfields;
244
245 switch (fieldType.GetId()) {
246 case Type::TypeId::U1:
247 case Type::TypeId::I8:
248 case Type::TypeId::U8:
249 ++num8bitSfields;
250 break;
251 case Type::TypeId::I16:
252 case Type::TypeId::U16:
253 ++num16bitSfields;
254 break;
255 case Type::TypeId::I32:
256 case Type::TypeId::U32:
257 case Type::TypeId::F32:
258 ++num32bitSfields;
259 break;
260 case Type::TypeId::I64:
261 case Type::TypeId::U64:
262 case Type::TypeId::F64:
263 ++num64bitSfields;
264 break;
265 case Type::TypeId::REFERENCE:
266 ++numRefSfields;
267 break;
268 case Type::TypeId::TAGGED:
269 ++numTaggedSfields;
270 break;
271 default:
272 UNREACHABLE();
273 break;
274 }
275 });
276
277 *outNumSfields = numSfields;
278
279 return Class::ComputeClassSize(vtableSize, imtSize, num8bitSfields, num16bitSfields, num32bitSfields,
280 num64bitSfields, numRefSfields, numTaggedSfields);
281 }
282
283 class ClassDataAccessorWrapper {
284 public:
ClassDataAccessorWrapper(panda_file::ClassDataAccessor * dataAccessor=nullptr)285 explicit ClassDataAccessorWrapper(panda_file::ClassDataAccessor *dataAccessor = nullptr)
286 : dataAccessor_(dataAccessor)
287 {
288 }
289
290 template <class Callback>
EnumerateStaticFieldTypes(const Callback & cb) const291 void EnumerateStaticFieldTypes(const Callback &cb) const
292 {
293 dataAccessor_->EnumerateFields([cb](panda_file::FieldDataAccessor &fda) {
294 if (!fda.IsStatic()) {
295 return;
296 }
297
298 cb(Type::GetTypeFromFieldEncoding(fda.GetType()));
299 });
300 }
301
302 ~ClassDataAccessorWrapper() = default;
303
304 DEFAULT_COPY_SEMANTIC(ClassDataAccessorWrapper);
305 DEFAULT_MOVE_SEMANTIC(ClassDataAccessorWrapper);
306
307 private:
308 panda_file::ClassDataAccessor *dataAccessor_;
309 };
310
FreeITableAndInterfaces(ITable itable,Span<Class * > & interfaces)311 void ClassLinker::FreeITableAndInterfaces(ITable itable, Span<Class *> &interfaces)
312 {
313 auto table = itable.Get();
314 if (!table.Empty()) {
315 for (size_t i = 0; i < table.Size(); i++) {
316 Span<Method *> imethods = table[i].GetMethods();
317 if (!imethods.Empty()) {
318 allocator_->Free(imethods.begin());
319 }
320 table[i].SetInterface(nullptr);
321 }
322 allocator_->Free(table.begin());
323 }
324 if (!interfaces.Empty()) {
325 allocator_->Free(interfaces.begin());
326 }
327 }
328
SetupClassInfo(ClassLinker::ClassInfo & info,panda_file::ClassDataAccessor * dataAccessor,Class * base,Span<Class * > interfaces,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)329 bool ClassLinker::SetupClassInfo(ClassLinker::ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base,
330 Span<Class *> interfaces, ClassLinkerContext *context,
331 ClassLinkerErrorHandler *errorHandler)
332 {
333 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(dataAccessor);
334
335 info.vtableBuilder = ctx.CreateVTableBuilder(errorHandler);
336 info.itableBuilder = ctx.CreateITableBuilder(errorHandler);
337 info.imtableBuilder = ctx.CreateIMTableBuilder();
338
339 ASSERT(info.itableBuilder != nullptr);
340 if (!info.itableBuilder->Build(this, base, interfaces, dataAccessor->IsInterface())) {
341 return false;
342 }
343 ASSERT(info.vtableBuilder != nullptr);
344 if (!info.vtableBuilder->Build(dataAccessor, base, info.itableBuilder->GetITable(), context)) {
345 FreeITableAndInterfaces(info.itableBuilder->GetITable(), interfaces);
346 return false;
347 }
348 info.imtableBuilder->Build(dataAccessor, info.itableBuilder->GetITable());
349
350 ClassDataAccessorWrapper dataAccessorWrapper(dataAccessor);
351 info.size = GetClassSize(dataAccessorWrapper, info.vtableBuilder->GetVTableSize(),
352 info.imtableBuilder->GetIMTSize(), &info.numSfields);
353 return true;
354 }
355
356 class ClassDataAccessor {
357 public:
ClassDataAccessor(Span<Field> fields)358 explicit ClassDataAccessor(Span<Field> fields) : fields_(fields) {}
359
360 template <class Callback>
EnumerateStaticFieldTypes(const Callback & cb) const361 void EnumerateStaticFieldTypes(const Callback &cb) const
362 {
363 for (const auto &field : fields_) {
364 if (!field.IsStatic()) {
365 continue;
366 }
367
368 cb(field.GetType());
369 }
370 }
371
372 ~ClassDataAccessor() = default;
373
374 DEFAULT_COPY_SEMANTIC(ClassDataAccessor);
375 DEFAULT_MOVE_SEMANTIC(ClassDataAccessor);
376
377 private:
378 Span<Field> fields_;
379 };
380
SetupClassInfo(ClassLinker::ClassInfo & info,Span<Method> methods,Span<Field> fields,Class * base,Span<Class * > interfaces,bool isInterface,ClassLinkerErrorHandler * errorHandler)381 bool ClassLinker::SetupClassInfo(ClassLinker::ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base,
382 Span<Class *> interfaces, bool isInterface, ClassLinkerErrorHandler *errorHandler)
383 {
384 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*base);
385
386 info.vtableBuilder = ctx.CreateVTableBuilder(errorHandler);
387 info.itableBuilder = ctx.CreateITableBuilder(errorHandler);
388 info.imtableBuilder = ctx.CreateIMTableBuilder();
389
390 ASSERT(info.itableBuilder != nullptr);
391 if (!info.itableBuilder->Build(this, base, interfaces, isInterface)) {
392 return false;
393 }
394 ASSERT(info.vtableBuilder != nullptr);
395 if (!info.vtableBuilder->Build(methods, base, info.itableBuilder->GetITable(), isInterface)) {
396 FreeITableAndInterfaces(info.itableBuilder->GetITable(), interfaces);
397 return false;
398 }
399 info.imtableBuilder->Build(info.itableBuilder->GetITable(), isInterface);
400
401 ClassDataAccessor dataAccessor(fields);
402 info.size = GetClassSize(dataAccessor, info.vtableBuilder->GetVTableSize(), info.imtableBuilder->GetIMTSize(),
403 &info.numSfields);
404 return true;
405 }
406
LoadMethod(Method * method,panda_file::MethodDataAccessor * methodDataAccessor,Class * klass,const LanguageContext & ctx,const ClassLinkerExtension * ext)407 static void LoadMethod(Method *method, panda_file::MethodDataAccessor *methodDataAccessor, Class *klass,
408 const LanguageContext &ctx, const ClassLinkerExtension *ext)
409 {
410 const auto &pf = methodDataAccessor->GetPandaFile();
411 panda_file::ProtoDataAccessor pda(pf, methodDataAccessor->GetProtoId());
412
413 uint32_t accessFlags = methodDataAccessor->GetAccessFlags();
414
415 auto *methodName = pf.GetStringData(methodDataAccessor->GetNameId()).data;
416 if (utf::IsEqual(methodName, ctx.GetCtorName()) || utf::IsEqual(methodName, ctx.GetCctorName())) {
417 accessFlags |= ACC_CONSTRUCTOR;
418 }
419
420 auto codeId = methodDataAccessor->GetCodeId();
421 size_t numArgs = (methodDataAccessor->IsStatic()) ? pda.GetNumArgs() : (pda.GetNumArgs() + 1);
422
423 if (!codeId.has_value()) {
424 InitializeMemory(method, klass, &pf, methodDataAccessor->GetMethodId(), panda_file::File::EntityId(0),
425 accessFlags, numArgs, reinterpret_cast<const uint16_t *>(pda.GetShorty().Data()));
426
427 if (methodDataAccessor->IsNative()) {
428 method->SetCompiledEntryPoint(ext->GetNativeEntryPointFor(method));
429 } else {
430 method->SetInterpreterEntryPoint();
431 }
432 } else {
433 InitializeMemory(method, klass, &pf, methodDataAccessor->GetMethodId(), codeId.value(), accessFlags, numArgs,
434 reinterpret_cast<const uint16_t *>(pda.GetShorty().Data()));
435 method->SetCompiledEntryPoint(GetCompiledCodeToInterpreterBridge(method));
436 }
437 }
438
MaybeLinkMethodToAotCode(Method * method,const compiler::AotClass & aotClass,size_t methodIndex)439 static void MaybeLinkMethodToAotCode(Method *method, const compiler::AotClass &aotClass, size_t methodIndex)
440 {
441 ASSERT(aotClass.IsValid());
442 if (method->IsIntrinsic()) {
443 return;
444 }
445 auto entry = aotClass.FindMethodCodeEntry(methodIndex);
446 if (entry != nullptr) {
447 method->SetCompiledEntryPoint(entry);
448 LOG(DEBUG, AOT) << "Found AOT entrypoint ["
449 << reinterpret_cast<const void *>(aotClass.FindMethodCodeSpan(methodIndex).data()) << ":"
450 << reinterpret_cast<const void *>(aotClass.FindMethodCodeSpan(methodIndex).end())
451 << "] for method: " << method->GetFullName();
452
453 EVENT_AOT_ENTRYPOINT_FOUND(method->GetFullName());
454 ASSERT(aotClass.FindMethodHeader(methodIndex)->methodId == method->GetFileId().GetOffset());
455 }
456 }
457
SetupCopiedMethods(Span<Method> methods,Span<const CopiedMethod> copiedMethods)458 static void SetupCopiedMethods(Span<Method> methods, Span<const CopiedMethod> copiedMethods)
459 {
460 size_t const numMethods = methods.size() - copiedMethods.size();
461
462 for (size_t i = 0; i < copiedMethods.size(); i++) {
463 Method *method = &methods[numMethods + i];
464 InitializeMemory(method, copiedMethods[i].GetMethod());
465 method->SetIsDefaultInterfaceMethod();
466 switch (copiedMethods[i].GetStatus()) {
467 case CopiedMethod::Status::ORDINARY:
468 break;
469 case CopiedMethod::Status::ABSTRACT:
470 method->SetCompiledEntryPoint(GetAbstractMethodStub());
471 break;
472 case CopiedMethod::Status::CONFLICT:
473 method->SetCompiledEntryPoint(GetDefaultConflictMethodStub());
474 break;
475 }
476 }
477 }
478
LoadMethods(Class * klass,ClassInfo * classInfo,panda_file::ClassDataAccessor * dataAccessor,ClassLinkerErrorHandler * errorHandler)479 bool ClassLinker::LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor,
480 [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
481 {
482 uint32_t numMethods = dataAccessor->GetMethodsNumber();
483
484 uint32_t numVmethods = klass->GetNumVirtualMethods();
485 uint32_t numSmethods = numMethods - numVmethods;
486
487 auto copiedMethods = classInfo->vtableBuilder->GetCopiedMethods();
488 uint32_t totalNumMethods = numMethods + copiedMethods.size();
489 if (totalNumMethods == 0) {
490 return true;
491 }
492
493 Span<Method> methods {allocator_->AllocArray<Method>(totalNumMethods), totalNumMethods};
494
495 size_t smethodIdx = numVmethods;
496 size_t vmethodIdx = 0;
497
498 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
499 auto *ext = GetExtension(ctx);
500 ASSERT(ext != nullptr);
501
502 auto aotPfile = aotManager_->FindPandaFile(klass->GetPandaFile()->GetFullFileName());
503 if (aotPfile != nullptr) {
504 EVENT_AOT_LOADED_FOR_CLASS(PandaString(aotPfile->GetFileName()), PandaString(klass->GetName()));
505 }
506
507 compiler::AotClass aotClass =
508 (aotPfile != nullptr) ? aotPfile->GetClass(klass->GetFileId().GetOffset()) : compiler::AotClass::Invalid();
509
510 size_t methodIndex = 0;
511 dataAccessor->EnumerateMethods([klass, &smethodIdx, &vmethodIdx, &methods, aotClass, ctx, ext,
512 &methodIndex](panda_file::MethodDataAccessor &methodDataAccessor) {
513 Method *method = methodDataAccessor.IsStatic() ? &methods[smethodIdx++] : &methods[vmethodIdx++];
514 LoadMethod(method, &methodDataAccessor, klass, ctx, ext);
515 if (aotClass.IsValid()) {
516 MaybeLinkMethodToAotCode(method, aotClass, methodIndex);
517 }
518 // Instead of checking if the method is abstract before every virtual call
519 // the special stub throwing AbstractMethodError is registered as compiled entry point.
520 if (method->IsAbstract()) {
521 method->SetCompiledEntryPoint(GetAbstractMethodStub());
522 }
523 methodIndex++;
524 });
525
526 SetupCopiedMethods(methods, copiedMethods);
527 klass->SetMethods(methods, numVmethods, numSmethods);
528 return true;
529 }
530
LoadFields(Class * klass,panda_file::ClassDataAccessor * dataAccessor,ClassLinkerErrorHandler * errorHandler)531 bool ClassLinker::LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor,
532 [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
533 {
534 uint32_t numFields = dataAccessor->GetFieldsNumber();
535 if (numFields == 0) {
536 return true;
537 }
538
539 uint32_t numSfields = klass->GetNumStaticFields();
540
541 Span<Field> fields {allocator_->AllocArray<Field>(numFields), numFields};
542
543 size_t sfieldsIdx = 0;
544 size_t ifieldsIdx = numSfields;
545 dataAccessor->EnumerateFields(
546 [klass, &sfieldsIdx, &ifieldsIdx, &fields](panda_file::FieldDataAccessor &fieldDataAccessor) {
547 Field *field = fieldDataAccessor.IsStatic() ? &fields[sfieldsIdx++] : &fields[ifieldsIdx++];
548 InitializeMemory(field, klass, fieldDataAccessor.GetFieldId(), fieldDataAccessor.GetAccessFlags(),
549 panda_file::Type::GetTypeFromFieldEncoding(fieldDataAccessor.GetType()));
550 });
551
552 klass->SetFields(fields, numSfields);
553
554 return true;
555 }
556
557 template <bool REVERSE_LAYOUT = false>
LayoutFieldsWithoutAlignment(size_t size,size_t * offset,size_t * space,PandaVector<Field * > * fields)558 static void LayoutFieldsWithoutAlignment(size_t size, size_t *offset, size_t *space, PandaVector<Field *> *fields)
559 {
560 auto lastProceededElement = fields->end();
561 // Iterating from beginning to end and erasing elements from the beginning of a vector
562 // is required for correct field layout between language class representation in C++ code
563 // and generated by methods in class linker.
564 // (e.g. class String should have length field before hash field, not vice versa)
565 for (auto i = fields->begin(); i != fields->end(); i++) {
566 if (!(space == nullptr || *space >= size)) {
567 lastProceededElement = i;
568 break;
569 }
570 Field *field = *i;
571 // NOLINTNEXTLINE(readability-braces-around-statements)
572 if constexpr (REVERSE_LAYOUT) {
573 *offset -= size;
574 field->SetOffset(*offset);
575 // NOLINTNEXTLINE(readability-misleading-indentation)
576 } else {
577 field->SetOffset(*offset);
578 *offset += size;
579 }
580 if (space != nullptr) {
581 *space -= size;
582 }
583 }
584 fields->erase(fields->begin(), lastProceededElement);
585 }
586
LayoutReferenceFields(size_t size,size_t * offset,const PandaVector<Field * > & fields)587 static uint32_t LayoutReferenceFields(size_t size, size_t *offset, const PandaVector<Field *> &fields)
588 {
589 uint32_t volatileFieldsNum = 0;
590 // layout volatile fields firstly
591 for (auto *field : fields) {
592 if (field->IsVolatile()) {
593 volatileFieldsNum++;
594 field->SetOffset(*offset);
595 *offset += size;
596 }
597 }
598 for (auto *field : fields) {
599 if (!field->IsVolatile()) {
600 field->SetOffset(*offset);
601 *offset += size;
602 }
603 }
604 return volatileFieldsNum;
605 }
606
607 constexpr size_t SIZE_64 = sizeof(uint64_t);
608 constexpr size_t SIZE_32 = sizeof(uint32_t);
609 constexpr size_t SIZE_16 = sizeof(uint16_t);
610 constexpr size_t SIZE_8 = sizeof(uint8_t);
611
612 // CC-OFFNXT(G.FUN.01) solid logic
LayoutFieldsInBaseClassPadding(Class * klass,PandaVector<Field * > * taggedFields,PandaVector<Field * > * fields64,PandaVector<Field * > * fields32,PandaVector<Field * > * fields16,PandaVector<Field * > * fields8,PandaVector<Field * > * refFields,bool isStatic)613 static size_t LayoutFieldsInBaseClassPadding(Class *klass, PandaVector<Field *> *taggedFields,
614 PandaVector<Field *> *fields64, PandaVector<Field *> *fields32,
615 PandaVector<Field *> *fields16, PandaVector<Field *> *fields8,
616 PandaVector<Field *> *refFields, bool isStatic)
617 {
618 size_t offset;
619
620 if (isStatic) {
621 offset = klass->GetStaticFieldsOffset();
622 } else {
623 offset = (klass->GetBase() != nullptr) ? klass->GetBase()->GetObjectSize() : ObjectHeader::ObjectHeaderSize();
624 }
625
626 size_t alignOffset = offset;
627 if (!refFields->empty()) {
628 alignOffset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
629 } else if (!(fields64->empty()) || !(taggedFields->empty())) {
630 alignOffset = AlignUp(offset, SIZE_64);
631 } else if (!fields32->empty()) {
632 alignOffset = AlignUp(offset, SIZE_32);
633 } else if (!fields16->empty()) {
634 alignOffset = AlignUp(offset, SIZE_16);
635 }
636 if (alignOffset != offset) {
637 size_t endOffset = alignOffset;
638 size_t padding = endOffset - offset;
639 // try to put short fields of child class at end of free space of base class
640 LayoutFieldsWithoutAlignment<true>(SIZE_32, &endOffset, &padding, fields32);
641 LayoutFieldsWithoutAlignment<true>(SIZE_16, &endOffset, &padding, fields16);
642 LayoutFieldsWithoutAlignment<true>(SIZE_8, &endOffset, &padding, fields8);
643 }
644 return alignOffset;
645 }
646
647 // CC-OFFNXT(G.FUN.01) solid logic
LayoutFields(Class * klass,PandaVector<Field * > * taggedFields,PandaVector<Field * > * fields64,PandaVector<Field * > * fields32,PandaVector<Field * > * fields16,PandaVector<Field * > * fields8,PandaVector<Field * > * refFields,bool isStatic)648 static size_t LayoutFields(Class *klass, PandaVector<Field *> *taggedFields, PandaVector<Field *> *fields64,
649 PandaVector<Field *> *fields32, PandaVector<Field *> *fields16,
650 PandaVector<Field *> *fields8, PandaVector<Field *> *refFields, bool isStatic)
651 {
652 size_t offset =
653 LayoutFieldsInBaseClassPadding(klass, taggedFields, fields64, fields32, fields16, fields8, refFields, isStatic);
654 if (!refFields->empty()) {
655 offset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
656 klass->SetRefFieldsNum(refFields->size(), isStatic);
657 klass->SetRefFieldsOffset(offset, isStatic);
658 auto volatileNum = LayoutReferenceFields(ClassHelper::OBJECT_POINTER_SIZE, &offset, *refFields);
659 klass->SetVolatileRefFieldsNum(volatileNum, isStatic);
660 }
661
662 static_assert(coretypes::TaggedValue::TaggedTypeSize() == SIZE_64,
663 "Please fix alignment of the fields of type \"TaggedValue\"");
664 if (!IsAligned<SIZE_64>(offset) && (!fields64->empty() || !taggedFields->empty())) {
665 size_t padding = AlignUp(offset, SIZE_64) - offset;
666
667 LayoutFieldsWithoutAlignment(SIZE_32, &offset, &padding, fields32);
668 LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
669 LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
670
671 offset += padding;
672 }
673
674 LayoutFieldsWithoutAlignment(coretypes::TaggedValue::TaggedTypeSize(), &offset, nullptr, taggedFields);
675 LayoutFieldsWithoutAlignment(SIZE_64, &offset, nullptr, fields64);
676
677 if (!IsAligned<SIZE_32>(offset) && !fields32->empty()) {
678 size_t padding = AlignUp(offset, SIZE_32) - offset;
679
680 LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
681 LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
682
683 offset += padding;
684 }
685
686 LayoutFieldsWithoutAlignment(SIZE_32, &offset, nullptr, fields32);
687
688 if (!IsAligned<SIZE_16>(offset) && !fields16->empty()) {
689 size_t padding = AlignUp(offset, SIZE_16) - offset;
690
691 LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
692
693 offset += padding;
694 }
695
696 LayoutFieldsWithoutAlignment(SIZE_16, &offset, nullptr, fields16);
697
698 LayoutFieldsWithoutAlignment(SIZE_8, &offset, nullptr, fields8);
699
700 return offset;
701 }
702
PushBackFieldIfNonPrimitiveType(Field & field,PandaVector<Field * > & refFields)703 static inline bool PushBackFieldIfNonPrimitiveType(Field &field, PandaVector<Field *> &refFields)
704 {
705 auto type = field.GetType();
706 if (!type.IsPrimitive()) {
707 refFields.push_back(&field);
708 return true;
709 }
710
711 return false;
712 }
713
714 /* static */
715 // CC-OFFNXT(huge_method) solid logic
LayoutFields(Class * klass,Span<Field> fields,bool isStatic,ClassLinkerErrorHandler * errorHandler)716 bool ClassLinker::LayoutFields(Class *klass, Span<Field> fields, bool isStatic,
717 [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
718 {
719 // These containers must be optimized
720 PandaVector<Field *> taggedFields;
721 PandaVector<Field *> fields64;
722 PandaVector<Field *> fields32;
723 PandaVector<Field *> fields16;
724 PandaVector<Field *> fields8;
725 PandaVector<Field *> refFields;
726 taggedFields.reserve(fields.size());
727 fields64.reserve(fields.size());
728 fields32.reserve(fields.size());
729 fields16.reserve(fields.size());
730 fields8.reserve(fields.size());
731 refFields.reserve(fields.size());
732
733 for (auto &field : fields) {
734 if (PushBackFieldIfNonPrimitiveType(field, refFields)) {
735 continue;
736 }
737
738 switch (field.GetType().GetId()) {
739 case Type::TypeId::U1:
740 case Type::TypeId::I8:
741 case Type::TypeId::U8:
742 fields8.push_back(&field);
743 break;
744 case Type::TypeId::I16:
745 case Type::TypeId::U16:
746 fields16.push_back(&field);
747 break;
748 case Type::TypeId::I32:
749 case Type::TypeId::U32:
750 case Type::TypeId::F32:
751 fields32.push_back(&field);
752 break;
753 case Type::TypeId::I64:
754 case Type::TypeId::U64:
755 case Type::TypeId::F64:
756 fields64.push_back(&field);
757 break;
758 case Type::TypeId::TAGGED:
759 taggedFields.push_back(&field);
760 break;
761 default:
762 UNREACHABLE();
763 break;
764 }
765 }
766
767 size_t size =
768 ark::LayoutFields(klass, &taggedFields, &fields64, &fields32, &fields16, &fields8, &refFields, isStatic);
769
770 if (!isStatic && !klass->IsVariableSize()) {
771 klass->SetObjectSize(size);
772 }
773
774 return true;
775 }
776
LinkMethods(Class * klass,ClassInfo * classInfo,ClassLinkerErrorHandler * errorHandler)777 bool ClassLinker::LinkMethods(Class *klass, ClassInfo *classInfo,
778 [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
779 {
780 classInfo->vtableBuilder->UpdateClass(klass);
781 ASSERT(classInfo->itableBuilder != nullptr);
782 if (!classInfo->itableBuilder->Resolve(klass)) {
783 return false;
784 }
785 classInfo->itableBuilder->UpdateClass(klass);
786 classInfo->imtableBuilder->UpdateClass(klass);
787 return true;
788 }
789
LinkFields(Class * klass,ClassLinkerErrorHandler * errorHandler)790 bool ClassLinker::LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler)
791 {
792 if (!LayoutFields(klass, klass->GetStaticFields(), true, errorHandler)) {
793 LOG(ERROR, CLASS_LINKER) << "Cannot layout static fields of class '" << klass->GetName() << "'";
794 return false;
795 }
796
797 if (!LayoutFields(klass, klass->GetInstanceFields(), false, errorHandler)) {
798 LOG(ERROR, CLASS_LINKER) << "Cannot layout instance fields of class '" << klass->GetName() << "'";
799 return false;
800 }
801
802 return true;
803 }
804
LoadBaseClass(panda_file::ClassDataAccessor * cda,const LanguageContext & ctx,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)805 Class *ClassLinker::LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx,
806 ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler)
807 {
808 auto baseClassId = cda->GetSuperClassId();
809 auto *ext = GetExtension(ctx);
810 ASSERT(ext != nullptr);
811 if (baseClassId.GetOffset() == 0) {
812 return ext->GetClassRoot(ClassRoot::OBJECT);
813 }
814
815 auto &pf = cda->GetPandaFile();
816 auto *baseClass = ext->GetClass(pf, baseClassId, context, errorHandler);
817 if (baseClass == nullptr) {
818 LOG(INFO, CLASS_LINKER) << "Cannot find base class '" << utf::Mutf8AsCString(pf.GetStringData(baseClassId).data)
819 << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
820 << "' in ctx " << context;
821 return nullptr;
822 }
823
824 return baseClass;
825 }
826
LoadInterfaces(panda_file::ClassDataAccessor * cda,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)827 std::optional<Span<Class *>> ClassLinker::LoadInterfaces(panda_file::ClassDataAccessor *cda,
828 ClassLinkerContext *context,
829 ClassLinkerErrorHandler *errorHandler)
830 {
831 ASSERT(context != nullptr);
832 size_t ifacesNum = cda->GetIfacesNumber();
833 if (ifacesNum == 0) {
834 return Span<Class *>(nullptr, ifacesNum);
835 }
836
837 Span<Class *> ifaces {allocator_->AllocArray<Class *>(ifacesNum), ifacesNum};
838
839 for (size_t i = 0; i < ifacesNum; i++) {
840 auto id = cda->GetInterfaceId(i);
841 auto &pf = cda->GetPandaFile();
842 auto *iface = GetClass(pf, id, context, errorHandler);
843 if (iface == nullptr) {
844 LOG(INFO, CLASS_LINKER) << "Cannot find interface '" << utf::Mutf8AsCString(pf.GetStringData(id).data)
845 << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
846 << "' in ctx " << context;
847 ASSERT(!ifaces.Empty());
848 allocator_->Free(ifaces.begin());
849 return {};
850 }
851
852 ifaces[i] = iface;
853 }
854
855 return ifaces;
856 }
857
858 using ClassLoadingSet = std::unordered_set<uint64_t>;
859
860 // This class is required to clear static unordered_set on return
861 class ClassScopeStaticSetAutoCleaner {
862 public:
863 ClassScopeStaticSetAutoCleaner() = default;
ClassScopeStaticSetAutoCleaner(ClassLoadingSet * setPtr,ClassLoadingSet ** tlSetPtr)864 explicit ClassScopeStaticSetAutoCleaner(ClassLoadingSet *setPtr, ClassLoadingSet **tlSetPtr)
865 : setPtr_(setPtr), tlSetPtr_(tlSetPtr)
866 {
867 }
~ClassScopeStaticSetAutoCleaner()868 ~ClassScopeStaticSetAutoCleaner()
869 {
870 setPtr_->clear();
871 if (tlSetPtr_ != nullptr) {
872 *tlSetPtr_ = nullptr;
873 }
874 }
875
876 NO_COPY_SEMANTIC(ClassScopeStaticSetAutoCleaner);
877 NO_MOVE_SEMANTIC(ClassScopeStaticSetAutoCleaner);
878
879 private:
880 ClassLoadingSet *setPtr_ {nullptr};
881 ClassLoadingSet **tlSetPtr_ {nullptr};
882 };
883
GetClassUniqueHash(uint32_t pandaFileHash,uint32_t classId)884 static uint64_t GetClassUniqueHash(uint32_t pandaFileHash, uint32_t classId)
885 {
886 const uint8_t bitsToShuffle = 32;
887 return (static_cast<uint64_t>(pandaFileHash) << bitsToShuffle) | static_cast<uint64_t>(classId);
888 }
889
LoadClass(panda_file::ClassDataAccessor * classDataAccessor,const uint8_t * descriptor,Class * baseClass,Span<Class * > interfaces,ClassLinkerContext * context,ClassLinkerExtension * ext,ClassLinkerErrorHandler * errorHandler)890 Class *ClassLinker::LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor,
891 Class *baseClass, Span<Class *> interfaces, ClassLinkerContext *context,
892 ClassLinkerExtension *ext, ClassLinkerErrorHandler *errorHandler)
893 {
894 ASSERT(context != nullptr);
895 ClassInfo classInfo {};
896 if (!SetupClassInfo(classInfo, classDataAccessor, baseClass, interfaces, context, errorHandler)) {
897 return nullptr;
898 }
899
900 ASSERT(classInfo.vtableBuilder != nullptr);
901 auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
902 classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
903
904 if (UNLIKELY(klass == nullptr)) {
905 return nullptr;
906 }
907
908 klass->SetLoadContext(context);
909 klass->SetBase(baseClass);
910 klass->SetInterfaces(interfaces);
911 klass->SetFileId(classDataAccessor->GetClassId());
912 klass->SetPandaFile(&classDataAccessor->GetPandaFile());
913 klass->SetAccessFlags(classDataAccessor->GetAccessFlags());
914
915 auto &pf = classDataAccessor->GetPandaFile();
916 auto classId = classDataAccessor->GetClassId();
917 klass->SetClassIndex(pf.GetClassIndex(classId));
918 klass->SetMethodIndex(pf.GetMethodIndex(classId));
919 klass->SetFieldIndex(pf.GetFieldIndex(classId));
920
921 klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
922 klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
923 klass->SetNumStaticFields(classInfo.numSfields);
924
925 auto const onFail = [this, descriptor, klass](std::string_view msg) {
926 FreeClass(klass);
927 LOG(ERROR, CLASS_LINKER) << msg << " '" << descriptor << "'";
928 return nullptr;
929 };
930 if (!LoadMethods(klass, &classInfo, classDataAccessor, errorHandler)) {
931 return onFail("Cannot load methods of class");
932 }
933 if (!LoadFields(klass, classDataAccessor, errorHandler)) {
934 return onFail("Cannot load fields of class");
935 }
936 if (!LinkMethods(klass, &classInfo, errorHandler)) {
937 return onFail("Cannot link methods of class");
938 }
939 if (!LinkFields(klass, errorHandler)) {
940 return onFail("Cannot link fields of class");
941 }
942 return klass;
943 }
944
LoadClass(const panda_file::File * pf,const uint8_t * descriptor,panda_file::SourceLang lang)945 Class *ClassLinker::LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang)
946 {
947 panda_file::File::EntityId classId = pf->GetClassId(descriptor);
948 if (!classId.IsValid() || pf->IsExternal(classId)) {
949 return nullptr;
950 }
951 ClassLinkerContext *context = GetExtension(lang)->GetBootContext();
952 return LoadClass(pf, classId, descriptor, context, nullptr);
953 }
954
OnError(ClassLinkerErrorHandler * errorHandler,ClassLinker::Error error,const PandaString & msg)955 static void OnError(ClassLinkerErrorHandler *errorHandler, ClassLinker::Error error, const PandaString &msg)
956 {
957 if (errorHandler != nullptr) {
958 errorHandler->OnError(error, msg);
959 }
960 }
961
TryInsertClassLoading(panda_file::File::EntityId & classId,const panda_file::File * pf,panda_file::ClassDataAccessor & classDataAccessor,ClassLoadingSet * threadLocalSet,ClassLinkerErrorHandler * errorHandler)962 static bool TryInsertClassLoading(panda_file::File::EntityId &classId, const panda_file::File *pf,
963 panda_file::ClassDataAccessor &classDataAccessor, ClassLoadingSet *threadLocalSet,
964 ClassLinkerErrorHandler *errorHandler)
965 {
966 uint32_t classIdInt = classId.GetOffset();
967 uint32_t pandaFileHash = pf->GetFilenameHash();
968 if (!threadLocalSet->insert(GetClassUniqueHash(pandaFileHash, classIdInt)).second) {
969 const PandaString &className = utf::Mutf8AsCString(pf->GetStringData(classDataAccessor.GetClassId()).data);
970 PandaString msg = "Class or interface \"" + className + "\" is its own superclass or superinterface";
971 OnError(errorHandler, ClassLinker::Error::CLASS_CIRCULARITY, msg);
972 return false;
973 }
974
975 return true;
976 }
977
IsContextCanBeLoaded(ClassLinkerContext * context,panda_file::ClassDataAccessor & classDataAccessor,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)978 static bool IsContextCanBeLoaded(ClassLinkerContext *context, panda_file::ClassDataAccessor &classDataAccessor,
979 const uint8_t *descriptor, ClassLinkerErrorHandler *errorHandler)
980 {
981 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
982 if (ctx.GetLanguage() != context->GetSourceLang()) {
983 LanguageContext currentCtx = Runtime::GetCurrent()->GetLanguageContext(context->GetSourceLang());
984 PandaStringStream ss;
985 ss << "Cannot load " << ctx << " class " << descriptor << " into " << currentCtx << " context";
986 LOG(ERROR, CLASS_LINKER) << ss.str();
987 OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
988 return false;
989 }
990
991 return true;
992 }
993
HandleNoExtensionError(LanguageContext & ctx,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)994 static void HandleNoExtensionError(LanguageContext &ctx, const uint8_t *descriptor,
995 ClassLinkerErrorHandler *errorHandler)
996 {
997 PandaStringStream ss;
998 ss << "Cannot load class '" << descriptor << "' as class linker hasn't " << ctx << " language extension";
999 LOG(ERROR, CLASS_LINKER) << ss.str();
1000 OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
1001 }
1002
1003 // CC-OFFNXT(G.FUN.01, huge_method) solid logic
LoadClass(const panda_file::File * pf,panda_file::File::EntityId classId,const uint8_t * descriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler,bool addToRuntime)1004 Class *ClassLinker::LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor,
1005 ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler,
1006 bool addToRuntime /* = true */)
1007 {
1008 ASSERT(!pf->IsExternal(classId));
1009 ASSERT(context != nullptr);
1010 panda_file::ClassDataAccessor classDataAccessor(*pf, classId);
1011 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
1012 if (!IsContextCanBeLoaded(context, classDataAccessor, descriptor, errorHandler)) {
1013 return nullptr;
1014 }
1015
1016 if (!HasExtension(ctx)) {
1017 HandleNoExtensionError(ctx, descriptor, errorHandler);
1018 return nullptr;
1019 }
1020
1021 // This set is used to find out if the class is its own superclass
1022 ClassLoadingSet loadingSet;
1023 static thread_local ClassLoadingSet *threadLocalSet = nullptr;
1024 ClassLoadingSet **threadLocalSetPtr = nullptr;
1025 if (threadLocalSet == nullptr) {
1026 threadLocalSet = &loadingSet;
1027 threadLocalSetPtr = &threadLocalSet;
1028 }
1029 ClassScopeStaticSetAutoCleaner classSetAutoCleanerOnReturn(threadLocalSet, threadLocalSetPtr);
1030
1031 auto *ext = GetExtension(ctx);
1032 Class *baseClass = nullptr;
1033 bool needLoadBase = IsInitialized() || !utf::IsEqual(ctx.GetObjectClassDescriptor(), descriptor);
1034 if (needLoadBase) {
1035 if (!TryInsertClassLoading(classId, pf, classDataAccessor, threadLocalSet, errorHandler)) {
1036 return nullptr;
1037 }
1038
1039 baseClass = LoadBaseClass(&classDataAccessor, ctx, context, errorHandler);
1040 if (baseClass == nullptr) {
1041 LOG(INFO, CLASS_LINKER) << "Cannot load base class of class '" << descriptor << "'";
1042 return nullptr;
1043 }
1044 }
1045
1046 auto res = LoadInterfaces(&classDataAccessor, context, errorHandler);
1047 if (!res) {
1048 LOG(INFO, CLASS_LINKER) << "Cannot load interfaces of class '" << descriptor << "'";
1049 return nullptr;
1050 }
1051
1052 auto *klass = LoadClass(&classDataAccessor, descriptor, baseClass, res.value(), context, ext, errorHandler);
1053 if (klass == nullptr) {
1054 return nullptr;
1055 }
1056
1057 Runtime::GetCurrent()->GetCha()->Update(klass);
1058
1059 if (LIKELY(ext->CanInitializeClasses())) {
1060 if (!ext->InitializeClass(klass)) {
1061 LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1062 FreeClass(klass);
1063 return nullptr;
1064 }
1065 klass->SetState(Class::State::LOADED);
1066 }
1067
1068 if (LIKELY(addToRuntime)) {
1069 Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1070
1071 auto *otherKlass = context->InsertClass(klass);
1072 if (otherKlass != nullptr) {
1073 // Someone has created the class in the other thread (increase the critical section?)
1074 FreeClass(klass);
1075 return otherKlass;
1076 }
1077
1078 RemoveCreatedClassInExtension(klass);
1079 Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1080 }
1081 return klass;
1082 }
1083
CopyMutf8String(mem::InternalAllocatorPtr allocator,const uint8_t * descriptor)1084 static const uint8_t *CopyMutf8String(mem::InternalAllocatorPtr allocator, const uint8_t *descriptor)
1085 {
1086 size_t size = utf::Mutf8Size(descriptor) + 1; // + 1 - null terminate
1087 auto *ptr = allocator->AllocArray<uint8_t>(size);
1088 memcpy_s(ptr, size, descriptor, size);
1089 return ptr;
1090 }
1091
LinkEntitiesAndInitClass(Class * klass,ClassInfo * classInfo,ClassLinkerExtension * ext,const uint8_t * descriptor)1092 bool ClassLinker::LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext,
1093 const uint8_t *descriptor)
1094 {
1095 if (!LinkMethods(klass, classInfo, ext->GetErrorHandler())) {
1096 LOG(ERROR, CLASS_LINKER) << "Cannot link class methods '" << descriptor << "'";
1097 return false;
1098 }
1099
1100 if (!LinkFields(klass, ext->GetErrorHandler())) {
1101 LOG(ERROR, CLASS_LINKER) << "Cannot link class fields '" << descriptor << "'";
1102 return false;
1103 }
1104
1105 if (!ext->InitializeClass(klass)) {
1106 LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1107 FreeClass(klass);
1108 return false;
1109 }
1110
1111 return true;
1112 }
1113
BuildClass(const uint8_t * descriptor,bool needCopyDescriptor,uint32_t accessFlags,Span<Method> methods,Span<Field> fields,Class * baseClass,Span<Class * > interfaces,ClassLinkerContext * context,bool isInterface)1114 Class *ClassLinker::BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags,
1115 Span<Method> methods, Span<Field> fields, Class *baseClass, Span<Class *> interfaces,
1116 ClassLinkerContext *context, bool isInterface)
1117 {
1118 ASSERT(context != nullptr);
1119 if (needCopyDescriptor) {
1120 descriptor = CopyMutf8String(allocator_, descriptor);
1121 os::memory::LockHolder lock(copiedNamesLock_);
1122 copiedNames_.push_front(descriptor);
1123 }
1124
1125 auto *ext = GetExtension(baseClass->GetSourceLang());
1126 ASSERT(ext != nullptr);
1127
1128 ClassInfo classInfo {};
1129 if (!SetupClassInfo(classInfo, methods, fields, baseClass, interfaces, isInterface, nullptr)) {
1130 return nullptr;
1131 }
1132
1133 // Need to protect ArenaAllocator and loaded_classes_
1134 ASSERT(classInfo.vtableBuilder != nullptr);
1135 auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
1136 classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
1137
1138 if (UNLIKELY(klass == nullptr)) {
1139 return nullptr;
1140 }
1141
1142 klass->SetLoadContext(context);
1143 klass->SetBase(baseClass);
1144 klass->SetInterfaces(interfaces);
1145 klass->SetAccessFlags(accessFlags);
1146
1147 klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
1148 klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
1149 klass->SetNumStaticFields(classInfo.numSfields);
1150
1151 ASSERT(klass->GetNumCopiedMethods() == 0);
1152
1153 size_t numSmethods = methods.size() - klass->GetNumVirtualMethods();
1154 klass->SetMethods(methods, klass->GetNumVirtualMethods(), numSmethods);
1155 klass->SetFields(fields, klass->GetNumStaticFields());
1156
1157 for (auto &method : methods) {
1158 method.SetClass(klass);
1159 }
1160
1161 for (auto &field : fields) {
1162 field.SetClass(klass);
1163 }
1164
1165 if (!LinkEntitiesAndInitClass(klass, &classInfo, ext, descriptor)) {
1166 return nullptr;
1167 }
1168
1169 klass->SetState(Class::State::LOADED);
1170
1171 Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1172
1173 auto *otherKlass = context->InsertClass(klass);
1174 if (otherKlass != nullptr) {
1175 // Someone has created the class in the other thread (increase the critical section?)
1176 FreeClass(klass);
1177 return otherKlass;
1178 }
1179
1180 RemoveCreatedClassInExtension(klass);
1181 Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1182
1183 return klass;
1184 }
1185
CreateArrayClass(ClassLinkerExtension * ext,const uint8_t * descriptor,bool needCopyDescriptor,Class * componentClass)1186 Class *ClassLinker::CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor,
1187 Class *componentClass)
1188 {
1189 if (needCopyDescriptor) {
1190 descriptor = CopyMutf8String(allocator_, descriptor);
1191 os::memory::LockHolder lock(copiedNamesLock_);
1192 copiedNames_.push_front(descriptor);
1193 }
1194
1195 auto *arrayClass = ext->CreateClass(descriptor, ext->GetArrayClassVTableSize(), ext->GetArrayClassIMTSize(),
1196 ext->GetArrayClassSize());
1197
1198 if (UNLIKELY(arrayClass == nullptr)) {
1199 return nullptr;
1200 }
1201
1202 arrayClass->SetLoadContext(componentClass->GetLoadContext());
1203
1204 if (UNLIKELY(!ext->InitializeArrayClass(arrayClass, componentClass))) {
1205 return nullptr;
1206 }
1207
1208 return arrayClass;
1209 }
1210
LoadArrayClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1211 Class *ClassLinker::LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1212 ClassLinkerErrorHandler *errorHandler)
1213 {
1214 Span<const uint8_t> sp(descriptor, 1);
1215
1216 Class *componentClass = GetClass(sp.cend(), needCopyDescriptor, context, errorHandler);
1217
1218 if (componentClass == nullptr) {
1219 return nullptr;
1220 }
1221
1222 if (UNLIKELY(componentClass->GetType().GetId() == panda_file::Type::TypeId::VOID)) {
1223 OnError(errorHandler, Error::NO_CLASS_DEF, "Try to create array with void component type");
1224 return nullptr;
1225 }
1226
1227 auto *ext = GetExtension(componentClass->GetSourceLang());
1228 ASSERT(ext != nullptr);
1229
1230 auto *componentClassContext = componentClass->GetLoadContext();
1231 ASSERT(componentClassContext != nullptr);
1232 if (componentClassContext != context) {
1233 auto *loadedClass = FindLoadedClass(descriptor, componentClassContext);
1234 if (loadedClass != nullptr) {
1235 return loadedClass;
1236 }
1237 }
1238
1239 auto *arrayClass = CreateArrayClass(ext, descriptor, needCopyDescriptor, componentClass);
1240
1241 if (UNLIKELY(arrayClass == nullptr)) {
1242 return nullptr;
1243 }
1244
1245 Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(arrayClass);
1246
1247 auto *otherKlass = componentClassContext->InsertClass(arrayClass);
1248 if (otherKlass != nullptr) {
1249 FreeClass(arrayClass);
1250 return otherKlass;
1251 }
1252
1253 RemoveCreatedClassInExtension(arrayClass);
1254 Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(arrayClass);
1255
1256 return arrayClass;
1257 }
1258
PandaFilesToString(const PandaVector<const panda_file::File * > & pandaFiles)1259 static PandaString PandaFilesToString(const PandaVector<const panda_file::File *> &pandaFiles)
1260 {
1261 PandaStringStream ss;
1262 ss << "[";
1263
1264 size_t n = pandaFiles.size();
1265 for (size_t i = 0; i < n; i++) {
1266 ss << pandaFiles[i]->GetFilename();
1267
1268 if (i < n - 1) {
1269 ss << ", ";
1270 }
1271 }
1272
1273 ss << "]";
1274 return ss.str();
1275 }
1276
GetClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1277 Class *ClassLinker::GetClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1278 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1279 {
1280 ASSERT(context != nullptr);
1281 ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1282 !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1283
1284 Class *cls = FindLoadedClass(descriptor, context);
1285 if (cls != nullptr) {
1286 return cls;
1287 }
1288
1289 if (ClassHelper::IsArrayDescriptor(descriptor)) {
1290 return LoadArrayClass(descriptor, needCopyDescriptor, context, errorHandler);
1291 }
1292
1293 if (context->IsBootContext()) {
1294 panda_file::File::EntityId classId;
1295 const panda_file::File *pandaFile {nullptr};
1296 {
1297 {
1298 os::memory::LockHolder lock {bootPandaFilesLock_};
1299 std::tie(classId, pandaFile) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1300 }
1301
1302 if (!classId.IsValid()) {
1303 PandaStringStream ss;
1304 {
1305 // can't make a wider scope for lock here - will get recursion
1306 os::memory::LockHolder lock {bootPandaFilesLock_};
1307 ss << "Cannot find class " << descriptor
1308 << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1309 }
1310 OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1311 return nullptr;
1312 }
1313 }
1314
1315 return LoadClass(pandaFile, classId, pandaFile->GetStringData(classId).data, context, errorHandler);
1316 }
1317
1318 return context->LoadClass(descriptor, needCopyDescriptor, errorHandler);
1319 }
1320
GetClass(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1321 Class *ClassLinker::GetClass(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context,
1322 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1323 {
1324 ASSERT(context != nullptr);
1325 ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1326 !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1327
1328 Class *cls = pf.GetPandaCache()->GetClassFromCache(id);
1329 if (cls != nullptr) {
1330 return cls;
1331 }
1332 const uint8_t *descriptor = pf.GetStringData(id).data;
1333
1334 cls = FindLoadedClass(descriptor, context);
1335 if (cls != nullptr) {
1336 pf.GetPandaCache()->SetClassCache(id, cls);
1337 return cls;
1338 }
1339
1340 if (ClassHelper::IsArrayDescriptor(descriptor)) {
1341 cls = LoadArrayClass(descriptor, false, context, errorHandler);
1342 if (LIKELY(cls != nullptr)) {
1343 pf.GetPandaCache()->SetClassCache(id, cls);
1344 }
1345 return cls;
1346 }
1347
1348 if (context->IsBootContext()) {
1349 const panda_file::File *pfPtr = nullptr;
1350 panda_file::File::EntityId extId;
1351 {
1352 os::memory::LockHolder lock {bootPandaFilesLock_};
1353 std::tie(extId, pfPtr) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1354 }
1355
1356 if (!extId.IsValid()) {
1357 PandaStringStream ss;
1358 {
1359 // can't make a wider scope for lock here - will get recursion
1360 os::memory::LockHolder lock {bootPandaFilesLock_};
1361 ss << "Cannot find class " << descriptor
1362 << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1363 }
1364 OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1365 return nullptr;
1366 }
1367
1368 cls = LoadClass(pfPtr, extId, descriptor, context, errorHandler);
1369 if (LIKELY(cls != nullptr)) {
1370 pf.GetPandaCache()->SetClassCache(id, cls);
1371 }
1372 return cls;
1373 }
1374
1375 return context->LoadClass(descriptor, false, errorHandler);
1376 }
1377
GetMethod(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1378 Method *ClassLinker::GetMethod(const panda_file::File &pf, panda_file::File::EntityId id,
1379 ClassLinkerContext *context /* = nullptr */,
1380 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1381 {
1382 Method *method = pf.GetPandaCache()->GetMethodFromCache(id);
1383 if (method != nullptr) {
1384 return method;
1385 }
1386 panda_file::MethodDataAccessor methodDataAccessor(pf, id);
1387
1388 auto classId = methodDataAccessor.GetClassId();
1389 if (context == nullptr) {
1390 panda_file::ClassDataAccessor classDataAccessor(pf, classId);
1391 auto lang = classDataAccessor.GetSourceLang();
1392 if (!lang) {
1393 LOG(INFO, CLASS_LINKER) << "Cannot resolve language context for class_id " << classId << " in file "
1394 << pf.GetFilename();
1395 return nullptr;
1396 }
1397 auto *extension = GetExtension(lang.value());
1398 context = extension->GetBootContext();
1399 }
1400
1401 Class *klass = GetClass(pf, classId, context, errorHandler);
1402
1403 if (klass == nullptr) {
1404 auto className = pf.GetStringData(classId).data;
1405 LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1406 return nullptr;
1407 }
1408 method = GetMethod(klass, methodDataAccessor, errorHandler);
1409 if (LIKELY(method != nullptr)) {
1410 pf.GetPandaCache()->SetMethodCache(id, method);
1411 }
1412 return method;
1413 }
1414
GetMethod(const Method & caller,panda_file::File::EntityId id,ClassLinkerErrorHandler * errorHandler)1415 Method *ClassLinker::GetMethod(const Method &caller, panda_file::File::EntityId id,
1416 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1417 {
1418 auto *pf = caller.GetPandaFile();
1419 Method *method = pf->GetPandaCache()->GetMethodFromCache(id);
1420 if (method != nullptr) {
1421 return method;
1422 }
1423
1424 panda_file::MethodDataAccessor methodDataAccessor(*pf, id);
1425 auto classId = methodDataAccessor.GetClassId();
1426
1427 auto *context = caller.GetClass()->GetLoadContext();
1428 auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1429 Class *klass = ext->GetClass(*pf, classId, context, errorHandler);
1430
1431 if (klass == nullptr) {
1432 auto className = pf->GetStringData(classId).data;
1433 LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1434 return nullptr;
1435 }
1436
1437 method = GetMethod(klass, methodDataAccessor, (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1438 if (LIKELY(method != nullptr)) {
1439 pf->GetPandaCache()->SetMethodCache(id, method);
1440 }
1441 return method;
1442 }
1443
GetMethod(const Class * klass,const panda_file::MethodDataAccessor & methodDataAccessor,ClassLinkerErrorHandler * errorHandler)1444 Method *ClassLinker::GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor,
1445 ClassLinkerErrorHandler *errorHandler)
1446 {
1447 Method *method;
1448 auto id = methodDataAccessor.GetMethodId();
1449 const auto &pf = methodDataAccessor.GetPandaFile();
1450
1451 bool isStatic = methodDataAccessor.IsStatic();
1452 if (!methodDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1453 if (klass->IsInterface()) {
1454 method = isStatic ? klass->GetStaticInterfaceMethod(id) : klass->GetVirtualInterfaceMethod(id);
1455 } else {
1456 method = isStatic ? klass->GetStaticClassMethod(id) : klass->GetVirtualClassMethod(id);
1457 }
1458
1459 if (method == nullptr) {
1460 Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1461 PandaStringStream ss;
1462 ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1463 << "' in class '" << klass->GetName() << "'";
1464 OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1465 return nullptr;
1466 }
1467
1468 return method;
1469 }
1470
1471 auto name = methodDataAccessor.GetName();
1472 Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1473 if (klass->IsInterface()) {
1474 method = isStatic ? klass->GetStaticInterfaceMethodByName(name, proto)
1475 : klass->GetVirtualInterfaceMethodByName(name, proto);
1476 } else {
1477 method =
1478 isStatic ? klass->GetStaticClassMethodByName(name, proto) : klass->GetVirtualClassMethodByName(name, proto);
1479 if (method == nullptr && klass->IsAbstract()) {
1480 method = klass->GetInterfaceMethod(name, proto);
1481 }
1482 }
1483
1484 if (method == nullptr) {
1485 PandaStringStream ss;
1486 ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1487 << "' in class '" << klass->GetName() << "'";
1488 OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1489 return nullptr;
1490 }
1491
1492 LOG_IF(method->IsStatic() != methodDataAccessor.IsStatic(), FATAL, CLASS_LINKER)
1493 << "Expected ACC_STATIC for method " << name.data << " in class " << klass->GetName()
1494 << " does not match loaded value";
1495
1496 return method;
1497 }
1498
GetFieldById(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler,bool isStatic)1499 Field *ClassLinker::GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1500 ClassLinkerErrorHandler *errorHandler, bool isStatic)
1501 {
1502 auto &pf = fieldDataAccessor.GetPandaFile();
1503 auto id = fieldDataAccessor.GetFieldId();
1504
1505 Field *field = isStatic ? klass->FindStaticFieldById(id) : klass->FindInstanceFieldById(id);
1506
1507 if (field == nullptr) {
1508 PandaStringStream ss;
1509 ss << "Cannot find field '" << pf.GetStringData(fieldDataAccessor.GetNameId()).data << "' in class '"
1510 << klass->GetName() << "'";
1511 OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1512 return nullptr;
1513 }
1514
1515 pf.GetPandaCache()->SetFieldCache(id, field);
1516 return field;
1517 }
1518
GetFieldBySignature(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler,bool isStatic)1519 Field *ClassLinker::GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1520 ClassLinkerErrorHandler *errorHandler, bool isStatic)
1521 {
1522 auto &pf = fieldDataAccessor.GetPandaFile();
1523 auto id = fieldDataAccessor.GetFieldId();
1524 auto fieldName = pf.GetStringData(fieldDataAccessor.GetNameId());
1525 auto fieldType = panda_file::Type::GetTypeFromFieldEncoding(fieldDataAccessor.GetType());
1526 auto filter = [&fieldDataAccessor, &fieldType, &fieldName, &id, &pf](const Field &fld) {
1527 if (fieldType == fld.GetType() && fieldName == fld.GetName()) {
1528 if (!fieldType.IsReference()) {
1529 return true;
1530 }
1531
1532 // compare field class type
1533 if (&pf == fld.GetPandaFile() && id == fld.GetFileId()) {
1534 return true;
1535 }
1536 auto typeId = panda_file::FieldDataAccessor::GetTypeId(*fld.GetPandaFile(), fld.GetFileId());
1537 if (pf.GetStringData(panda_file::File::EntityId(fieldDataAccessor.GetType())) ==
1538 fld.GetPandaFile()->GetStringData(typeId)) {
1539 return true;
1540 }
1541 }
1542 return false;
1543 };
1544 Field *field = isStatic ? klass->FindStaticField(filter) : klass->FindInstanceField(filter);
1545
1546 if (field == nullptr) {
1547 PandaStringStream ss;
1548 ss << "Cannot find field '" << fieldName.data << "' in class '" << klass->GetName() << "'";
1549 OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1550 return nullptr;
1551 }
1552
1553 pf.GetPandaCache()->SetFieldCache(id, field);
1554 return field;
1555 }
1556
GetField(const panda_file::File & pf,panda_file::File::EntityId id,bool isStatic,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1557 Field *ClassLinker::GetField(const panda_file::File &pf, panda_file::File::EntityId id, bool isStatic,
1558 ClassLinkerContext *context /* = nullptr */,
1559 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1560 {
1561 Field *field = pf.GetPandaCache()->GetFieldFromCache(id);
1562 if (field != nullptr) {
1563 return field;
1564 }
1565 panda_file::FieldDataAccessor fieldDataAccessor(pf, id);
1566
1567 Class *klass = GetClass(pf, fieldDataAccessor.GetClassId(), context, errorHandler);
1568
1569 if (klass == nullptr) {
1570 auto className = pf.GetStringData(fieldDataAccessor.GetClassId()).data;
1571 LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1572 return nullptr;
1573 }
1574
1575 if (!fieldDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1576 field = GetFieldById(klass, fieldDataAccessor, errorHandler, isStatic);
1577 } else {
1578 field = GetFieldBySignature(klass, fieldDataAccessor, errorHandler, isStatic);
1579 }
1580 return field;
1581 }
1582
InitializeClass(ManagedThread * thread,Class * klass)1583 bool ClassLinker::InitializeClass(ManagedThread *thread, Class *klass)
1584 {
1585 ASSERT(klass != nullptr);
1586 if (klass->IsInitialized()) {
1587 return true;
1588 }
1589
1590 LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
1591 return ctx.InitializeClass(this, thread, klass);
1592 }
1593
NumLoadedClasses()1594 size_t ClassLinker::NumLoadedClasses()
1595 {
1596 size_t sum = 0;
1597
1598 for (auto &ext : extensions_) {
1599 if (ext == nullptr) {
1600 continue;
1601 }
1602
1603 sum += ext->NumLoadedClasses();
1604 }
1605
1606 return sum;
1607 }
1608
VisitLoadedClasses(size_t flag)1609 void ClassLinker::VisitLoadedClasses(size_t flag)
1610 {
1611 for (auto &ext : extensions_) {
1612 if (ext == nullptr) {
1613 continue;
1614 }
1615 ext->VisitLoadedClasses(flag);
1616 }
1617 }
1618
GetField(const Method & caller,panda_file::File::EntityId id,bool isStatic,ClassLinkerErrorHandler * errorHandler)1619 Field *ClassLinker::GetField(const Method &caller, panda_file::File::EntityId id, bool isStatic,
1620 ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1621 {
1622 Field *field = caller.GetPandaFile()->GetPandaCache()->GetFieldFromCache(id);
1623 if (field != nullptr) {
1624 return field;
1625 }
1626 auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1627 field = GetField(*caller.GetPandaFile(), id, isStatic, caller.GetClass()->GetLoadContext(),
1628 (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1629 if (LIKELY(field != nullptr)) {
1630 caller.GetPandaFile()->GetPandaCache()->SetFieldCache(id, field);
1631 }
1632 return field;
1633 }
1634
RemoveCreatedClassInExtension(Class * klass)1635 void ClassLinker::RemoveCreatedClassInExtension(Class *klass)
1636 {
1637 if (klass == nullptr) {
1638 return;
1639 }
1640 auto ext = GetExtension(klass->GetSourceLang());
1641 if (ext != nullptr) {
1642 ext->OnClassPrepared(klass);
1643 }
1644 }
1645
1646 } // namespace ark
1647