2021SC@SDUSC
今天分析的是src/mapleall/maple_driver/src/dex2mpl_compiler.cpp的代码
它的头文件是
#include "compiler.h"
#include "default_options.def"
#include <memory>
#ifdef INTERGRATE_DRIVER
#include "dex2mpl_runner.h"
#include "mir_function.h"
#endif
这个类的定义也是在compiler.h中,但相比 Cpp2MplCompiler其中定义的方法较少。
class Dex2MplCompiler : public Compiler {
public:
explicit Dex2MplCompiler(const std::string &name) : Compiler(name) {}
~Dex2MplCompiler() = default;
#ifdef INTERGRATE_DRIVER
ErrorCode Compile(MplOptions &options, std::unique_ptr<MIRModule> &theModule) override;
#endif
相类似的几个方法如下:
const std::string &Dex2MplCompiler::GetBinName() const {
return kBinNameDex2mpl;
}
DefaultOption Dex2MplCompiler::GetDefaultOptions(const MplOptions &options, const Action&) const {
uint32_t len = 0;
MplOption *kDex2mplDefaultOptions = nullptr;
if (options.GetOptimizationLevel() == kO0 && options.HasSetDefaultLevel()) {
len = sizeof(kDex2mplDefaultOptionsO0) / sizeof(MplOption);
kDex2mplDefaultOptions = kDex2mplDefaultOptionsO0;
} else if (options.GetOptimizationLevel() == kO2 && options.HasSetDefaultLevel()) {
len = sizeof(kDex2mplDefaultOptionsO2) / sizeof(MplOption);
kDex2mplDefaultOptions = kDex2mplDefaultOptionsO2;
}
if (kDex2mplDefaultOptions == nullptr) {
return DefaultOption();
}
DefaultOption defaultOptions = { std::make_unique<MplOption[]>(len), len };
for (uint32_t i = 0; i < len; ++i) {
defaultOptions.mplOptions[i] = kDex2mplDefaultOptions[i];
}
for (unsigned int i = 0; i < defaultOptions.length; ++i) {
defaultOptions.mplOptions[i].SetValue(
FileUtils::AppendMapleRootIfNeeded(defaultOptions.mplOptions[i].GetNeedRootPath(),
defaultOptions.mplOptions[i].GetValue(),
options.GetExeFolder()));
}
return defaultOptions;
}
void Dex2MplCompiler::GetTmpFilesToDelete(const MplOptions&, const Action &action,
std::vector<std::string> &tempFiles) const {
tempFiles.push_back(action.GetFullOutputName() + ".mpl");
tempFiles.push_back(action.GetFullOutputName() + ".mplt");
}
std::unordered_set<std::string> Dex2MplCompiler::GetFinalOutputs(const MplOptions&,
const Action &action) const {
auto finalOutputs = std::unordered_set<std::string>();
(void)finalOutputs.insert(action.GetFullOutputName() + ".mpl");
(void)finalOutputs.insert(action.GetFullOutputName() + ".mplt");
return finalOutputs;
}
还有一个打印指令的方法:
void Dex2MplCompiler::PrintCommand(const MplOptions &options) const {
std::string runStr = "--run=";
std::string optionStr = "--option=\"";
std::string connectSym = "";
if (options.GetExeOptions().find(kBinNameDex2mpl) != options.GetExeOptions().end()) {
runStr += "dex2mpl";
auto inputDex2mplOptions = options.GetExeOptions().find(kBinNameDex2mpl);
for (auto &opt : inputDex2mplOptions->second) {
connectSym = opt.Args() != "" ? "=" : "";
optionStr += " --" + opt.OptionKey() + connectSym + opt.Args();
}
}
optionStr += "\"";
LogInfo::MapleLogger() << "Starting:" << options.GetExeFolder() << "maple " << runStr << " " << optionStr
<< " --infile " << GetInputFileName(options) << '\n';
}
如果dex2mpl对应的binname不在options的末尾,则在字符串runstr后边加上dex2mpl,同时,通过遍历options中含dex2mpl对应binname的option,在字符串optionstr后边加上每一个opt的key,args,最后输出由上述几部分组成的字符串到控制台。
之后,是预处理器块部分。
void Dex2MplCompiler::PostDex2Mpl(std::unique_ptr<MIRModule> &theModule) const {
// for each function
for (auto *func : theModule->GetFunctionList()) {
if (func == nullptr) {
continue;
}
MIRSymbolTable *symTab = func->GetSymTab();
// for each symbol
for (size_t i = 0; i != symTab->GetSymbolTableSize(); ++i) {
MIRSymbol *currSymbol = symTab->GetSymbolFromStIdx(i);
if (currSymbol == nullptr) {
continue;
}
// (1) replace void ptr with void ref
if (theModule->IsJavaModule() && currSymbol->GetType() == GlobalTables::GetTypeTable().GetVoidPtr()) {
MIRType *voidRef = GlobalTables::GetTypeTable().GetOrCreatePointerType(
*GlobalTables::GetTypeTable().GetVoid(), PTY_ref);
currSymbol->SetTyIdx(voidRef->GetTypeIndex());
}
// (2) replace String ref with String ptr if symbol's name starts with "L_STR"
if (currSymbol->GetType()->GetKind() == kTypePointer && currSymbol->GetName().find("L_STR") == 0) {
MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(currSymbol->GetTyIdx());
auto *ptrTy = static_cast<MIRPtrType *>(ty->CopyMIRTypeNode());
ASSERT(ptrTy != nullptr, "null ptr check");
ptrTy->SetPrimType(PTY_ptr);
TyIdx newTyIdx = GlobalTables::GetTypeTable().GetOrCreateMIRType(ptrTy);
delete ptrTy;
currSymbol->SetTyIdx(newTyIdx);
}
}
// (3) reset pregIndex of pregTab if function has body
if (func->GetBody() != nullptr) {
uint32 maxPregNo = 0;
for (uint32 i = 0; i < func->GetFormalCount(); ++i) {
MIRSymbol *formalSt = func->GetFormal(i);
if (formalSt->IsPreg()) {
// no special register appears in the formals
uint32 pRegNo = static_cast<uint32>(formalSt->GetPreg()->GetPregNo());
if (pRegNo > maxPregNo) {
maxPregNo = pRegNo;
}
}
}
if (func->GetPregTab() == nullptr) {
continue;
}
func->GetPregTab()->SetIndex(maxPregNo + 1);
}
}
// (4) fix unmatched MIRConst type of global symbols
for (size_t i = 0; i != GlobalTables::GetGsymTable().GetSymbolTableSize(); ++i) {
MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(i);
if (symbol == nullptr || !symbol->IsConst()) {
continue;
}
TyIdx stTyIdx = symbol->GetTyIdx();
if (stTyIdx == 0) {
continue;
}
MIRType *stType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(stTyIdx);
MIRConst *mirConst = symbol->GetKonst();
if (mirConst == nullptr || mirConst->GetKind() != kConstInt) {
continue;
}
if (static_cast<MIRIntConst*>(mirConst)->GetValue() != 0) {
continue;
}
MIRType &valueType = mirConst->GetType();
if (valueType.GetTypeIndex() != stTyIdx) {
auto *newIntConst = theModule->GetMemPool()->New<MIRIntConst>(0, *stType);
symbol->SetValue({newIntConst});
}
}
// (5) remove type attr `rcunowned` of local symbol in rclocalunowned function specified by dex2mpl
for (auto *func : theModule->GetFunctionList()) {
if (func == nullptr || !func->GetAttr(FUNCATTR_rclocalunowned)) {
continue;
}
MIRSymbolTable *symTab = func->GetSymTab();
for (size_t i = 0; i != symTab->GetSymbolTableSize(); ++i) {
MIRSymbol *symbol = symTab->GetSymbolFromStIdx(i);
if (symbol == nullptr) {
continue;
}
if (symbol->GetAttr(ATTR_rcunowned)) {
symbol->ResetAttr(ATTR_rcunowned);
}
}
}
// 1: MIRStructType::isImported has different meaning for dex2mpl and binary mplt importer.
// for dex2mpl, `isImported` means whether a type is imported from mplt file instead of dex file, so all types from
// mplt are marked imported. But for binary mplt importer, `isImported` means whether a type is loaded successfully,
// so only complete types are marked imported.
// The workaround is to reset `isImported` according to the completeness of a type.
for (MIRType *type : GlobalTables::GetTypeTable().GetTypeTable()) {
if (type == nullptr) {
continue;
}
MIRTypeKind typeKind = type->GetKind();
if (typeKind == kTypeStructIncomplete || typeKind == kTypeClassIncomplete || typeKind == kTypeInterfaceIncomplete) {
auto *structType = static_cast<MIRStructType*>(type);
structType->SetIsImported(false);
} else if (typeKind == kTypeClass || typeKind == kTypeInterface) {
auto *structType = static_cast<MIRStructType*>(type);
structType->SetIsImported(true);
}
}
}
参数部分是一个智能独占指针。
遍历每一个function,对于每一个function,进行如下几个操作:
(1) replace void ptr with void ref
(2) replace String ref with String ptr if symbol's name starts with "L_STR"
(3) reset pregIndex of pregTab if function has body
(4) fix unmatched MIRConst type of global symbols
(5) remove type attr `rcunowned` of local symbol in rclocalunowned function specified by dex2mpl
最后,再判定type是否为imported,即从mplt文件中导入的。