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