1*0fca6ea1SDimitry Andric //===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric // This file implements interpreter support for code execution in WebAssembly. 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #include "Wasm.h" 14*0fca6ea1SDimitry Andric #include "IncrementalExecutor.h" 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include <llvm/IR/LegacyPassManager.h> 17*0fca6ea1SDimitry Andric #include <llvm/IR/Module.h> 18*0fca6ea1SDimitry Andric #include <llvm/MC/TargetRegistry.h> 19*0fca6ea1SDimitry Andric #include <llvm/Target/TargetMachine.h> 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric #include <clang/Interpreter/Interpreter.h> 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric #include <string> 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric namespace lld { 26*0fca6ea1SDimitry Andric namespace wasm { 27*0fca6ea1SDimitry Andric bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, 28*0fca6ea1SDimitry Andric llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput); 29*0fca6ea1SDimitry Andric } // namespace wasm 30*0fca6ea1SDimitry Andric } // namespace lld 31*0fca6ea1SDimitry Andric 32*0fca6ea1SDimitry Andric #include <dlfcn.h> 33*0fca6ea1SDimitry Andric 34*0fca6ea1SDimitry Andric namespace clang { 35*0fca6ea1SDimitry Andric 36*0fca6ea1SDimitry Andric WasmIncrementalExecutor::WasmIncrementalExecutor( 37*0fca6ea1SDimitry Andric llvm::orc::ThreadSafeContext &TSC) 38*0fca6ea1SDimitry Andric : IncrementalExecutor(TSC) {} 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) { 41*0fca6ea1SDimitry Andric std::string ErrorString; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric const llvm::Target *Target = llvm::TargetRegistry::lookupTarget( 44*0fca6ea1SDimitry Andric PTU.TheModule->getTargetTriple(), ErrorString); 45*0fca6ea1SDimitry Andric if (!Target) { 46*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ", 47*0fca6ea1SDimitry Andric llvm::inconvertibleErrorCode()); 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric llvm::TargetOptions TO = llvm::TargetOptions(); 51*0fca6ea1SDimitry Andric llvm::TargetMachine *TargetMachine = Target->createTargetMachine( 52*0fca6ea1SDimitry Andric PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_); 53*0fca6ea1SDimitry Andric PTU.TheModule->setDataLayout(TargetMachine->createDataLayout()); 54*0fca6ea1SDimitry Andric std::string OutputFileName = PTU.TheModule->getName().str() + ".wasm"; 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric std::error_code Error; 57*0fca6ea1SDimitry Andric llvm::raw_fd_ostream OutputFile(llvm::StringRef(OutputFileName), Error); 58*0fca6ea1SDimitry Andric 59*0fca6ea1SDimitry Andric llvm::legacy::PassManager PM; 60*0fca6ea1SDimitry Andric if (TargetMachine->addPassesToEmitFile(PM, OutputFile, nullptr, 61*0fca6ea1SDimitry Andric llvm::CodeGenFileType::ObjectFile)) { 62*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>( 63*0fca6ea1SDimitry Andric "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode()); 64*0fca6ea1SDimitry Andric } 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric if (!PM.run(*PTU.TheModule)) { 67*0fca6ea1SDimitry Andric 68*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.", 69*0fca6ea1SDimitry Andric llvm::inconvertibleErrorCode()); 70*0fca6ea1SDimitry Andric } 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric OutputFile.close(); 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric std::vector<const char *> LinkerArgs = {"wasm-ld", 75*0fca6ea1SDimitry Andric "-pie", 76*0fca6ea1SDimitry Andric "--import-memory", 77*0fca6ea1SDimitry Andric "--no-entry", 78*0fca6ea1SDimitry Andric "--export-all", 79*0fca6ea1SDimitry Andric "--experimental-pic", 80*0fca6ea1SDimitry Andric "--no-export-dynamic", 81*0fca6ea1SDimitry Andric "--stack-first", 82*0fca6ea1SDimitry Andric OutputFileName.c_str(), 83*0fca6ea1SDimitry Andric "-o", 84*0fca6ea1SDimitry Andric OutputFileName.c_str()}; 85*0fca6ea1SDimitry Andric int Result = 86*0fca6ea1SDimitry Andric lld::wasm::link(LinkerArgs, llvm::outs(), llvm::errs(), false, false); 87*0fca6ea1SDimitry Andric if (!Result) 88*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>( 89*0fca6ea1SDimitry Andric "Failed to link incremental module", llvm::inconvertibleErrorCode()); 90*0fca6ea1SDimitry Andric 91*0fca6ea1SDimitry Andric void *LoadedLibModule = 92*0fca6ea1SDimitry Andric dlopen(OutputFileName.c_str(), RTLD_NOW | RTLD_GLOBAL); 93*0fca6ea1SDimitry Andric if (LoadedLibModule == nullptr) { 94*0fca6ea1SDimitry Andric llvm::errs() << dlerror() << '\n'; 95*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>( 96*0fca6ea1SDimitry Andric "Failed to load incremental module", llvm::inconvertibleErrorCode()); 97*0fca6ea1SDimitry Andric } 98*0fca6ea1SDimitry Andric 99*0fca6ea1SDimitry Andric return llvm::Error::success(); 100*0fca6ea1SDimitry Andric } 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) { 103*0fca6ea1SDimitry Andric return llvm::make_error<llvm::StringError>("Not implemented yet", 104*0fca6ea1SDimitry Andric llvm::inconvertibleErrorCode()); 105*0fca6ea1SDimitry Andric } 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric llvm::Error WasmIncrementalExecutor::runCtors() const { 108*0fca6ea1SDimitry Andric // This seems to be automatically done when using dlopen() 109*0fca6ea1SDimitry Andric return llvm::Error::success(); 110*0fca6ea1SDimitry Andric } 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric WasmIncrementalExecutor::~WasmIncrementalExecutor() = default; 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric } // namespace clang 115