int Compiler::compile(bool compileOnly) {
  llvm::Target const *Target = NULL;
  llvm::TargetData *TD = NULL;
  llvm::TargetMachine *TM = NULL;

  std::string FeaturesStr;

  llvm::NamedMDNode const *PragmaMetadata;
  llvm::NamedMDNode const *ExportVarMetadata;
  llvm::NamedMDNode const *ExportFuncMetadata;
  llvm::NamedMDNode const *ObjectSlotMetadata;

  if (mModule == NULL)  // No module was loaded
    return 0;

  // Create TargetMachine
  Target = llvm::TargetRegistry::lookupTarget(Triple, mError);
  if (hasError())
    goto on_bcc_compile_error;

  if (!CPU.empty() || !Features.empty()) {
    llvm::SubtargetFeatures F;

    for (std::vector<std::string>::const_iterator
         I = Features.begin(), E = Features.end(); I != E; I++) {
      F.AddFeature(*I);
    }

    FeaturesStr = F.getString();
  }

#if defined(DEFAULT_X86_64_CODEGEN)
  // Data address in X86_64 architecture may reside in a far-away place
  TM = Target->createTargetMachine(Triple, CPU, FeaturesStr,
                                   llvm::Reloc::Static,
                                   llvm::CodeModel::Medium);
#else
  // This is set for the linker (specify how large of the virtual addresses
  // we can access for all unknown symbols.)
  TM = Target->createTargetMachine(Triple, CPU, FeaturesStr,
                                   llvm::Reloc::Static,
                                   llvm::CodeModel::Small);
#endif
  if (TM == NULL) {
    setError("Failed to create target machine implementation for the"
             " specified triple '" + Triple + "'");
    goto on_bcc_compile_error;
  }

  // Get target data from Module
  TD = new llvm::TargetData(mModule);

  // Load named metadata
  ExportVarMetadata = mModule->getNamedMetadata(ExportVarMetadataName);
  ExportFuncMetadata = mModule->getNamedMetadata(ExportFuncMetadataName);
  PragmaMetadata = mModule->getNamedMetadata(PragmaMetadataName);
  ObjectSlotMetadata = mModule->getNamedMetadata(ObjectSlotMetadataName);

  // Perform link-time optimization if we have multiple modules
  if (mHasLinked) {
    runLTO(new llvm::TargetData(*TD), ExportVarMetadata, ExportFuncMetadata);
  }

  // Perform code generation
#if USE_OLD_JIT
  if (runCodeGen(new llvm::TargetData(*TD), TM,
                 ExportVarMetadata, ExportFuncMetadata) != 0) {
    goto on_bcc_compile_error;
  }
#endif

#if USE_MCJIT
  if (runMCCodeGen(new llvm::TargetData(*TD), TM) != 0) {
    goto on_bcc_compile_error;
  }

  if (compileOnly)
    return 0;

  // Load the ELF Object
  mRSExecutable =
    rsloaderCreateExec((unsigned char *)&*mEmittedELFExecutable.begin(),
                       mEmittedELFExecutable.size(),
                       &resolveSymbolAdapter, this);

  if (!mRSExecutable) {
    setError("Fail to load emitted ELF relocatable file");
    goto on_bcc_compile_error;
  }

  if (ExportVarMetadata) {
    ScriptCompiled::ExportVarList &varList = mpResult->mExportVars;
    std::vector<std::string> &varNameList = mpResult->mExportVarsName;

    for (int i = 0, e = ExportVarMetadata->getNumOperands(); i != e; i++) {
      llvm::MDNode *ExportVar = ExportVarMetadata->getOperand(i);
      if (ExportVar != NULL && ExportVar->getNumOperands() > 1) {
        llvm::Value *ExportVarNameMDS = ExportVar->getOperand(0);
        if (ExportVarNameMDS->getValueID() == llvm::Value::MDStringVal) {
          llvm::StringRef ExportVarName =
            static_cast<llvm::MDString*>(ExportVarNameMDS)->getString();

          varList.push_back(
            rsloaderGetSymbolAddress(mRSExecutable,
                                     ExportVarName.str().c_str()));
          varNameList.push_back(ExportVarName.str());
#if DEBUG_MCJIT_REFLECT
          LOGD("runMCCodeGen(): Exported Var: %s @ %p\n", ExportVarName.str().c_str(),
               varList.back());
#endif
          continue;
        }
      }

      varList.push_back(NULL);
    }
  }

  if (ExportFuncMetadata) {
    ScriptCompiled::ExportFuncList &funcList = mpResult->mExportFuncs;
    std::vector<std::string> &funcNameList = mpResult->mExportFuncsName;

    for (int i = 0, e = ExportFuncMetadata->getNumOperands(); i != e; i++) {
      llvm::MDNode *ExportFunc = ExportFuncMetadata->getOperand(i);
      if (ExportFunc != NULL && ExportFunc->getNumOperands() > 0) {
        llvm::Value *ExportFuncNameMDS = ExportFunc->getOperand(0);
        if (ExportFuncNameMDS->getValueID() == llvm::Value::MDStringVal) {
          llvm::StringRef ExportFuncName =
            static_cast<llvm::MDString*>(ExportFuncNameMDS)->getString();

          funcList.push_back(
            rsloaderGetSymbolAddress(mRSExecutable,
                                     ExportFuncName.str().c_str()));
          funcNameList.push_back(ExportFuncName.str());
#if DEBUG_MCJIT_RELECT
          LOGD("runMCCodeGen(): Exported Func: %s @ %p\n", ExportFuncName.str().c_str(),
               funcList.back());
#endif
        }
      }
    }
  }

#if DEBUG_MCJIT_DISASSEMBLER
  {
    // Get MC codegen emitted function name list
    size_t func_list_size = rsloaderGetFuncCount(mRSExecutable);
    std::vector<char const *> func_list(func_list_size, NULL);
    rsloaderGetFuncNameList(mRSExecutable, func_list_size, &*func_list.begin());

    // Disassemble each function
    for (size_t i = 0; i < func_list_size; ++i) {
      void *func = rsloaderGetSymbolAddress(mRSExecutable, func_list[i]);
      if (func) {
        size_t size = rsloaderGetSymbolSize(mRSExecutable, func_list[i]);
        Disassemble(DEBUG_MCJIT_DISASSEMBLER_FILE,
                    Target, TM, func_list[i], (unsigned char const *)func, size);
      }
    }
  }
#endif
#endif

  // Read pragma information from the metadata node of the module.
  if (PragmaMetadata) {
    ScriptCompiled::PragmaList &pragmaList = mpResult->mPragmas;

    for (int i = 0, e = PragmaMetadata->getNumOperands(); i != e; i++) {
      llvm::MDNode *Pragma = PragmaMetadata->getOperand(i);
      if (Pragma != NULL &&
          Pragma->getNumOperands() == 2 /* should have exactly 2 operands */) {
        llvm::Value *PragmaNameMDS = Pragma->getOperand(0);
        llvm::Value *PragmaValueMDS = Pragma->getOperand(1);

        if ((PragmaNameMDS->getValueID() == llvm::Value::MDStringVal) &&
            (PragmaValueMDS->getValueID() == llvm::Value::MDStringVal)) {
          llvm::StringRef PragmaName =
            static_cast<llvm::MDString*>(PragmaNameMDS)->getString();
          llvm::StringRef PragmaValue =
            static_cast<llvm::MDString*>(PragmaValueMDS)->getString();

          pragmaList.push_back(
            std::make_pair(std::string(PragmaName.data(),
                                       PragmaName.size()),
                           std::string(PragmaValue.data(),
                                       PragmaValue.size())));
#if DEBUG_BCC_REFLECT
          LOGD("compile(): Pragma: %s -> %s\n",
               pragmaList.back().first.c_str(),
               pragmaList.back().second.c_str());
#endif
        }
      }
    }
  }

  if (ObjectSlotMetadata) {
    ScriptCompiled::ObjectSlotList &objectSlotList = mpResult->mObjectSlots;

    for (int i = 0, e = ObjectSlotMetadata->getNumOperands(); i != e; i++) {
      llvm::MDNode *ObjectSlot = ObjectSlotMetadata->getOperand(i);
      if (ObjectSlot != NULL &&
          ObjectSlot->getNumOperands() == 1) {
        llvm::Value *SlotMDS = ObjectSlot->getOperand(0);
        if (SlotMDS->getValueID() == llvm::Value::MDStringVal) {
          llvm::StringRef Slot =
              static_cast<llvm::MDString*>(SlotMDS)->getString();
          uint32_t USlot = 0;
          if (Slot.getAsInteger(10, USlot)) {
            setError("Non-integer object slot value '" + Slot.str() + "'");
            goto on_bcc_compile_error;
          }
          objectSlotList.push_back(USlot);
#if DEBUG_BCC_REFLECT
          LOGD("compile(): RefCount Slot: %s @ %u\n", Slot.str().c_str(), USlot);
#endif
        }
      }
    }
  }

on_bcc_compile_error:
  // LOGE("on_bcc_compiler_error");
  if (TD) {
    delete TD;
  }

  if (TM) {
    delete TM;
  }

  if (mError.empty()) {
    return 0;
  }

  // LOGE(getErrorMessage());
  return 1;
}
void *Compiler::getSymbolAddress(char const *name) {
  return rsloaderGetSymbolAddress(mRSExecutable, name);
}
void *ScriptCached::lookup(const char *name) {
  return rsloaderGetSymbolAddress(mRSExecutable, name);
}