Skip to content

Commit 8286544

Browse files
argentitevgvassilev
authored andcommitted
[clang-repl] Support wasm execution.
This commit introduces support for running clang-repl and executing C++ code interactively inside a Javascript engine using WebAssembly when built with Emscripten. This is achieved by producing WASM "shared libraries" that can be loaded by the Emscripten runtime using dlopen() More discussion is available in https://reviews.llvm.org/D158140
1 parent b68e2eb commit 8286544

File tree

6 files changed

+163
-6
lines changed

6 files changed

+163
-6
lines changed

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_clang_library(clangInterpreter
2020
Interpreter.cpp
2121
InterpreterUtils.cpp
2222
Value.cpp
23+
WASM.cpp
2324

2425
DEPENDS
2526
intrinsics_gen

clang/lib/Interpreter/IncrementalExecutor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ LLVM_ATTRIBUTE_USED void linkComponents() {
3535
}
3636

3737
namespace clang {
38+
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC)
39+
: TSCtx(TSC) {}
3840

3941
IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
4042
llvm::Error &Err,

clang/lib/Interpreter/IncrementalExecutor.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,16 +41,19 @@ class IncrementalExecutor {
4141
llvm::DenseMap<const PartialTranslationUnit *, llvm::orc::ResourceTrackerSP>
4242
ResourceTrackers;
4343

44+
protected:
45+
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC);
46+
4447
public:
4548
enum SymbolNameKind { IRName, LinkerName };
4649

4750
IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err,
4851
const clang::TargetInfo &TI);
49-
~IncrementalExecutor();
52+
virtual ~IncrementalExecutor();
5053

51-
llvm::Error addModule(PartialTranslationUnit &PTU);
52-
llvm::Error removeModule(PartialTranslationUnit &PTU);
53-
llvm::Error runCtors() const;
54+
virtual llvm::Error addModule(PartialTranslationUnit &PTU);
55+
virtual llvm::Error removeModule(PartialTranslationUnit &PTU);
56+
virtual llvm::Error runCtors() const;
5457
llvm::Error cleanUp();
5558
llvm::Expected<llvm::orc::ExecutorAddr>
5659
getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "IncrementalExecutor.h"
1616
#include "IncrementalParser.h"
1717
#include "InterpreterUtils.h"
18+
#include "WASM.h"
1819

