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