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 enum Flavor { 27 Invalid, 28 Gnu, // -flavor gnu 29 MinGW, // -flavor gnu MinGW 30 WinLink, // -flavor link 31 Darwin, // -flavor darwin 32 Wasm, // -flavor wasm 33 }; 34 35 using Driver = bool (*)(llvm::ArrayRef<const char *>, llvm::raw_ostream &, 36 llvm::raw_ostream &, bool, bool); 37 38 struct DriverDef { 39 Flavor f; 40 Driver d; 41 }; 42 43 struct Result { 44 int retCode; 45 bool canRunAgain; 46 }; 47 48 Result lldMain(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 49 llvm::raw_ostream &stderrOS, llvm::ArrayRef<DriverDef> drivers); 50 51 namespace wasm { 52 bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 53 llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); 54 } // namespace wasm 55 } // namespace lld 56 57 #include <dlfcn.h> 58 59 namespace clang { 60 61 WasmIncrementalExecutor::WasmIncrementalExecutor( 62 llvm::orc::ThreadSafeContext &TSC) 63 : IncrementalExecutor(TSC) {} 64 65 llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { 66 std::string ErrorString; 67 68 const llvm::Target *Target = llvm::TargetRegistry::lookupTarget( 69 PTU.TheModule->getTargetTriple(), ErrorString); 70 if (!Target) { 71 return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ", 72 llvm::inconvertibleErrorCode()); 73 } 74 75 llvm::TargetOptions TO = llvm::TargetOptions(); 76 llvm::TargetMachine *TargetMachine = Target->createTargetMachine( 77 PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_); 78 PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); 79 std::string ObjectFileName = PTU.TheModule->getName().str() + ".o"; 80 std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm"; 81 82 std::error_code Error; 83 llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error); 84 85 llvm::legacy::PassManager PM; 86 if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr, 87 llvm::CodeGenFileType::ObjectFile)) { 88 return llvm::make_error<llvm::StringError>( 89 "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode()); 90 } 91 92 if (!PM.run(*PTU.TheModule)) { 93 94 return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.", 95 llvm::inconvertibleErrorCode()); 96 } 97 98 ObjectFileOutput.close(); 99 100 std::vector<const char *> LinkerArgs = {"wasm-ld", 101 "-shared", 102 "--import-memory", 103 "--experimental-pic", 104 "--stack-first", 105 "--allow-undefined", 106 ObjectFileName.c_str(), 107 "-o", 108 BinaryFileName.c_str()}; 109 110 const lld::DriverDef WasmDriver = {lld::Flavor::Wasm, &lld::wasm::link}; 111 std::vector<lld::DriverDef> WasmDriverArgs; 112 WasmDriverArgs.push_back(WasmDriver); 113 lld::Result Result = 114 lld::lldMain(LinkerArgs, llvm::outs(), llvm::errs(), WasmDriverArgs); 115 116 if (Result.retCode) 117 return llvm::make_error<llvm::StringError>( 118 "Failed to link incremental module", llvm::inconvertibleErrorCode()); 119 120 void *LoadedLibModule = 121 dlopen(BinaryFileName.c_str(), RTLD_NOW | RTLD_GLOBAL); 122 if (LoadedLibModule == nullptr) { 123 llvm::errs() << dlerror() << '\n'; 124 return llvm::make_error<llvm::StringError>( 125 "Failed to load incremental module", llvm::inconvertibleErrorCode()); 126 } 127 128 return llvm::Error::success(); 129 } 130 131 llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) { 132 return llvm::make_error<llvm::StringError>("Not implemented yet", 133 llvm::inconvertibleErrorCode()); 134 } 135 136 llvm::Error WasmIncrementalExecutor::runCtors() const { 137 // This seems to be automatically done when using dlopen() 138 return llvm::Error::success(); 139 } 140 141 llvm::Error WasmIncrementalExecutor::cleanUp() { 142 // Can't call cleanUp through IncrementalExecutor as it 143 // tries to deinitialize JIT which hasn't been initialized 144 return llvm::Error::success(); 145 } 146 147 WasmIncrementalExecutor::~WasmIncrementalExecutor() = default; 148 149 } // namespace clang