mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
* Use clang's effective llvm triple for IR generation Instead of using the target that was passed to the driver. Use the target from the clang importer that might have been changed by clang (i.e armv7 to thumbv7 on darwin) rdar://32599805 * Address review comments * Fix test case osx-targets.swift * Fix pic.swift test case * Fix test abi_v7k.swift * Address review comment for test osx-targets.swift
397 lines
13 KiB
C++
397 lines
13 KiB
C++
//===--- Immediate.cpp - the swift immediate mode -------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This is the implementation of the swift interpreter, which takes a
|
|
// source file and JITs it.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "swift-immediate"
|
|
#include "swift/Immediate/Immediate.h"
|
|
#include "ImmediateImpl.h"
|
|
|
|
#include "swift/Subsystems.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/DiagnosticsFrontend.h"
|
|
#include "swift/AST/IRGenOptions.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "swift/Basic/LLVMContext.h"
|
|
#include "swift/Frontend/Frontend.h"
|
|
#include "swift/SILOptimizer/PassManager/Passes.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/Config/config.h"
|
|
#include "llvm/ExecutionEngine/MCJIT.h"
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/Linker/Linker.h"
|
|
#include "llvm/Transforms/IPO.h"
|
|
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#if defined(_WIN32)
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOMINMAX
|
|
#include <windows.h>
|
|
#else
|
|
#include <dlfcn.h>
|
|
#endif
|
|
|
|
using namespace swift;
|
|
using namespace swift::immediate;
|
|
|
|
static void *loadRuntimeLib(StringRef runtimeLibPathWithName) {
|
|
#if defined(_WIN32)
|
|
return LoadLibraryA(runtimeLibPathWithName.str().c_str());
|
|
#else
|
|
return dlopen(runtimeLibPathWithName.str().c_str(), RTLD_LAZY | RTLD_GLOBAL);
|
|
#endif
|
|
}
|
|
|
|
static void *loadRuntimeLib(StringRef sharedLibName, StringRef runtimeLibPath) {
|
|
// FIXME: Need error-checking.
|
|
llvm::SmallString<128> Path = runtimeLibPath;
|
|
llvm::sys::path::append(Path, sharedLibName);
|
|
return loadRuntimeLib(Path);
|
|
}
|
|
|
|
void *swift::immediate::loadSwiftRuntime(StringRef runtimeLibPath) {
|
|
return loadRuntimeLib("libswiftCore" LTDL_SHLIB_EXT, runtimeLibPath);
|
|
}
|
|
|
|
static bool tryLoadLibrary(LinkLibrary linkLib,
|
|
SearchPathOptions searchPathOpts) {
|
|
llvm::SmallString<128> path = linkLib.getName();
|
|
|
|
// If we have an absolute or relative path, just try to load it now.
|
|
if (llvm::sys::path::has_parent_path(path.str())) {
|
|
return loadRuntimeLib(path);
|
|
}
|
|
|
|
bool success = false;
|
|
switch (linkLib.getKind()) {
|
|
case LibraryKind::Library: {
|
|
llvm::SmallString<32> stem;
|
|
if (llvm::sys::path::has_extension(path.str())) {
|
|
stem = std::move(path);
|
|
} else {
|
|
// FIXME: Try the appropriate extension for the current platform?
|
|
stem = "lib";
|
|
stem += path;
|
|
stem += LTDL_SHLIB_EXT;
|
|
}
|
|
|
|
// Try user-provided library search paths first.
|
|
for (auto &libDir : searchPathOpts.LibrarySearchPaths) {
|
|
path = libDir;
|
|
llvm::sys::path::append(path, stem.str());
|
|
success = loadRuntimeLib(path);
|
|
if (success)
|
|
break;
|
|
}
|
|
|
|
// Let loadRuntimeLib determine the best search paths.
|
|
if (!success)
|
|
success = loadRuntimeLib(stem);
|
|
|
|
// If that fails, try our runtime library path.
|
|
if (!success)
|
|
success = loadRuntimeLib(stem, searchPathOpts.RuntimeLibraryPath);
|
|
break;
|
|
}
|
|
case LibraryKind::Framework: {
|
|
// If we have a framework, mangle the name to point to the framework
|
|
// binary.
|
|
llvm::SmallString<64> frameworkPart{std::move(path)};
|
|
frameworkPart += ".framework";
|
|
llvm::sys::path::append(frameworkPart, linkLib.getName());
|
|
|
|
// Try user-provided framework search paths first; frameworks contain
|
|
// binaries as well as modules.
|
|
for (auto &frameworkDir : searchPathOpts.FrameworkSearchPaths) {
|
|
path = frameworkDir.Path;
|
|
llvm::sys::path::append(path, frameworkPart.str());
|
|
success = loadRuntimeLib(path);
|
|
if (success)
|
|
break;
|
|
}
|
|
|
|
// If that fails, let loadRuntimeLib search for system frameworks.
|
|
if (!success)
|
|
success = loadRuntimeLib(frameworkPart);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool swift::immediate::tryLoadLibraries(ArrayRef<LinkLibrary> LinkLibraries,
|
|
SearchPathOptions SearchPathOpts,
|
|
DiagnosticEngine &Diags) {
|
|
SmallVector<bool, 4> LoadedLibraries;
|
|
LoadedLibraries.append(LinkLibraries.size(), false);
|
|
|
|
// Libraries are not sorted in the topological order of dependencies, and we
|
|
// don't know the dependencies in advance. Try to load all libraries until
|
|
// we stop making progress.
|
|
bool HadProgress;
|
|
do {
|
|
HadProgress = false;
|
|
for (unsigned i = 0; i != LinkLibraries.size(); ++i) {
|
|
if (!LoadedLibraries[i] &&
|
|
tryLoadLibrary(LinkLibraries[i], SearchPathOpts)) {
|
|
LoadedLibraries[i] = true;
|
|
HadProgress = true;
|
|
}
|
|
}
|
|
} while (HadProgress);
|
|
|
|
return std::all_of(LoadedLibraries.begin(), LoadedLibraries.end(),
|
|
[](bool Value) { return Value; });
|
|
}
|
|
|
|
static void linkerDiagnosticHandlerNoCtx(const llvm::DiagnosticInfo &DI) {
|
|
if (DI.getSeverity() != llvm::DS_Error)
|
|
return;
|
|
|
|
std::string MsgStorage;
|
|
{
|
|
llvm::raw_string_ostream Stream(MsgStorage);
|
|
llvm::DiagnosticPrinterRawOStream DP(Stream);
|
|
DI.print(DP);
|
|
}
|
|
llvm::errs() << "Error linking swift modules\n";
|
|
llvm::errs() << MsgStorage << "\n";
|
|
}
|
|
|
|
|
|
|
|
static void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI,
|
|
void *Context) {
|
|
// This assert self documents our precondition that Context is always
|
|
// nullptr. It seems that parts of LLVM are using the flexibility of having a
|
|
// context. We don't really care about this.
|
|
assert(Context == nullptr && "We assume Context is always a nullptr");
|
|
|
|
return linkerDiagnosticHandlerNoCtx(DI);
|
|
}
|
|
|
|
bool swift::immediate::linkLLVMModules(llvm::Module *Module,
|
|
std::unique_ptr<llvm::Module> SubModule
|
|
// TODO: reactivate the linker mode if it is
|
|
// supported in llvm again. Otherwise remove the
|
|
// commented code completely.
|
|
/*, llvm::Linker::LinkerMode LinkerMode */)
|
|
{
|
|
llvm::LLVMContext &Ctx = SubModule->getContext();
|
|
auto OldHandler = Ctx.getDiagnosticHandler();
|
|
void *OldDiagnosticContext = Ctx.getDiagnosticContext();
|
|
Ctx.setDiagnosticHandler(linkerDiagnosticHandler, nullptr);
|
|
bool Failed = llvm::Linker::linkModules(*Module, std::move(SubModule));
|
|
Ctx.setDiagnosticHandler(OldHandler, OldDiagnosticContext);
|
|
|
|
return !Failed;
|
|
}
|
|
|
|
bool swift::immediate::IRGenImportedModules(
|
|
CompilerInstance &CI,
|
|
llvm::Module &Module,
|
|
llvm::SmallPtrSet<swift::ModuleDecl *, 8> &ImportedModules,
|
|
SmallVectorImpl<llvm::Function*> &InitFns,
|
|
IRGenOptions &IRGenOpts,
|
|
const SILOptions &SILOpts) {
|
|
swift::ModuleDecl *M = CI.getMainModule();
|
|
|
|
// Perform autolinking.
|
|
SmallVector<LinkLibrary, 4> AllLinkLibraries(IRGenOpts.LinkLibraries);
|
|
auto addLinkLibrary = [&](LinkLibrary linkLib) {
|
|
AllLinkLibraries.push_back(linkLib);
|
|
};
|
|
|
|
M->forAllVisibleModules({}, /*includePrivateTopLevelImports=*/true,
|
|
[&](ModuleDecl::ImportedModule import) {
|
|
import.second->collectLinkLibraries(addLinkLibrary);
|
|
});
|
|
|
|
// Hack to handle thunks eagerly synthesized by the Clang importer.
|
|
swift::ModuleDecl *prev = nullptr;
|
|
for (auto external : CI.getASTContext().ExternalDefinitions) {
|
|
swift::ModuleDecl *next = external->getModuleContext();
|
|
if (next == prev)
|
|
continue;
|
|
next->collectLinkLibraries(addLinkLibrary);
|
|
prev = next;
|
|
}
|
|
|
|
tryLoadLibraries(AllLinkLibraries, CI.getASTContext().SearchPathOpts,
|
|
CI.getDiags());
|
|
|
|
ImportedModules.insert(M);
|
|
if (!CI.hasSourceImport())
|
|
return false;
|
|
|
|
// IRGen the modules this module depends on. This is only really necessary
|
|
// for imported source, but that's a very convenient thing to do in -i mode.
|
|
// FIXME: Crawling all loaded modules is a hack.
|
|
// FIXME: And re-doing SILGen, SIL-linking, SIL diagnostics, and IRGen is
|
|
// expensive, because it's not properly being limited to new things right now.
|
|
bool hadError = false;
|
|
for (auto &entry : CI.getASTContext().LoadedModules) {
|
|
swift::ModuleDecl *import = entry.second;
|
|
if (!ImportedModules.insert(import).second)
|
|
continue;
|
|
|
|
std::unique_ptr<SILModule> SILMod = performSILGeneration(import,
|
|
CI.getSILOptions());
|
|
performSILLinking(SILMod.get());
|
|
if (runSILDiagnosticPasses(*SILMod)) {
|
|
hadError = true;
|
|
break;
|
|
}
|
|
runSILLoweringPasses(*SILMod);
|
|
|
|
// FIXME: We shouldn't need to use the global context here, but
|
|
// something is persisting across calls to performIRGeneration.
|
|
auto SubModule = performIRGeneration(IRGenOpts, import,
|
|
std::move(SILMod),
|
|
import->getName().str(),
|
|
getGlobalLLVMContext());
|
|
|
|
if (CI.getASTContext().hadError()) {
|
|
hadError = true;
|
|
break;
|
|
}
|
|
|
|
if (!linkLLVMModules(&Module, std::move(SubModule)
|
|
// TODO: reactivate the linker mode if it is
|
|
// supported in llvm again. Otherwise remove the
|
|
// commented code completely.
|
|
/*, llvm::Linker::DestroySource */)) {
|
|
hadError = true;
|
|
break;
|
|
}
|
|
|
|
// FIXME: This is an ugly hack; need to figure out how this should
|
|
// actually work.
|
|
SmallVector<char, 20> NameBuf;
|
|
StringRef InitFnName = (import->getName().str() + ".init").toStringRef(NameBuf);
|
|
llvm::Function *InitFn = Module.getFunction(InitFnName);
|
|
if (InitFn)
|
|
InitFns.push_back(InitFn);
|
|
}
|
|
|
|
return hadError;
|
|
}
|
|
|
|
int swift::RunImmediately(CompilerInstance &CI, const ProcessCmdLine &CmdLine,
|
|
IRGenOptions &IRGenOpts, const SILOptions &SILOpts) {
|
|
ASTContext &Context = CI.getASTContext();
|
|
|
|
// IRGen the main module.
|
|
auto *swiftModule = CI.getMainModule();
|
|
// FIXME: We shouldn't need to use the global context here, but
|
|
// something is persisting across calls to performIRGeneration.
|
|
auto ModuleOwner = performIRGeneration(IRGenOpts, swiftModule,
|
|
CI.takeSILModule(),
|
|
swiftModule->getName().str(),
|
|
getGlobalLLVMContext());
|
|
auto *Module = ModuleOwner.get();
|
|
|
|
if (Context.hadError())
|
|
return -1;
|
|
|
|
// Load libSwiftCore to setup process arguments.
|
|
//
|
|
// This must be done here, before any library loading has been done, to avoid
|
|
// racing with the static initializers in user code.
|
|
auto stdlib = loadSwiftRuntime(Context.SearchPathOpts.RuntimeLibraryPath);
|
|
if (!stdlib) {
|
|
CI.getDiags().diagnose(SourceLoc(),
|
|
diag::error_immediate_mode_missing_stdlib);
|
|
return -1;
|
|
}
|
|
|
|
// Setup interpreted process arguments.
|
|
using ArgOverride = void (*)(const char **, int);
|
|
#if defined(_WIN32)
|
|
auto module = static_cast<HMODULE>(stdlib);
|
|
auto emplaceProcessArgs = reinterpret_cast<ArgOverride>(
|
|
GetProcAddress(module, "_swift_stdlib_overrideUnsafeArgvArgc"));
|
|
if (emplaceProcessArgs == nullptr)
|
|
return -1;
|
|
#else
|
|
auto emplaceProcessArgs
|
|
= (ArgOverride)dlsym(stdlib, "_swift_stdlib_overrideUnsafeArgvArgc");
|
|
if (dlerror())
|
|
return -1;
|
|
#endif
|
|
|
|
SmallVector<const char *, 32> argBuf;
|
|
for (size_t i = 0; i < CmdLine.size(); ++i) {
|
|
argBuf.push_back(CmdLine[i].c_str());
|
|
}
|
|
argBuf.push_back(nullptr);
|
|
|
|
(*emplaceProcessArgs)(argBuf.data(), CmdLine.size());
|
|
|
|
SmallVector<llvm::Function*, 8> InitFns;
|
|
llvm::SmallPtrSet<swift::ModuleDecl *, 8> ImportedModules;
|
|
if (IRGenImportedModules(CI, *Module, ImportedModules, InitFns,
|
|
IRGenOpts, SILOpts))
|
|
return -1;
|
|
|
|
llvm::PassManagerBuilder PMBuilder;
|
|
PMBuilder.OptLevel = 2;
|
|
PMBuilder.Inliner = llvm::createFunctionInliningPass(200);
|
|
|
|
// Build the ExecutionEngine.
|
|
llvm::EngineBuilder builder(std::move(ModuleOwner));
|
|
std::string ErrorMsg;
|
|
llvm::TargetOptions TargetOpt;
|
|
std::string CPU;
|
|
std::string Triple;
|
|
std::vector<std::string> Features;
|
|
std::tie(TargetOpt, CPU, Features, Triple)
|
|
= getIRTargetOptions(IRGenOpts, swiftModule->getASTContext());
|
|
builder.setRelocationModel(llvm::Reloc::PIC_);
|
|
builder.setTargetOptions(TargetOpt);
|
|
builder.setMCPU(CPU);
|
|
builder.setMAttrs(Features);
|
|
builder.setErrorStr(&ErrorMsg);
|
|
builder.setEngineKind(llvm::EngineKind::JIT);
|
|
llvm::ExecutionEngine *EE = builder.create();
|
|
if (!EE) {
|
|
llvm::errs() << "Error loading JIT: " << ErrorMsg;
|
|
return -1;
|
|
}
|
|
|
|
DEBUG(llvm::dbgs() << "Module to be executed:\n";
|
|
Module->dump());
|
|
|
|
EE->finalizeObject();
|
|
|
|
// Run the generated program.
|
|
for (auto InitFn : InitFns) {
|
|
DEBUG(llvm::dbgs() << "Running initialization function "
|
|
<< InitFn->getName() << '\n');
|
|
EE->runFunctionAsMain(InitFn, CmdLine, nullptr);
|
|
}
|
|
|
|
DEBUG(llvm::dbgs() << "Running static constructors\n");
|
|
EE->runStaticConstructorsDestructors(false);
|
|
DEBUG(llvm::dbgs() << "Running main\n");
|
|
llvm::Function *EntryFn = Module->getFunction("main");
|
|
return EE->runFunctionAsMain(EntryFn, CmdLine, nullptr);
|
|
}
|