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