• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "class_hierarchy.h"
17 #include <iostream>
18 #include <fstream>
19 #include "option.h"
20 
21 // Class Hierarchy Analysis
22 // This phase is a foundation phase of compilation. This phase build
23 // the class hierarchy for both this module and all modules it depends
24 // on. So many phases rely on this phase's analysis result, such as
25 // call graph, ssa and so on.
26 // The main procedure shows as following.
27 // A. Based on the information read from mplts, it collects all class that
28 //    declared in modules. And creates a Klass for each class.
29 // B. Fill class method info. Connect superclass<->subclass and
30 //    interface->implementation edges.
31 // C. Tag All Throwable class and its child class.
32 // D. In the case of "class C implements B; interface B extends A;",
33 //    we need to add a link between C and A. So we recursively traverse
34 //    Klass and collect all interfaces it implements.
35 // E. Topological Sort
36 // F. Based on Topological Sort Order, for each virtual method in a class,
37 //    we collect all its potential implementation. If the number of
38 //    potential implementations is 1, it means all virtual calls to this
39 //    method can be easily devirtualized.
40 namespace maple {
41 bool KlassHierarchy::traceFlag = false;
42 
IsSystemPreloadedClass(const std::string & className)43 bool IsSystemPreloadedClass(const std::string &className)
44 {
45     return false;
46 }
47 
Klass(MIRStructType * type,MapleAllocator * alc)48 Klass::Klass(MIRStructType *type, MapleAllocator *alc)
49     : structType(type),
50       alloc(alc),
51       superKlasses(alloc->Adapter()),
52       subKlasses(alloc->Adapter()),
53       implKlasses(alloc->Adapter()),
54       implInterfaces(alloc->Adapter()),
55       methods(alloc->Adapter()),
56       strIdx2Method(alloc->Adapter()),
57       strIdx2CandidateMap(alloc->Adapter())
58 {
59     DEBUG_ASSERT(type != nullptr, "type is nullptr in Klass::Klass!");
60     DEBUG_ASSERT(type->GetKind() == kTypeClass || type->GetKind() == kTypeInterface || type->IsIncomplete(),
61                  "runtime check error");
62 }
63 
DumpKlassMethods() const64 void Klass::DumpKlassMethods() const
65 {
66     if (methods.empty()) {
67         return;
68     }
69     LogInfo::MapleLogger() << "   class member methods:\n";
70     for (MIRFunction *method : methods) {
71         LogInfo::MapleLogger() << "   \t" << method->GetName() << " , ";
72         method->GetFuncSymbol()->GetAttrs().DumpAttributes();
73         LogInfo::MapleLogger() << "\n";
74     }
75     for (const auto &m2cPair : strIdx2CandidateMap) {
76         LogInfo::MapleLogger() << "   \t" << GlobalTables::GetStrTable().GetStringFromStrIdx(m2cPair.first)
77                                << "   , # of target:" << m2cPair.second->size() << "\n";
78     }
79 }
80 
DumpKlassImplKlasses() const81 void Klass::DumpKlassImplKlasses() const
82 {
83     if (implKlasses.empty()) {
84         return;
85     }
86     LogInfo::MapleLogger() << "  implemented by:\n";
87     for (Klass *implKlass : implKlasses) {
88         LogInfo::MapleLogger() << "   \t@implbyclass_idx " << implKlass->structType->GetTypeIndex() << "\n";
89     }
90 }
91 
DumpKlassImplInterfaces() const92 void Klass::DumpKlassImplInterfaces() const
93 {
94     if (implInterfaces.empty()) {
95         return;
96     }
97     LogInfo::MapleLogger() << "  implements:\n";
98     for (Klass *interface : implInterfaces) {
99         LogInfo::MapleLogger() << "   \t@implinterface_idx " << interface->structType->GetTypeIndex() << "\n";
100     }
101 }
102 
DumpKlassSuperKlasses() const103 void Klass::DumpKlassSuperKlasses() const
104 {
105     if (superKlasses.empty()) {
106         return;
107     }
108     LogInfo::MapleLogger() << "   superclasses:\n";
109     for (Klass *superKlass : superKlasses) {
110         LogInfo::MapleLogger() << "   \t@superclass_idx " << superKlass->structType->GetTypeIndex() << "\n";
111     }
112 }
113 
DumpKlassSubKlasses() const114 void Klass::DumpKlassSubKlasses() const
115 {
116     if (subKlasses.empty()) {
117         return;
118     }
119     LogInfo::MapleLogger() << "   subclasses:\n";
120     for (Klass *subKlass : subKlasses) {
121         LogInfo::MapleLogger() << "   \t@subclass_idx " << subKlass->structType->GetTypeIndex() << "\n";
122     }
123 }
124 
Dump() const125 void Klass::Dump() const
126 {
127     // Dump detailed class info
128     LogInfo::MapleLogger() << "class \" " << GetKlassName() << " \" @class_id " << structType->GetTypeIndex() << "\n";
129     DumpKlassSuperKlasses();
130     DumpKlassSubKlasses();
131     DumpKlassImplInterfaces();
132     DumpKlassImplKlasses();
133     DumpKlassMethods();
134 }
135 
GetClosestMethod(GStrIdx funcName) const136 MIRFunction *Klass::GetClosestMethod(GStrIdx funcName) const
137 {
138     MapleVector<MIRFunction *> *cands = GetCandidates(funcName);
139     if (cands != nullptr && !cands->empty()) {
140         return cands->at(0);
141     }
142     return nullptr;
143 }
144 
DelMethod(const MIRFunction & func)145 void Klass::DelMethod(const MIRFunction &func)
146 {
147     if (GetMethod(func.GetBaseFuncNameWithTypeStrIdx()) == &func) {
148         strIdx2Method.erase(func.GetBaseFuncNameWithTypeStrIdx());
149     }
150     for (auto it = methods.begin(); it != methods.end(); ++it) {
151         if (*it == &func) {
152             methods.erase(it--);
153             return;
154         }
155     }
156 }
157 
158 // This for class only, which only has 0 or 1 super class
GetSuperKlass() const159 Klass *Klass::GetSuperKlass() const
160 {
161     switch (superKlasses.size()) {
162         case 0:
163             return nullptr;
164         case 1:
165             return *superKlasses.begin();
166         default:
167             LogInfo::MapleLogger() << GetKlassName() << "\n";
168             CHECK_FATAL(false, "GetSuperKlass expects less than one super class");
169     }
170 }
171 
IsKlassMethod(const MIRFunction * func) const172 bool Klass::IsKlassMethod(const MIRFunction *func) const
173 {
174     if (func == nullptr) {
175         return false;
176     }
177     for (MIRFunction *method : methods) {
178         if (method == func) {
179             return true;
180         }
181     }
182     return false;
183 }
184 
ImplementsKlass() const185 bool Klass::ImplementsKlass() const
186 {
187     if (IsInterface() || IsInterfaceIncomplete()) {
188         return false;
189     }
190     MIRClassType *classType = GetMIRClassType();
191     DEBUG_ASSERT(classType != nullptr, "null ptr check");
192     return (!classType->GetInterfaceImplemented().empty());
193 }
194 
GetCandidates(GStrIdx mnameNoklassStrIdx) const195 MapleVector<MIRFunction *> *Klass::GetCandidates(GStrIdx mnameNoklassStrIdx) const
196 {
197     auto it = strIdx2CandidateMap.find(mnameNoklassStrIdx);
198     return ((it != strIdx2CandidateMap.end()) ? (it->second) : nullptr);
199 }
200 
GetUniqueMethod(GStrIdx mnameNoklassStrIdx) const201 MIRFunction *Klass::GetUniqueMethod(GStrIdx mnameNoklassStrIdx) const
202 {
203     if (structType->IsIncomplete()) {
204         return nullptr;
205     }
206     auto it = strIdx2CandidateMap.find(mnameNoklassStrIdx);
207     if (it != strIdx2CandidateMap.end()) {
208         MapleVector<MIRFunction *> *fv = it->second;
209         if (fv != nullptr && fv->size() == 1) {
210             return fv->at(0);
211         }
212     }
213     return nullptr;
214 }
215 
IsVirtualMethod(const MIRFunction & func) const216 bool Klass::IsVirtualMethod(const MIRFunction &func) const
217 {
218     // May add other checking conditions in future
219     return (func.GetAttr(FUNCATTR_virtual) && !func.GetAttr(FUNCATTR_private) && !func.GetAttr(FUNCATTR_abstract));
220 }
221 
CountVirtMethTopDown(const KlassHierarchy & kh)222 void Klass::CountVirtMethTopDown(const KlassHierarchy &kh)
223 {
224     MapleVector<MIRFunction *> *vec, *pvec;
225     GStrIdx strIdx;
226     auto *superAndImplClasses = alloc->GetMemPool()->New<MapleVector<Klass *>>(alloc->Adapter());
227     // Add default methods of interface. Add them first because they have lowest
228     // priorities compared with methods defined in classes
229     if (IsClass() || IsClassIncomplete()) {
230         for (TyIdx tyIdx : GetMIRClassType()->GetInterfaceImplemented()) {
231             Klass *interface = kh.GetKlassFromTyIdx(tyIdx);
232             if (interface != nullptr) {
233                 superAndImplClasses->push_back(interface);
234             }
235         }
236     }
237 
238     // Then add methods from superclasses
239     for (Klass *superKlass : superKlasses) {
240         superAndImplClasses->push_back(superKlass);
241     }
242     // Initialize strIdx2CandidateMap based on the superclass methods
243     for (Klass *superAndImplClass : *superAndImplClasses) {
244         DEBUG_ASSERT(superAndImplClass != nullptr, "Not a valid super class of interface");
245         for (const auto &pair : superAndImplClass->strIdx2CandidateMap) {
246             strIdx = pair.first;
247             pvec = pair.second;
248             DEBUG_ASSERT(pvec->size() == 1, "Expect exactly one method definition from parent class");
249             if (strIdx2CandidateMap.find(strIdx) == strIdx2CandidateMap.end()) {
250                 vec = alloc->GetMemPool()->New<MapleVector<MIRFunction *>>(alloc->Adapter());
251                 vec->push_back(pvec->at(0));
252                 strIdx2CandidateMap[strIdx] = vec;
253             } else {
254                 // Override the method coming from previous klass (must be an interface)
255                 DEBUG_ASSERT(strIdx2CandidateMap[strIdx]->size() == 1, "Expect exactly one method definition");
256                 DEBUG_ASSERT(
257                     kh.GetKlassFromStrIdx(strIdx2CandidateMap[strIdx]->at(0)->GetBaseClassNameStrIdx())->IsInterface(),
258                     "Override interface default methods");
259                 // Interfaces implemented methods override, need to determine the inherit relation.
260                 // class method can override interface method, interface method can override its parent's methods
261                 vec = strIdx2CandidateMap[strIdx];
262                 DEBUG_ASSERT(vec != nullptr, "nullptr check!");
263                 DEBUG_ASSERT(vec->size() == 1, "Expect exactly one method definition from parent class");
264                 Klass *parentKlass = kh.GetKlassFromFunc((*vec)[0]);
265                 Klass *childKlass = kh.GetKlassFromFunc((*pvec)[0]);
266                 CHECK_FATAL(childKlass != nullptr, "childKlass is null in Klass::CountVirtMethTopDown");
267                 if (childKlass->IsInterface() && !kh.IsSuperKlassForInterface(parentKlass, childKlass)) {
268                     continue;
269                 }
270                 (*vec)[0] = (*pvec)[0];
271             }
272         }
273     }
274     // Initialize mstridx2count_map based on the current class methods
275     for (MIRFunction *method : methods) {
276         DEBUG_ASSERT(method != nullptr, "null ptr check!");
277         if (!IsVirtualMethod(*method)) {
278             continue;
279         }
280         strIdx = method->GetBaseFuncNameWithTypeStrIdx();
281         if (strIdx2CandidateMap.find(strIdx) != strIdx2CandidateMap.end()) {
282             // Override the method coming from parent
283             vec = strIdx2CandidateMap[strIdx];
284             DEBUG_ASSERT(vec != nullptr, "nullptr check!");
285             DEBUG_ASSERT(vec->size() == 1, "Expect exactly one method definition from parent class");
286             (*vec)[0] = method;
287         } else {
288             // Newly declared and defined
289             vec = alloc->GetMemPool()->New<MapleVector<MIRFunction *>>(alloc->Adapter());
290             vec->push_back(method);
291             strIdx2CandidateMap[strIdx] = vec;
292         }
293     }
294 }
295 
CountVirtMethBottomUp()296 void Klass::CountVirtMethBottomUp()
297 {
298     MapleVector<MIRFunction *> *vec;
299     GStrIdx strIdx;
300     for (Klass *subKlass : subKlasses) {
301         CHECK_FATAL(subKlass != nullptr, "nullptr check failed");
302         for (const auto &pair : subKlass->strIdx2CandidateMap) {
303             strIdx = pair.first;
304             if (strIdx2CandidateMap.find(strIdx) == strIdx2CandidateMap.end()) {
305                 continue;
306             }
307             vec = strIdx2CandidateMap[strIdx];
308             MapleVector<MIRFunction *> *subv = pair.second;
309             if (!vec->empty() && !subv->empty() && vec->at(0) == subv->at(0)) {
310                 // If this class and subclass share the same default implementation,
311                 // then we have to avoid duplicated counting.
312                 vec->insert(vec->end(), subv->begin() + 1, subv->end());
313             } else {
314                 vec->insert(vec->end(), subv->begin(), subv->end());
315             }
316         }
317     }
318 }
319 
HasMethod(const std::string & funcname) const320 const MIRFunction *Klass::HasMethod(const std::string &funcname) const
321 {
322     for (auto *method : methods) {
323         if (method->GetBaseFuncNameWithType().find(funcname) != std::string::npos) {
324             return method;
325         }
326     }
327     return nullptr;
328 }
329 
GetKlassFromStrIdx(GStrIdx strIdx) const330 Klass *KlassHierarchy::GetKlassFromStrIdx(GStrIdx strIdx) const
331 {
332     auto it = strIdx2KlassMap.find(strIdx);
333     return ((it != strIdx2KlassMap.end()) ? (it->second) : nullptr);
334 }
335 
GetKlassFromTyIdx(TyIdx tyIdx) const336 Klass *KlassHierarchy::GetKlassFromTyIdx(TyIdx tyIdx) const
337 {
338     MIRType *type = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyIdx);
339     return (type != nullptr ? GetKlassFromStrIdx(type->GetNameStrIdx()) : nullptr);
340 }
341 
GetKlassFromFunc(const MIRFunction * func) const342 Klass *KlassHierarchy::GetKlassFromFunc(const MIRFunction *func) const
343 {
344     return (func != nullptr ? GetKlassFromStrIdx(func->GetBaseClassNameStrIdx()) : nullptr);
345 }
346 
GetKlassFromName(const std::string & name) const347 Klass *KlassHierarchy::GetKlassFromName(const std::string &name) const
348 {
349     return GetKlassFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(name));
350 }
351 
GetKlassFromLiteral(const std::string & name) const352 Klass *KlassHierarchy::GetKlassFromLiteral(const std::string &name) const
353 {
354     return GetKlassFromStrIdx(GlobalTables::GetStrTable().GetStrIdxFromName(namemangler::GetInternalNameLiteral(name)));
355 }
356 
357 // check if super is a superclass of base
358 // 1/0/-1: true/false/unknown
IsSuperKlass(TyIdx superTyIdx,TyIdx baseTyIdx) const359 int KlassHierarchy::IsSuperKlass(TyIdx superTyIdx, TyIdx baseTyIdx) const
360 {
361     if (superTyIdx == 0u || baseTyIdx == 0u) {
362         return -1;
363     }
364     if (superTyIdx == baseTyIdx) {
365         return 1;
366     }
367     Klass *super = GetKlassFromTyIdx(superTyIdx);
368     Klass *base = GetKlassFromTyIdx(baseTyIdx);
369     if (super == nullptr || base == nullptr) {
370         return -1;
371     }
372     while (base != nullptr) {
373         if (base == super) {
374             return 1;
375         }
376         base = base->GetSuperKlass();
377     }
378     return 0;
379 }
380 
IsSuperKlass(const Klass * super,const Klass * base) const381 bool KlassHierarchy::IsSuperKlass(const Klass *super, const Klass *base) const
382 {
383     if (super == nullptr || base == nullptr || base->IsInterface()) {
384         return false;
385     }
386     while (base != nullptr) {
387         if (base == super) {
388             return true;
389         }
390         base = base->GetSuperKlass();
391     }
392     return false;
393 }
394 
395 // Interface
IsSuperKlassForInterface(const Klass * super,const Klass * base) const396 bool KlassHierarchy::IsSuperKlassForInterface(const Klass *super, const Klass *base) const
397 {
398     if (super == nullptr || base == nullptr) {
399         return false;
400     }
401     if (!super->IsInterface() || !base->IsInterface()) {
402         return false;
403     }
404     std::vector<const Klass *> tmpVector;
405     tmpVector.push_back(base);
406     for (size_t idx = 0; idx < tmpVector.size(); ++idx) {
407         if (tmpVector[idx] == super) {
408             return true;
409         }
410         for (const Klass *superKlass : tmpVector[idx]->GetSuperKlasses()) {
411             tmpVector.push_back(superKlass);
412         }
413     }
414     return false;
415 }
416 
IsInterfaceImplemented(Klass * interface,const Klass * base) const417 bool KlassHierarchy::IsInterfaceImplemented(Klass *interface, const Klass *base) const
418 {
419     if (interface == nullptr || base == nullptr) {
420         return false;
421     }
422     if (!interface->IsInterface() || !base->IsClass()) {
423         return false;
424     }
425     // All the implemented interfaces and their parent interfaces
426     // are directly stored in this set, so no need to look up super
427     return (base->GetImplInterfaces().find(interface) != base->GetImplInterfaces().end());
428 }
429 
GetFieldIDOffsetBetweenClasses(const Klass & super,const Klass & base) const430 int KlassHierarchy::GetFieldIDOffsetBetweenClasses(const Klass &super, const Klass &base) const
431 {
432     int offset = 0;
433     const Klass *superPtr = &super;
434     const Klass *basePtr = &base;
435     while (basePtr != superPtr) {
436         basePtr = basePtr->GetSuperKlass();
437         CHECK_FATAL(basePtr != nullptr, "null ptr check");
438         offset++;
439     }
440     return offset;
441 }
442 
UpdateFieldID(TyIdx baseTypeIdx,TyIdx targetTypeIdx,FieldID & fldID) const443 bool KlassHierarchy::UpdateFieldID(TyIdx baseTypeIdx, TyIdx targetTypeIdx, FieldID &fldID) const
444 {
445     MIRType *baseType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(baseTypeIdx);
446     MIRType *targetType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(targetTypeIdx);
447     if (baseType->GetKind() == kTypePointer && targetType->GetKind() == kTypePointer) {
448         baseType = static_cast<const MIRPtrType *>(baseType)->GetPointedType();
449         targetType = static_cast<const MIRPtrType *>(targetType)->GetPointedType();
450     }
451     if (baseType->GetKind() != kTypeClass || targetType->GetKind() != kTypeClass) {
452         return false;
453     }
454     Klass *baseKlass = GetKlassFromTyIdx(baseType->GetTypeIndex());
455     DEBUG_ASSERT(baseKlass != nullptr, "null ptr check");
456     Klass *targetKlass = GetKlassFromTyIdx(targetType->GetTypeIndex());
457     DEBUG_ASSERT(targetKlass != nullptr, "null ptr check");
458     if (IsSuperKlass(baseKlass, targetKlass)) {
459         fldID += GetFieldIDOffsetBetweenClasses(*baseKlass, *targetKlass);
460         return true;
461     } else if (IsSuperKlass(targetKlass, baseKlass)) {
462         fldID -= GetFieldIDOffsetBetweenClasses(*targetKlass, *baseKlass);
463         return true;
464     }
465     return false;
466 }
467 
NeedClinitCheckRecursively(const Klass & kl) const468 bool KlassHierarchy::NeedClinitCheckRecursively(const Klass &kl) const
469 {
470     if (kl.HasFlag(kClassRuntimeVerify)) {
471         return true;
472     }
473     const Klass *klass = &kl;
474     if (klass->IsClass()) {
475         while (klass != nullptr) {
476             if (klass->GetClinit()) {
477                 return true;
478             }
479             klass = klass->GetSuperKlass();
480         }
481         for (Klass *implInterface : kl.GetImplInterfaces()) {
482             if (implInterface->GetClinit()) {
483                 for (auto &func : implInterface->GetMethods()) {
484                     if (!func->GetAttr(FUNCATTR_abstract) && !func->GetAttr(FUNCATTR_static)) {
485                         return true;
486                     }
487                 }
488             }
489         }
490         return false;
491     }
492     if (klass->IsInterface()) {
493         return klass->GetClinit();
494     }
495     return true;
496 }
497 
498 // Get lowest common ancestor for two classes
GetLCA(Klass * klass1,Klass * klass2) const499 Klass *KlassHierarchy::GetLCA(Klass *klass1, Klass *klass2) const
500 {
501     std::vector<Klass *> v1, v2;
502     while (klass1 != nullptr) {
503         v1.push_back(klass1);
504         klass1 = klass1->GetSuperKlass();
505     }
506     while (klass2 != nullptr) {
507         v2.push_back(klass2);
508         klass2 = klass2->GetSuperKlass();
509     }
510     Klass *result = nullptr;
511     size_t size1 = v1.size();
512     size_t size2 = v2.size();
513     size_t min = (size1 < size2) ? size1 : size2;
514     for (size_t i = 1; i <= min; ++i) {
515         if (v1[size1 - i] != v2[size2 - i]) {
516             break;
517         }
518         result = v1[size1 - i];
519     }
520     return result;
521 }
522 
GetLCA(TyIdx ty1,TyIdx ty2) const523 TyIdx KlassHierarchy::GetLCA(TyIdx ty1, TyIdx ty2) const
524 {
525     Klass *result = GetLCA(GetKlassFromTyIdx(ty1), GetKlassFromTyIdx(ty2));
526     return (result != nullptr ? result->GetTypeIdx() : TyIdx(0));
527 }
528 
GetLCA(GStrIdx str1,GStrIdx str2) const529 GStrIdx KlassHierarchy::GetLCA(GStrIdx str1, GStrIdx str2) const
530 {
531     Klass *result = GetLCA(GetKlassFromStrIdx(str1), GetKlassFromStrIdx(str2));
532     return (result != nullptr ? result->GetKlassNameStrIdx() : GStrIdx(0));
533 }
534 
GetLCA(const std::string & name1,const std::string & name2) const535 const std::string &KlassHierarchy::GetLCA(const std::string &name1, const std::string &name2) const
536 {
537     Klass *result = GetLCA(GetKlassFromName(name1), GetKlassFromName(name2));
538     return (result != nullptr ? result->GetKlassName() : GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(0)));
539 }
540 
AddKlasses()541 void KlassHierarchy::AddKlasses()
542 {
543     for (MIRType *type : GlobalTables::GetTypeTable().GetTypeTable()) {
544 #if DEBUG
545         if (type != nullptr) {
546             MIRTypeKind kd = type->GetKind();
547             if (kd == kTypeStructIncomplete || kd == kTypeClassIncomplete || kd == kTypeInterfaceIncomplete)
548                 LogInfo::MapleLogger() << "Warning: KlassHierarchy::AddKlasses "
549                                        << GlobalTables::GetStrTable().GetStringFromStrIdx(type->GetNameStrIdx())
550                                        << " INCOMPLETE \n";
551         }
552 #endif
553         if (Options::deferredVisit2 && type && (type->IsIncomplete())) {
554             GStrIdx stridx = type->GetNameStrIdx();
555             std::string strName = GlobalTables::GetStrTable().GetStringFromStrIdx(stridx);
556 #if DEBUG
557             LogInfo::MapleLogger() << "Waring: " << strName << " INCOMPLETE \n";
558 #endif
559             if (strName == namemangler::kClassMetadataTypeName) {
560                 continue;
561             }
562         } else if (type == nullptr || (type->GetKind() != kTypeClass && type->GetKind() != kTypeInterface)) {
563             continue;
564         }
565         GStrIdx strIdx = type->GetNameStrIdx();
566         Klass *klass = GetKlassFromStrIdx(strIdx);
567         if (klass != nullptr) {
568             if (klass->GetKlassName().compare(namemangler::kThrowClassStr) == 0) {
569                 klass->SetExceptionKlass();
570             }
571             continue;
572         }
573         auto *stype = static_cast<MIRStructType *>(type);
574         klass = GetMempool()->New<Klass>(stype, &alloc);
575         strIdx2KlassMap[strIdx] = klass;
576     }
577 }
578 
ExceptionFlagProp(Klass & klass)579 void KlassHierarchy::ExceptionFlagProp(Klass &klass)
580 {
581     klass.SetExceptionKlass();
582     for (Klass *subClass : klass.GetSubKlasses()) {
583         DEBUG_ASSERT(subClass != nullptr, "null ptr check!");
584         subClass->SetExceptionKlass();
585         ExceptionFlagProp(*subClass);
586     }
587 }
588 
AddKlassRelationAndMethods()589 void KlassHierarchy::AddKlassRelationAndMethods()
590 {
591     for (const auto &pair : strIdx2KlassMap) {
592         Klass *klass = pair.second;
593         DEBUG_ASSERT(klass, "null ptr check");
594         Klass *superKlass = nullptr;
595         if (klass->IsInterface() || klass->IsInterfaceIncomplete()) {
596             MIRInterfaceType *itype = klass->GetMIRInterfaceType();
597             DEBUG_ASSERT(itype != nullptr, "null ptr check");
598             // Java interface supports multiple inheritance
599             for (TyIdx superTyIdx : itype->GetParentsTyIdx()) {
600                 superKlass = GetKlassFromTyIdx(superTyIdx);
601                 if (superKlass != nullptr) {
602                     klass->AddSuperKlass(superKlass);
603                     superKlass->AddSubKlass(klass);
604                 }
605             }
606         } else if (klass->IsClass() || klass->IsClassIncomplete()) {
607             // Class
608             MIRClassType *classType = klass->GetMIRClassType();
609             DEBUG_ASSERT(classType != nullptr, "null ptr check");
610             // Add interface relationship
611             for (TyIdx intfTyIdx : classType->GetInterfaceImplemented()) {
612                 Klass *intfKlass = GetKlassFromTyIdx(intfTyIdx);
613                 if (intfKlass != nullptr) {
614                     intfKlass->AddImplKlass(klass);
615                     klass->AddImplInterface(intfKlass);
616                 }
617             }
618             superKlass = GetKlassFromTyIdx(classType->GetParentTyIdx());
619             // Add superclass/subclass for each class.
620             if (superKlass != nullptr) {
621                 klass->AddSuperKlass(superKlass);
622                 superKlass->AddSubKlass(klass);
623                 // klass implements same interfaces inherited from its parent
624                 for (Klass *intfklass : superKlass->GetImplInterfaces()) {
625                     intfklass->AddImplKlass(klass);
626                     klass->AddImplInterface(intfklass);
627                 }
628             }
629         }
630         // Add method info
631         for (const auto &methodPair : klass->GetMIRStructType()->GetMethods()) {
632             MIRSymbol *funcSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(methodPair.first.Idx());
633             MIRFunction *method = funcSym->GetFunction();
634             klass->AddMethod(method);
635             if (method->GetName().compare(klass->GetKlassName() + namemangler::kClinitSuffix) == 0) {
636                 klass->SetClinit(method);
637             }
638         }
639     }
640     // Propagate isExceptionKlass flag
641     if (GetKlassFromLiteral(namemangler::kThrowClassStr) != nullptr) {
642         ExceptionFlagProp(*GetKlassFromLiteral(namemangler::kThrowClassStr));
643         CHECK_FATAL(GetKlassFromLiteral(namemangler::kThrowClassStr)->IsExceptionKlass(), "must be exception class");
644     }
645     if (GetKlassFromLiteral(kJavaLangNoMethodStr) != nullptr) {
646         CHECK_FATAL(GetKlassFromLiteral(kJavaLangNoMethodStr)->IsExceptionKlass(), "must be exception class");
647     }
648 }
649 
TagThrowableKlasses()650 void KlassHierarchy::TagThrowableKlasses()
651 {
652     Klass *throwable = GetKlassFromName(namemangler::kThrowClassStr);
653     if (throwable == nullptr) {
654         return;
655     }
656     for (const auto &pair : strIdx2KlassMap) {
657         Klass *klass = pair.second;
658         DEBUG_ASSERT(klass != nullptr, "unexpeced null klass");
659         if (!klass->IsInterface() && IsSuperKlass(throwable, klass)) {
660             klass->SetExceptionKlass();
661         }
662     }
663 }
664 
CollectImplInterfaces(const Klass & klass,std::set<Klass * > & implInterfaceSet)665 static void CollectImplInterfaces(const Klass &klass, std::set<Klass *> &implInterfaceSet)
666 {
667     for (Klass *superKlass : klass.GetSuperKlasses()) {
668         if (implInterfaceSet.find(superKlass) == implInterfaceSet.end()) {
669             DEBUG_ASSERT(superKlass != nullptr, "null ptr check!");
670             if (superKlass->IsInterface()) {
671                 implInterfaceSet.insert(superKlass);
672             }
673             CollectImplInterfaces(*superKlass, implInterfaceSet);
674         }
675     }
676     for (Klass *interfaceKlass : klass.GetImplInterfaces()) {
677         if (implInterfaceSet.find(interfaceKlass) == implInterfaceSet.end()) {
678             implInterfaceSet.insert(interfaceKlass);
679             DEBUG_ASSERT(interfaceKlass != nullptr, "null ptr check!");
680             CollectImplInterfaces(*interfaceKlass, implInterfaceSet);
681         }
682     }
683 }
684 
UpdateImplementedInterfaces()685 void KlassHierarchy::UpdateImplementedInterfaces()
686 {
687     for (const auto &pair : strIdx2KlassMap) {
688         Klass *klass = pair.second;
689         DEBUG_ASSERT(klass != nullptr, "null ptr check");
690         if (!klass->IsInterface()) {
691             std::set<Klass *> implInterfaceSet;
692             CollectImplInterfaces(*klass, implInterfaceSet);
693             for (auto interface : implInterfaceSet) {
694                 // Add missing parent interface to class link
695                 interface->AddImplKlass(klass);
696                 klass->AddImplInterface(interface);
697             }
698         }
699     }
700 }
701 
GetParentKlasses(const Klass & klass,std::vector<Klass * > & parentKlasses) const702 void KlassHierarchy::GetParentKlasses(const Klass &klass, std::vector<Klass *> &parentKlasses) const
703 {
704     for (Klass *superKlass : klass.GetSuperKlasses()) {
705         parentKlasses.push_back(superKlass);
706     }
707     if (!klass.IsInterface()) {
708         for (Klass *iklass : klass.GetImplInterfaces()) {
709             parentKlasses.push_back(iklass);
710         }
711     }
712 }
713 
GetChildKlasses(const Klass & klass,std::vector<Klass * > & childKlasses) const714 void KlassHierarchy::GetChildKlasses(const Klass &klass, std::vector<Klass *> &childKlasses) const
715 {
716     for (Klass *subKlass : klass.GetSubKlasses()) {
717         childKlasses.push_back(subKlass);
718     }
719     if (klass.IsInterface()) {
720         for (Klass *implKlass : klass.GetImplKlasses()) {
721             childKlasses.push_back(implKlass);
722         }
723     }
724 }
725 
TopologicalSortKlasses()726 void KlassHierarchy::TopologicalSortKlasses()
727 {
728     std::set<Klass *> inQueue;  // Local variable, no need to use MapleSet
729     for (const auto &pair : strIdx2KlassMap) {
730         Klass *klass = pair.second;
731         DEBUG_ASSERT(klass != nullptr, "klass can not be nullptr");
732         if (!klass->HasSuperKlass() && !klass->ImplementsKlass()) {
733             topoWorkList.push_back(klass);
734             inQueue.insert(klass);
735         }
736     }
737     // Top-down iterates all nodes
738     for (size_t i = 0; i < topoWorkList.size(); ++i) {
739         Klass *klass = topoWorkList[i];
740         std::vector<Klass *> childklasses;
741         DEBUG_ASSERT(klass != nullptr, "null ptr check!");
742         GetChildKlasses(*klass, childklasses);
743         for (Klass *childklass : childklasses) {
744             if (inQueue.find(childklass) == inQueue.end()) {
745                 // callee has not been visited
746                 bool parentKlassAllVisited = true;
747                 std::vector<Klass *> parentKlasses;
748                 DEBUG_ASSERT(childklass != nullptr, "null ptr check!");
749                 GetParentKlasses(*childklass, parentKlasses);
750                 // Check whether all callers of the current callee have been visited
751                 for (Klass *parentKlass : parentKlasses) {
752                     if (inQueue.find(parentKlass) == inQueue.end()) {
753                         parentKlassAllVisited = false;
754                         break;
755                     }
756                 }
757                 if (parentKlassAllVisited) {
758                     topoWorkList.push_back(childklass);
759                     inQueue.insert(childklass);
760                 }
761             }
762         }
763     }
764 }
765 
CountVirtualMethods() const766 void KlassHierarchy::CountVirtualMethods() const
767 {
768     // Top-down iterates all klass nodes
769     for (Klass *klass : topoWorkList) {
770         klass->CountVirtMethTopDown(*this);
771     }
772     // Bottom-up iterates all klass nodes
773     for (size_t i = topoWorkList.size(); i != 0; --i) {
774         topoWorkList[i - 1]->CountVirtMethBottomUp();
775     }
776 }
777 
AddClassFlag(const std::string & name,uint32 flag)778 Klass *KlassHierarchy::AddClassFlag(const std::string &name, uint32 flag)
779 {
780     Klass *refKlass = GetKlassFromLiteral(name);
781     if (refKlass != nullptr) {
782         refKlass->SetFlag(flag);
783     }
784     return refKlass;
785 }
786 
787 // Mark klasses those implement the finalize method, or inherit
788 // from super klass (except java.lang.Object).
789 // Mark klasses those or superclasses are references.
MarkClassFlags()790 void KlassHierarchy::MarkClassFlags()
791 {
792     Klass *cleanerKlass = AddClassFlag("Lsun_2Fmisc_2FCleaner_3B", kClassCleaner);
793     AddClassFlag("Ljava_2Flang_2Fref_2FSoftReference_3B", kClassSoftreference);
794     AddClassFlag("Ljava_2Flang_2Fref_2FWeakReference_3B", kClassWeakreference);
795     AddClassFlag("Ljava_2Flang_2Fref_2FPhantomReference_3B", kClassPhantomreference);
796     AddClassFlag("Ljava_2Flang_2Fref_2FFinalizerReference_3B", kClassFinalizereference);
797     AddClassFlag("Ljava_2Flang_2Fref_2FFinalizerReference_24Sentinel_3B", kClassFinalizerreferenceSentinel);
798     Klass *klassObject = GetKlassFromLiteral(namemangler::kJavaLangObjectStr);
799     GStrIdx finalize = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("finalize_7C_28_29V");
800     for (Klass *klass : topoWorkList) {
801         if (klass == klassObject) {
802             continue;
803         }
804         if (klass->IsInterface()) {
805             continue;
806         }
807         Klass *super = klass->GetSuperKlass();
808         // Mark Reference
809         // sun.misc.Cleaner's superclass is PhantomReference.
810         // Break this chain to process Cleaner correctly.
811         if (super != nullptr && super->IsReference() && klass != cleanerKlass) {
812             klass->SetFlag(super->GetFlag(kClassReference));
813         }
814         // Mark Finalizer
815         if (super != nullptr && super->HasFinalizer()) {
816             klass->SetHasFinalizer();
817         } else {
818             for (auto &method : klass->GetMethods()) {
819                 if (method->GetBaseFuncNameWithTypeStrIdx() == finalize) {
820                     klass->SetHasFinalizer();
821                     break;
822                 }
823             }
824         }
825         // Mark native function info
826         for (auto &method : klass->GetMethods()) {
827             if (method->GetAttr(FUNCATTR_native)) {
828                 klass->SetHasNativeMethod(true);
829                 break;
830             }
831         }
832     }
833 }
834 
Dump() const835 void KlassHierarchy::Dump() const
836 {
837     for (Klass *klass : topoWorkList) {
838         klass->Dump();
839     }
840 }
841 
GetUniqueMethod(GStrIdx vfuncNameStridx) const842 GStrIdx KlassHierarchy::GetUniqueMethod(GStrIdx vfuncNameStridx) const
843 {
844     auto it = vfunc2RfuncMap.find(vfuncNameStridx);
845     return (it != vfunc2RfuncMap.end() ? it->second : GStrIdx(0));
846 }
847 
IsDevirtualListEmpty() const848 bool KlassHierarchy::IsDevirtualListEmpty() const
849 {
850     return vfunc2RfuncMap.empty();
851 }
852 
DumpDevirtualList(const std::string & outputFileName) const853 void KlassHierarchy::DumpDevirtualList(const std::string &outputFileName) const
854 {
855     std::unordered_map<std::string, std::string> funcMap;
856     for (Klass *klass : topoWorkList) {
857         for (MIRFunction *func : klass->GetMethods()) {
858             MIRFunction *uniqCand = klass->GetUniqueMethod(func->GetBaseFuncNameWithTypeStrIdx());
859             if (uniqCand != nullptr) {
860                 funcMap[func->GetName()] = uniqCand->GetName();
861             }
862         }
863     }
864     std::ofstream outputFile;
865     outputFile.open(outputFileName);
866     for (auto it : funcMap) {
867         outputFile << it.first << "\t" << it.second << "\n";
868     }
869     outputFile.close();
870 }
871 
ReadDevirtualList(const std::string & inputFileName)872 void KlassHierarchy::ReadDevirtualList(const std::string &inputFileName)
873 {
874     std::ifstream inputFile;
875     inputFile.open(inputFileName);
876     std::string vfuncName;
877     std::string rfuncName;
878     while (inputFile >> vfuncName >> rfuncName) {
879         vfunc2RfuncMap[GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(vfuncName)] =
880             GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(rfuncName);
881     }
882     inputFile.close();
883 }
884 
BuildHierarchy()885 void KlassHierarchy::BuildHierarchy()
886 {
887     // Scan class list and generate Klass without method information
888     AddKlasses();
889     // Fill class method info. Connect superclass<->subclass and
890     // interface->implementation edges.
891     AddKlassRelationAndMethods();
892     TagThrowableKlasses();
893     // In the case of "class C implements B; interface B extends A;",
894     // we need to add a link between C and A.
895     UpdateImplementedInterfaces();
896     TopologicalSortKlasses();
897     MarkClassFlags();
898     if (!strIdx2KlassMap.empty()) {
899         WKTypes::Init();
900     }
901     // Use --dump-devirtual-list=... to dump a closed-wolrd analysis result into a file
902     if (!Options::dumpDevirtualList.empty()) {
903         DumpDevirtualList(Options::dumpDevirtualList);
904     }
905     // Use --read-devirtual-list=... to read in a closed-world analysis result
906     if (!Options::readDevirtualList.empty()) {
907         ReadDevirtualList(Options::readDevirtualList);
908     }
909 }
910 
KlassHierarchy(MIRModule * mirmodule,MemPool * memPool)911 KlassHierarchy::KlassHierarchy(MIRModule *mirmodule, MemPool *memPool)
912     : AnalysisResult(memPool),
913       alloc(memPool),
914       mirModule(mirmodule),
915       strIdx2KlassMap(std::less<GStrIdx>(), alloc.Adapter()),
916       vfunc2RfuncMap(std::less<GStrIdx>(), alloc.Adapter()),
917       topoWorkList(alloc.Adapter())
918 {
919 }
920 
921 MIRType *WKTypes::javaLangObject;
922 MIRType *WKTypes::javaLangString;
923 MIRType *WKTypes::javaLangObjectSerializable;
924 MIRType *WKTypes::javaLangComparable;
925 MIRType *WKTypes::javaLangCharSequence;
926 MIRType *WKTypes::javaLangClass;
927 MIRType *WKTypes::javaLangRefGenericDeclaration;
928 MIRType *WKTypes::javaLangRefAnnotatedElement;
929 MIRType *WKTypes::javaLangRefType;
930 MIRType *WKTypes::javaLangRefMethod;
931 MIRType *WKTypes::javaLangRefExecutable;
932 MIRType *WKTypes::javaLangRefAccessibleObject;
933 MIRType *WKTypes::javaLangRefMember;
934 MIRType *WKTypes::javaLangRefField;
935 MIRType *WKTypes::javaLangRefConstructor;
GetMIRTypeFromName(const std::string & name)936 inline static MIRType *GetMIRTypeFromName(const std::string &name)
937 {
938     GStrIdx gStrIdx = GlobalTables::GetStrTable().GetStrIdxFromName(namemangler::GetInternalNameLiteral(name));
939     return GlobalTables::GetTypeTable().GetTypeFromTyIdx(GlobalTables::GetTypeNameTable().GetTyIdxFromGStrIdx(gStrIdx));
940 }
941 
Init()942 void WKTypes::Init()
943 {
944     javaLangObject = GetMIRTypeFromName(namemangler::kJavaLangObjectStr);
945     javaLangString = GetMIRTypeFromName("Ljava_2Flang_2FString_3B");
946     javaLangObjectSerializable = GetMIRTypeFromName("Ljava_2Fio_2FSerializable_3B");
947     javaLangComparable = GetMIRTypeFromName("Ljava_2Flang_2FComparable_3B");
948     javaLangCharSequence = GetMIRTypeFromName("Ljava_2Flang_2FCharSequence_3B");
949     javaLangClass = GetMIRTypeFromName("Ljava_2Flang_2FClass_3B");
950     javaLangRefGenericDeclaration = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FGenericDeclaration_3B");
951     javaLangRefAnnotatedElement = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FAnnotatedElement_3B");
952     javaLangRefType = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FType_3B");
953     javaLangRefMethod = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FMethod_3B");
954     javaLangRefExecutable = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FExecutable_3B");
955     javaLangRefAccessibleObject = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FAccessibleObject_3B");
956     javaLangRefMember = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FMember_3B");
957     javaLangRefField = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FField_3B");
958     javaLangRefConstructor = GetMIRTypeFromName("Ljava_2Flang_2Freflect_2FConstructor_3B");
959 }
960 
961 // Return true if node n may point to a String object.
962 // String is declared as:
963 //   public final class String implements java.io.Serializable, Comparable<String>, CharSequence
964 // So n can point to String only if n's type is a ref to String or Object, or is an interface
965 // type of java.io.Serializable, Comparable or CharSequence
MayRefString(const BaseNode & n,MIRType & type)966 bool WKTypes::Util::MayRefString(const BaseNode &n, MIRType &type)
967 {
968     if ((n.GetPrimType() == PTY_ref || n.GetPrimType() == PTY_ptr) && type.GetKind() == kTypePointer) {
969         auto *pointType = static_cast<MIRPtrType *>(&type);
970         MIRType *pointedType = pointType->GetPointedType();
971         if (pointedType == javaLangString || pointedType == javaLangObjectSerializable ||
972             pointedType == javaLangComparable || pointedType == javaLangCharSequence || pointedType == javaLangObject) {
973             return true;
974         }
975     }
976     return false;
977 }
978 
979 // Return true if node n may point to Meta object, i.e, n is a reference
980 // of java.lang.Class, java.lang.reflect.Method, java.lang.reflect.Field,
981 // java.lang.reflect.Constructor
MayRefMeta(const BaseNode & n,MIRType & type)982 bool WKTypes::Util::MayRefMeta(const BaseNode &n, MIRType &type)
983 {
984     if ((n.GetPrimType() == PTY_ref || n.GetPrimType() == PTY_ptr) && type.GetKind() == kTypePointer) {
985         auto *pointType = static_cast<MIRPtrType *>(&type);
986         MIRType *pointedType = pointType->GetPointedType();
987         // Definition of java.lang.Class:
988         // public final class Class<T> implements java.io.Serializable,
989         // GenericDeclaration,
990         // Type,
991         // AnnotatedElement {...}
992         // public interface Serializable {}
993         // public interface GenericDeclaration extends AnnotatedElement {...}
994         // public interface AnnotatedElement {...}
995         // public interface Type {...}
996         // public interface AnnotatedElement {...}
997         if (pointedType == javaLangClass || pointedType == javaLangObjectSerializable ||
998             pointedType == javaLangRefGenericDeclaration || pointedType == javaLangRefAnnotatedElement ||
999             pointedType == javaLangRefType || pointedType == javaLangObject) {
1000             return true;
1001         }
1002         // Definition of java.lang.reflect.Method:
1003         // public final class Method extends Executable {...}
1004         // public abstract class Executable extends AccessibleObject
1005         // implements Member, GenericDeclaration {...}
1006         // public class AccessibleObject implements AnnotatedElement {...}
1007         // public interface AnnotatedElement {...}
1008         // public interface Member {...}
1009         // public interface GenericDeclaration extends AnnotatedElement {...}
1010         // public interface AnnotatedElement {...}
1011         if (pointedType == javaLangRefMethod || pointedType == javaLangRefExecutable ||
1012             pointedType == javaLangRefAccessibleObject || pointedType == javaLangRefMember ||
1013             pointedType == javaLangRefGenericDeclaration || pointedType == javaLangRefAnnotatedElement ||
1014             pointedType == javaLangObject) {
1015             return true;
1016         }
1017         // Definition of java.lang.reflect.Field:
1018         // public final class Field extends AccessibleObject implements Member {...}
1019         if (pointedType == javaLangRefField) {  // super classes/interfaces are checked by javaLangRefMethod
1020             return true;
1021         }
1022         // Definition of java.lang.reflect.Constructor:
1023         // public final class Constructor<T> extends Executable {...}
1024         if (pointedType == javaLangRefConstructor) {  // super classes are checked by javaLangRefMethod
1025             return true;
1026         }
1027     }
1028     return false;
1029 }
1030 
1031 // Return true if node 'n', whose type is 'type', can not form a reference cycle.
1032 // E.g, all fields are primitive types, String, array of primitive, etc.
MayNotRefCyclicly(const BaseNode & n,MIRType & type)1033 bool WKTypes::Util::MayNotRefCyclicly(const BaseNode &n, MIRType &type)
1034 {
1035     CHECK_FATAL((n.GetPrimType() == PTY_ref || n.GetPrimType() == PTY_ptr) && type.GetKind() == kTypePointer,
1036                 "n must be a reference");
1037     std::set<MIRType *> workList;
1038     workList.insert(&type);
1039     return NotCyclicType(type, workList);
1040 }
1041 
1042 // Helper function of WKTypes::Util::MayNotRefCyclicly.
NotCyclicType(MIRType & type,std::set<MIRType * > & workList)1043 bool WKTypes::Util::NotCyclicType(MIRType &type, std::set<MIRType *> &workList)
1044 {
1045     // Fast path for special cases: String, Class
1046     if (&type == javaLangString || &type == javaLangClass) {
1047         return true;
1048     }
1049     if (type.GetKind() == kTypeScalar) {  // primitive type
1050         return true;
1051     }
1052     if (type.GetKind() == kTypePointer) {
1053         auto *pointedType = static_cast<MIRPtrType *>(&type)->GetPointedType();
1054         DEBUG_ASSERT(pointedType != nullptr, "null ptr check!");
1055         return NotCyclicType(*pointedType, workList);
1056     }
1057     if (type.GetKind() == kTypeJArray) {
1058         MIRType *elemType =
1059             GlobalTables::GetTypeTable().GetTypeFromTyIdx(static_cast<MIRJarrayType *>(&type)->GetElemTyIdx());
1060         DEBUG_ASSERT(elemType != nullptr, "null ptr check!");
1061         return NotCyclicType(*elemType, workList);
1062     }
1063     if (type.GetKind() == kTypeClass) {
1064         auto *classType = static_cast<MIRClassType *>(&type);
1065         if (!classType->IsFinal()) {  // Not sure what actual class it refers to
1066             return false;
1067         }
1068         std::vector<FieldPair> allFields;
1069         allFields.insert(allFields.end(), classType->GetFields().begin(), classType->GetFields().end());
1070         // ignore static fields for now, they are not recycled anyway
1071         MIRType *parentType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(classType->GetParentTyIdx());
1072         while (parentType != nullptr) {
1073             CHECK_FATAL(parentType->GetKind() == kTypeClass, "parent class");
1074             auto *parentclass = static_cast<MIRClassType *>(parentType);
1075             allFields.insert(allFields.end(), parentclass->GetFields().begin(), parentclass->GetFields().end());
1076             // ignore static fields for now, they are not recycled anyway
1077             parentType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentclass->GetParentTyIdx());
1078         }
1079         // Ignore interface fields, as they are all static final (constant) variables
1080         for (FieldPair &fieldPair : allFields) {
1081             MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first);
1082             DEBUG_ASSERT(fieldType != nullptr, "null ptr check!");
1083             if (fieldType->GetKind() == kTypePointer) {
1084                 // Strictly, we should check whether fieldType is 'assignable' from any type
1085                 // recorded in worklist, which means a cycle may be formed. However, this
1086                 // function returns false for any non-final calss (see above), so we only
1087                 // check if fieldType is 'equal' to any type recorded in the worklist.
1088                 // An example:
1089                 // class B extends A {
1090                 //    A field_a;
1091                 // }
1092                 // field_a may point to an instance of B and henceforce a possible cycle.
1093                 // Since A is not a final class, we can recognize it as a cycle candidate.
1094                 if (workList.find(fieldType) != workList.end()) {
1095                     return false;
1096                 }
1097                 workList.insert(fieldType);
1098             }
1099             if (!NotCyclicType(*fieldType, workList)) {
1100                 return false;
1101             }
1102         }
1103         return true;
1104     }
1105     if (type.GetKind() == kTypeInterface) {
1106         // Perhaps something more can do.
1107         return false;
1108     }
1109     return false;
1110 }
1111 }  // namespace maple
1112