xref: /freebsd-src/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp (revision 71ac745d76c3ba442e753daff1870893f272b29d)
10fca6ea1SDimitry Andric //===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===//
20fca6ea1SDimitry Andric //
30fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60fca6ea1SDimitry Andric //
70fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
80fca6ea1SDimitry Andric //
90fca6ea1SDimitry Andric // This file implements interpreter support for code execution in WebAssembly.
100fca6ea1SDimitry Andric //
110fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
120fca6ea1SDimitry Andric 
130fca6ea1SDimitry Andric #include "Wasm.h"
140fca6ea1SDimitry Andric #include "IncrementalExecutor.h"
150fca6ea1SDimitry Andric 
160fca6ea1SDimitry Andric #include <llvm/IR/LegacyPassManager.h>
170fca6ea1SDimitry Andric #include <llvm/IR/Module.h>
180fca6ea1SDimitry Andric #include <llvm/MC/TargetRegistry.h>
190fca6ea1SDimitry Andric #include <llvm/Target/TargetMachine.h>
200fca6ea1SDimitry Andric 
210fca6ea1SDimitry Andric #include <clang/Interpreter/Interpreter.h>
220fca6ea1SDimitry Andric 
230fca6ea1SDimitry Andric #include <string>
240fca6ea1SDimitry Andric 
250fca6ea1SDimitry Andric namespace lld {
26*71ac745dSDimitry Andric enum Flavor {
27*71ac745dSDimitry Andric   Invalid,
28*71ac745dSDimitry Andric   Gnu,     // -flavor gnu
29*71ac745dSDimitry Andric   MinGW,   // -flavor gnu MinGW
30*71ac745dSDimitry Andric   WinLink, // -flavor link
31*71ac745dSDimitry Andric   Darwin,  // -flavor darwin
32*71ac745dSDimitry Andric   Wasm,    // -flavor wasm
33*71ac745dSDimitry Andric };
34*71ac745dSDimitry Andric 
35*71ac745dSDimitry Andric using Driver = bool (*)(llvm::ArrayRef<const char *>, llvm::raw_ostream &,
36*71ac745dSDimitry Andric                         llvm::raw_ostream &, bool, bool);
37*71ac745dSDimitry Andric 
38*71ac745dSDimitry Andric struct DriverDef {
39*71ac745dSDimitry Andric   Flavor f;
40*71ac745dSDimitry Andric   Driver d;
41*71ac745dSDimitry Andric };
42*71ac745dSDimitry Andric 
43*71ac745dSDimitry Andric struct Result {
44*71ac745dSDimitry Andric   int retCode;
45*71ac745dSDimitry Andric   bool canRunAgain;
46*71ac745dSDimitry Andric };
47*71ac745dSDimitry Andric 
48*71ac745dSDimitry Andric Result lldMain(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
49*71ac745dSDimitry Andric                llvm::raw_ostream &stderrOS, llvm::ArrayRef<DriverDef> drivers);
50*71ac745dSDimitry Andric 
510fca6ea1SDimitry Andric namespace wasm {
520fca6ea1SDimitry Andric bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
530fca6ea1SDimitry Andric           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
540fca6ea1SDimitry Andric } // namespace wasm
550fca6ea1SDimitry Andric } // namespace lld
560fca6ea1SDimitry Andric 
570fca6ea1SDimitry Andric #include <dlfcn.h>
580fca6ea1SDimitry Andric 
590fca6ea1SDimitry Andric namespace clang {
600fca6ea1SDimitry Andric 
610fca6ea1SDimitry Andric WasmIncrementalExecutor::WasmIncrementalExecutor(
620fca6ea1SDimitry Andric     llvm::orc::ThreadSafeContext &TSC)
630fca6ea1SDimitry Andric     : IncrementalExecutor(TSC) {}
640fca6ea1SDimitry Andric 
650fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
660fca6ea1SDimitry Andric   std::string ErrorString;
670fca6ea1SDimitry Andric 
680fca6ea1SDimitry Andric   const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
690fca6ea1SDimitry Andric       PTU.TheModule->getTargetTriple(), ErrorString);
700fca6ea1SDimitry Andric   if (!Target) {
710fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ",
720fca6ea1SDimitry Andric                                                llvm::inconvertibleErrorCode());
730fca6ea1SDimitry Andric   }
740fca6ea1SDimitry Andric 
750fca6ea1SDimitry Andric   llvm::TargetOptions TO = llvm::TargetOptions();
760fca6ea1SDimitry Andric   llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
770fca6ea1SDimitry Andric       PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
780fca6ea1SDimitry Andric   PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
79*71ac745dSDimitry Andric   std::string ObjectFileName = PTU.TheModule->getName().str() + ".o";
80*71ac745dSDimitry Andric   std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm";
810fca6ea1SDimitry Andric 
820fca6ea1SDimitry Andric   std::error_code Error;
83*71ac745dSDimitry Andric   llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error);
840fca6ea1SDimitry Andric 
850fca6ea1SDimitry Andric   llvm::legacy::PassManager PM;
86*71ac745dSDimitry Andric   if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr,
870fca6ea1SDimitry Andric                                          llvm::CodeGenFileType::ObjectFile)) {
880fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
890fca6ea1SDimitry Andric         "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode());
900fca6ea1SDimitry Andric   }
910fca6ea1SDimitry Andric 
920fca6ea1SDimitry Andric   if (!PM.run(*PTU.TheModule)) {
930fca6ea1SDimitry Andric 
940fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.",
950fca6ea1SDimitry Andric                                                llvm::inconvertibleErrorCode());
960fca6ea1SDimitry Andric   }
970fca6ea1SDimitry Andric 
98*71ac745dSDimitry Andric   ObjectFileOutput.close();
990fca6ea1SDimitry Andric 
1000fca6ea1SDimitry Andric   std::vector<const char *> LinkerArgs = {"wasm-ld",
101*71ac745dSDimitry Andric                                           "-shared",
1020fca6ea1SDimitry Andric                                           "--import-memory",
1030fca6ea1SDimitry Andric                                           "--experimental-pic",
1040fca6ea1SDimitry Andric                                           "--stack-first",
105*71ac745dSDimitry Andric                                           "--allow-undefined",
106*71ac745dSDimitry Andric                                           ObjectFileName.c_str(),
1070fca6ea1SDimitry Andric                                           "-o",
108*71ac745dSDimitry Andric                                           BinaryFileName.c_str()};
109*71ac745dSDimitry Andric 
110*71ac745dSDimitry Andric   const lld::DriverDef WasmDriver = {lld::Flavor::Wasm, &lld::wasm::link};
111*71ac745dSDimitry Andric   std::vector<lld::DriverDef> WasmDriverArgs;
112*71ac745dSDimitry Andric   WasmDriverArgs.push_back(WasmDriver);
113*71ac745dSDimitry Andric   lld::Result Result =
114*71ac745dSDimitry Andric       lld::lldMain(LinkerArgs, llvm::outs(), llvm::errs(), WasmDriverArgs);
115*71ac745dSDimitry Andric 
116*71ac745dSDimitry Andric   if (Result.retCode)
1170fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
1180fca6ea1SDimitry Andric         "Failed to link incremental module", llvm::inconvertibleErrorCode());
1190fca6ea1SDimitry Andric 
1200fca6ea1SDimitry Andric   void *LoadedLibModule =
121*71ac745dSDimitry Andric       dlopen(BinaryFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
1220fca6ea1SDimitry Andric   if (LoadedLibModule == nullptr) {
1230fca6ea1SDimitry Andric     llvm::errs() << dlerror() << '\n';
1240fca6ea1SDimitry Andric     return llvm::make_error<llvm::StringError>(
1250fca6ea1SDimitry Andric         "Failed to load incremental module", llvm::inconvertibleErrorCode());
1260fca6ea1SDimitry Andric   }
1270fca6ea1SDimitry Andric 
1280fca6ea1SDimitry Andric   return llvm::Error::success();
1290fca6ea1SDimitry Andric }
1300fca6ea1SDimitry Andric 
1310fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
1320fca6ea1SDimitry Andric   return llvm::make_error<llvm::StringError>("Not implemented yet",
1330fca6ea1SDimitry Andric                                              llvm::inconvertibleErrorCode());
1340fca6ea1SDimitry Andric }
1350fca6ea1SDimitry Andric 
1360fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::runCtors() const {
1370fca6ea1SDimitry Andric   // This seems to be automatically done when using dlopen()
1380fca6ea1SDimitry Andric   return llvm::Error::success();
1390fca6ea1SDimitry Andric }
1400fca6ea1SDimitry Andric 
141*71ac745dSDimitry Andric llvm::Error WasmIncrementalExecutor::cleanUp() {
142*71ac745dSDimitry Andric   // Can't call cleanUp through IncrementalExecutor as it
143*71ac745dSDimitry Andric   // tries to deinitialize JIT which hasn't been initialized
144*71ac745dSDimitry Andric   return llvm::Error::success();
145*71ac745dSDimitry Andric }
146*71ac745dSDimitry Andric 
1470fca6ea1SDimitry Andric WasmIncrementalExecutor::~WasmIncrementalExecutor() = default;
1480fca6ea1SDimitry Andric 
1490fca6ea1SDimitry Andric } // namespace clang