• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "runtime/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 
SetupClassInfo(ClassLinker::ClassInfo & info,panda_file::ClassDataAccessor * dataAccessor,Class * base,Span<Class * > interfaces,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)311 bool ClassLinker::SetupClassInfo(ClassLinker::ClassInfo &info, panda_file::ClassDataAccessor *dataAccessor, Class *base,
312                                  Span<Class *> interfaces, ClassLinkerContext *context,
313                                  ClassLinkerErrorHandler *errorHandler)
314 {
315     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(dataAccessor);
316 
317     info.vtableBuilder = ctx.CreateVTableBuilder(errorHandler);
318     info.itableBuilder = ctx.CreateITableBuilder(errorHandler);
319     info.imtableBuilder = ctx.CreateIMTableBuilder();
320 
321     if (!info.itableBuilder->Build(this, base, interfaces, dataAccessor->IsInterface())) {
322         return false;
323     }
324     if (!info.vtableBuilder->Build(dataAccessor, base, info.itableBuilder->GetITable(), context)) {
325         return false;
326     }
327     info.imtableBuilder->Build(dataAccessor, info.itableBuilder->GetITable());
328 
329     ClassDataAccessorWrapper dataAccessorWrapper(dataAccessor);
330     info.size = GetClassSize(dataAccessorWrapper, info.vtableBuilder->GetVTableSize(),
331                              info.imtableBuilder->GetIMTSize(), &info.numSfields);
332     return true;
333 }
334 
335 class ClassDataAccessor {
336 public:
ClassDataAccessor(Span<Field> fields)337     explicit ClassDataAccessor(Span<Field> fields) : fields_(fields) {}
338 
339     template <class Callback>
EnumerateStaticFieldTypes(const Callback & cb) const340     void EnumerateStaticFieldTypes(const Callback &cb) const
341     {
342         for (const auto &field : fields_) {
343             if (!field.IsStatic()) {
344                 continue;
345             }
346 
347             cb(field.GetType());
348         }
349     }
350 
351     ~ClassDataAccessor() = default;
352 
353     DEFAULT_COPY_SEMANTIC(ClassDataAccessor);
354     DEFAULT_MOVE_SEMANTIC(ClassDataAccessor);
355 
356 private:
357     Span<Field> fields_;
358 };
359 
SetupClassInfo(ClassLinker::ClassInfo & info,Span<Method> methods,Span<Field> fields,Class * base,Span<Class * > interfaces,bool isInterface,ClassLinkerErrorHandler * errorHandler)360 bool ClassLinker::SetupClassInfo(ClassLinker::ClassInfo &info, Span<Method> methods, Span<Field> fields, Class *base,
361                                  Span<Class *> interfaces, bool isInterface, ClassLinkerErrorHandler *errorHandler)
362 {
363     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*base);
364 
365     info.vtableBuilder = ctx.CreateVTableBuilder(errorHandler);
366     info.itableBuilder = ctx.CreateITableBuilder(errorHandler);
367     info.imtableBuilder = ctx.CreateIMTableBuilder();
368 
369     if (!info.itableBuilder->Build(this, base, interfaces, isInterface)) {
370         return false;
371     }
372     if (!info.vtableBuilder->Build(methods, base, info.itableBuilder->GetITable(), isInterface)) {
373         return false;
374     }
375     info.imtableBuilder->Build(info.itableBuilder->GetITable(), isInterface);
376 
377     ClassDataAccessor dataAccessor(fields);
378     info.size = GetClassSize(dataAccessor, info.vtableBuilder->GetVTableSize(), info.imtableBuilder->GetIMTSize(),
379                              &info.numSfields);
380     return true;
381 }
382 
LoadMethod(Method * method,panda_file::MethodDataAccessor * methodDataAccessor,Class * klass,const LanguageContext & ctx,const ClassLinkerExtension * ext)383 static void LoadMethod(Method *method, panda_file::MethodDataAccessor *methodDataAccessor, Class *klass,
384                        const LanguageContext &ctx, const ClassLinkerExtension *ext)
385 {
386     const auto &pf = methodDataAccessor->GetPandaFile();
387     panda_file::ProtoDataAccessor pda(pf, methodDataAccessor->GetProtoId());
388 
389     uint32_t accessFlags = methodDataAccessor->GetAccessFlags();
390 
391     auto *methodName = pf.GetStringData(methodDataAccessor->GetNameId()).data;
392     if (utf::IsEqual(methodName, ctx.GetCtorName()) || utf::IsEqual(methodName, ctx.GetCctorName())) {
393         accessFlags |= ACC_CONSTRUCTOR;
394     }
395 
396     auto codeId = methodDataAccessor->GetCodeId();
397     size_t numArgs = (methodDataAccessor->IsStatic()) ? pda.GetNumArgs() : (pda.GetNumArgs() + 1);
398 
399     if (!codeId.has_value()) {
400         InitializeMemory(method, klass, &pf, methodDataAccessor->GetMethodId(), panda_file::File::EntityId(0),
401                          accessFlags, numArgs, reinterpret_cast<const uint16_t *>(pda.GetShorty().Data()));
402 
403         if (methodDataAccessor->IsNative()) {
404             method->SetCompiledEntryPoint(ext->GetNativeEntryPointFor(method));
405         } else {
406             method->SetInterpreterEntryPoint();
407         }
408     } else {
409         InitializeMemory(method, klass, &pf, methodDataAccessor->GetMethodId(), codeId.value(), accessFlags, numArgs,
410                          reinterpret_cast<const uint16_t *>(pda.GetShorty().Data()));
411         method->SetCompiledEntryPoint(GetCompiledCodeToInterpreterBridge(method));
412     }
413 }
414 
MaybeLinkMethodToAotCode(Method * method,const compiler::AotClass & aotClass,size_t methodIndex)415 static void MaybeLinkMethodToAotCode(Method *method, const compiler::AotClass &aotClass, size_t methodIndex)
416 {
417     ASSERT(aotClass.IsValid());
418     if (method->IsIntrinsic()) {
419         return;
420     }
421     auto entry = aotClass.FindMethodCodeEntry(methodIndex);
422     if (entry != nullptr) {
423         method->SetCompiledEntryPoint(entry);
424         LOG(INFO, AOT) << "Found AOT entrypoint ["
425                        << reinterpret_cast<const void *>(aotClass.FindMethodCodeSpan(methodIndex).data()) << ":"
426                        << reinterpret_cast<const void *>(aotClass.FindMethodCodeSpan(methodIndex).end())
427                        << "] for method: " << method->GetFullName();
428 
429         EVENT_AOT_ENTRYPOINT_FOUND(method->GetFullName());
430         ASSERT(aotClass.FindMethodHeader(methodIndex)->methodId == method->GetFileId().GetOffset());
431     }
432 }
433 
SetupCopiedMethods(Span<Method> methods,Span<const CopiedMethod> copiedMethods)434 static void SetupCopiedMethods(Span<Method> methods, Span<const CopiedMethod> copiedMethods)
435 {
436     size_t const numMethods = methods.size() - copiedMethods.size();
437 
438     for (size_t i = 0; i < copiedMethods.size(); i++) {
439         Method *method = &methods[numMethods + i];
440         InitializeMemory(method, copiedMethods[i].GetMethod());
441         method->SetIsDefaultInterfaceMethod();
442         switch (copiedMethods[i].GetStatus()) {
443             case CopiedMethod::Status::ORDINARY:
444                 break;
445             case CopiedMethod::Status::ABSTRACT:
446                 method->SetCompiledEntryPoint(GetAbstractMethodStub());
447                 break;
448             case CopiedMethod::Status::CONFLICT:
449                 method->SetCompiledEntryPoint(GetDefaultConflictMethodStub());
450                 break;
451         }
452     }
453 }
454 
LoadMethods(Class * klass,ClassInfo * classInfo,panda_file::ClassDataAccessor * dataAccessor,ClassLinkerErrorHandler * errorHandler)455 bool ClassLinker::LoadMethods(Class *klass, ClassInfo *classInfo, panda_file::ClassDataAccessor *dataAccessor,
456                               [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
457 {
458     uint32_t numMethods = dataAccessor->GetMethodsNumber();
459 
460     uint32_t numVmethods = klass->GetNumVirtualMethods();
461     uint32_t numSmethods = numMethods - numVmethods;
462 
463     auto copiedMethods = classInfo->vtableBuilder->GetCopiedMethods();
464     uint32_t totalNumMethods = numMethods + copiedMethods.size();
465     if (totalNumMethods == 0) {
466         return true;
467     }
468 
469     Span<Method> methods {allocator_->AllocArray<Method>(totalNumMethods), totalNumMethods};
470 
471     size_t smethodIdx = numVmethods;
472     size_t vmethodIdx = 0;
473 
474     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
475     auto *ext = GetExtension(ctx);
476     ASSERT(ext != nullptr);
477 
478     auto aotPfile = aotManager_->FindPandaFile(klass->GetPandaFile()->GetFullFileName());
479     if (aotPfile != nullptr) {
480         EVENT_AOT_LOADED_FOR_CLASS(PandaString(aotPfile->GetFileName()), PandaString(klass->GetName()));
481     }
482 
483     compiler::AotClass aotClass =
484         (aotPfile != nullptr) ? aotPfile->GetClass(klass->GetFileId().GetOffset()) : compiler::AotClass::Invalid();
485 
486     size_t methodIndex = 0;
487     dataAccessor->EnumerateMethods([klass, &smethodIdx, &vmethodIdx, &methods, aotClass, ctx, ext,
488                                     &methodIndex](panda_file::MethodDataAccessor &methodDataAccessor) {
489         Method *method = methodDataAccessor.IsStatic() ? &methods[smethodIdx++] : &methods[vmethodIdx++];
490         LoadMethod(method, &methodDataAccessor, klass, ctx, ext);
491         if (aotClass.IsValid()) {
492             MaybeLinkMethodToAotCode(method, aotClass, methodIndex);
493         }
494         // Instead of checking if the method is abstract before every virtual call
495         // the special stub throwing AbstractMethodError is registered as compiled entry point.
496         if (method->IsAbstract()) {
497             method->SetCompiledEntryPoint(GetAbstractMethodStub());
498         }
499         methodIndex++;
500     });
501 
502     SetupCopiedMethods(methods, copiedMethods);
503     klass->SetMethods(methods, numVmethods, numSmethods);
504     return true;
505 }
506 
LoadFields(Class * klass,panda_file::ClassDataAccessor * dataAccessor,ClassLinkerErrorHandler * errorHandler)507 bool ClassLinker::LoadFields(Class *klass, panda_file::ClassDataAccessor *dataAccessor,
508                              [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
509 {
510     uint32_t numFields = dataAccessor->GetFieldsNumber();
511     if (numFields == 0) {
512         return true;
513     }
514 
515     uint32_t numSfields = klass->GetNumStaticFields();
516 
517     Span<Field> fields {allocator_->AllocArray<Field>(numFields), numFields};
518 
519     size_t sfieldsIdx = 0;
520     size_t ifieldsIdx = numSfields;
521     dataAccessor->EnumerateFields(
522         [klass, &sfieldsIdx, &ifieldsIdx, &fields](panda_file::FieldDataAccessor &fieldDataAccessor) {
523             Field *field = fieldDataAccessor.IsStatic() ? &fields[sfieldsIdx++] : &fields[ifieldsIdx++];
524             InitializeMemory(field, klass, fieldDataAccessor.GetFieldId(), fieldDataAccessor.GetAccessFlags(),
525                              panda_file::Type::GetTypeFromFieldEncoding(fieldDataAccessor.GetType()));
526         });
527 
528     klass->SetFields(fields, numSfields);
529 
530     return true;
531 }
532 
533 template <bool REVERSE_LAYOUT = false>
LayoutFieldsWithoutAlignment(size_t size,size_t * offset,size_t * space,PandaVector<Field * > * fields)534 static void LayoutFieldsWithoutAlignment(size_t size, size_t *offset, size_t *space, PandaVector<Field *> *fields)
535 {
536     auto lastProceededElement = fields->end();
537     // Iterating from beginning to end and erasing elements from the beginning of a vector
538     // is required for correct field layout between language class representation in C++ code
539     // and generated by methods in class linker.
540     // (e.g. class String should have length field before hash field, not vice versa)
541     for (auto i = fields->begin(); i != fields->end(); i++) {
542         if (!(space == nullptr || *space >= size)) {
543             lastProceededElement = i;
544             break;
545         }
546         Field *field = *i;
547         // NOLINTNEXTLINE(readability-braces-around-statements)
548         if constexpr (REVERSE_LAYOUT) {
549             *offset -= size;
550             field->SetOffset(*offset);
551             // NOLINTNEXTLINE(readability-misleading-indentation)
552         } else {
553             field->SetOffset(*offset);
554             *offset += size;
555         }
556         if (space != nullptr) {
557             *space -= size;
558         }
559     }
560     fields->erase(fields->begin(), lastProceededElement);
561 }
562 
LayoutReferenceFields(size_t size,size_t * offset,const PandaVector<Field * > & fields)563 static uint32_t LayoutReferenceFields(size_t size, size_t *offset, const PandaVector<Field *> &fields)
564 {
565     uint32_t volatileFieldsNum = 0;
566     // layout volatile fields firstly
567     for (auto *field : fields) {
568         if (field->IsVolatile()) {
569             volatileFieldsNum++;
570             field->SetOffset(*offset);
571             *offset += size;
572         }
573     }
574     for (auto *field : fields) {
575         if (!field->IsVolatile()) {
576             field->SetOffset(*offset);
577             *offset += size;
578         }
579     }
580     return volatileFieldsNum;
581 }
582 
583 constexpr size_t SIZE_64 = sizeof(uint64_t);
584 constexpr size_t SIZE_32 = sizeof(uint32_t);
585 constexpr size_t SIZE_16 = sizeof(uint16_t);
586 constexpr size_t SIZE_8 = sizeof(uint8_t);
587 
588 // 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)589 static size_t LayoutFieldsInBaseClassPadding(Class *klass, PandaVector<Field *> *taggedFields,
590                                              PandaVector<Field *> *fields64, PandaVector<Field *> *fields32,
591                                              PandaVector<Field *> *fields16, PandaVector<Field *> *fields8,
592                                              PandaVector<Field *> *refFields, bool isStatic)
593 {
594     size_t offset;
595 
596     if (isStatic) {
597         offset = klass->GetStaticFieldsOffset();
598     } else {
599         offset = (klass->GetBase() != nullptr) ? klass->GetBase()->GetObjectSize() : ObjectHeader::ObjectHeaderSize();
600     }
601 
602     size_t alignOffset = offset;
603     if (!refFields->empty()) {
604         alignOffset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
605     } else if (!(fields64->empty()) || !(taggedFields->empty())) {
606         alignOffset = AlignUp(offset, SIZE_64);
607     } else if (!fields32->empty()) {
608         alignOffset = AlignUp(offset, SIZE_32);
609     } else if (!fields16->empty()) {
610         alignOffset = AlignUp(offset, SIZE_16);
611     }
612     if (alignOffset != offset) {
613         size_t endOffset = alignOffset;
614         size_t padding = endOffset - offset;
615         // try to put short fields of child class at end of free space of base class
616         LayoutFieldsWithoutAlignment<true>(SIZE_32, &endOffset, &padding, fields32);
617         LayoutFieldsWithoutAlignment<true>(SIZE_16, &endOffset, &padding, fields16);
618         LayoutFieldsWithoutAlignment<true>(SIZE_8, &endOffset, &padding, fields8);
619     }
620     return alignOffset;
621 }
622 
623 // 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)624 static size_t LayoutFields(Class *klass, PandaVector<Field *> *taggedFields, PandaVector<Field *> *fields64,
625                            PandaVector<Field *> *fields32, PandaVector<Field *> *fields16,
626                            PandaVector<Field *> *fields8, PandaVector<Field *> *refFields, bool isStatic)
627 {
628     size_t offset =
629         LayoutFieldsInBaseClassPadding(klass, taggedFields, fields64, fields32, fields16, fields8, refFields, isStatic);
630     if (!refFields->empty()) {
631         offset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
632         klass->SetRefFieldsNum(refFields->size(), isStatic);
633         klass->SetRefFieldsOffset(offset, isStatic);
634         auto volatileNum = LayoutReferenceFields(ClassHelper::OBJECT_POINTER_SIZE, &offset, *refFields);
635         klass->SetVolatileRefFieldsNum(volatileNum, isStatic);
636     }
637 
638     static_assert(coretypes::TaggedValue::TaggedTypeSize() == SIZE_64,
639                   "Please fix alignment of the fields of type \"TaggedValue\"");
640     if (!IsAligned<SIZE_64>(offset) && (!fields64->empty() || !taggedFields->empty())) {
641         size_t padding = AlignUp(offset, SIZE_64) - offset;
642 
643         LayoutFieldsWithoutAlignment(SIZE_32, &offset, &padding, fields32);
644         LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
645         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
646 
647         offset += padding;
648     }
649 
650     LayoutFieldsWithoutAlignment(coretypes::TaggedValue::TaggedTypeSize(), &offset, nullptr, taggedFields);
651     LayoutFieldsWithoutAlignment(SIZE_64, &offset, nullptr, fields64);
652 
653     if (!IsAligned<SIZE_32>(offset) && !fields32->empty()) {
654         size_t padding = AlignUp(offset, SIZE_32) - offset;
655 
656         LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
657         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
658 
659         offset += padding;
660     }
661 
662     LayoutFieldsWithoutAlignment(SIZE_32, &offset, nullptr, fields32);
663 
664     if (!IsAligned<SIZE_16>(offset) && !fields16->empty()) {
665         size_t padding = AlignUp(offset, SIZE_16) - offset;
666 
667         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
668 
669         offset += padding;
670     }
671 
672     LayoutFieldsWithoutAlignment(SIZE_16, &offset, nullptr, fields16);
673 
674     LayoutFieldsWithoutAlignment(SIZE_8, &offset, nullptr, fields8);
675 
676     return offset;
677 }
678 
PushBackFieldIfNonPrimitiveType(Field & field,PandaVector<Field * > & refFields)679 static inline bool PushBackFieldIfNonPrimitiveType(Field &field, PandaVector<Field *> &refFields)
680 {
681     auto type = field.GetType();
682     if (!type.IsPrimitive()) {
683         refFields.push_back(&field);
684         return true;
685     }
686 
687     return false;
688 }
689 
690 /* static */
691 // CC-OFFNXT(huge_method) solid logic
LayoutFields(Class * klass,Span<Field> fields,bool isStatic,ClassLinkerErrorHandler * errorHandler)692 bool ClassLinker::LayoutFields(Class *klass, Span<Field> fields, bool isStatic,
693                                [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
694 {
695     // These containers must be optimized
696     PandaVector<Field *> taggedFields;
697     PandaVector<Field *> fields64;
698     PandaVector<Field *> fields32;
699     PandaVector<Field *> fields16;
700     PandaVector<Field *> fields8;
701     PandaVector<Field *> refFields;
702     taggedFields.reserve(fields.size());
703     fields64.reserve(fields.size());
704     fields32.reserve(fields.size());
705     fields16.reserve(fields.size());
706     fields8.reserve(fields.size());
707     refFields.reserve(fields.size());
708 
709     for (auto &field : fields) {
710         if (PushBackFieldIfNonPrimitiveType(field, refFields)) {
711             continue;
712         }
713 
714         switch (field.GetType().GetId()) {
715             case Type::TypeId::U1:
716             case Type::TypeId::I8:
717             case Type::TypeId::U8:
718                 fields8.push_back(&field);
719                 break;
720             case Type::TypeId::I16:
721             case Type::TypeId::U16:
722                 fields16.push_back(&field);
723                 break;
724             case Type::TypeId::I32:
725             case Type::TypeId::U32:
726             case Type::TypeId::F32:
727                 fields32.push_back(&field);
728                 break;
729             case Type::TypeId::I64:
730             case Type::TypeId::U64:
731             case Type::TypeId::F64:
732                 fields64.push_back(&field);
733                 break;
734             case Type::TypeId::TAGGED:
735                 taggedFields.push_back(&field);
736                 break;
737             default:
738                 UNREACHABLE();
739                 break;
740         }
741     }
742 
743     size_t size =
744         ark::LayoutFields(klass, &taggedFields, &fields64, &fields32, &fields16, &fields8, &refFields, isStatic);
745 
746     if (!isStatic && !klass->IsVariableSize()) {
747         klass->SetObjectSize(size);
748     }
749 
750     return true;
751 }
752 
LinkMethods(Class * klass,ClassInfo * classInfo,ClassLinkerErrorHandler * errorHandler)753 bool ClassLinker::LinkMethods(Class *klass, ClassInfo *classInfo,
754                               [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
755 {
756     classInfo->vtableBuilder->UpdateClass(klass);
757     if (!classInfo->itableBuilder->Resolve(klass)) {
758         return false;
759     }
760     classInfo->itableBuilder->UpdateClass(klass);
761     classInfo->imtableBuilder->UpdateClass(klass);
762     return true;
763 }
764 
LinkFields(Class * klass,ClassLinkerErrorHandler * errorHandler)765 bool ClassLinker::LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler)
766 {
767     if (!LayoutFields(klass, klass->GetStaticFields(), true, errorHandler)) {
768         LOG(ERROR, CLASS_LINKER) << "Cannot layout static fields of class '" << klass->GetName() << "'";
769         return false;
770     }
771 
772     if (!LayoutFields(klass, klass->GetInstanceFields(), false, errorHandler)) {
773         LOG(ERROR, CLASS_LINKER) << "Cannot layout instance fields of class '" << klass->GetName() << "'";
774         return false;
775     }
776 
777     return true;
778 }
779 
LoadBaseClass(panda_file::ClassDataAccessor * cda,const LanguageContext & ctx,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)780 Class *ClassLinker::LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx,
781                                   ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler)
782 {
783     auto baseClassId = cda->GetSuperClassId();
784     auto *ext = GetExtension(ctx);
785     ASSERT(ext != nullptr);
786     if (baseClassId.GetOffset() == 0) {
787         return ext->GetClassRoot(ClassRoot::OBJECT);
788     }
789 
790     auto &pf = cda->GetPandaFile();
791     auto *baseClass = ext->GetClass(pf, baseClassId, context, errorHandler);
792     if (baseClass == nullptr) {
793         LOG(INFO, CLASS_LINKER) << "Cannot find base class '" << utf::Mutf8AsCString(pf.GetStringData(baseClassId).data)
794                                 << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
795                                 << "' in ctx " << context;
796         return nullptr;
797     }
798 
799     return baseClass;
800 }
801 
LoadInterfaces(panda_file::ClassDataAccessor * cda,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)802 std::optional<Span<Class *>> ClassLinker::LoadInterfaces(panda_file::ClassDataAccessor *cda,
803                                                          ClassLinkerContext *context,
804                                                          ClassLinkerErrorHandler *errorHandler)
805 {
806     ASSERT(context != nullptr);
807     size_t ifacesNum = cda->GetIfacesNumber();
808     if (ifacesNum == 0) {
809         return Span<Class *>(nullptr, ifacesNum);
810     }
811 
812     Span<Class *> ifaces {allocator_->AllocArray<Class *>(ifacesNum), ifacesNum};
813 
814     for (size_t i = 0; i < ifacesNum; i++) {
815         auto id = cda->GetInterfaceId(i);
816         auto &pf = cda->GetPandaFile();
817         auto *iface = GetClass(pf, id, context, errorHandler);
818         if (iface == nullptr) {
819             LOG(INFO, CLASS_LINKER) << "Cannot find interface '" << utf::Mutf8AsCString(pf.GetStringData(id).data)
820                                     << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
821                                     << "' in ctx " << context;
822             ASSERT(!ifaces.Empty());
823             allocator_->Free(ifaces.begin());
824             return {};
825         }
826 
827         ifaces[i] = iface;
828     }
829 
830     return ifaces;
831 }
832 
833 using ClassLoadingSet = std::unordered_set<uint64_t>;
834 
835 // This class is required to clear static unordered_set on return
836 class ClassScopeStaticSetAutoCleaner {
837 public:
838     ClassScopeStaticSetAutoCleaner() = default;
ClassScopeStaticSetAutoCleaner(ClassLoadingSet * setPtr,ClassLoadingSet ** tlSetPtr)839     explicit ClassScopeStaticSetAutoCleaner(ClassLoadingSet *setPtr, ClassLoadingSet **tlSetPtr)
840         : setPtr_(setPtr), tlSetPtr_(tlSetPtr)
841     {
842     }
~ClassScopeStaticSetAutoCleaner()843     ~ClassScopeStaticSetAutoCleaner()
844     {
845         setPtr_->clear();
846         if (tlSetPtr_ != nullptr) {
847             *tlSetPtr_ = nullptr;
848         }
849     }
850 
851     NO_COPY_SEMANTIC(ClassScopeStaticSetAutoCleaner);
852     NO_MOVE_SEMANTIC(ClassScopeStaticSetAutoCleaner);
853 
854 private:
855     ClassLoadingSet *setPtr_ {nullptr};
856     ClassLoadingSet **tlSetPtr_ {nullptr};
857 };
858 
GetClassUniqueHash(uint32_t pandaFileHash,uint32_t classId)859 static uint64_t GetClassUniqueHash(uint32_t pandaFileHash, uint32_t classId)
860 {
861     const uint8_t bitsToShuffle = 32;
862     return (static_cast<uint64_t>(pandaFileHash) << bitsToShuffle) | static_cast<uint64_t>(classId);
863 }
864 
LoadClass(panda_file::ClassDataAccessor * classDataAccessor,const uint8_t * descriptor,Class * baseClass,Span<Class * > interfaces,ClassLinkerContext * context,ClassLinkerExtension * ext,ClassLinkerErrorHandler * errorHandler)865 Class *ClassLinker::LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor,
866                               Class *baseClass, Span<Class *> interfaces, ClassLinkerContext *context,
867                               ClassLinkerExtension *ext, ClassLinkerErrorHandler *errorHandler)
868 {
869     ASSERT(context != nullptr);
870     ClassInfo classInfo {};
871     if (!SetupClassInfo(classInfo, classDataAccessor, baseClass, interfaces, context, errorHandler)) {
872         return nullptr;
873     }
874 
875     auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
876                                    classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
877 
878     if (UNLIKELY(klass == nullptr)) {
879         return nullptr;
880     }
881 
882     klass->SetLoadContext(context);
883     klass->SetBase(baseClass);
884     klass->SetInterfaces(interfaces);
885     klass->SetFileId(classDataAccessor->GetClassId());
886     klass->SetPandaFile(&classDataAccessor->GetPandaFile());
887     klass->SetAccessFlags(classDataAccessor->GetAccessFlags());
888 
889     auto &pf = classDataAccessor->GetPandaFile();
890     auto classId = classDataAccessor->GetClassId();
891     klass->SetClassIndex(pf.GetClassIndex(classId));
892     klass->SetMethodIndex(pf.GetMethodIndex(classId));
893     klass->SetFieldIndex(pf.GetFieldIndex(classId));
894 
895     klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
896     klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
897     klass->SetNumStaticFields(classInfo.numSfields);
898 
899     auto const onFail = [this, descriptor, klass](std::string_view msg) {
900         FreeClass(klass);
901         LOG(ERROR, CLASS_LINKER) << msg << " '" << descriptor << "'";
902         return nullptr;
903     };
904     if (!LoadMethods(klass, &classInfo, classDataAccessor, errorHandler)) {
905         return onFail("Cannot load methods of class");
906     }
907     if (!LoadFields(klass, classDataAccessor, errorHandler)) {
908         return onFail("Cannot load fields of class");
909     }
910     if (!LinkMethods(klass, &classInfo, errorHandler)) {
911         return onFail("Cannot link methods of class");
912     }
913     if (!LinkFields(klass, errorHandler)) {
914         return onFail("Cannot link fields of class");
915     }
916     return klass;
917 }
918 
LoadClass(const panda_file::File * pf,const uint8_t * descriptor,panda_file::SourceLang lang)919 Class *ClassLinker::LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang)
920 {
921     panda_file::File::EntityId classId = pf->GetClassId(descriptor);
922     if (!classId.IsValid() || pf->IsExternal(classId)) {
923         return nullptr;
924     }
925     ClassLinkerContext *context = GetExtension(lang)->GetBootContext();
926     return LoadClass(pf, classId, descriptor, context, nullptr);
927 }
928 
OnError(ClassLinkerErrorHandler * errorHandler,ClassLinker::Error error,const PandaString & msg)929 static void OnError(ClassLinkerErrorHandler *errorHandler, ClassLinker::Error error, const PandaString &msg)
930 {
931     if (errorHandler != nullptr) {
932         errorHandler->OnError(error, msg);
933     }
934 }
935 
TryInsertClassLoading(panda_file::File::EntityId & classId,const panda_file::File * pf,panda_file::ClassDataAccessor & classDataAccessor,ClassLoadingSet * threadLocalSet,ClassLinkerErrorHandler * errorHandler)936 static bool TryInsertClassLoading(panda_file::File::EntityId &classId, const panda_file::File *pf,
937                                   panda_file::ClassDataAccessor &classDataAccessor, ClassLoadingSet *threadLocalSet,
938                                   ClassLinkerErrorHandler *errorHandler)
939 {
940     uint32_t classIdInt = classId.GetOffset();
941     uint32_t pandaFileHash = pf->GetFilenameHash();
942     if (!threadLocalSet->insert(GetClassUniqueHash(pandaFileHash, classIdInt)).second) {
943         const PandaString &className = utf::Mutf8AsCString(pf->GetStringData(classDataAccessor.GetClassId()).data);
944         PandaString msg = "Class or interface \"" + className + "\" is its own superclass or superinterface";
945         OnError(errorHandler, ClassLinker::Error::CLASS_CIRCULARITY, msg);
946         return false;
947     }
948 
949     return true;
950 }
951 
IsContextCanBeLoaded(ClassLinkerContext * context,panda_file::ClassDataAccessor & classDataAccessor,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)952 static bool IsContextCanBeLoaded(ClassLinkerContext *context, panda_file::ClassDataAccessor &classDataAccessor,
953                                  const uint8_t *descriptor, ClassLinkerErrorHandler *errorHandler)
954 {
955     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
956     if (ctx.GetLanguage() != context->GetSourceLang()) {
957         LanguageContext currentCtx = Runtime::GetCurrent()->GetLanguageContext(context->GetSourceLang());
958         PandaStringStream ss;
959         ss << "Cannot load " << ctx << " class " << descriptor << " into " << currentCtx << " context";
960         LOG(ERROR, CLASS_LINKER) << ss.str();
961         OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
962         return false;
963     }
964 
965     return true;
966 }
967 
HandleNoExtensionError(LanguageContext & ctx,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)968 static void HandleNoExtensionError(LanguageContext &ctx, const uint8_t *descriptor,
969                                    ClassLinkerErrorHandler *errorHandler)
970 {
971     PandaStringStream ss;
972     ss << "Cannot load class '" << descriptor << "' as class linker hasn't " << ctx << " language extension";
973     LOG(ERROR, CLASS_LINKER) << ss.str();
974     OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
975 }
976 
977 // 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)978 Class *ClassLinker::LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor,
979                               ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler,
980                               bool addToRuntime /* = true */)
981 {
982     ASSERT(!pf->IsExternal(classId));
983     ASSERT(context != nullptr);
984     panda_file::ClassDataAccessor classDataAccessor(*pf, classId);
985     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
986     if (!IsContextCanBeLoaded(context, classDataAccessor, descriptor, errorHandler)) {
987         return nullptr;
988     }
989 
990     if (!HasExtension(ctx)) {
991         HandleNoExtensionError(ctx, descriptor, errorHandler);
992         return nullptr;
993     }
994 
995     // This set is used to find out if the class is its own superclass
996     ClassLoadingSet loadingSet;
997     static thread_local ClassLoadingSet *threadLocalSet = nullptr;
998     ClassLoadingSet **threadLocalSetPtr = nullptr;
999     if (threadLocalSet == nullptr) {
1000         threadLocalSet = &loadingSet;
1001         threadLocalSetPtr = &threadLocalSet;
1002     }
1003     ClassScopeStaticSetAutoCleaner classSetAutoCleanerOnReturn(threadLocalSet, threadLocalSetPtr);
1004 
1005     auto *ext = GetExtension(ctx);
1006     Class *baseClass = nullptr;
1007     bool needLoadBase = IsInitialized() || !utf::IsEqual(ctx.GetObjectClassDescriptor(), descriptor);
1008     if (needLoadBase) {
1009         if (!TryInsertClassLoading(classId, pf, classDataAccessor, threadLocalSet, errorHandler)) {
1010             return nullptr;
1011         }
1012 
1013         baseClass = LoadBaseClass(&classDataAccessor, ctx, context, errorHandler);
1014         if (baseClass == nullptr) {
1015             LOG(INFO, CLASS_LINKER) << "Cannot load base class of class '" << descriptor << "'";
1016             return nullptr;
1017         }
1018     }
1019 
1020     auto res = LoadInterfaces(&classDataAccessor, context, errorHandler);
1021     if (!res) {
1022         LOG(INFO, CLASS_LINKER) << "Cannot load interfaces of class '" << descriptor << "'";
1023         return nullptr;
1024     }
1025 
1026     auto *klass = LoadClass(&classDataAccessor, descriptor, baseClass, res.value(), context, ext, errorHandler);
1027     if (klass == nullptr) {
1028         return nullptr;
1029     }
1030 
1031     Runtime::GetCurrent()->GetCha()->Update(klass);
1032 
1033     if (LIKELY(ext->CanInitializeClasses())) {
1034         if (!ext->InitializeClass(klass)) {
1035             LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1036             FreeClass(klass);
1037             return nullptr;
1038         }
1039         klass->SetState(Class::State::LOADED);
1040     }
1041 
1042     if (LIKELY(addToRuntime)) {
1043         Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1044 
1045         auto *otherKlass = context->InsertClass(klass);
1046         if (otherKlass != nullptr) {
1047             // Someone has created the class in the other thread (increase the critical section?)
1048             FreeClass(klass);
1049             return otherKlass;
1050         }
1051 
1052         RemoveCreatedClassInExtension(klass);
1053         Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1054     }
1055     return klass;
1056 }
1057 
CopyMutf8String(mem::InternalAllocatorPtr allocator,const uint8_t * descriptor)1058 static const uint8_t *CopyMutf8String(mem::InternalAllocatorPtr allocator, const uint8_t *descriptor)
1059 {
1060     size_t size = utf::Mutf8Size(descriptor) + 1;  // + 1 - null terminate
1061     auto *ptr = allocator->AllocArray<uint8_t>(size);
1062     memcpy_s(ptr, size, descriptor, size);
1063     return ptr;
1064 }
1065 
LinkEntitiesAndInitClass(Class * klass,ClassInfo * classInfo,ClassLinkerExtension * ext,const uint8_t * descriptor)1066 bool ClassLinker::LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext,
1067                                            const uint8_t *descriptor)
1068 {
1069     if (!LinkMethods(klass, classInfo, ext->GetErrorHandler())) {
1070         LOG(ERROR, CLASS_LINKER) << "Cannot link class methods '" << descriptor << "'";
1071         return false;
1072     }
1073 
1074     if (!LinkFields(klass, ext->GetErrorHandler())) {
1075         LOG(ERROR, CLASS_LINKER) << "Cannot link class fields '" << descriptor << "'";
1076         return false;
1077     }
1078 
1079     if (!ext->InitializeClass(klass)) {
1080         LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1081         FreeClass(klass);
1082         return false;
1083     }
1084 
1085     return true;
1086 }
1087 
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)1088 Class *ClassLinker::BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags,
1089                                Span<Method> methods, Span<Field> fields, Class *baseClass, Span<Class *> interfaces,
1090                                ClassLinkerContext *context, bool isInterface)
1091 {
1092     ASSERT(context != nullptr);
1093     if (needCopyDescriptor) {
1094         descriptor = CopyMutf8String(allocator_, descriptor);
1095         os::memory::LockHolder lock(copiedNamesLock_);
1096         copiedNames_.push_front(descriptor);
1097     }
1098 
1099     auto *ext = GetExtension(baseClass->GetSourceLang());
1100     ASSERT(ext != nullptr);
1101 
1102     ClassInfo classInfo {};
1103     if (!SetupClassInfo(classInfo, methods, fields, baseClass, interfaces, isInterface, nullptr)) {
1104         return nullptr;
1105     }
1106 
1107     // Need to protect ArenaAllocator and loaded_classes_
1108     auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
1109                                    classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
1110 
1111     if (UNLIKELY(klass == nullptr)) {
1112         return nullptr;
1113     }
1114 
1115     klass->SetLoadContext(context);
1116     klass->SetBase(baseClass);
1117     klass->SetInterfaces(interfaces);
1118     klass->SetAccessFlags(accessFlags);
1119 
1120     klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
1121     klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
1122     klass->SetNumStaticFields(classInfo.numSfields);
1123 
1124     ASSERT(klass->GetNumCopiedMethods() == 0);
1125 
1126     size_t numSmethods = methods.size() - klass->GetNumVirtualMethods();
1127     klass->SetMethods(methods, klass->GetNumVirtualMethods(), numSmethods);
1128     klass->SetFields(fields, klass->GetNumStaticFields());
1129 
1130     for (auto &method : methods) {
1131         method.SetClass(klass);
1132     }
1133 
1134     for (auto &field : fields) {
1135         field.SetClass(klass);
1136     }
1137 
1138     if (!LinkEntitiesAndInitClass(klass, &classInfo, ext, descriptor)) {
1139         return nullptr;
1140     }
1141 
1142     klass->SetState(Class::State::LOADED);
1143 
1144     Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1145 
1146     auto *otherKlass = context->InsertClass(klass);
1147     if (otherKlass != nullptr) {
1148         // Someone has created the class in the other thread (increase the critical section?)
1149         FreeClass(klass);
1150         return otherKlass;
1151     }
1152 
1153     RemoveCreatedClassInExtension(klass);
1154     Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1155 
1156     return klass;
1157 }
1158 
CreateArrayClass(ClassLinkerExtension * ext,const uint8_t * descriptor,bool needCopyDescriptor,Class * componentClass)1159 Class *ClassLinker::CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor,
1160                                      Class *componentClass)
1161 {
1162     if (needCopyDescriptor) {
1163         descriptor = CopyMutf8String(allocator_, descriptor);
1164         os::memory::LockHolder lock(copiedNamesLock_);
1165         copiedNames_.push_front(descriptor);
1166     }
1167 
1168     auto *arrayClass = ext->CreateClass(descriptor, ext->GetArrayClassVTableSize(), ext->GetArrayClassIMTSize(),
1169                                         ext->GetArrayClassSize());
1170 
1171     if (UNLIKELY(arrayClass == nullptr)) {
1172         return nullptr;
1173     }
1174 
1175     arrayClass->SetLoadContext(componentClass->GetLoadContext());
1176 
1177     if (UNLIKELY(!ext->InitializeArrayClass(arrayClass, componentClass))) {
1178         return nullptr;
1179     }
1180 
1181     return arrayClass;
1182 }
1183 
LoadArrayClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1184 Class *ClassLinker::LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1185                                    ClassLinkerErrorHandler *errorHandler)
1186 {
1187     Span<const uint8_t> sp(descriptor, 1);
1188 
1189     Class *componentClass = GetClass(sp.cend(), needCopyDescriptor, context, errorHandler);
1190 
1191     if (componentClass == nullptr) {
1192         return nullptr;
1193     }
1194 
1195     if (UNLIKELY(componentClass->GetType().GetId() == panda_file::Type::TypeId::VOID)) {
1196         OnError(errorHandler, Error::NO_CLASS_DEF, "Try to create array with void component type");
1197         return nullptr;
1198     }
1199 
1200     auto *ext = GetExtension(componentClass->GetSourceLang());
1201     ASSERT(ext != nullptr);
1202 
1203     auto *componentClassContext = componentClass->GetLoadContext();
1204     ASSERT(componentClassContext != nullptr);
1205     if (componentClassContext != context) {
1206         auto *loadedClass = FindLoadedClass(descriptor, componentClassContext);
1207         if (loadedClass != nullptr) {
1208             return loadedClass;
1209         }
1210     }
1211 
1212     auto *arrayClass = CreateArrayClass(ext, descriptor, needCopyDescriptor, componentClass);
1213 
1214     if (UNLIKELY(arrayClass == nullptr)) {
1215         return nullptr;
1216     }
1217 
1218     Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(arrayClass);
1219 
1220     auto *otherKlass = componentClassContext->InsertClass(arrayClass);
1221     if (otherKlass != nullptr) {
1222         FreeClass(arrayClass);
1223         return otherKlass;
1224     }
1225 
1226     RemoveCreatedClassInExtension(arrayClass);
1227     Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(arrayClass);
1228 
1229     return arrayClass;
1230 }
1231 
PandaFilesToString(const PandaVector<const panda_file::File * > & pandaFiles)1232 static PandaString PandaFilesToString(const PandaVector<const panda_file::File *> &pandaFiles)
1233 {
1234     PandaStringStream ss;
1235     ss << "[";
1236 
1237     size_t n = pandaFiles.size();
1238     for (size_t i = 0; i < n; i++) {
1239         ss << pandaFiles[i]->GetFilename();
1240 
1241         if (i < n - 1) {
1242             ss << ", ";
1243         }
1244     }
1245 
1246     ss << "]";
1247     return ss.str();
1248 }
1249 
GetClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1250 Class *ClassLinker::GetClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1251                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1252 {
1253     ASSERT(context != nullptr);
1254     ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1255            !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1256 
1257     Class *cls = FindLoadedClass(descriptor, context);
1258     if (cls != nullptr) {
1259         return cls;
1260     }
1261 
1262     if (ClassHelper::IsArrayDescriptor(descriptor)) {
1263         return LoadArrayClass(descriptor, needCopyDescriptor, context, errorHandler);
1264     }
1265 
1266     if (context->IsBootContext()) {
1267         panda_file::File::EntityId classId;
1268         const panda_file::File *pandaFile {nullptr};
1269         {
1270             {
1271                 os::memory::LockHolder lock {bootPandaFilesLock_};
1272                 std::tie(classId, pandaFile) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1273             }
1274 
1275             if (!classId.IsValid()) {
1276                 PandaStringStream ss;
1277                 {
1278                     // can't make a wider scope for lock here - will get recursion
1279                     os::memory::LockHolder lock {bootPandaFilesLock_};
1280                     ss << "Cannot find class " << descriptor
1281                        << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1282                 }
1283                 OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1284                 return nullptr;
1285             }
1286         }
1287 
1288         return LoadClass(pandaFile, classId, pandaFile->GetStringData(classId).data, context, errorHandler);
1289     }
1290 
1291     return context->LoadClass(descriptor, needCopyDescriptor, errorHandler);
1292 }
1293 
GetClass(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1294 Class *ClassLinker::GetClass(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context,
1295                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1296 {
1297     ASSERT(context != nullptr);
1298     ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1299            !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1300 
1301     Class *cls = pf.GetPandaCache()->GetClassFromCache(id);
1302     if (cls != nullptr) {
1303         return cls;
1304     }
1305     const uint8_t *descriptor = pf.GetStringData(id).data;
1306 
1307     cls = FindLoadedClass(descriptor, context);
1308     if (cls != nullptr) {
1309         pf.GetPandaCache()->SetClassCache(id, cls);
1310         return cls;
1311     }
1312 
1313     if (ClassHelper::IsArrayDescriptor(descriptor)) {
1314         cls = LoadArrayClass(descriptor, false, context, errorHandler);
1315         if (LIKELY(cls != nullptr)) {
1316             pf.GetPandaCache()->SetClassCache(id, cls);
1317         }
1318         return cls;
1319     }
1320 
1321     if (context->IsBootContext()) {
1322         const panda_file::File *pfPtr = nullptr;
1323         panda_file::File::EntityId extId;
1324         {
1325             os::memory::LockHolder lock {bootPandaFilesLock_};
1326             std::tie(extId, pfPtr) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1327         }
1328 
1329         if (!extId.IsValid()) {
1330             PandaStringStream ss;
1331             {
1332                 // can't make a wider scope for lock here - will get recursion
1333                 os::memory::LockHolder lock {bootPandaFilesLock_};
1334                 ss << "Cannot find class " << descriptor
1335                    << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1336             }
1337             OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1338             return nullptr;
1339         }
1340 
1341         cls = LoadClass(pfPtr, extId, descriptor, context, errorHandler);
1342         if (LIKELY(cls != nullptr)) {
1343             pf.GetPandaCache()->SetClassCache(id, cls);
1344         }
1345         return cls;
1346     }
1347 
1348     return context->LoadClass(descriptor, false, errorHandler);
1349 }
1350 
GetMethod(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1351 Method *ClassLinker::GetMethod(const panda_file::File &pf, panda_file::File::EntityId id,
1352                                ClassLinkerContext *context /* = nullptr */,
1353                                ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1354 {
1355     Method *method = pf.GetPandaCache()->GetMethodFromCache(id);
1356     if (method != nullptr) {
1357         return method;
1358     }
1359     panda_file::MethodDataAccessor methodDataAccessor(pf, id);
1360 
1361     auto classId = methodDataAccessor.GetClassId();
1362     if (context == nullptr) {
1363         panda_file::ClassDataAccessor classDataAccessor(pf, classId);
1364         auto lang = classDataAccessor.GetSourceLang();
1365         if (!lang) {
1366             LOG(INFO, CLASS_LINKER) << "Cannot resolve language context for class_id " << classId << " in file "
1367                                     << pf.GetFilename();
1368             return nullptr;
1369         }
1370         auto *extension = GetExtension(lang.value());
1371         context = extension->GetBootContext();
1372     }
1373 
1374     Class *klass = GetClass(pf, classId, context, errorHandler);
1375 
1376     if (klass == nullptr) {
1377         auto className = pf.GetStringData(classId).data;
1378         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1379         return nullptr;
1380     }
1381     method = GetMethod(klass, methodDataAccessor, errorHandler);
1382     if (LIKELY(method != nullptr)) {
1383         pf.GetPandaCache()->SetMethodCache(id, method);
1384     }
1385     return method;
1386 }
1387 
GetMethod(const Method & caller,panda_file::File::EntityId id,ClassLinkerErrorHandler * errorHandler)1388 Method *ClassLinker::GetMethod(const Method &caller, panda_file::File::EntityId id,
1389                                ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1390 {
1391     auto *pf = caller.GetPandaFile();
1392     Method *method = pf->GetPandaCache()->GetMethodFromCache(id);
1393     if (method != nullptr) {
1394         return method;
1395     }
1396 
1397     panda_file::MethodDataAccessor methodDataAccessor(*pf, id);
1398     auto classId = methodDataAccessor.GetClassId();
1399 
1400     auto *context = caller.GetClass()->GetLoadContext();
1401     auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1402     Class *klass = ext->GetClass(*pf, classId, context, errorHandler);
1403 
1404     if (klass == nullptr) {
1405         auto className = pf->GetStringData(classId).data;
1406         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1407         return nullptr;
1408     }
1409 
1410     method = GetMethod(klass, methodDataAccessor, (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1411     if (LIKELY(method != nullptr)) {
1412         pf->GetPandaCache()->SetMethodCache(id, method);
1413     }
1414     return method;
1415 }
1416 
GetMethod(const Class * klass,const panda_file::MethodDataAccessor & methodDataAccessor,ClassLinkerErrorHandler * errorHandler)1417 Method *ClassLinker::GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor,
1418                                ClassLinkerErrorHandler *errorHandler)
1419 {
1420     Method *method;
1421     auto id = methodDataAccessor.GetMethodId();
1422     const auto &pf = methodDataAccessor.GetPandaFile();
1423 
1424     bool isStatic = methodDataAccessor.IsStatic();
1425     if (!methodDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1426         if (klass->IsInterface()) {
1427             method = isStatic ? klass->GetStaticInterfaceMethod(id) : klass->GetVirtualInterfaceMethod(id);
1428         } else {
1429             method = isStatic ? klass->GetStaticClassMethod(id) : klass->GetVirtualClassMethod(id);
1430         }
1431 
1432         if (method == nullptr) {
1433             Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1434             PandaStringStream ss;
1435             ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1436                << "' in class '" << klass->GetName() << "'";
1437             OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1438             return nullptr;
1439         }
1440 
1441         return method;
1442     }
1443 
1444     auto name = methodDataAccessor.GetName();
1445     Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1446     if (klass->IsInterface()) {
1447         method = isStatic ? klass->GetStaticInterfaceMethodByName(name, proto)
1448                           : klass->GetVirtualInterfaceMethodByName(name, proto);
1449     } else {
1450         method =
1451             isStatic ? klass->GetStaticClassMethodByName(name, proto) : klass->GetVirtualClassMethodByName(name, proto);
1452         if (method == nullptr && klass->IsAbstract()) {
1453             method = klass->GetInterfaceMethod(name, proto);
1454         }
1455     }
1456 
1457     if (method == nullptr) {
1458         PandaStringStream ss;
1459         ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1460            << "' in class '" << klass->GetName() << "'";
1461         OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1462         return nullptr;
1463     }
1464 
1465     LOG_IF(method->IsStatic() != methodDataAccessor.IsStatic(), FATAL, CLASS_LINKER)
1466         << "Expected ACC_STATIC for method " << name.data << " in class " << klass->GetName()
1467         << " does not match loaded value";
1468 
1469     return method;
1470 }
1471 
GetFieldById(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler)1472 Field *ClassLinker::GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1473                                  ClassLinkerErrorHandler *errorHandler)
1474 {
1475     bool isStatic = fieldDataAccessor.IsStatic();
1476     auto &pf = fieldDataAccessor.GetPandaFile();
1477     auto id = fieldDataAccessor.GetFieldId();
1478 
1479     Field *field = isStatic ? klass->FindStaticFieldById(id) : klass->FindInstanceFieldById(id);
1480 
1481     if (field == nullptr) {
1482         PandaStringStream ss;
1483         ss << "Cannot find field '" << pf.GetStringData(fieldDataAccessor.GetNameId()).data << "' in class '"
1484            << klass->GetName() << "'";
1485         OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1486         return nullptr;
1487     }
1488 
1489     pf.GetPandaCache()->SetFieldCache(id, field);
1490     return field;
1491 }
1492 
GetFieldBySignature(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler)1493 Field *ClassLinker::GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1494                                         ClassLinkerErrorHandler *errorHandler)
1495 {
1496     auto &pf = fieldDataAccessor.GetPandaFile();
1497     auto id = fieldDataAccessor.GetFieldId();
1498     auto fieldName = pf.GetStringData(fieldDataAccessor.GetNameId());
1499     auto fieldType = panda_file::Type::GetTypeFromFieldEncoding(fieldDataAccessor.GetType());
1500     Field *field = klass->FindField([&fieldDataAccessor, &fieldType, &fieldName, &id, &pf](const Field &fld) {
1501         if (fieldType == fld.GetType() && fieldName == fld.GetName()) {
1502             if (!fieldType.IsReference()) {
1503                 return true;
1504             }
1505 
1506             // compare field class type
1507             if (&pf == fld.GetPandaFile() && id == fld.GetFileId()) {
1508                 return true;
1509             }
1510             auto typeId = panda_file::FieldDataAccessor::GetTypeId(*fld.GetPandaFile(), fld.GetFileId());
1511             if (pf.GetStringData(panda_file::File::EntityId(fieldDataAccessor.GetType())) ==
1512                 fld.GetPandaFile()->GetStringData(typeId)) {
1513                 return true;
1514             }
1515         }
1516         return false;
1517     });
1518 
1519     if (field == nullptr) {
1520         PandaStringStream ss;
1521         ss << "Cannot find field '" << fieldName.data << "' in class '" << klass->GetName() << "'";
1522         OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1523         return nullptr;
1524     }
1525 
1526     pf.GetPandaCache()->SetFieldCache(id, field);
1527     return field;
1528 }
1529 
GetField(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1530 Field *ClassLinker::GetField(const panda_file::File &pf, panda_file::File::EntityId id,
1531                              ClassLinkerContext *context /* = nullptr */,
1532                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1533 {
1534     Field *field = pf.GetPandaCache()->GetFieldFromCache(id);
1535     if (field != nullptr) {
1536         return field;
1537     }
1538     panda_file::FieldDataAccessor fieldDataAccessor(pf, id);
1539 
1540     Class *klass = GetClass(pf, fieldDataAccessor.GetClassId(), context, errorHandler);
1541 
1542     if (klass == nullptr) {
1543         auto className = pf.GetStringData(fieldDataAccessor.GetClassId()).data;
1544         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1545         return nullptr;
1546     }
1547 
1548     if (!fieldDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1549         field = GetFieldById(klass, fieldDataAccessor, errorHandler);
1550     } else {
1551         field = GetFieldBySignature(klass, fieldDataAccessor, errorHandler);
1552     }
1553     return field;
1554 }
1555 
InitializeClass(ManagedThread * thread,Class * klass)1556 bool ClassLinker::InitializeClass(ManagedThread *thread, Class *klass)
1557 {
1558     ASSERT(klass != nullptr);
1559     if (klass->IsInitialized()) {
1560         return true;
1561     }
1562 
1563     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
1564     return ctx.InitializeClass(this, thread, klass);
1565 }
1566 
NumLoadedClasses()1567 size_t ClassLinker::NumLoadedClasses()
1568 {
1569     size_t sum = 0;
1570 
1571     for (auto &ext : extensions_) {
1572         if (ext == nullptr) {
1573             continue;
1574         }
1575 
1576         sum += ext->NumLoadedClasses();
1577     }
1578 
1579     return sum;
1580 }
1581 
VisitLoadedClasses(size_t flag)1582 void ClassLinker::VisitLoadedClasses(size_t flag)
1583 {
1584     for (auto &ext : extensions_) {
1585         if (ext == nullptr) {
1586             continue;
1587         }
1588         ext->VisitLoadedClasses(flag);
1589     }
1590 }
1591 
GetField(const Method & caller,panda_file::File::EntityId id,ClassLinkerErrorHandler * errorHandler)1592 Field *ClassLinker::GetField(const Method &caller, panda_file::File::EntityId id,
1593                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1594 {
1595     Field *field = caller.GetPandaFile()->GetPandaCache()->GetFieldFromCache(id);
1596     if (field != nullptr) {
1597         return field;
1598     }
1599     auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1600     field = GetField(*caller.GetPandaFile(), id, caller.GetClass()->GetLoadContext(),
1601                      (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1602     if (LIKELY(field != nullptr)) {
1603         caller.GetPandaFile()->GetPandaCache()->SetFieldCache(id, field);
1604     }
1605     return field;
1606 }
1607 
RemoveCreatedClassInExtension(Class * klass)1608 void ClassLinker::RemoveCreatedClassInExtension(Class *klass)
1609 {
1610     if (klass == nullptr) {
1611         return;
1612     }
1613     auto ext = GetExtension(klass->GetSourceLang());
1614     if (ext != nullptr) {
1615         ext->OnClassPrepared(klass);
1616     }
1617 }
1618 
1619 }  // namespace ark
1620