1920
#include "clang/AST/ASTContext.h"
2021
#include "clang/AST/Mangle.h"
@@ -183,6 +184,12 @@ IncrementalCompilerBuilder::CreateCpp() {
183184
std::vector<const char *> Argv;
184185
Argv.reserve(5 + 1 + UserArgs.size());
185186
Argv.push_back("-xc++");
187+
#ifdef __EMSCRIPTEN__
188+
Argv.push_back("-target");
189+
Argv.push_back("wasm32-unknown-emscripten");
190+
Argv.push_back("-pie");
191+
Argv.push_back("-shared");
192+
#endif
186193
Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
187194

188195
std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
@@ -373,14 +380,18 @@ Interpreter::Parse(llvm::StringRef Code) {
373380
}
374381

375382
llvm::Error Interpreter::CreateExecutor() {
376-
const clang::TargetInfo &TI =
377-
getCompilerInstance()->getASTContext().getTargetInfo();
378383
if (IncrExecutor)
379384
return llvm::make_error<llvm::StringError>("Operation failed. "
380385
"Execution engine exists",
381386
std::error_code());
382387
llvm::Error Err = llvm::Error::success();
388+
const clang::TargetInfo &TI =
389+
getCompilerInstance()->getASTContext().getTargetInfo();
390+
#ifdef __EMSCRIPTEN__
391+
auto Executor = std::make_unique<WASMIncrementalExecutor>(*TSCtx, Err, TI);
392+
#else
383393
auto Executor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
394+
#endif
384395
if (!Err)
385396
IncrExecutor = std::move(Executor);
386397

clang/lib/Interpreter/WASM.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
//===----------------- WASM.cpp - WASM Interpreter --------------*- 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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements interpreter support for code execution in WebAssembly.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "WASM.h"
14+
#include "IncrementalExecutor.h"
15+
16+
#include <llvm/IR/LegacyPassManager.h>
17+
#include <llvm/IR/Module.h>
18+
#include <llvm/MC/TargetRegistry.h>
19+
#include <llvm/Target/TargetMachine.h>
20+
21+
#include <clang/Interpreter/Interpreter.h>
22+
23+
#include <dlfcn.h>
24+
25+
namespace clang {
26+
27+
WASMIncrementalExecutor::WASMIncrementalExecutor(
28+
llvm::orc::ThreadSafeContext &TSC)
29+
: IncrementalExecutor(TSC) {}
30+
31+
llvm::Error WASMIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
32+
PTU.TheModule->dump();
33+
34+
std::string ErrorString;
35+
36+
const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
37+
PTU.TheModule->getTargetTriple(), ErrorString);
38+
if (!Target) {
39+
return llvm::make_error<llvm::StringError>("Failed to create WASM Target: ",
40+
llvm::inconvertibleErrorCode());
41+
}
42+
43+
llvm::TargetOptions TO = llvm::TargetOptions();
44+
llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
45+
PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
46+
PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
47+
std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm";
48+
49+
std::error_code Error;
50+
llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error);
51+
52+
llvm::legacy::PassManager PM;
53+
if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr,
54+
llvm::CGFT_ObjectFile)) {
55+
return llvm::make_error<llvm::StringError>(
56+
"WASM backend cannot produce object.", llvm::inconvertibleErrorCode());
57+
}
58+
59+
if (!PM.run(*PTU.TheModule)) {
60+
61+
return llvm::make_error<llvm::StringError>("Failed to emit WASM object.",
62+
llvm::inconvertibleErrorCode());
63+
}
64+
65+
OutputFile.close();
66+
67+
std::vector<const char *> LinkerArgs = {"wasm-ld",
68+
"-pie",
69+
"--import-memory",
70+
"--no-entry",
71+
"--export-all",
72+
"--experimental-pic",
73+
"--no-export-dynamic",
74+
"--stack-first",
75+
OutputFileName.c_str(),
76+
"-o",
77+
OutputFileName.c_str()};
78+
int Result =
79+
lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false);
80+
if (!Result)
81+
return llvm::make_error<llvm::StringError>(
82+
"Failed to link incremental module", llvm::inconvertibleErrorCode());
83+
84+
void *LoadedLibModule =
85+
dlopen(OutputFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
86+
if (LoadedLibModule == nullptr) {
87+
llvm::errs() << dlerror() << '\n';
88+
return llvm::make_error<llvm::StringError>(
89+
"Failed to load incremental module", llvm::inconvertibleErrorCode());
90+
}
91+
92+
return llvm::Error::success();
93+
}
94+
95+
llvm::Error WASMIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
96+
return llvm::make_error<llvm::StringError>("Not implemented yet",
97+
llvm::inconvertibleErrorCode());
98+
}
99+
100+
llvm::Error WASMIncrementalExecutor::runCtors() const {
101+
// This seems to be automatically done when using dlopen()
102+
return llvm::Error::success();
103+
}
104+
105+
WASMIncrementalExecutor::~WASMIncrementalExecutor() = default;
106+
107+
} // namespace clang

clang/lib/Interpreter/WASM.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===------------------ WASM.h - WASM Interpreter ---------------*- 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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file implements interpreter support for code execution in WebAssembly.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_LIB_INTERPRETER_WASM_H
14+
#define LLVM_CLANG_LIB_INTERPRETER_WASM_H
15+
16+
#include "IncrementalExecutor.h"
17+
18+
namespace clang {
19+
20+
class WASMIncrementalExecutor : public IncrementalExecutor {
21+
public:
22+
WASMIncrementalExecutor(llvm::orc::ThreadSafeContext &TSC);
23+
24+
llvm::Error addModule(PartialTranslationUnit &PTU) override;
25+
llvm::Error removeModule(PartialTranslationUnit &PTU) override;
26+
llvm::Error runCtors() const override;
27+
28+
~WASMIncrementalExecutor() override;
29+
};
30+
31+
} // namespace clang
32+
33+
#endif // LLVM_CLANG_LIB_INTERPRETER_WASM_H

0 commit comments

Comments
 (0)