xref: /llvm-project/clang/lib/Interpreter/Wasm.cpp (revision a174aa1e416c4e27945f5a8c646b119126dc8441)
19a9546e3SVassil Vassilev //===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===//
29a9546e3SVassil Vassilev //
39a9546e3SVassil Vassilev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49a9546e3SVassil Vassilev // See https://llvm.org/LICENSE.txt for license information.
59a9546e3SVassil Vassilev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69a9546e3SVassil Vassilev //
79a9546e3SVassil Vassilev //===----------------------------------------------------------------------===//
89a9546e3SVassil Vassilev //
99a9546e3SVassil Vassilev // This file implements interpreter support for code execution in WebAssembly.
109a9546e3SVassil Vassilev //
119a9546e3SVassil Vassilev //===----------------------------------------------------------------------===//
129a9546e3SVassil Vassilev 
139a9546e3SVassil Vassilev #include "Wasm.h"
149a9546e3SVassil Vassilev #include "IncrementalExecutor.h"
159a9546e3SVassil Vassilev 
169a9546e3SVassil Vassilev #include <llvm/IR/LegacyPassManager.h>
179a9546e3SVassil Vassilev #include <llvm/IR/Module.h>
189a9546e3SVassil Vassilev #include <llvm/MC/TargetRegistry.h>
199a9546e3SVassil Vassilev #include <llvm/Target/TargetMachine.h>
209a9546e3SVassil Vassilev 
219a9546e3SVassil Vassilev #include <clang/Interpreter/Interpreter.h>
229a9546e3SVassil Vassilev 
239a9546e3SVassil Vassilev #include <string>
249a9546e3SVassil Vassilev 
259a9546e3SVassil Vassilev namespace lld {
26*a174aa1eSAnutosh Bhat enum Flavor {
27*a174aa1eSAnutosh Bhat   Invalid,
28*a174aa1eSAnutosh Bhat   Gnu,     // -flavor gnu
29*a174aa1eSAnutosh Bhat   MinGW,   // -flavor gnu MinGW
30*a174aa1eSAnutosh Bhat   WinLink, // -flavor link
31*a174aa1eSAnutosh Bhat   Darwin,  // -flavor darwin
32*a174aa1eSAnutosh Bhat   Wasm,    // -flavor wasm
33*a174aa1eSAnutosh Bhat };
34*a174aa1eSAnutosh Bhat 
35*a174aa1eSAnutosh Bhat using Driver = bool (*)(llvm::ArrayRef<const char *>, llvm::raw_ostream &,
36*a174aa1eSAnutosh Bhat                         llvm::raw_ostream &, bool, bool);
37*a174aa1eSAnutosh Bhat 
38*a174aa1eSAnutosh Bhat struct DriverDef {
39*a174aa1eSAnutosh Bhat   Flavor f;
40*a174aa1eSAnutosh Bhat   Driver d;
41*a174aa1eSAnutosh Bhat };
42*a174aa1eSAnutosh Bhat 
43*a174aa1eSAnutosh Bhat struct Result {
44*a174aa1eSAnutosh Bhat   int retCode;
45*a174aa1eSAnutosh Bhat   bool canRunAgain;
46*a174aa1eSAnutosh Bhat };
47*a174aa1eSAnutosh Bhat 
48*a174aa1eSAnutosh Bhat Result lldMain(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
49*a174aa1eSAnutosh Bhat                llvm::raw_ostream &stderrOS, llvm::ArrayRef<DriverDef> drivers);
50*a174aa1eSAnutosh Bhat 
519a9546e3SVassil Vassilev namespace wasm {
529a9546e3SVassil Vassilev bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
539a9546e3SVassil Vassilev           llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
549a9546e3SVassil Vassilev } // namespace wasm
559a9546e3SVassil Vassilev } // namespace lld
569a9546e3SVassil Vassilev 
579a9546e3SVassil Vassilev #include <dlfcn.h>
589a9546e3SVassil Vassilev 
599a9546e3SVassil Vassilev namespace clang {
609a9546e3SVassil Vassilev 
619a9546e3SVassil Vassilev WasmIncrementalExecutor::WasmIncrementalExecutor(
629a9546e3SVassil Vassilev     llvm::orc::ThreadSafeContext &TSC)
639a9546e3SVassil Vassilev     : IncrementalExecutor(TSC) {}
649a9546e3SVassil Vassilev 
659a9546e3SVassil Vassilev llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
669a9546e3SVassil Vassilev   std::string ErrorString;
679a9546e3SVassil Vassilev 
689a9546e3SVassil Vassilev   const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
699a9546e3SVassil Vassilev       PTU.TheModule->getTargetTriple(), ErrorString);
709a9546e3SVassil Vassilev   if (!Target) {
719a9546e3SVassil Vassilev     return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ",
729a9546e3SVassil Vassilev                                                llvm::inconvertibleErrorCode());
739a9546e3SVassil Vassilev   }
749a9546e3SVassil Vassilev 
759a9546e3SVassil Vassilev   llvm::TargetOptions TO = llvm::TargetOptions();
769a9546e3SVassil Vassilev   llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
779a9546e3SVassil Vassilev       PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
789a9546e3SVassil Vassilev   PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
79*a174aa1eSAnutosh Bhat   std::string ObjectFileName = PTU.TheModule->getName().str() + ".o";
80*a174aa1eSAnutosh Bhat   std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm";
819a9546e3SVassil Vassilev 
829a9546e3SVassil Vassilev   std::error_code Error;
83*a174aa1eSAnutosh Bhat   llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error);
849a9546e3SVassil Vassilev 
859a9546e3SVassil Vassilev   llvm::legacy::PassManager PM;
86*a174aa1eSAnutosh Bhat   if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr,
879a9546e3SVassil Vassilev                                          llvm::CodeGenFileType::ObjectFile)) {
889a9546e3SVassil Vassilev     return llvm::make_error<llvm::StringError>(
899a9546e3SVassil Vassilev         "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode());
909a9546e3SVassil Vassilev   }
919a9546e3SVassil Vassilev 
929a9546e3SVassil Vassilev   if (!PM.run(*PTU.TheModule)) {
939a9546e3SVassil Vassilev 
949a9546e3SVassil Vassilev     return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.",
959a9546e3SVassil Vassilev                                                llvm::inconvertibleErrorCode());
969a9546e3SVassil Vassilev   }
979a9546e3SVassil Vassilev 
98*a174aa1eSAnutosh Bhat   ObjectFileOutput.close();
999a9546e3SVassil Vassilev 
1009a9546e3SVassil Vassilev   std::vector<const char *> LinkerArgs = {"wasm-ld",
101752dbd61SAnutosh Bhat                                           "-shared",
1029a9546e3SVassil Vassilev                                           "--import-memory",
1039a9546e3SVassil Vassilev                                           "--experimental-pic",
1049a9546e3SVassil Vassilev                                           "--stack-first",
105752dbd61SAnutosh Bhat                                           "--allow-undefined",
106*a174aa1eSAnutosh Bhat                                           ObjectFileName.c_str(),
1079a9546e3SVassil Vassilev                                           "-o",
108*a174aa1eSAnutosh Bhat                                           BinaryFileName.c_str()};
109*a174aa1eSAnutosh Bhat 
110*a174aa1eSAnutosh Bhat   const lld::DriverDef WasmDriver = {lld::Flavor::Wasm, &lld::wasm::link};
111*a174aa1eSAnutosh Bhat   std::vector<lld::DriverDef> WasmDriverArgs;
112*a174aa1eSAnutosh Bhat   WasmDriverArgs.push_back(WasmDriver);
113*a174aa1eSAnutosh Bhat   lld::Result Result =
114*a174aa1eSAnutosh Bhat       lld::lldMain(LinkerArgs, llvm::outs(), llvm::errs(), WasmDriverArgs);
115*a174aa1eSAnutosh Bhat 
116*a174aa1eSAnutosh Bhat   if (Result.retCode)
1179a9546e3SVassil Vassilev     return llvm::make_error<llvm::StringError>(
1189a9546e3SVassil Vassilev         "Failed to link incremental module", llvm::inconvertibleErrorCode());
1199a9546e3SVassil Vassilev 
1209a9546e3SVassil Vassilev   void *LoadedLibModule =
121*a174aa1eSAnutosh Bhat       dlopen(BinaryFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
1229a9546e3SVassil Vassilev   if (LoadedLibModule == nullptr) {
1239a9546e3SVassil Vassilev     llvm::errs() << dlerror() << '\n';
1249a9546e3SVassil Vassilev     return llvm::make_error<llvm::StringError>(
1259a9546e3SVassil Vassilev         "Failed to load incremental module", llvm::inconvertibleErrorCode());
1269a9546e3SVassil Vassilev   }
1279a9546e3SVassil Vassilev 
1289a9546e3SVassil Vassilev   return llvm::Error::success();
1299a9546e3SVassil Vassilev }
1309a9546e3SVassil Vassilev 
1319a9546e3SVassil Vassilev llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
1329a9546e3SVassil Vassilev   return llvm::make_error<llvm::StringError>("Not implemented yet",
1339a9546e3SVassil Vassilev                                              llvm::inconvertibleErrorCode());
1349a9546e3SVassil Vassilev }
1359a9546e3SVassil Vassilev 
1369a9546e3SVassil Vassilev llvm::Error WasmIncrementalExecutor::runCtors() const {
1379a9546e3SVassil Vassilev   // This seems to be automatically done when using dlopen()
1389a9546e3SVassil Vassilev   return llvm::Error::success();
1399a9546e3SVassil Vassilev }
1409a9546e3SVassil Vassilev 
141*a174aa1eSAnutosh Bhat llvm::Error WasmIncrementalExecutor::cleanUp() {
142752dbd61SAnutosh Bhat   // Can't call cleanUp through IncrementalExecutor as it
143752dbd61SAnutosh Bhat   // tries to deinitialize JIT which hasn't been initialized
144752dbd61SAnutosh Bhat   return llvm::Error::success();
145752dbd61SAnutosh Bhat }
146752dbd61SAnutosh Bhat 
1479a9546e3SVassil Vassilev WasmIncrementalExecutor::~WasmIncrementalExecutor() = default;
1489a9546e3SVassil Vassilev 
1499a9546e3SVassil Vassilev } // namespace clang