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