Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,15 @@ class Interpreter {
std::string OrcRuntimePath = "";
/// PID of the out-of-process JIT executor.
uint32_t ExecutorPID = 0;
/// Custom lambda to be executed inside child process/executor
std::function<void()> CustomizeFork = nullptr;
/// An optional code model to provide to the JITTargetMachineBuilder
std::optional<llvm::CodeModel::Model> CM = std::nullopt;

JITConfig()
: IsOutOfProcess(false), OOPExecutor(""), OOPExecutorConnect(""),
UseSharedMemory(false), SlabAllocateSize(0), OrcRuntimePath(""),
ExecutorPID(0), CM(std::nullopt) {}
ExecutorPID(0), CustomizeFork(nullptr), CM(std::nullopt) {}
};

protected:
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Interpreter/IncrementalExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ createSharedMemoryManager(llvm::orc::SimpleRemoteEPC &SREPC,
llvm::Expected<std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint32_t>>
IncrementalExecutor::launchExecutor(llvm::StringRef ExecutablePath,
bool UseSharedMemory,
unsigned SlabAllocateSize) {
unsigned SlabAllocateSize,
std::function<void()> CustomizeFork) {
#ifndef LLVM_ON_UNIX
// FIXME: Add support for Windows.
return llvm::make_error<llvm::StringError>(
Expand Down Expand Up @@ -215,6 +216,9 @@ IncrementalExecutor::launchExecutor(llvm::StringRef ExecutablePath,
close(ToExecutor[WriteEnd]);
close(FromExecutor[ReadEnd]);

if (CustomizeFork)
CustomizeFork();

// Execute the child process.
std::unique_ptr<char[]> ExecutorPath, FDSpecifier;
{
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Interpreter/IncrementalExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ class IncrementalExecutor {
static llvm::Expected<
std::pair<std::unique_ptr<llvm::orc::SimpleRemoteEPC>, uint32_t>>
launchExecutor(llvm::StringRef ExecutablePath, bool UseSharedMemory,
unsigned SlabAllocateSize);
unsigned SlabAllocateSize,
std::function<void()> CustomizeFork = nullptr);

#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS
static llvm::Expected<std::unique_ptr<llvm::orc::SimpleRemoteEPC>>
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Interpreter/Interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,8 @@ Interpreter::outOfProcessJITBuilder(JITConfig Config) {
if (!Config.OOPExecutor.empty()) {
// Launch an out-of-process executor locally in a child process.
auto ResultOrErr = IncrementalExecutor::launchExecutor(
Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize);
Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize,
Config.CustomizeFork);
if (!ResultOrErr)
return ResultOrErr.takeError();
childPid = ResultOrErr->second;
Expand Down
23 changes: 22 additions & 1 deletion clang/unittests/Interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,25 @@ set(CLANG_LIBS_TO_LINK
)
endif()

add_distinct_clang_unittest(ClangReplInterpreterTests
set(CLANG_REPL_TEST_SOURCES
IncrementalCompilerBuilderTest.cpp
IncrementalProcessingTest.cpp
InterpreterTest.cpp
InterpreterExtensionsTest.cpp
CodeCompletionTest.cpp
)

if(TARGET compiler-rt)
list(APPEND CLANG_REPL_TEST_SOURCES
OutOfProcessInterpreterTests.cpp
)
message(STATUS "Compiler-RT found, enabling out of process JIT tests")
endif()

add_distinct_clang_unittest(ClangReplInterpreterTests
${CLANG_REPL_TEST_SOURCES}

PARTIAL_SOURCES_INTENDED

EXPORT_SYMBOLS

Expand All @@ -48,6 +61,14 @@ add_distinct_clang_unittest(ClangReplInterpreterTests
${LLVM_COMPONENTS_TO_LINK}
)

if(TARGET compiler-rt)
add_dependencies(ClangReplInterpreterTests
llvm-jitlink-executor
compiler-rt
)
message(STATUS "Adding dependency on compiler-rt for out of process JIT tests")
endif()

if(EMSCRIPTEN)
# Without the above you try to link to LLVMSupport twice, and end
# up with a duplicate symbol error when creating the main module
Expand Down
203 changes: 203 additions & 0 deletions clang/unittests/Interpreter/OutOfProcessInterpreterTests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
//===- unittests/Interpreter/OutOfProcessInterpreterTest.cpp --- Interpreter
// tests when Out-of-Process ----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Unit tests for Clang's Interpreter library.
//
//===----------------------------------------------------------------------===//

#include "InterpreterTestFixture.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclGroup.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/Version.h"
#include "clang/Config/config.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Interpreter/Value.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "llvm/Support/Error.h"
#include "llvm/TargetParser/Host.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <memory>
#include <signal.h>
#include <sstream>
#include <unistd.h>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this include is portable. Compiling on Windows I get llvm-project\clang\unittests\Interpreter\OutOfProcessInterpreterTests.cpp(33): fatal error C1083: Cannot open include file: 'unistd.h': No such file or directory

@kr-2003 or @vgvassilev please could you take a look?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#159404

This PR introduces conditional compilation of OutOfProcessInterpreterTests.cpp. It's meant to be built on UNIX platforms only.


using namespace clang;

llvm::ExitOnError ExitOnError;

namespace {

using Args = std::vector<const char *>;

struct FileDeleter {
void operator()(FILE *f) {
if (f)
fclose(f);
}
};

struct IOContext {
std::unique_ptr<FILE, FileDeleter> stdin_file;
std::unique_ptr<FILE, FileDeleter> stdout_file;
std::unique_ptr<FILE, FileDeleter> stderr_file;

bool initializeTempFiles() {
stdin_file.reset(tmpfile());
stdout_file.reset(tmpfile());
stderr_file.reset(tmpfile());
return stdin_file && stdout_file && stderr_file;
}

std::string readStdoutContent() {
if (!stdout_file)
return "";
rewind(stdout_file.get());
std::ostringstream content;
char buffer[1024];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), stdout_file.get())) >
0) {
content.write(buffer, bytes_read);
}
return content.str();
}

std::string readStderrContent() {
if (!stderr_file)
return "";
rewind(stderr_file.get());
std::ostringstream content;
char buffer[1024];
size_t bytes_read;
while ((bytes_read = fread(buffer, 1, sizeof(buffer), stderr_file.get())) >
0) {
content.write(buffer, bytes_read);
}
return content.str();
}
};

static void removePathComponent(unsigned N, llvm::SmallString<256> &Path) {
for (unsigned i = 0; i < N; ++i)
llvm::sys::path::remove_filename(Path);
}

static std::string getExecutorPath() {
llvm::SmallString<256> ExecutorPath(llvm::sys::fs::getMainExecutable(
nullptr, reinterpret_cast<void *>(&getExecutorPath)));
removePathComponent(5, ExecutorPath);
llvm::sys::path::append(ExecutorPath, "bin", "llvm-jitlink-executor");
return ExecutorPath.str().str();
}

static std::string getOrcRuntimePath() {
llvm::SmallString<256> RuntimePath(llvm::sys::fs::getMainExecutable(
nullptr, reinterpret_cast<void *>(&getOrcRuntimePath)));
removePathComponent(5, RuntimePath);
llvm::sys::path::append(RuntimePath, CLANG_INSTALL_LIBDIR_BASENAME, "clang",
CLANG_VERSION_MAJOR_STRING, "lib");

llvm::Triple SystemTriple(llvm::sys::getProcessTriple());
if (SystemTriple.isOSBinFormatMachO()) {
llvm::sys::path::append(RuntimePath, "darwin", "liborc_rt_osx.a");
} else if (SystemTriple.isOSBinFormatELF()) {
llvm::sys::path::append(RuntimePath, "x86_64-unknown-linux-gnu",
"liborc_rt.a");
}
return RuntimePath.str().str();
}

static std::unique_ptr<Interpreter>
createInterpreterWithRemoteExecution(std::shared_ptr<IOContext> io_ctx,
const Args &ExtraArgs = {}) {
Args ClangArgs = {"-Xclang", "-emit-llvm-only"};
llvm::append_range(ClangArgs, ExtraArgs);
auto CB = clang::IncrementalCompilerBuilder();
CB.SetCompilerArgs(ClangArgs);
auto CI = cantFail(CB.CreateCpp());

clang::Interpreter::JITConfig Config;
llvm::Triple SystemTriple(llvm::sys::getProcessTriple());

if (SystemTriple.isOSBinFormatELF() || SystemTriple.isOSBinFormatMachO()) {
Config.IsOutOfProcess = true;
Config.OOPExecutor = getExecutorPath();
Config.UseSharedMemory = false;
Config.SlabAllocateSize = 0;
Config.OrcRuntimePath = getOrcRuntimePath();

int stdin_fd = fileno(io_ctx->stdin_file.get());
int stdout_fd = fileno(io_ctx->stdout_file.get());
int stderr_fd = fileno(io_ctx->stderr_file.get());

Config.CustomizeFork = [=] {
auto redirect = [](int from, int to) {
if (from != to) {
dup2(from, to);
close(from);
}
};

redirect(stdin_fd, STDIN_FILENO);
redirect(stdout_fd, STDOUT_FILENO);
redirect(stderr_fd, STDERR_FILENO);

setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);

printf("CustomizeFork executed\n");
fflush(stdout);
};
}

return cantFail(clang::Interpreter::create(std::move(CI), Config));
}

static size_t DeclsSize(TranslationUnitDecl *PTUDecl) {
return std::distance(PTUDecl->decls().begin(), PTUDecl->decls().end());
}

TEST_F(InterpreterTestBase, SanityWithRemoteExecution) {
if (!HostSupportsJIT())
GTEST_SKIP();

std::string OrcRuntimePath = getOrcRuntimePath();
std::string ExecutorPath = getExecutorPath();

if (!llvm::sys::fs::exists(OrcRuntimePath) ||
!llvm::sys::fs::exists(ExecutorPath))
GTEST_SKIP();

auto io_ctx = std::make_shared<IOContext>();
ASSERT_TRUE(io_ctx->initializeTempFiles());

std::unique_ptr<Interpreter> Interp =
createInterpreterWithRemoteExecution(io_ctx);
ASSERT_TRUE(Interp);

using PTU = PartialTranslationUnit;
PTU &R1(cantFail(Interp->Parse("void g(); void g() {}")));
EXPECT_EQ(2U, DeclsSize(R1.TUPart));

PTU &R2(cantFail(Interp->Parse("int i = 42;")));
EXPECT_EQ(1U, DeclsSize(R2.TUPart));

std::string captured_stdout = io_ctx->readStdoutContent();
std::string captured_stderr = io_ctx->readStderrContent();

EXPECT_TRUE(captured_stdout.find("CustomizeFork executed") !=
std::string::npos);
}

} // end anonymous namespace