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