xref: /freebsd/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp (revision 609fa228bae6d864558f5167d4a964aab2a5fc88)
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 <string>
24 
25 namespace lld {
26 namespace wasm {
27 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
28           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
29 } // namespace wasm
30 } // namespace lld
31 
32 #include <dlfcn.h>
33 
34 namespace clang {
35 
36 WasmIncrementalExecutor::WasmIncrementalExecutor(
37     llvm::orc::ThreadSafeContext &TSC)
38     : IncrementalExecutor(TSC) {}
39 
40 llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
41   std::string ErrorString;
42 
43   const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
44       PTU.TheModule->getTargetTriple(), ErrorString);
45   if (!Target) {
46     return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ",
47                                                llvm::inconvertibleErrorCode());
48   }
49 
50   llvm::TargetOptions TO = llvm::TargetOptions();
51   llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
52       PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
53   PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
54   std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm";
55 
56   std::error_code Error;
57   llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error);
58 
59   llvm::legacy::PassManager PM;
60   if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr,
61                                          llvm::CodeGenFileType::ObjectFile)) {
62     return llvm::make_error<llvm::StringError>(
63         "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode());
64   }
65 
66   if (!PM.run(*PTU.TheModule)) {
67 
68     return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.",
69                                                llvm::inconvertibleErrorCode());
70   }
71 
72   OutputFile.close();
73 
74   std::vector<const char *> LinkerArgs = {"wasm-ld",
75                                           "-pie",
76                                           "--import-memory",
77                                           "--no-entry",
78                                           "--export-all",
79                                           "--experimental-pic",
80                                           "--no-export-dynamic",
81                                           "--stack-first",
82                                           OutputFileName.c_str(),
83                                           "-o",
84                                           OutputFileName.c_str()};
85   int Result =
86       lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false);
87   if (!Result)
88     return llvm::make_error<llvm::StringError>(
89         "Failed to link incremental module", llvm::inconvertibleErrorCode());
90 
91   void *LoadedLibModule =
92       dlopen(OutputFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
93   if (LoadedLibModule == nullptr) {
94     llvm::errs() << dlerror() << '\n';
95     return llvm::make_error<llvm::StringError>(
96         "Failed to load incremental module", llvm::inconvertibleErrorCode());
97   }
98 
99   return llvm::Error::success();
100 }
101 
102 llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
103   return llvm::make_error<llvm::StringError>("Not implemented yet",
104                                              llvm::inconvertibleErrorCode());
105 }
106 
107 llvm::Error WasmIncrementalExecutor::runCtors() const {
108   // This seems to be automatically done when using dlopen()
109   return llvm::Error::success();
110 }
111 
112 WasmIncrementalExecutor::~WasmIncrementalExecutor() = default;
113 
114 } // namespace clang
115