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 <set>
17 #include "emit.h"
18
19 namespace maplebe {
20 using namespace maple;
21
22 #define JAVALANG (mirModule->IsJavaModule())
23
SetTarget(CG & target)24 void Globals::SetTarget(CG &target)
25 {
26 cg = ⌖
27 }
GetTarget() const28 const CG *Globals::GetTarget() const
29 {
30 DEBUG_ASSERT(cg, " set target info please ");
31 return cg;
32 }
33
34 CGFunc *CG::currentCGFunction = nullptr;
35 std::map<MIRFunction *, std::pair<LabelIdx, LabelIdx>> CG::funcWrapLabels;
36
~CG()37 CG::~CG()
38 {
39 if (emitter != nullptr) {
40 emitter->CloseOutput();
41 }
42 delete memPool;
43 memPool = nullptr;
44 mirModule = nullptr;
45 emitter = nullptr;
46 currentCGFunction = nullptr;
47 instrumentationFunction = nullptr;
48 dbgTraceEnter = nullptr;
49 dbgTraceExit = nullptr;
50 dbgFuncProfile = nullptr;
51 }
52 /* This function intends to be a more general form of GenFieldOffsetmap. */
GenExtraTypeMetadata(const std::string & classListFileName,const std::string & outputBaseName)53 void CG::GenExtraTypeMetadata(const std::string &classListFileName, const std::string &outputBaseName)
54 {
55 const std::string &cMacroDefSuffix = ".macros.def";
56 BECommon *beCommon = Globals::GetInstance()->GetBECommon();
57 std::vector<MIRClassType *> classesToGenerate;
58
59 if (classListFileName.empty()) {
60 /*
61 * Class list not specified. Visit all classes.
62 */
63 std::set<std::string> visited;
64
65 for (const auto &tyId : mirModule->GetClassList()) {
66 MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyId);
67 if ((mirType->GetKind() != kTypeClass) && (mirType->GetKind() != kTypeClassIncomplete)) {
68 continue; /* Skip non-class. Too paranoid. We just enumerated classlist_! */
69 }
70 MIRClassType *classType = static_cast<MIRClassType *>(mirType);
71 const std::string &name = classType->GetName();
72
73 if (visited.find(name) != visited.end()) {
74 continue; /* Skip duplicated class definitions. */
75 }
76
77 (void)visited.insert(name);
78 classesToGenerate.emplace_back(classType);
79 }
80 } else {
81 /* Visit listed classes. */
82 std::ifstream inFile(classListFileName);
83 CHECK_FATAL(inFile.is_open(), "Failed to open file: %s", classListFileName.c_str());
84 std::string str;
85
86 /* check each class name first and expose all unknown classes */
87 while (inFile >> str) {
88 MIRType *type = GlobalTables::GetTypeTable().GetOrCreateClassType(str, *mirModule);
89 MIRClassType *classType = static_cast<MIRClassType *>(type);
90 if (classType == nullptr) {
91 LogInfo::MapleLogger() << " >>>>>>>> unknown class: " << str.c_str() << "\n";
92 return;
93 }
94
95 classesToGenerate.emplace_back(classType);
96 }
97 }
98
99 if (cgOption.GenDef()) {
100 const std::string &outputFileName = outputBaseName + cMacroDefSuffix;
101 FILE *outputFile = fopen(outputFileName.c_str(), "w");
102 if (outputFile == nullptr) {
103 FATAL(kLncFatal, "open file failed in CG::GenExtraTypeMetadata");
104 }
105
106 for (auto classType : classesToGenerate) {
107 beCommon->GenObjSize(*classType, *outputFile);
108 beCommon->GenFieldOffsetMap(*classType, *outputFile);
109 }
110 fclose(outputFile);
111 }
112
113 if (cgOption.GenGctib()) {
114 maple::LogInfo::MapleLogger(kLlErr) << "--gen-gctib-file option not implemented";
115 }
116 }
117
GenPrimordialObjectList(const std::string & outputBaseName)118 void CG::GenPrimordialObjectList(const std::string &outputBaseName)
119 {
120 const std::string &kPrimorListSuffix = ".primordials.txt";
121 if (!cgOption.GenPrimorList()) {
122 return;
123 }
124
125 const std::string &outputFileName = outputBaseName + kPrimorListSuffix;
126 FILE *outputFile = fopen(outputFileName.c_str(), "w");
127 if (outputFile == nullptr) {
128 FATAL(kLncFatal, "open file failed in CG::GenPrimordialObjectList");
129 }
130
131 for (StIdx stIdx : mirModule->GetSymbolSet()) {
132 MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx());
133 DEBUG_ASSERT(symbol != nullptr, "get symbol from st idx failed");
134 if (symbol->IsPrimordialObject()) {
135 const std::string &name = symbol->GetName();
136 fprintf(outputFile, "%s\n", name.c_str());
137 }
138 }
139
140 fclose(outputFile);
141 }
142
AddStackGuardvar()143 void CG::AddStackGuardvar()
144 {
145 MIRSymbol *chkGuard = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
146 chkGuard->SetNameStrIdx(std::string("__stack_chk_guard"));
147 chkGuard->SetStorageClass(kScExtern);
148 chkGuard->SetSKind(kStVar);
149 CHECK_FATAL(GlobalTables::GetTypeTable().GetTypeTable().size() > PTY_u64, "out of vector range");
150 chkGuard->SetTyIdx(GlobalTables::GetTypeTable().GetTypeTable()[PTY_u64]->GetTypeIndex());
151 GlobalTables::GetGsymTable().AddToStringSymbolMap(*chkGuard);
152
153 MIRSymbol *chkFunc = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
154 chkFunc->SetNameStrIdx(std::string("__stack_chk_fail"));
155 chkFunc->SetStorageClass(kScText);
156 chkFunc->SetSKind(kStFunc);
157 GlobalTables::GetGsymTable().AddToStringSymbolMap(*chkFunc);
158 }
159
SetInstrumentationFunction(const std::string & name)160 void CG::SetInstrumentationFunction(const std::string &name)
161 {
162 instrumentationFunction = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
163 instrumentationFunction->SetNameStrIdx(std::string("__").append(name).append("__"));
164 instrumentationFunction->SetStorageClass(kScText);
165 instrumentationFunction->SetSKind(kStFunc);
166 }
167
168 #define DBG_TRACE_ENTER MplDtEnter
169 #define DBG_TRACE_EXIT MplDtExit
170 #define XSTR(s) str(s)
171 #define str(s) #s
172
DefineDebugTraceFunctions()173 void CG::DefineDebugTraceFunctions()
174 {
175 dbgTraceEnter = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
176 dbgTraceEnter->SetNameStrIdx(std::string("__" XSTR(DBG_TRACE_ENTER) "__"));
177 dbgTraceEnter->SetStorageClass(kScText);
178 dbgTraceEnter->SetSKind(kStFunc);
179
180 dbgTraceExit = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
181 dbgTraceExit->SetNameStrIdx(std::string("__" XSTR(DBG_TRACE_EXIT) "__"));
182 dbgTraceExit->SetStorageClass(kScText);
183 dbgTraceExit->SetSKind(kStFunc);
184
185 dbgFuncProfile = GlobalTables::GetGsymTable().CreateSymbol(kScopeGlobal);
186 dbgFuncProfile->SetNameStrIdx(std::string("__" XSTR(MplFuncProfile) "__"));
187 dbgFuncProfile->SetStorageClass(kScText);
188 dbgFuncProfile->SetSKind(kStFunc);
189 }
190
191 /*
192 * Add the fields of curStructType to the result. Used to handle recursive
193 * structures.
194 */
AppendReferenceOffsets64(const BECommon & beCommon,MIRStructType & curStructType,int64 & curOffset,std::vector<int64> & result)195 static void AppendReferenceOffsets64(const BECommon &beCommon, MIRStructType &curStructType, int64 &curOffset,
196 std::vector<int64> &result)
197 {
198 /*
199 * We are going to reimplement BECommon::GetFieldOffset so that we can do
200 * this in one pass through all fields.
201 *
202 * The tricky part is to make sure the object layout described here is
203 * compatible with the rest of the system. This implies that we need
204 * something like a "Maple ABI" documented for each platform.
205 */
206 if (curStructType.GetKind() == kTypeClass) {
207 MIRClassType &curClassTy = static_cast<MIRClassType &>(curStructType);
208 auto maybeParent = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curClassTy.GetParentTyIdx());
209 if (maybeParent != nullptr) {
210 if (maybeParent->GetKind() == kTypeClass) {
211 auto parentClassType = static_cast<MIRClassType *>(maybeParent);
212 AppendReferenceOffsets64(beCommon, *parentClassType, curOffset, result);
213 } else {
214 LogInfo::MapleLogger() << "WARNING:: generating objmap for incomplete class\n";
215 }
216 }
217 }
218
219 for (const auto &fieldPair : curStructType.GetFields()) {
220 auto fieldNameIdx = fieldPair.first;
221 auto fieldTypeIdx = fieldPair.second.first;
222
223 auto &fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldNameIdx);
224 auto fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTypeIdx);
225 auto &fieldTypeName = GlobalTables::GetStrTable().GetStringFromStrIdx(fieldType->GetNameStrIdx());
226 auto fieldTypeKind = fieldType->GetKind();
227
228 auto fieldSize = beCommon.GetTypeSize(fieldTypeIdx);
229 auto fieldAlign = beCommon.GetTypeAlign(fieldTypeIdx);
230 int64 myOffset = static_cast<int64>(RoundUp(curOffset, fieldAlign));
231 int64 nextOffset = myOffset + fieldSize;
232
233 if (!CGOptions::IsQuiet()) {
234 LogInfo::MapleLogger() << " field: " << fieldName << "\n";
235 LogInfo::MapleLogger() << " type: " << fieldTypeIdx << ": " << fieldTypeName << "\n";
236 LogInfo::MapleLogger() << " type kind: " << fieldTypeKind << "\n";
237 LogInfo::MapleLogger() << " size: " << fieldSize << "\n"; /* int64 */
238 LogInfo::MapleLogger() << " align: " << static_cast<uint32>(fieldAlign) << "\n"; /* int8_t */
239 LogInfo::MapleLogger() << " field offset:" << myOffset << "\n"; /* int64 */
240 }
241
242 if (fieldTypeKind == kTypePointer) {
243 if (!CGOptions::IsQuiet()) {
244 LogInfo::MapleLogger() << " ** Is a pointer field.\n";
245 }
246 result.emplace_back(myOffset);
247 }
248
249 if ((fieldTypeKind == kTypeArray) || (fieldTypeKind == kTypeStruct) || (fieldTypeKind == kTypeClass) ||
250 (fieldTypeKind == kTypeInterface)) {
251 if (!CGOptions::IsQuiet()) {
252 LogInfo::MapleLogger() << " ** ERROR: We are not expecting nested aggregate type. ";
253 LogInfo::MapleLogger() << "All Java classes are flat -- no nested structs. ";
254 LogInfo::MapleLogger() << "Please extend me if we are going to work with non-java languages.\n";
255 }
256 }
257
258 curOffset = nextOffset;
259 }
260 }
261
262 /* Return a list of offsets of reference fields. */
GetReferenceOffsets64(const BECommon & beCommon,MIRStructType & structType)263 std::vector<int64> CG::GetReferenceOffsets64(const BECommon &beCommon, MIRStructType &structType)
264 {
265 std::vector<int64> result;
266 /* java class layout has already been done in previous phase. */
267 if (structType.GetKind() == kTypeClass) {
268 for (auto fieldInfo : beCommon.GetJClassLayout(static_cast<MIRClassType &>(structType))) {
269 if (fieldInfo.IsRef()) {
270 result.emplace_back(static_cast<int64>(fieldInfo.GetOffset()));
271 }
272 }
273 } else if (structType.GetKind() != kTypeInterface) { /* interface doesn't have reference fields */
274 int64 curOffset = 0;
275 AppendReferenceOffsets64(beCommon, structType, curOffset, result);
276 }
277
278 return result;
279 }
280
ExtractFuncName(const std::string & str)281 const std::string CG::ExtractFuncName(const std::string &str)
282 {
283 /* 3: length of "_7C" */
284 size_t offset = 3;
285 size_t pos1 = str.find("_7C");
286 if (pos1 == std::string::npos) {
287 return str;
288 }
289 size_t pos2 = str.find("_7C", pos1 + offset);
290 if (pos2 == std::string::npos) {
291 return str;
292 }
293 std::string funcName = str.substr(pos1 + offset, pos2 - pos1 - offset);
294 /* avoid funcName like __LINE__ and __FILE__ which will be resolved by assembler */
295 if (funcName.find("__") != std::string::npos) {
296 return str;
297 }
298 if (funcName == "_3Cinit_3E") {
299 return "init";
300 }
301 if (funcName == "_3Cclinit_3E") {
302 return "clinit";
303 }
304 return funcName;
305 }
306 } /* namespace maplebe */
307