Пример #1
0
// This is the method invoked by the EE to Jit code.
CorJitResult LLILCJit::compileMethod(ICorJitInfo *JitInfo,
                                     CORINFO_METHOD_INFO *MethodInfo,
                                     UINT Flags, BYTE **NativeEntry,
                                     ULONG *NativeSizeOfCode) {

  // Bail if input is malformed
  if (nullptr == JitInfo || nullptr == MethodInfo || nullptr == NativeEntry ||
      nullptr == NativeSizeOfCode) {
    return CORJIT_INTERNALERROR;
  }

  // Prep main outputs
  *NativeEntry = nullptr;
  *NativeSizeOfCode = 0;

  // Set up state for this thread (if necessary)
  LLILCJitPerThreadState *PerThreadState = State.get();
  if (PerThreadState == nullptr) {
    PerThreadState = new LLILCJitPerThreadState();
    State.set(PerThreadState);
  }

  // Set up context for this Jit request
  LLILCJitContext Context = LLILCJitContext(PerThreadState);

  // Fill in context information from the CLR
  Context.JitInfo = JitInfo;
  Context.MethodInfo = MethodInfo;
  Context.Flags = Flags;
  JitInfo->getEEInfo(&Context.EEInfo);

  // Fill in context information from LLVM
  Context.LLVMContext = &PerThreadState->LLVMContext;
  std::unique_ptr<Module> M = Context.getModuleForMethod(MethodInfo);
  Context.CurrentModule = M.get();
  Context.CurrentModule->setTargetTriple(LLILC_TARGET_TRIPLE);
  Context.MethodName = Context.CurrentModule->getModuleIdentifier();
  Context.TheABIInfo = ABIInfo::get(*Context.CurrentModule);

  // Initialize per invocation JIT options. This should be done after the
  // rest of the Context is filled out as it has dependencies on JitInfo,
  // Flags and MethodInfo.
  JitOptions JitOptions(Context);

  Context.Options = &JitOptions;

  EngineBuilder Builder(std::move(M));
  std::string ErrStr;
  Builder.setErrorStr(&ErrStr);

  std::unique_ptr<RTDyldMemoryManager> MM(new EEMemoryManager(&Context));
  Builder.setMCJITMemoryManager(std::move(MM));

  TargetOptions Options;
  if (Context.Options->OptLevel != OptLevel::DEBUG_CODE) {
    Builder.setOptLevel(CodeGenOpt::Level::Default);
  } else {
    Builder.setOptLevel(CodeGenOpt::Level::None);
    Options.NoFramePointerElim = true;
  }

  Builder.setTargetOptions(Options);

  ExecutionEngine *NewEngine = Builder.create();

  if (!NewEngine) {
    errs() << "Could not create ExecutionEngine: " << ErrStr << "\n";
    return CORJIT_INTERNALERROR;
  }

  // Don't allow the EE to search for external symbols.
  NewEngine->DisableSymbolSearching();
  Context.EE = NewEngine;

  // Now jit the method.
  CorJitResult Result = CORJIT_INTERNALERROR;
  if (Context.Options->DumpLevel == DumpLevel::VERBOSE) {
    Context.outputDebugMethodName();
  }
  bool HasMethod = this->readMethod(&Context);

  if (HasMethod) {

    if (Context.Options->DoInsertStatepoints) {
      // If using Precise GC, run the GC-Safepoint insertion
      // and lowering passes before generating code.
      legacy::PassManager Passes;
      Passes.add(createPlaceSafepointsPass());

      PassManagerBuilder PMBuilder;
      PMBuilder.OptLevel = 0;  // Set optimization level to -O0
      PMBuilder.SizeLevel = 0; // so that no additional phases are run.
      PMBuilder.populateModulePassManager(Passes);

      Passes.add(createRewriteStatepointsForGCPass(false));
      Passes.run(*Context.CurrentModule);
    }

    Context.EE->generateCodeForModule(Context.CurrentModule);

    // You need to pick up the COFFDyld changes from the MS branch of LLVM
    // or this will fail with an "Incompatible object format!" error
    // from LLVM's dynamic loader.
    uint64_t FunctionAddress =
        Context.EE->getFunctionAddress(Context.MethodName);
    *NativeEntry = (BYTE *)FunctionAddress;

    // TODO: ColdCodeSize, or separated code, is not enabled or included.
    *NativeSizeOfCode = Context.HotCodeSize + Context.ReadOnlyDataSize;

    // This is a stop-gap point to issue a default stub of GC info. This lets
    // the CLR consume our methods cleanly. (and the ETW tracing still works)
    // Down the road this will be superseded by a CLR specific
    // GCMetadataPrinter instance or similar.
    this->outputGCInfo(&Context);

    // Dump out any enabled timing info.
    TimerGroup::printAll(errs());

    // Tell the CLR that we've successfully generated code for this method.
    Result = CORJIT_OK;
  }

  // Clean up a bit
  delete Context.EE;
  Context.EE = nullptr;
  delete Context.TheABIInfo;
  Context.TheABIInfo = nullptr;

  return Result;
}