brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.8 KiB · 11ab2cf Raw
362 lines · cpp
1//===--- IncrementalExecutor.cpp - Incremental Execution --------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the class which performs incremental code execution.10//11//===----------------------------------------------------------------------===//12 13#include "IncrementalExecutor.h"14 15#include "clang/Basic/TargetInfo.h"16#include "clang/Basic/TargetOptions.h"17#include "clang/Interpreter/PartialTranslationUnit.h"18#include "llvm/ADT/StringExtras.h"19#include "llvm/ExecutionEngine/ExecutionEngine.h"20#include "llvm/ExecutionEngine/Orc/CompileUtils.h"21#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"22#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"23#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"24#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"25#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"26#include "llvm/ExecutionEngine/Orc/LLJIT.h"27#include "llvm/ExecutionEngine/Orc/MapperJITLinkMemoryManager.h"28#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"29#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"30#include "llvm/ExecutionEngine/Orc/Shared/SimpleRemoteEPCUtils.h"31#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"32#include "llvm/ExecutionEngine/SectionMemoryManager.h"33#include "llvm/IR/Module.h"34#include "llvm/Support/FileSystem.h"35#include "llvm/Support/ManagedStatic.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/TargetSelect.h"38#include "llvm/TargetParser/Host.h"39 40#ifdef LLVM_ON_UNIX41#include <netdb.h>42#include <netinet/in.h>43#include <sys/socket.h>44#include <unistd.h>45#endif // LLVM_ON_UNIX46 47// Force linking some of the runtimes that helps attaching to a debugger.48LLVM_ATTRIBUTE_USED void linkComponents() {49  llvm::errs() << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;50}51 52namespace clang {53IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC)54    : TSCtx(TSC) {}55 56llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>57IncrementalExecutor::createDefaultJITBuilder(58    llvm::orc::JITTargetMachineBuilder JTMB) {59  auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();60  JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));61  JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {62    // Try to enable debugging of JIT'd code (only works with JITLink for63    // ELF and MachO).64    consumeError(llvm::orc::enableDebuggerSupport(J));65    return llvm::Error::success();66  });67  return std::move(JITBuilder);68}69 70IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,71                                         llvm::orc::LLJITBuilder &JITBuilder,72                                         Interpreter::JITConfig Config,73                                         llvm::Error &Err)74    : TSCtx(TSC), OutOfProcessChildPid(Config.ExecutorPID) {75  using namespace llvm::orc;76  llvm::ErrorAsOutParameter EAO(&Err);77 78  if (auto JitOrErr = JITBuilder.create())79    Jit = std::move(*JitOrErr);80  else {81    Err = JitOrErr.takeError();82    return;83  }84}85 86IncrementalExecutor::~IncrementalExecutor() {}87 88llvm::Error IncrementalExecutor::addModule(PartialTranslationUnit &PTU) {89  llvm::orc::ResourceTrackerSP RT =90      Jit->getMainJITDylib().createResourceTracker();91  ResourceTrackers[&PTU] = RT;92 93  return Jit->addIRModule(RT, {std::move(PTU.TheModule), TSCtx});94}95 96llvm::Error IncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {97 98  llvm::orc::ResourceTrackerSP RT = std::move(ResourceTrackers[&PTU]);99  if (!RT)100    return llvm::Error::success();101 102  ResourceTrackers.erase(&PTU);103  if (llvm::Error Err = RT->remove())104    return Err;105  return llvm::Error::success();106}107 108// Clean up the JIT instance.109llvm::Error IncrementalExecutor::cleanUp() {110  // This calls the global dtors of registered modules.111  return Jit->deinitialize(Jit->getMainJITDylib());112}113 114llvm::Error IncrementalExecutor::runCtors() const {115  return Jit->initialize(Jit->getMainJITDylib());116}117 118llvm::Expected<llvm::orc::ExecutorAddr>119IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,120                                      SymbolNameKind NameKind) const {121  using namespace llvm::orc;122  auto SO = makeJITDylibSearchOrder({&Jit->getMainJITDylib(),123                                     Jit->getPlatformJITDylib().get(),124                                     Jit->getProcessSymbolsJITDylib().get()});125 126  ExecutionSession &ES = Jit->getExecutionSession();127 128  auto SymOrErr =129      ES.lookup(SO, (NameKind == LinkerName) ? ES.intern(Name)130                                             : Jit->mangleAndIntern(Name));131  if (auto Err = SymOrErr.takeError())132    return std::move(Err);133  return SymOrErr->getAddress();134}135 136Expected<std::unique_ptr<llvm::jitlink::JITLinkMemoryManager>>137createSharedMemoryManager(llvm::orc::SimpleRemoteEPC &SREPC,138                          unsigned SlabAllocateSize) {139  llvm::orc::SharedMemoryMapper::SymbolAddrs SAs;140  if (auto Err = SREPC.getBootstrapSymbols(141          {{SAs.Instance,142            llvm::orc::rt::ExecutorSharedMemoryMapperServiceInstanceName},143           {SAs.Reserve,144            llvm::orc::rt::ExecutorSharedMemoryMapperServiceReserveWrapperName},145           {SAs.Initialize,146            llvm::orc::rt::147                ExecutorSharedMemoryMapperServiceInitializeWrapperName},148           {SAs.Deinitialize,149            llvm::orc::rt::150                ExecutorSharedMemoryMapperServiceDeinitializeWrapperName},151           {SAs.Release,152            llvm::orc::rt::153                ExecutorSharedMemoryMapperServiceReleaseWrapperName}}))154    return std::move(Err);155 156  size_t SlabSize;157  if (llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows())158    SlabSize = 1024 * 1024;159  else160    SlabSize = 1024 * 1024 * 1024;161 162  if (SlabAllocateSize > 0)163    SlabSize = SlabAllocateSize;164 165  return llvm::orc::MapperJITLinkMemoryManager::CreateWithMapper<166      llvm::orc::SharedMemoryMapper>(SlabSize, SREPC, SAs);167}168 169llvm::Expected<std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint32_t>>170IncrementalExecutor::launchExecutor(llvm::StringRef ExecutablePath,171                                    bool UseSharedMemory,172                                    unsigned SlabAllocateSize,173                                    std::function<void()> CustomizeFork) {174#ifndef LLVM_ON_UNIX175  // FIXME: Add support for Windows.176  return llvm::make_error<llvm::StringError>(177      "-" + ExecutablePath + " not supported on non-unix platforms",178      llvm::inconvertibleErrorCode());179#elif !LLVM_ENABLE_THREADS180  // Out of process mode using SimpleRemoteEPC depends on threads.181  return llvm::make_error<llvm::StringError>(182      "-" + ExecutablePath +183          " requires threads, but LLVM was built with "184          "LLVM_ENABLE_THREADS=Off",185      llvm::inconvertibleErrorCode());186#else187 188  if (!llvm::sys::fs::can_execute(ExecutablePath))189    return llvm::make_error<llvm::StringError>(190        llvm::formatv("Specified executor invalid: {0}", ExecutablePath),191        llvm::inconvertibleErrorCode());192 193  constexpr int ReadEnd = 0;194  constexpr int WriteEnd = 1;195 196  // Pipe FDs.197  int ToExecutor[2];198  int FromExecutor[2];199 200  uint32_t ChildPID;201 202  // Create pipes to/from the executor..203  if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0)204    return llvm::make_error<llvm::StringError>(205        "Unable to create pipe for executor", llvm::inconvertibleErrorCode());206 207  ChildPID = fork();208 209  if (ChildPID == 0) {210    // In the child...211 212    // Close the parent ends of the pipes213    close(ToExecutor[WriteEnd]);214    close(FromExecutor[ReadEnd]);215 216    if (CustomizeFork)217      CustomizeFork();218 219    // Execute the child process.220    std::unique_ptr<char[]> ExecutorPath, FDSpecifier;221    {222      ExecutorPath = std::make_unique<char[]>(ExecutablePath.size() + 1);223      strcpy(ExecutorPath.get(), ExecutablePath.data());224 225      std::string FDSpecifierStr("filedescs=");226      FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]);227      FDSpecifierStr += ',';228      FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]);229      FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1);230      strcpy(FDSpecifier.get(), FDSpecifierStr.c_str());231    }232 233    char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr};234    int RC = execvp(ExecutorPath.get(), Args);235    if (RC != 0) {236      llvm::errs() << "unable to launch out-of-process executor \""237                   << ExecutorPath.get() << "\"\n";238      exit(1);239    }240  }241  // else we're the parent...242 243  // Close the child ends of the pipes244  close(ToExecutor[ReadEnd]);245  close(FromExecutor[WriteEnd]);246 247  llvm::orc::SimpleRemoteEPC::Setup S = llvm::orc::SimpleRemoteEPC::Setup();248  if (UseSharedMemory)249    S.CreateMemoryManager =250        [SlabAllocateSize](llvm::orc::SimpleRemoteEPC &EPC) {251          return createSharedMemoryManager(EPC, SlabAllocateSize);252        };253 254  auto EPCOrErr =255      llvm::orc::SimpleRemoteEPC::Create<llvm::orc::FDSimpleRemoteEPCTransport>(256          std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(257              std::nullopt),258          std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]);259  if (!EPCOrErr)260    return EPCOrErr.takeError();261  return std::make_pair(std::move(*EPCOrErr), ChildPID);262#endif263}264 265#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS266 267static Expected<int> connectTCPSocketImpl(std::string Host,268                                          std::string PortStr) {269  addrinfo *AI;270  addrinfo Hints{};271  Hints.ai_family = AF_INET;272  Hints.ai_socktype = SOCK_STREAM;273  Hints.ai_flags = AI_NUMERICSERV;274 275  if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI))276    return llvm::make_error<llvm::StringError>(277        llvm::formatv("address resolution failed ({0})", strerror(EC)),278        llvm::inconvertibleErrorCode());279  // Cycle through the returned addrinfo structures and connect to the first280  // reachable endpoint.281  int SockFD;282  addrinfo *Server;283  for (Server = AI; Server != nullptr; Server = Server->ai_next) {284    // socket might fail, e.g. if the address family is not supported. Skip to285    // the next addrinfo structure in such a case.286    if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0)287      continue;288 289    // If connect returns null, we exit the loop with a working socket.290    if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0)291      break;292 293    close(SockFD);294  }295  freeaddrinfo(AI);296 297  // If we reached the end of the loop without connecting to a valid endpoint,298  // dump the last error that was logged in socket() or connect().299  if (Server == nullptr)300    return llvm::make_error<llvm::StringError>("invalid hostname",301                                               llvm::inconvertibleErrorCode());302 303  return SockFD;304}305 306llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>307IncrementalExecutor::connectTCPSocket(llvm::StringRef NetworkAddress,308                                      bool UseSharedMemory,309                                      unsigned SlabAllocateSize) {310#ifndef LLVM_ON_UNIX311  // FIXME: Add TCP support for Windows.312  return llvm::make_error<llvm::StringError>(313      "-" + NetworkAddress + " not supported on non-unix platforms",314      llvm::inconvertibleErrorCode());315#elif !LLVM_ENABLE_THREADS316  // Out of process mode using SimpleRemoteEPC depends on threads.317  return llvm::make_error<llvm::StringError>(318      "-" + NetworkAddress +319          " requires threads, but LLVM was built with "320          "LLVM_ENABLE_THREADS=Off",321      llvm::inconvertibleErrorCode());322#else323 324  auto CreateErr = [NetworkAddress](Twine Details) {325    return llvm::make_error<llvm::StringError>(326        formatv("Failed to connect TCP socket '{0}': {1}", NetworkAddress,327                Details),328        llvm::inconvertibleErrorCode());329  };330 331  StringRef Host, PortStr;332  std::tie(Host, PortStr) = NetworkAddress.split(':');333  if (Host.empty())334    return CreateErr("Host name for -" + NetworkAddress + " can not be empty");335  if (PortStr.empty())336    return CreateErr("Port number in -" + NetworkAddress + " can not be empty");337  int Port = 0;338  if (PortStr.getAsInteger(10, Port))339    return CreateErr("Port number '" + PortStr + "' is not a valid integer");340 341  Expected<int> SockFD = connectTCPSocketImpl(Host.str(), PortStr.str());342  if (!SockFD)343    return SockFD.takeError();344 345  llvm::orc::SimpleRemoteEPC::Setup S = llvm::orc::SimpleRemoteEPC::Setup();346  if (UseSharedMemory)347    S.CreateMemoryManager =348        [SlabAllocateSize](llvm::orc::SimpleRemoteEPC &EPC) {349          return createSharedMemoryManager(EPC, SlabAllocateSize);350        };351 352  return llvm::orc::SimpleRemoteEPC::Create<353      llvm::orc::FDSimpleRemoteEPCTransport>(354      std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(355          std::nullopt),356      std::move(S), *SockFD, *SockFD);357#endif358}359#endif // _WIN32360 361} // namespace clang362