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