• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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