方舟编译器源码分析(九)

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文件中导入的。

这个编译器的源代码是我原先为了完成编译原理实验课作业而写的,所以只具有教学价值,现在发出来和大家共享 ;-)<br/><br/>和网上流传的版本不同,它从文法开始,一直做到了符号表的实现. 想实现自己的编译器的话,只需在把Initializtion.h中的文法修改为自己的即可.<br/><br/>工程结构:<br/>Initializtion.h 初始化文法,便于进一步进行分析,它为构造GRAMMAR类提供了信息.其中默认非终极符用<>括上,修改时需要注意.<br/>Grammar.cpp Grammar.h 定义了文法GRAMMAR类,它通过initializtion.h的信息建立文法的内部表示。<br/>LL1_Analyser.cpp LL1_Analyser.h 定义了LL1分析器,即LL1_Analyser类.<br/>LL1_Recognizer.cpp LL1_Recognizer.h 为LL1语法分析驱动器,可以通过文法,TOKEN序列和LL1分析表,判定语法是否正确,同时驱动动作.<br/>Rec_Parse.cpp Rec_Pares.h 实现了递归下降分析器Rec_Parse类, 递归下降的思想和LL1驱动器一样,不过是把压栈改成调用自己,而把弹栈改成返回.<br/>Scanner.cpp Scanner.h 实现了词法分析器,可以将程序变为TOKEN序列. 扫描的源程序文件路径也在这里被定义(默认为.//demo.txt)<br/>Action.cpp Action.h 实现了语义栈的操作,_Action类定义了动作符号所对应的动作.<br/>SymTable.cpp SymTable.h 实现了符号表的建立和输出.<br/><br/>希望大家能通过该程序对STL和编译原理有更深刻的理解,Have Fun and Good Luck!<br/><br/> -- David.Morre
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值