xref: /freebsd-src/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file implements interpreter support for code execution in WebAssembly.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "Wasm.h"
14*0fca6ea1SDimitry Andric #include "IncrementalExecutor.h"
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric #include <llvm/IR/LegacyPassManager.h>
17*0fca6ea1SDimitry Andric #include <llvm/IR/Module.h>
18*0fca6ea1SDimitry Andric #include <llvm/MC/TargetRegistry.h>
19*0fca6ea1SDimitry Andric #include <llvm/Target/TargetMachine.h>
20*0fca6ea1SDimitry Andric 
21*0fca6ea1SDimitry Andric #include <clang/Interpreter/Interpreter.h>
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric #include <string>
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric namespace lld {
26*0fca6ea1SDimitry Andric namespace wasm {
27*0fca6ea1SDimitry Andric bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
28*0fca6ea1SDimitry Andric           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
29*0fca6ea1SDimitry Andric } // namespace wasm
30*0fca6ea1SDimitry Andric } // namespace lld
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric #include <dlfcn.h>
33*0fca6ea1SDimitry Andric 
34*0fca6ea1SDimitry Andric namespace clang {
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric WasmIncrementalExecutor::WasmIncrementalExecutor(
37*0fca6ea1SDimitry Andric     llvm::orc::ThreadSafeContext &TSC)
38*0fca6ea1SDimitry Andric     : IncrementalExecutor(TSC) {}
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
41*0fca6ea1SDimitry Andric   std::string ErrorString;
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric   const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
44*0fca6ea1SDimitry Andric       PTU.TheModule->getTargetTriple(), ErrorString);
45*0fca6ea1SDimitry Andric   if (!Target) {
46*0fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ",
47*0fca6ea1SDimitry Andric                                                llvm::inconvertibleErrorCode());
48*0fca6ea1SDimitry Andric   }
49*0fca6ea1SDimitry Andric 
50*0fca6ea1SDimitry Andric   llvm::TargetOptions TO = llvm::TargetOptions();
51*0fca6ea1SDimitry Andric   llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
52*0fca6ea1SDimitry Andric       PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
53*0fca6ea1SDimitry Andric   PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
54*0fca6ea1SDimitry Andric   std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm";
55*0fca6ea1SDimitry Andric 
56*0fca6ea1SDimitry Andric   std::error_code Error;
57*0fca6ea1SDimitry Andric   llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error);
58*0fca6ea1SDimitry Andric 
59*0fca6ea1SDimitry Andric   llvm::legacy::PassManager PM;
60*0fca6ea1SDimitry Andric   if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr,
61*0fca6ea1SDimitry Andric                                          llvm::CodeGenFileType::ObjectFile)) {
62*0fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
63*0fca6ea1SDimitry Andric         "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode());
64*0fca6ea1SDimitry Andric   }
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric   if (!PM.run(*PTU.TheModule)) {
67*0fca6ea1SDimitry Andric 
68*0fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.",
69*0fca6ea1SDimitry Andric                                                llvm::inconvertibleErrorCode());
70*0fca6ea1SDimitry Andric   }
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric   OutputFile.close();
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric   std::vector<const char *> LinkerArgs = {"wasm-ld",
75*0fca6ea1SDimitry Andric                                           "-pie",
76*0fca6ea1SDimitry Andric                                           "--import-memory",
77*0fca6ea1SDimitry Andric                                           "--no-entry",
78*0fca6ea1SDimitry Andric                                           "--export-all",
79*0fca6ea1SDimitry Andric                                           "--experimental-pic",
80*0fca6ea1SDimitry Andric                                           "--no-export-dynamic",
81*0fca6ea1SDimitry Andric                                           "--stack-first",
82*0fca6ea1SDimitry Andric                                           OutputFileName.c_str(),
83*0fca6ea1SDimitry Andric                                           "-o",
84*0fca6ea1SDimitry Andric                                           OutputFileName.c_str()};
85*0fca6ea1SDimitry Andric   int Result =
86*0fca6ea1SDimitry Andric       lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false);
87*0fca6ea1SDimitry Andric   if (!Result)
88*0fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
89*0fca6ea1SDimitry Andric         "Failed to link incremental module", llvm::inconvertibleErrorCode());
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric   void *LoadedLibModule =
92*0fca6ea1SDimitry Andric       dlopen(OutputFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
93*0fca6ea1SDimitry Andric   if (LoadedLibModule == nullptr) {
94*0fca6ea1SDimitry Andric     llvm::errs() << dlerror() << '\n';
95*0fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
96*0fca6ea1SDimitry Andric         "Failed to load incremental module", llvm::inconvertibleErrorCode());
97*0fca6ea1SDimitry Andric   }
98*0fca6ea1SDimitry Andric 
99*0fca6ea1SDimitry Andric   return llvm::Error::success();
100*0fca6ea1SDimitry Andric }
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
103*0fca6ea1SDimitry Andric   return llvm::make_error<llvm::StringError>("Not implemented yet",
104*0fca6ea1SDimitry Andric                                              llvm::inconvertibleErrorCode());
105*0fca6ea1SDimitry Andric }
106*0fca6ea1SDimitry Andric 
107*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::runCtors() const {
108*0fca6ea1SDimitry Andric   // This seems to be automatically done when using dlopen()
109*0fca6ea1SDimitry Andric   return llvm::Error::success();
110*0fca6ea1SDimitry Andric }
111*0fca6ea1SDimitry Andric 
112*0fca6ea1SDimitry Andric WasmIncrementalExecutor::~WasmIncrementalExecutor() = default;
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric } // namespace clang
115