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