• 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 
LayoutFieldsInBaseClassPadding(Class * klass,PandaVector<Field * > * taggedFields,PandaVector<Field * > * fields64,PandaVector<Field * > * fields32,PandaVector<Field * > * fields16,PandaVector<Field * > * fields8,PandaVector<Field * > * refFields,bool isStatic)588 static size_t LayoutFieldsInBaseClassPadding(Class *klass, PandaVector<Field *> *taggedFields,
589                                              PandaVector<Field *> *fields64, PandaVector<Field *> *fields32,
590                                              PandaVector<Field *> *fields16, PandaVector<Field *> *fields8,
591                                              PandaVector<Field *> *refFields, bool isStatic)
592 {
593     size_t offset;
594 
595     if (isStatic) {
596         offset = klass->GetStaticFieldsOffset();
597     } else {
598         offset = (klass->GetBase() != nullptr) ? klass->GetBase()->GetObjectSize() : ObjectHeader::ObjectHeaderSize();
599     }
600 
601     size_t alignOffset = offset;
602     if (!refFields->empty()) {
603         alignOffset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
604     } else if (!(fields64->empty()) || !(taggedFields->empty())) {
605         alignOffset = AlignUp(offset, SIZE_64);
606     } else if (!fields32->empty()) {
607         alignOffset = AlignUp(offset, SIZE_32);
608     } else if (!fields16->empty()) {
609         alignOffset = AlignUp(offset, SIZE_16);
610     }
611     if (alignOffset != offset) {
612         size_t endOffset = alignOffset;
613         size_t padding = endOffset - offset;
614         // try to put short fields of child class at end of free space of base class
615         LayoutFieldsWithoutAlignment<true>(SIZE_32, &endOffset, &padding, fields32);
616         LayoutFieldsWithoutAlignment<true>(SIZE_16, &endOffset, &padding, fields16);
617         LayoutFieldsWithoutAlignment<true>(SIZE_8, &endOffset, &padding, fields8);
618     }
619     return alignOffset;
620 }
621 
LayoutFields(Class * klass,PandaVector<Field * > * taggedFields,PandaVector<Field * > * fields64,PandaVector<Field * > * fields32,PandaVector<Field * > * fields16,PandaVector<Field * > * fields8,PandaVector<Field * > * refFields,bool isStatic)622 static size_t LayoutFields(Class *klass, PandaVector<Field *> *taggedFields, PandaVector<Field *> *fields64,
623                            PandaVector<Field *> *fields32, PandaVector<Field *> *fields16,
624                            PandaVector<Field *> *fields8, PandaVector<Field *> *refFields, bool isStatic)
625 {
626     size_t offset =
627         LayoutFieldsInBaseClassPadding(klass, taggedFields, fields64, fields32, fields16, fields8, refFields, isStatic);
628     if (!refFields->empty()) {
629         offset = AlignUp(offset, ClassHelper::OBJECT_POINTER_SIZE);
630         klass->SetRefFieldsNum(refFields->size(), isStatic);
631         klass->SetRefFieldsOffset(offset, isStatic);
632         auto volatileNum = LayoutReferenceFields(ClassHelper::OBJECT_POINTER_SIZE, &offset, *refFields);
633         klass->SetVolatileRefFieldsNum(volatileNum, isStatic);
634     }
635 
636     static_assert(coretypes::TaggedValue::TaggedTypeSize() == SIZE_64,
637                   "Please fix alignment of the fields of type \"TaggedValue\"");
638     if (!IsAligned<SIZE_64>(offset) && (!fields64->empty() || !taggedFields->empty())) {
639         size_t padding = AlignUp(offset, SIZE_64) - offset;
640 
641         LayoutFieldsWithoutAlignment(SIZE_32, &offset, &padding, fields32);
642         LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
643         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
644 
645         offset += padding;
646     }
647 
648     LayoutFieldsWithoutAlignment(coretypes::TaggedValue::TaggedTypeSize(), &offset, nullptr, taggedFields);
649     LayoutFieldsWithoutAlignment(SIZE_64, &offset, nullptr, fields64);
650 
651     if (!IsAligned<SIZE_32>(offset) && !fields32->empty()) {
652         size_t padding = AlignUp(offset, SIZE_32) - offset;
653 
654         LayoutFieldsWithoutAlignment(SIZE_16, &offset, &padding, fields16);
655         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
656 
657         offset += padding;
658     }
659 
660     LayoutFieldsWithoutAlignment(SIZE_32, &offset, nullptr, fields32);
661 
662     if (!IsAligned<SIZE_16>(offset) && !fields16->empty()) {
663         size_t padding = AlignUp(offset, SIZE_16) - offset;
664 
665         LayoutFieldsWithoutAlignment(SIZE_8, &offset, &padding, fields8);
666 
667         offset += padding;
668     }
669 
670     LayoutFieldsWithoutAlignment(SIZE_16, &offset, nullptr, fields16);
671 
672     LayoutFieldsWithoutAlignment(SIZE_8, &offset, nullptr, fields8);
673 
674     return offset;
675 }
676 
PushBackFieldIfNonPrimitiveType(Field & field,PandaVector<Field * > & refFields)677 static inline bool PushBackFieldIfNonPrimitiveType(Field &field, PandaVector<Field *> &refFields)
678 {
679     auto type = field.GetType();
680     if (!type.IsPrimitive()) {
681         refFields.push_back(&field);
682         return true;
683     }
684 
685     return false;
686 }
687 
688 /* static */
LayoutFields(Class * klass,Span<Field> fields,bool isStatic,ClassLinkerErrorHandler * errorHandler)689 bool ClassLinker::LayoutFields(Class *klass, Span<Field> fields, bool isStatic,
690                                [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
691 {
692     // These containers must be optimized
693     PandaVector<Field *> taggedFields;
694     PandaVector<Field *> fields64;
695     PandaVector<Field *> fields32;
696     PandaVector<Field *> fields16;
697     PandaVector<Field *> fields8;
698     PandaVector<Field *> refFields;
699     taggedFields.reserve(fields.size());
700     fields64.reserve(fields.size());
701     fields32.reserve(fields.size());
702     fields16.reserve(fields.size());
703     fields8.reserve(fields.size());
704     refFields.reserve(fields.size());
705 
706     for (auto &field : fields) {
707         if (PushBackFieldIfNonPrimitiveType(field, refFields)) {
708             continue;
709         }
710 
711         switch (field.GetType().GetId()) {
712             case Type::TypeId::U1:
713             case Type::TypeId::I8:
714             case Type::TypeId::U8:
715                 fields8.push_back(&field);
716                 break;
717             case Type::TypeId::I16:
718             case Type::TypeId::U16:
719                 fields16.push_back(&field);
720                 break;
721             case Type::TypeId::I32:
722             case Type::TypeId::U32:
723             case Type::TypeId::F32:
724                 fields32.push_back(&field);
725                 break;
726             case Type::TypeId::I64:
727             case Type::TypeId::U64:
728             case Type::TypeId::F64:
729                 fields64.push_back(&field);
730                 break;
731             case Type::TypeId::TAGGED:
732                 taggedFields.push_back(&field);
733                 break;
734             default:
735                 UNREACHABLE();
736                 break;
737         }
738     }
739 
740     size_t size =
741         ark::LayoutFields(klass, &taggedFields, &fields64, &fields32, &fields16, &fields8, &refFields, isStatic);
742 
743     if (!isStatic && !klass->IsVariableSize()) {
744         klass->SetObjectSize(size);
745     }
746 
747     return true;
748 }
749 
LinkMethods(Class * klass,ClassInfo * classInfo,ClassLinkerErrorHandler * errorHandler)750 bool ClassLinker::LinkMethods(Class *klass, ClassInfo *classInfo,
751                               [[maybe_unused]] ClassLinkerErrorHandler *errorHandler)
752 {
753     classInfo->vtableBuilder->UpdateClass(klass);
754     if (!classInfo->itableBuilder->Resolve(klass)) {
755         return false;
756     }
757     classInfo->itableBuilder->UpdateClass(klass);
758     classInfo->imtableBuilder->UpdateClass(klass);
759     return true;
760 }
761 
LinkFields(Class * klass,ClassLinkerErrorHandler * errorHandler)762 bool ClassLinker::LinkFields(Class *klass, ClassLinkerErrorHandler *errorHandler)
763 {
764     if (!LayoutFields(klass, klass->GetStaticFields(), true, errorHandler)) {
765         LOG(ERROR, CLASS_LINKER) << "Cannot layout static fields of class '" << klass->GetName() << "'";
766         return false;
767     }
768 
769     if (!LayoutFields(klass, klass->GetInstanceFields(), false, errorHandler)) {
770         LOG(ERROR, CLASS_LINKER) << "Cannot layout instance fields of class '" << klass->GetName() << "'";
771         return false;
772     }
773 
774     return true;
775 }
776 
LoadBaseClass(panda_file::ClassDataAccessor * cda,const LanguageContext & ctx,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)777 Class *ClassLinker::LoadBaseClass(panda_file::ClassDataAccessor *cda, const LanguageContext &ctx,
778                                   ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler)
779 {
780     auto baseClassId = cda->GetSuperClassId();
781     auto *ext = GetExtension(ctx);
782     ASSERT(ext != nullptr);
783     if (baseClassId.GetOffset() == 0) {
784         return ext->GetClassRoot(ClassRoot::OBJECT);
785     }
786 
787     auto &pf = cda->GetPandaFile();
788     auto *baseClass = ext->GetClass(pf, baseClassId, context, errorHandler);
789     if (baseClass == nullptr) {
790         LOG(INFO, CLASS_LINKER) << "Cannot find base class '" << utf::Mutf8AsCString(pf.GetStringData(baseClassId).data)
791                                 << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
792                                 << "' in ctx " << context;
793         return nullptr;
794     }
795 
796     return baseClass;
797 }
798 
LoadInterfaces(panda_file::ClassDataAccessor * cda,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)799 std::optional<Span<Class *>> ClassLinker::LoadInterfaces(panda_file::ClassDataAccessor *cda,
800                                                          ClassLinkerContext *context,
801                                                          ClassLinkerErrorHandler *errorHandler)
802 {
803     ASSERT(context != nullptr);
804     size_t ifacesNum = cda->GetIfacesNumber();
805     if (ifacesNum == 0) {
806         return Span<Class *>(nullptr, ifacesNum);
807     }
808 
809     Span<Class *> ifaces {allocator_->AllocArray<Class *>(ifacesNum), ifacesNum};
810 
811     for (size_t i = 0; i < ifacesNum; i++) {
812         auto id = cda->GetInterfaceId(i);
813         auto &pf = cda->GetPandaFile();
814         auto *iface = GetClass(pf, id, context, errorHandler);
815         if (iface == nullptr) {
816             LOG(INFO, CLASS_LINKER) << "Cannot find interface '" << utf::Mutf8AsCString(pf.GetStringData(id).data)
817                                     << "' of class '" << utf::Mutf8AsCString(pf.GetStringData(cda->GetClassId()).data)
818                                     << "' in ctx " << context;
819             ASSERT(!ifaces.Empty());
820             allocator_->Free(ifaces.begin());
821             return {};
822         }
823 
824         ifaces[i] = iface;
825     }
826 
827     return ifaces;
828 }
829 
830 using ClassLoadingSet = std::unordered_set<uint64_t>;
831 
832 // This class is required to clear static unordered_set on return
833 class ClassScopeStaticSetAutoCleaner {
834 public:
835     ClassScopeStaticSetAutoCleaner() = default;
ClassScopeStaticSetAutoCleaner(ClassLoadingSet * setPtr,ClassLoadingSet ** tlSetPtr)836     explicit ClassScopeStaticSetAutoCleaner(ClassLoadingSet *setPtr, ClassLoadingSet **tlSetPtr)
837         : setPtr_(setPtr), tlSetPtr_(tlSetPtr)
838     {
839     }
~ClassScopeStaticSetAutoCleaner()840     ~ClassScopeStaticSetAutoCleaner()
841     {
842         setPtr_->clear();
843         if (tlSetPtr_ != nullptr) {
844             *tlSetPtr_ = nullptr;
845         }
846     }
847 
848     NO_COPY_SEMANTIC(ClassScopeStaticSetAutoCleaner);
849     NO_MOVE_SEMANTIC(ClassScopeStaticSetAutoCleaner);
850 
851 private:
852     ClassLoadingSet *setPtr_ {nullptr};
853     ClassLoadingSet **tlSetPtr_ {nullptr};
854 };
855 
GetClassUniqueHash(uint32_t pandaFileHash,uint32_t classId)856 static uint64_t GetClassUniqueHash(uint32_t pandaFileHash, uint32_t classId)
857 {
858     const uint8_t bitsToShuffle = 32;
859     return (static_cast<uint64_t>(pandaFileHash) << bitsToShuffle) | static_cast<uint64_t>(classId);
860 }
861 
LoadClass(panda_file::ClassDataAccessor * classDataAccessor,const uint8_t * descriptor,Class * baseClass,Span<Class * > interfaces,ClassLinkerContext * context,ClassLinkerExtension * ext,ClassLinkerErrorHandler * errorHandler)862 Class *ClassLinker::LoadClass(panda_file::ClassDataAccessor *classDataAccessor, const uint8_t *descriptor,
863                               Class *baseClass, Span<Class *> interfaces, ClassLinkerContext *context,
864                               ClassLinkerExtension *ext, ClassLinkerErrorHandler *errorHandler)
865 {
866     ASSERT(context != nullptr);
867     ClassInfo classInfo {};
868     if (!SetupClassInfo(classInfo, classDataAccessor, baseClass, interfaces, context, errorHandler)) {
869         return nullptr;
870     }
871 
872     auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
873                                    classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
874 
875     if (UNLIKELY(klass == nullptr)) {
876         return nullptr;
877     }
878 
879     klass->SetLoadContext(context);
880     klass->SetBase(baseClass);
881     klass->SetInterfaces(interfaces);
882     klass->SetFileId(classDataAccessor->GetClassId());
883     klass->SetPandaFile(&classDataAccessor->GetPandaFile());
884     klass->SetAccessFlags(classDataAccessor->GetAccessFlags());
885 
886     auto &pf = classDataAccessor->GetPandaFile();
887     auto classId = classDataAccessor->GetClassId();
888     klass->SetClassIndex(pf.GetClassIndex(classId));
889     klass->SetMethodIndex(pf.GetMethodIndex(classId));
890     klass->SetFieldIndex(pf.GetFieldIndex(classId));
891 
892     klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
893     klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
894     klass->SetNumStaticFields(classInfo.numSfields);
895 
896     auto const onFail = [this, descriptor, klass](std::string_view msg) {
897         FreeClass(klass);
898         LOG(ERROR, CLASS_LINKER) << msg << " '" << descriptor << "'";
899         return nullptr;
900     };
901     if (!LoadMethods(klass, &classInfo, classDataAccessor, errorHandler)) {
902         return onFail("Cannot load methods of class");
903     }
904     if (!LoadFields(klass, classDataAccessor, errorHandler)) {
905         return onFail("Cannot load fields of class");
906     }
907     if (!LinkMethods(klass, &classInfo, errorHandler)) {
908         return onFail("Cannot link methods of class");
909     }
910     if (!LinkFields(klass, errorHandler)) {
911         return onFail("Cannot link fields of class");
912     }
913     return klass;
914 }
915 
LoadClass(const panda_file::File * pf,const uint8_t * descriptor,panda_file::SourceLang lang)916 Class *ClassLinker::LoadClass(const panda_file::File *pf, const uint8_t *descriptor, panda_file::SourceLang lang)
917 {
918     panda_file::File::EntityId classId = pf->GetClassId(descriptor);
919     if (!classId.IsValid() || pf->IsExternal(classId)) {
920         return nullptr;
921     }
922     ClassLinkerContext *context = GetExtension(lang)->GetBootContext();
923     return LoadClass(pf, classId, descriptor, context, nullptr);
924 }
925 
OnError(ClassLinkerErrorHandler * errorHandler,ClassLinker::Error error,const PandaString & msg)926 static void OnError(ClassLinkerErrorHandler *errorHandler, ClassLinker::Error error, const PandaString &msg)
927 {
928     if (errorHandler != nullptr) {
929         errorHandler->OnError(error, msg);
930     }
931 }
932 
TryInsertClassLoading(panda_file::File::EntityId & classId,const panda_file::File * pf,panda_file::ClassDataAccessor & classDataAccessor,ClassLoadingSet * threadLocalSet,ClassLinkerErrorHandler * errorHandler)933 static bool TryInsertClassLoading(panda_file::File::EntityId &classId, const panda_file::File *pf,
934                                   panda_file::ClassDataAccessor &classDataAccessor, ClassLoadingSet *threadLocalSet,
935                                   ClassLinkerErrorHandler *errorHandler)
936 {
937     uint32_t classIdInt = classId.GetOffset();
938     uint32_t pandaFileHash = pf->GetFilenameHash();
939     if (!threadLocalSet->insert(GetClassUniqueHash(pandaFileHash, classIdInt)).second) {
940         const PandaString &className = utf::Mutf8AsCString(pf->GetStringData(classDataAccessor.GetClassId()).data);
941         PandaString msg = "Class or interface \"" + className + "\" is its own superclass or superinterface";
942         OnError(errorHandler, ClassLinker::Error::CLASS_CIRCULARITY, msg);
943         return false;
944     }
945 
946     return true;
947 }
948 
IsContextCanBeLoaded(ClassLinkerContext * context,panda_file::ClassDataAccessor & classDataAccessor,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)949 static bool IsContextCanBeLoaded(ClassLinkerContext *context, panda_file::ClassDataAccessor &classDataAccessor,
950                                  const uint8_t *descriptor, ClassLinkerErrorHandler *errorHandler)
951 {
952     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
953     if (ctx.GetLanguage() != context->GetSourceLang()) {
954         LanguageContext currentCtx = Runtime::GetCurrent()->GetLanguageContext(context->GetSourceLang());
955         PandaStringStream ss;
956         ss << "Cannot load " << ctx << " class " << descriptor << " into " << currentCtx << " context";
957         LOG(ERROR, CLASS_LINKER) << ss.str();
958         OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
959         return false;
960     }
961 
962     return true;
963 }
964 
HandleNoExtensionError(LanguageContext & ctx,const uint8_t * descriptor,ClassLinkerErrorHandler * errorHandler)965 static void HandleNoExtensionError(LanguageContext &ctx, const uint8_t *descriptor,
966                                    ClassLinkerErrorHandler *errorHandler)
967 {
968     PandaStringStream ss;
969     ss << "Cannot load class '" << descriptor << "' as class linker hasn't " << ctx << " language extension";
970     LOG(ERROR, CLASS_LINKER) << ss.str();
971     OnError(errorHandler, ClassLinker::Error::CLASS_NOT_FOUND, ss.str());
972 }
973 
LoadClass(const panda_file::File * pf,panda_file::File::EntityId classId,const uint8_t * descriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler,bool addToRuntime)974 Class *ClassLinker::LoadClass(const panda_file::File *pf, panda_file::File::EntityId classId, const uint8_t *descriptor,
975                               ClassLinkerContext *context, ClassLinkerErrorHandler *errorHandler,
976                               bool addToRuntime /* = true */)
977 {
978     ASSERT(!pf->IsExternal(classId));
979     ASSERT(context != nullptr);
980     panda_file::ClassDataAccessor classDataAccessor(*pf, classId);
981     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(&classDataAccessor);
982     if (!IsContextCanBeLoaded(context, classDataAccessor, descriptor, errorHandler)) {
983         return nullptr;
984     }
985 
986     if (!HasExtension(ctx)) {
987         HandleNoExtensionError(ctx, descriptor, errorHandler);
988         return nullptr;
989     }
990 
991     // This set is used to find out if the class is its own superclass
992     ClassLoadingSet loadingSet;
993     static thread_local ClassLoadingSet *threadLocalSet = nullptr;
994     ClassLoadingSet **threadLocalSetPtr = nullptr;
995     if (threadLocalSet == nullptr) {
996         threadLocalSet = &loadingSet;
997         threadLocalSetPtr = &threadLocalSet;
998     }
999     ClassScopeStaticSetAutoCleaner classSetAutoCleanerOnReturn(threadLocalSet, threadLocalSetPtr);
1000 
1001     auto *ext = GetExtension(ctx);
1002     Class *baseClass = nullptr;
1003     bool needLoadBase = IsInitialized() || !utf::IsEqual(ctx.GetObjectClassDescriptor(), descriptor);
1004     if (needLoadBase) {
1005         if (!TryInsertClassLoading(classId, pf, classDataAccessor, threadLocalSet, errorHandler)) {
1006             return nullptr;
1007         }
1008 
1009         baseClass = LoadBaseClass(&classDataAccessor, ctx, context, errorHandler);
1010         if (baseClass == nullptr) {
1011             LOG(INFO, CLASS_LINKER) << "Cannot load base class of class '" << descriptor << "'";
1012             return nullptr;
1013         }
1014     }
1015 
1016     auto res = LoadInterfaces(&classDataAccessor, context, errorHandler);
1017     if (!res) {
1018         LOG(INFO, CLASS_LINKER) << "Cannot load interfaces of class '" << descriptor << "'";
1019         return nullptr;
1020     }
1021 
1022     auto *klass = LoadClass(&classDataAccessor, descriptor, baseClass, res.value(), context, ext, errorHandler);
1023     if (klass == nullptr) {
1024         return nullptr;
1025     }
1026 
1027     Runtime::GetCurrent()->GetCha()->Update(klass);
1028 
1029     if (LIKELY(ext->CanInitializeClasses())) {
1030         if (!ext->InitializeClass(klass)) {
1031             LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1032             FreeClass(klass);
1033             return nullptr;
1034         }
1035         klass->SetState(Class::State::LOADED);
1036     }
1037 
1038     if (LIKELY(addToRuntime)) {
1039         Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1040 
1041         auto *otherKlass = context->InsertClass(klass);
1042         if (otherKlass != nullptr) {
1043             // Someone has created the class in the other thread (increase the critical section?)
1044             FreeClass(klass);
1045             return otherKlass;
1046         }
1047 
1048         RemoveCreatedClassInExtension(klass);
1049         Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1050     }
1051     return klass;
1052 }
1053 
CopyMutf8String(mem::InternalAllocatorPtr allocator,const uint8_t * descriptor)1054 static const uint8_t *CopyMutf8String(mem::InternalAllocatorPtr allocator, const uint8_t *descriptor)
1055 {
1056     size_t size = utf::Mutf8Size(descriptor) + 1;  // + 1 - null terminate
1057     auto *ptr = allocator->AllocArray<uint8_t>(size);
1058     memcpy_s(ptr, size, descriptor, size);
1059     return ptr;
1060 }
1061 
LinkEntitiesAndInitClass(Class * klass,ClassInfo * classInfo,ClassLinkerExtension * ext,const uint8_t * descriptor)1062 bool ClassLinker::LinkEntitiesAndInitClass(Class *klass, ClassInfo *classInfo, ClassLinkerExtension *ext,
1063                                            const uint8_t *descriptor)
1064 {
1065     if (!LinkMethods(klass, classInfo, ext->GetErrorHandler())) {
1066         LOG(ERROR, CLASS_LINKER) << "Cannot link class methods '" << descriptor << "'";
1067         return false;
1068     }
1069 
1070     if (!LinkFields(klass, ext->GetErrorHandler())) {
1071         LOG(ERROR, CLASS_LINKER) << "Cannot link class fields '" << descriptor << "'";
1072         return false;
1073     }
1074 
1075     if (!ext->InitializeClass(klass)) {
1076         LOG(ERROR, CLASS_LINKER) << "Language specific initialization for class '" << descriptor << "' failed";
1077         FreeClass(klass);
1078         return false;
1079     }
1080 
1081     return true;
1082 }
1083 
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)1084 Class *ClassLinker::BuildClass(const uint8_t *descriptor, bool needCopyDescriptor, uint32_t accessFlags,
1085                                Span<Method> methods, Span<Field> fields, Class *baseClass, Span<Class *> interfaces,
1086                                ClassLinkerContext *context, bool isInterface)
1087 {
1088     ASSERT(context != nullptr);
1089     if (needCopyDescriptor) {
1090         descriptor = CopyMutf8String(allocator_, descriptor);
1091         os::memory::LockHolder lock(copiedNamesLock_);
1092         copiedNames_.push_front(descriptor);
1093     }
1094 
1095     auto *ext = GetExtension(baseClass->GetSourceLang());
1096     ASSERT(ext != nullptr);
1097 
1098     ClassInfo classInfo {};
1099     if (!SetupClassInfo(classInfo, methods, fields, baseClass, interfaces, isInterface, nullptr)) {
1100         return nullptr;
1101     }
1102 
1103     // Need to protect ArenaAllocator and loaded_classes_
1104     auto *klass = ext->CreateClass(descriptor, classInfo.vtableBuilder->GetVTableSize(),
1105                                    classInfo.imtableBuilder->GetIMTSize(), classInfo.size);
1106 
1107     if (UNLIKELY(klass == nullptr)) {
1108         return nullptr;
1109     }
1110 
1111     klass->SetLoadContext(context);
1112     klass->SetBase(baseClass);
1113     klass->SetInterfaces(interfaces);
1114     klass->SetAccessFlags(accessFlags);
1115 
1116     klass->SetNumVirtualMethods(classInfo.vtableBuilder->GetNumVirtualMethods());
1117     klass->SetNumCopiedMethods(classInfo.vtableBuilder->GetCopiedMethods().size());
1118     klass->SetNumStaticFields(classInfo.numSfields);
1119 
1120     ASSERT(klass->GetNumCopiedMethods() == 0);
1121 
1122     size_t numSmethods = methods.size() - klass->GetNumVirtualMethods();
1123     klass->SetMethods(methods, klass->GetNumVirtualMethods(), numSmethods);
1124     klass->SetFields(fields, klass->GetNumStaticFields());
1125 
1126     for (auto &method : methods) {
1127         method.SetClass(klass);
1128     }
1129 
1130     for (auto &field : fields) {
1131         field.SetClass(klass);
1132     }
1133 
1134     if (!LinkEntitiesAndInitClass(klass, &classInfo, ext, descriptor)) {
1135         return nullptr;
1136     }
1137 
1138     klass->SetState(Class::State::LOADED);
1139 
1140     Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(klass);
1141 
1142     auto *otherKlass = context->InsertClass(klass);
1143     if (otherKlass != nullptr) {
1144         // Someone has created the class in the other thread (increase the critical section?)
1145         FreeClass(klass);
1146         return otherKlass;
1147     }
1148 
1149     RemoveCreatedClassInExtension(klass);
1150     Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(klass);
1151 
1152     return klass;
1153 }
1154 
CreateArrayClass(ClassLinkerExtension * ext,const uint8_t * descriptor,bool needCopyDescriptor,Class * componentClass)1155 Class *ClassLinker::CreateArrayClass(ClassLinkerExtension *ext, const uint8_t *descriptor, bool needCopyDescriptor,
1156                                      Class *componentClass)
1157 {
1158     if (needCopyDescriptor) {
1159         descriptor = CopyMutf8String(allocator_, descriptor);
1160         os::memory::LockHolder lock(copiedNamesLock_);
1161         copiedNames_.push_front(descriptor);
1162     }
1163 
1164     auto *arrayClass = ext->CreateClass(descriptor, ext->GetArrayClassVTableSize(), ext->GetArrayClassIMTSize(),
1165                                         ext->GetArrayClassSize());
1166 
1167     if (UNLIKELY(arrayClass == nullptr)) {
1168         return nullptr;
1169     }
1170 
1171     arrayClass->SetLoadContext(componentClass->GetLoadContext());
1172 
1173     if (UNLIKELY(!ext->InitializeArrayClass(arrayClass, componentClass))) {
1174         return nullptr;
1175     }
1176 
1177     return arrayClass;
1178 }
1179 
LoadArrayClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1180 Class *ClassLinker::LoadArrayClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1181                                    ClassLinkerErrorHandler *errorHandler)
1182 {
1183     Span<const uint8_t> sp(descriptor, 1);
1184 
1185     Class *componentClass = GetClass(sp.cend(), needCopyDescriptor, context, errorHandler);
1186 
1187     if (componentClass == nullptr) {
1188         return nullptr;
1189     }
1190 
1191     if (UNLIKELY(componentClass->GetType().GetId() == panda_file::Type::TypeId::VOID)) {
1192         OnError(errorHandler, Error::NO_CLASS_DEF, "Try to create array with void component type");
1193         return nullptr;
1194     }
1195 
1196     auto *ext = GetExtension(componentClass->GetSourceLang());
1197     ASSERT(ext != nullptr);
1198 
1199     auto *componentClassContext = componentClass->GetLoadContext();
1200     ASSERT(componentClassContext != nullptr);
1201     if (componentClassContext != context) {
1202         auto *loadedClass = FindLoadedClass(descriptor, componentClassContext);
1203         if (loadedClass != nullptr) {
1204             return loadedClass;
1205         }
1206     }
1207 
1208     auto *arrayClass = CreateArrayClass(ext, descriptor, needCopyDescriptor, componentClass);
1209 
1210     if (UNLIKELY(arrayClass == nullptr)) {
1211         return nullptr;
1212     }
1213 
1214     Runtime::GetCurrent()->GetNotificationManager()->ClassLoadEvent(arrayClass);
1215 
1216     auto *otherKlass = componentClassContext->InsertClass(arrayClass);
1217     if (otherKlass != nullptr) {
1218         FreeClass(arrayClass);
1219         return otherKlass;
1220     }
1221 
1222     RemoveCreatedClassInExtension(arrayClass);
1223     Runtime::GetCurrent()->GetNotificationManager()->ClassPrepareEvent(arrayClass);
1224 
1225     return arrayClass;
1226 }
1227 
PandaFilesToString(const PandaVector<const panda_file::File * > & pandaFiles)1228 static PandaString PandaFilesToString(const PandaVector<const panda_file::File *> &pandaFiles)
1229 {
1230     PandaStringStream ss;
1231     ss << "[";
1232 
1233     size_t n = pandaFiles.size();
1234     for (size_t i = 0; i < n; i++) {
1235         ss << pandaFiles[i]->GetFilename();
1236 
1237         if (i < n - 1) {
1238             ss << ", ";
1239         }
1240     }
1241 
1242     ss << "]";
1243     return ss.str();
1244 }
1245 
GetClass(const uint8_t * descriptor,bool needCopyDescriptor,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1246 Class *ClassLinker::GetClass(const uint8_t *descriptor, bool needCopyDescriptor, ClassLinkerContext *context,
1247                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1248 {
1249     ASSERT(context != nullptr);
1250     ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1251            !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1252 
1253     Class *cls = FindLoadedClass(descriptor, context);
1254     if (cls != nullptr) {
1255         return cls;
1256     }
1257 
1258     if (ClassHelper::IsArrayDescriptor(descriptor)) {
1259         return LoadArrayClass(descriptor, needCopyDescriptor, context, errorHandler);
1260     }
1261 
1262     if (context->IsBootContext()) {
1263         panda_file::File::EntityId classId;
1264         const panda_file::File *pandaFile {nullptr};
1265         {
1266             {
1267                 os::memory::LockHolder lock {bootPandaFilesLock_};
1268                 std::tie(classId, pandaFile) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1269             }
1270 
1271             if (!classId.IsValid()) {
1272                 PandaStringStream ss;
1273                 {
1274                     // can't make a wider scope for lock here - will get recursion
1275                     os::memory::LockHolder lock {bootPandaFilesLock_};
1276                     ss << "Cannot find class " << descriptor
1277                        << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1278                 }
1279                 OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1280                 return nullptr;
1281             }
1282         }
1283 
1284         return LoadClass(pandaFile, classId, pandaFile->GetStringData(classId).data, context, errorHandler);
1285     }
1286 
1287     return context->LoadClass(descriptor, needCopyDescriptor, errorHandler);
1288 }
1289 
GetClass(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1290 Class *ClassLinker::GetClass(const panda_file::File &pf, panda_file::File::EntityId id, ClassLinkerContext *context,
1291                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1292 {
1293     ASSERT(context != nullptr);
1294     ASSERT(!MTManagedThread::ThreadIsMTManagedThread(Thread::GetCurrent()) ||
1295            !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
1296 
1297     Class *cls = pf.GetPandaCache()->GetClassFromCache(id);
1298     if (cls != nullptr) {
1299         return cls;
1300     }
1301     const uint8_t *descriptor = pf.GetStringData(id).data;
1302 
1303     cls = FindLoadedClass(descriptor, context);
1304     if (cls != nullptr) {
1305         pf.GetPandaCache()->SetClassCache(id, cls);
1306         return cls;
1307     }
1308 
1309     if (ClassHelper::IsArrayDescriptor(descriptor)) {
1310         cls = LoadArrayClass(descriptor, false, context, errorHandler);
1311         if (LIKELY(cls != nullptr)) {
1312             pf.GetPandaCache()->SetClassCache(id, cls);
1313         }
1314         return cls;
1315     }
1316 
1317     if (context->IsBootContext()) {
1318         const panda_file::File *pfPtr = nullptr;
1319         panda_file::File::EntityId extId;
1320         {
1321             os::memory::LockHolder lock {bootPandaFilesLock_};
1322             std::tie(extId, pfPtr) = FindClassInPandaFiles(descriptor, bootPandaFiles_);
1323         }
1324 
1325         if (!extId.IsValid()) {
1326             PandaStringStream ss;
1327             {
1328                 // can't make a wider scope for lock here - will get recursion
1329                 os::memory::LockHolder lock {bootPandaFilesLock_};
1330                 ss << "Cannot find class " << descriptor
1331                    << " in boot panda files: " << PandaFilesToString(bootPandaFiles_);
1332             }
1333             OnError(errorHandler, Error::CLASS_NOT_FOUND, ss.str());
1334             return nullptr;
1335         }
1336 
1337         cls = LoadClass(pfPtr, extId, descriptor, context, errorHandler);
1338         if (LIKELY(cls != nullptr)) {
1339             pf.GetPandaCache()->SetClassCache(id, cls);
1340         }
1341         return cls;
1342     }
1343 
1344     return context->LoadClass(descriptor, false, errorHandler);
1345 }
1346 
GetMethod(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1347 Method *ClassLinker::GetMethod(const panda_file::File &pf, panda_file::File::EntityId id,
1348                                ClassLinkerContext *context /* = nullptr */,
1349                                ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1350 {
1351     Method *method = pf.GetPandaCache()->GetMethodFromCache(id);
1352     if (method != nullptr) {
1353         return method;
1354     }
1355     panda_file::MethodDataAccessor methodDataAccessor(pf, id);
1356 
1357     auto classId = methodDataAccessor.GetClassId();
1358     if (context == nullptr) {
1359         panda_file::ClassDataAccessor classDataAccessor(pf, classId);
1360         auto lang = classDataAccessor.GetSourceLang();
1361         if (!lang) {
1362             LOG(INFO, CLASS_LINKER) << "Cannot resolve language context for class_id " << classId << " in file "
1363                                     << pf.GetFilename();
1364             return nullptr;
1365         }
1366         auto *extension = GetExtension(lang.value());
1367         context = extension->GetBootContext();
1368     }
1369 
1370     Class *klass = GetClass(pf, classId, context, errorHandler);
1371 
1372     if (klass == nullptr) {
1373         auto className = pf.GetStringData(classId).data;
1374         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1375         return nullptr;
1376     }
1377     method = GetMethod(klass, methodDataAccessor, errorHandler);
1378     if (LIKELY(method != nullptr)) {
1379         pf.GetPandaCache()->SetMethodCache(id, method);
1380     }
1381     return method;
1382 }
1383 
GetMethod(const Method & caller,panda_file::File::EntityId id,ClassLinkerErrorHandler * errorHandler)1384 Method *ClassLinker::GetMethod(const Method &caller, panda_file::File::EntityId id,
1385                                ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1386 {
1387     auto *pf = caller.GetPandaFile();
1388     Method *method = pf->GetPandaCache()->GetMethodFromCache(id);
1389     if (method != nullptr) {
1390         return method;
1391     }
1392 
1393     panda_file::MethodDataAccessor methodDataAccessor(*pf, id);
1394     auto classId = methodDataAccessor.GetClassId();
1395 
1396     auto *context = caller.GetClass()->GetLoadContext();
1397     auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1398     Class *klass = ext->GetClass(*pf, classId, context, errorHandler);
1399 
1400     if (klass == nullptr) {
1401         auto className = pf->GetStringData(classId).data;
1402         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1403         return nullptr;
1404     }
1405 
1406     method = GetMethod(klass, methodDataAccessor, (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1407     if (LIKELY(method != nullptr)) {
1408         pf->GetPandaCache()->SetMethodCache(id, method);
1409     }
1410     return method;
1411 }
1412 
GetMethod(const Class * klass,const panda_file::MethodDataAccessor & methodDataAccessor,ClassLinkerErrorHandler * errorHandler)1413 Method *ClassLinker::GetMethod(const Class *klass, const panda_file::MethodDataAccessor &methodDataAccessor,
1414                                ClassLinkerErrorHandler *errorHandler)
1415 {
1416     Method *method;
1417     auto id = methodDataAccessor.GetMethodId();
1418     const auto &pf = methodDataAccessor.GetPandaFile();
1419 
1420     bool isStatic = methodDataAccessor.IsStatic();
1421     if (!methodDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1422         if (klass->IsInterface()) {
1423             method = isStatic ? klass->GetStaticInterfaceMethod(id) : klass->GetVirtualInterfaceMethod(id);
1424         } else {
1425             method = isStatic ? klass->GetStaticClassMethod(id) : klass->GetVirtualClassMethod(id);
1426         }
1427 
1428         if (method == nullptr) {
1429             Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1430             PandaStringStream ss;
1431             ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1432                << "' in class '" << klass->GetName() << "'";
1433             OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1434             return nullptr;
1435         }
1436 
1437         return method;
1438     }
1439 
1440     auto name = methodDataAccessor.GetName();
1441     Method::Proto proto(pf, methodDataAccessor.GetProtoId());
1442     if (klass->IsInterface()) {
1443         method = isStatic ? klass->GetStaticInterfaceMethodByName(name, proto)
1444                           : klass->GetVirtualInterfaceMethodByName(name, proto);
1445     } else {
1446         method =
1447             isStatic ? klass->GetStaticClassMethodByName(name, proto) : klass->GetVirtualClassMethodByName(name, proto);
1448         if (method == nullptr && klass->IsAbstract()) {
1449             method = klass->GetInterfaceMethod(name, proto);
1450         }
1451     }
1452 
1453     if (method == nullptr) {
1454         PandaStringStream ss;
1455         ss << "Cannot find method '" << methodDataAccessor.GetName().data << " " << proto.GetSignature(true)
1456            << "' in class '" << klass->GetName() << "'";
1457         OnError(errorHandler, Error::METHOD_NOT_FOUND, ss.str());
1458         return nullptr;
1459     }
1460 
1461     LOG_IF(method->IsStatic() != methodDataAccessor.IsStatic(), FATAL, CLASS_LINKER)
1462         << "Expected ACC_STATIC for method " << name.data << " in class " << klass->GetName()
1463         << " does not match loaded value";
1464 
1465     return method;
1466 }
1467 
GetFieldById(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler)1468 Field *ClassLinker::GetFieldById(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1469                                  ClassLinkerErrorHandler *errorHandler)
1470 {
1471     bool isStatic = fieldDataAccessor.IsStatic();
1472     auto &pf = fieldDataAccessor.GetPandaFile();
1473     auto id = fieldDataAccessor.GetFieldId();
1474 
1475     Field *field = isStatic ? klass->FindStaticFieldById(id) : klass->FindInstanceFieldById(id);
1476 
1477     if (field == nullptr) {
1478         PandaStringStream ss;
1479         ss << "Cannot find field '" << pf.GetStringData(fieldDataAccessor.GetNameId()).data << "' in class '"
1480            << klass->GetName() << "'";
1481         OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1482         return nullptr;
1483     }
1484 
1485     pf.GetPandaCache()->SetFieldCache(id, field);
1486     return field;
1487 }
1488 
GetFieldBySignature(Class * klass,const panda_file::FieldDataAccessor & fieldDataAccessor,ClassLinkerErrorHandler * errorHandler)1489 Field *ClassLinker::GetFieldBySignature(Class *klass, const panda_file::FieldDataAccessor &fieldDataAccessor,
1490                                         ClassLinkerErrorHandler *errorHandler)
1491 {
1492     auto &pf = fieldDataAccessor.GetPandaFile();
1493     auto id = fieldDataAccessor.GetFieldId();
1494     auto fieldName = pf.GetStringData(fieldDataAccessor.GetNameId());
1495     auto fieldType = panda_file::Type::GetTypeFromFieldEncoding(fieldDataAccessor.GetType());
1496     Field *field = klass->FindField([&fieldDataAccessor, &fieldType, &fieldName, &id, &pf](const Field &fld) {
1497         if (fieldType == fld.GetType() && fieldName == fld.GetName()) {
1498             if (!fieldType.IsReference()) {
1499                 return true;
1500             }
1501 
1502             // compare field class type
1503             if (&pf == fld.GetPandaFile() && id == fld.GetFileId()) {
1504                 return true;
1505             }
1506             auto typeId = panda_file::FieldDataAccessor::GetTypeId(*fld.GetPandaFile(), fld.GetFileId());
1507             if (pf.GetStringData(panda_file::File::EntityId(fieldDataAccessor.GetType())) ==
1508                 fld.GetPandaFile()->GetStringData(typeId)) {
1509                 return true;
1510             }
1511         }
1512         return false;
1513     });
1514 
1515     if (field == nullptr) {
1516         PandaStringStream ss;
1517         ss << "Cannot find field '" << fieldName.data << "' in class '" << klass->GetName() << "'";
1518         OnError(errorHandler, Error::FIELD_NOT_FOUND, ss.str());
1519         return nullptr;
1520     }
1521 
1522     pf.GetPandaCache()->SetFieldCache(id, field);
1523     return field;
1524 }
1525 
GetField(const panda_file::File & pf,panda_file::File::EntityId id,ClassLinkerContext * context,ClassLinkerErrorHandler * errorHandler)1526 Field *ClassLinker::GetField(const panda_file::File &pf, panda_file::File::EntityId id,
1527                              ClassLinkerContext *context /* = nullptr */,
1528                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1529 {
1530     Field *field = pf.GetPandaCache()->GetFieldFromCache(id);
1531     if (field != nullptr) {
1532         return field;
1533     }
1534     panda_file::FieldDataAccessor fieldDataAccessor(pf, id);
1535 
1536     Class *klass = GetClass(pf, fieldDataAccessor.GetClassId(), context, errorHandler);
1537 
1538     if (klass == nullptr) {
1539         auto className = pf.GetStringData(fieldDataAccessor.GetClassId()).data;
1540         LOG(INFO, CLASS_LINKER) << "Cannot find class '" << className << "' in ctx " << context;
1541         return nullptr;
1542     }
1543 
1544     if (!fieldDataAccessor.IsExternal() && klass->GetPandaFile() == &pf) {
1545         field = GetFieldById(klass, fieldDataAccessor, errorHandler);
1546     } else {
1547         field = GetFieldBySignature(klass, fieldDataAccessor, errorHandler);
1548     }
1549     return field;
1550 }
1551 
InitializeClass(ManagedThread * thread,Class * klass)1552 bool ClassLinker::InitializeClass(ManagedThread *thread, Class *klass)
1553 {
1554     ASSERT(klass != nullptr);
1555     if (klass->IsInitialized()) {
1556         return true;
1557     }
1558 
1559     LanguageContext ctx = Runtime::GetCurrent()->GetLanguageContext(*klass);
1560     return ctx.InitializeClass(this, thread, klass);
1561 }
1562 
NumLoadedClasses()1563 size_t ClassLinker::NumLoadedClasses()
1564 {
1565     size_t sum = 0;
1566 
1567     for (auto &ext : extensions_) {
1568         if (ext == nullptr) {
1569             continue;
1570         }
1571 
1572         sum += ext->NumLoadedClasses();
1573     }
1574 
1575     return sum;
1576 }
1577 
VisitLoadedClasses(size_t flag)1578 void ClassLinker::VisitLoadedClasses(size_t flag)
1579 {
1580     for (auto &ext : extensions_) {
1581         if (ext == nullptr) {
1582             continue;
1583         }
1584         ext->VisitLoadedClasses(flag);
1585     }
1586 }
1587 
GetField(const Method & caller,panda_file::File::EntityId id,ClassLinkerErrorHandler * errorHandler)1588 Field *ClassLinker::GetField(const Method &caller, panda_file::File::EntityId id,
1589                              ClassLinkerErrorHandler *errorHandler /* = nullptr */)
1590 {
1591     Field *field = caller.GetPandaFile()->GetPandaCache()->GetFieldFromCache(id);
1592     if (field != nullptr) {
1593         return field;
1594     }
1595     auto *ext = GetExtension(caller.GetClass()->GetSourceLang());
1596     field = GetField(*caller.GetPandaFile(), id, caller.GetClass()->GetLoadContext(),
1597                      (errorHandler == nullptr) ? ext->GetErrorHandler() : errorHandler);
1598     if (LIKELY(field != nullptr)) {
1599         caller.GetPandaFile()->GetPandaCache()->SetFieldCache(id, field);
1600     }
1601     return field;
1602 }
1603 
RemoveCreatedClassInExtension(Class * klass)1604 void ClassLinker::RemoveCreatedClassInExtension(Class *klass)
1605 {
1606     if (klass == nullptr) {
1607         return;
1608     }
1609     auto ext = GetExtension(klass->GetSourceLang());
1610     if (ext != nullptr) {
1611         ext->OnClassPrepared(klass);
1612     }
1613 }
1614 
1615 }  // namespace ark
1616