• 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_init.h"
17 #include <iostream>
18 #include <fstream>
19 
20 namespace {
21 constexpr char kCinfString[] = "__cinf_Ljava_2Flang_2FString_3B";
22 constexpr char kINFOFilename[] = "INFO_filename";
23 constexpr char kCoreAll[] = "core-all";
24 constexpr char kMCCPreClinitCheck[] = "MCC_PreClinitCheck";
25 constexpr char kMCCPostClinitCheck[] = "MCC_PostClinitCheck";
26 }  // namespace
27 
28 // This phase does two things.
29 // 1. Insert clinit(class initialization) check, a intrinsic call INTRN_MPL_CLINIT_CHECK
30 //   for place where needed.
31 //   Insert clinit check for static native methods which are not private.
32 // 2. Lower JAVA_CLINIT_CHECK to MPL_CLINIT_CHECK.
33 //   Before insert or tranform the clinit check, we used a optimise based on
34 //   white list. When the dexname is core-all and the class is in the white list
35 //   we dont't insert clinit check.Because the class in the white list is intialized
36 //   in the system bootup.
37 namespace maple {
CanRemoveClinitCheck(const std::string & clinitClassname) const38 bool ClassInit::CanRemoveClinitCheck(const std::string &clinitClassname) const
39 {
40     if (!Options::usePreloadedClass) {
41         return false;
42     }
43     if (clinitClassname.empty()) {
44         return false;
45     }
46     if (clinitClassname == kCinfString) {
47         return true;
48     }
49     uint32 dexNameIdx =
50         GetMIRModule().GetFileinfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(kINFOFilename));
51     const std::string &dexName = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(dexNameIdx));
52     if (dexName.find(kCoreAll) != std::string::npos) {
53         return false;
54     }
55     return IsSystemPreloadedClass(clinitClassname);
56 }
57 
GenClassInitCheckProfile(MIRFunction & func,const MIRSymbol & classInfo,StmtNode * clinit) const58 void ClassInit::GenClassInitCheckProfile(MIRFunction &func, const MIRSymbol &classInfo, StmtNode *clinit) const
59 {
60     GenPreClassInitCheck(func, classInfo, clinit);
61     GenPostClassInitCheck(func, classInfo, clinit);
62 }
63 
GenPreClassInitCheck(MIRFunction & func,const MIRSymbol & classInfo,const StmtNode * clinit) const64 void ClassInit::GenPreClassInitCheck(MIRFunction &func, const MIRSymbol &classInfo, const StmtNode *clinit) const
65 {
66     MIRFunction *preClinit = builder->GetOrCreateFunction(kMCCPreClinitCheck, (TyIdx)(PTY_void));
67     BaseNode *classInfoNode = builder->CreateExprAddrof(0, classInfo);
68     MapleVector<BaseNode *> args(builder->GetCurrentFuncCodeMpAllocator()->Adapter());
69     args.push_back(classInfoNode);
70     CallNode *callPreclinit = builder->CreateStmtCall(preClinit->GetPuidx(), args);
71     func.GetBody()->InsertBefore(clinit, callPreclinit);
72 }
73 
GenPostClassInitCheck(MIRFunction & func,const MIRSymbol & classInfo,const StmtNode * clinit) const74 void ClassInit::GenPostClassInitCheck(MIRFunction &func, const MIRSymbol &classInfo, const StmtNode *clinit) const
75 {
76     MIRFunction *postClinit = builder->GetOrCreateFunction(kMCCPostClinitCheck, (TyIdx)(PTY_void));
77     BaseNode *classInfoNode = builder->CreateExprAddrof(0, classInfo);
78     MapleVector<BaseNode *> args(builder->GetCurrentFuncCodeMpAllocator()->Adapter());
79     args.push_back(classInfoNode);
80     CallNode *callPostClinit = builder->CreateStmtCall(postClinit->GetPuidx(), args);
81     func.GetBody()->InsertAfter(clinit, callPostClinit);
82 }
83 
ProcessFunc(MIRFunction * func)84 void ClassInit::ProcessFunc(MIRFunction *func)
85 {
86     // No field will be involved in critical native funcs.
87     DEBUG_ASSERT(func != nullptr, "null ptr check!");
88     if (func->IsEmpty() || func->GetAttr(FUNCATTR_critical_native)) {
89         return;
90     }
91     currFunc = func;
92     builder->SetCurrentFunction(*func);
93     // Insert clinit check for static methods.
94     MIRType *selfClassType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->GetClassTyIdx());
95     std::string selfClassName;
96     if (selfClassType != nullptr) {
97         selfClassName = GlobalTables::GetStrTable().GetStringFromStrIdx(selfClassType->GetNameStrIdx());
98     } else {
99         const std::string &funcName = func->GetName();
100         size_t pos = funcName.find(namemangler::kNameSplitterStr);
101         constexpr size_t prePos = 2;
102         constexpr size_t ligalPos = 2;
103         while (pos != std::string::npos &&
104                (pos >= ligalPos && funcName[pos - 1] == '_' && funcName[pos - prePos] != '_')) {
105             constexpr size_t nextPos = 3;
106             pos = funcName.find(namemangler::kNameSplitterStr, pos + nextPos);
107         }
108         selfClassName = funcName.substr(0, pos);
109     }
110     // Insert clinit check for static native methods which are not private.
111     // We have to do this here because native methods are generated as empty by maplefe,
112     // If we simply insert clinit-check (which does not have return value), there will
113     // be no return statement for native methods which do hava a return value.
114     // clinit check for static java (non-native) methods which are not private is
115     // already inserted by maplefe.
116     if (func->IsStatic() && !func->IsPrivate() && !func->IsClinit() && func->IsNative()) {
117         MIRType *classType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(func->GetClassTyIdx());
118         CHECK_FATAL(classType != nullptr, "class type is nullptr");
119         const std::string &className = GlobalTables::GetStrTable().GetStringFromStrIdx(classType->GetNameStrIdx());
120         if (!CanRemoveClinitCheck(className)) {
121             Klass *klass = klassHierarchy->GetKlassFromName(className);
122             CHECK_FATAL(klass != nullptr, "klass is nullptr in ClassInit::ProcessFunc");
123             if (klass->GetClinit() && func != klass->GetClinit()) {
124                 MIRSymbol *classInfo = GetClassInfo(className);
125                 BaseNode *classInfoNode = builder->CreateExprAddrof(0, *classInfo);
126                 if (trace) {
127                     LogInfo::MapleLogger() << "\t- low-cost clinit - insert check in static method " << func->GetName()
128                                            << "clasname " << className << "\n";
129                 }
130                 MapleVector<BaseNode *> args(builder->GetCurrentFuncCodeMpAllocator()->Adapter());
131                 args.push_back(classInfoNode);
132                 StmtNode *intrinsicCall = builder->CreateStmtIntrinsicCall(INTRN_MPL_CLINIT_CHECK, args);
133                 func->GetBody()->InsertFirst(intrinsicCall);
134                 DEBUG_ASSERT(classInfo != nullptr, "null ptr check!");
135 #ifdef CLINIT_CHECK
136                 GenClassInitCheckProfile(*func, *classInfo, intrinsicCall);
137 #endif  // CLINIT_CHECK
138             }
139         }
140     }
141     // Lower JAVA_CLINIT_CHECK to MPL_CLINIT_CHECK.
142     StmtNode *stmt = func->GetBody()->GetFirst();
143     while (stmt != nullptr) {
144         if (stmt->GetOpCode() == OP_intrinsiccallwithtype) {
145             auto *intrinsicCall = static_cast<IntrinsiccallNode *>(stmt);
146             if (intrinsicCall->GetIntrinsic() == INTRN_JAVA_CLINIT_CHECK) {
147                 // intrinsiccallwithtype <$LTest_3B> JAVA_CLINIT_CHECK ()        -->
148                 // intrinsiccall MPL_CLINIT_CHECK (addrof ptr $__cinf_LTest_3B)
149                 CHECK_FATAL(intrinsicCall->GetNopndSize() == 0, "wrong arg vectors");
150                 CHECK_FATAL(intrinsicCall->GetTyIdx() < GlobalTables::GetTypeTable().GetTypeTable().size(),
151                             "index out of range");
152                 MIRType *classType = GlobalTables::GetTypeTable().GetTypeTable()[intrinsicCall->GetTyIdx()];
153                 DEBUG_ASSERT(classType != nullptr, "null ptr check!");
154                 CHECK_FATAL(classType->GetNameStrIdx() != 0u, "symbol name is null for type index %d",
155                             static_cast<uint32>(intrinsicCall->GetTyIdx()));
156                 const std::string &className =
157                     GlobalTables::GetStrTable().GetStringFromStrIdx(classType->GetNameStrIdx());
158                 Klass *klass = klassHierarchy->GetKlassFromName(className);
159                 bool doClinitCheck = false;
160                 if (klass == nullptr) {
161                     WARN(kLncWarn, "ClassInit::ProcessFunc: Skip INCOMPLETE type %s", className.c_str());
162                     doClinitCheck = true;
163                 } else {
164                     doClinitCheck =
165                         !CanRemoveClinitCheck(className) && klassHierarchy->NeedClinitCheckRecursively(*klass);
166                 }
167                 if (Options::buildApp != 0) {
168                     doClinitCheck = true;
169                 }
170                 if (doClinitCheck) {
171                     MIRSymbol *classInfo = GetClassInfo(className);
172                     AddrofNode *classInfoNode = builder->CreateExprAddrof(0, *classInfo);
173                     MapleVector<BaseNode *> args(builder->GetCurrentFuncCodeMpAllocator()->Adapter());
174                     args.push_back(classInfoNode);
175                     StmtNode *mplIntrinsicCall = builder->CreateStmtIntrinsicCall(INTRN_MPL_CLINIT_CHECK, args);
176                     func->GetBody()->ReplaceStmt1WithStmt2(stmt, mplIntrinsicCall);
177                     if (trace) {
178                         LogInfo::MapleLogger() << "\t- low-cost clinit - lower JAVA_CLINIT_CHECK " << className
179                                                << " in " << func->GetName() << "()\n";
180                     }
181                     DEBUG_ASSERT(classInfo != nullptr, "null ptr check!");
182 #ifdef CLINIT_CHECK
183                     GenClassInitCheckProfile(*func, *classInfo, mplIntrinsicCall);
184 #endif  // CLINIT_CHECK
185                 } else {
186                     func->GetBody()->RemoveStmt(stmt);
187                 }
188             }
189         }
190         stmt = stmt->GetNext();
191     }
192 }
193 
GetClassInfo(const std::string & classname)194 MIRSymbol *ClassInit::GetClassInfo(const std::string &classname)
195 {
196     const std::string &classInfoName = CLASSINFO_PREFIX_STR + classname;
197     MIRType *classInfoType =
198         GlobalTables::GetTypeTable().GetOrCreateClassType(namemangler::kClassMetadataTypeName, GetMIRModule());
199     MIRSymbol *classInfo = builder->GetOrCreateGlobalDecl(classInfoName, *classInfoType);
200     Klass *klass = klassHierarchy->GetKlassFromName(classname);
201     if (klass == nullptr || !klass->GetMIRStructType()->IsLocal()) {
202         classInfo->SetStorageClass(kScExtern);
203     }
204     return classInfo;
205 }
206 
207 }  // namespace maple
208