It is not necessary to represent WebAssembly - support already exists in modern browsers. But technology is not just for them.
WebAssembly - cross-platform bytecode. So, this bytecode can be run on any platform where its virtual machine is. And for this, you do not need a browser and a Javascript engine.
Next - test the concept of strength, tools and the first script module.
Wasm modules can be used in the same cases as scripting languages: for the execution of dynamically loaded logic. Where Lua and Javascript are used. But the cost of interpreting wasm is less than that of scripting languages, and more optimizations can be applied to wasm. Because these optimizations are done at compile time on the source machine, and not interpretation or JIT compilation on the client.
WebAssembly is potentially independent of the source language. In the future, the script writer (the one who will write the scripts) can do this in a language that is convenient for him, not be tied to a specific language.
In addition to scripting languages, the technology can be compared with LLVM bytecode and a Java machine.
Comparison with LLVM-IR has already been made during the development of WebAssembly. The authors argue their refusal at the MVP stage as follows:
Compared to Java and its virtual machine:
WebAssembly can occupy its own niche in the portable code infrastructure, where neither scripting languages, nor LLVM-IR, nor JVM can solve problems efficiently.
The idea of ​​using WebAssembly without a web environment arose from a specific task. You need to create modules with interactive graphics that would work on the website and in the mobile application. The initial solution is to embed a Javascript engine into a mobile application and transfer the logic with javascript code. But the engines were quite massive and complex in the device (except, perhaps, JerryScript ). Using the engine for one small task looked like serious over-engineering. At this point, we came to the conclusion that similar modules on WebAssembly would be better due to the small size of the interpreter and faster interpretation.
Another use is to compile WebAssembly templates for web pages. To do this, simply create a backend to your favorite templating engine. Such templates are quite simple to run both on the server through the interpreter and in the browser by standard means. Creating a backend to a template engine is easier than porting your favorite template engine to your favorite system. Formally, the backend is easier to do for C code, which then will be compiled into wasm.
The WebAssembly site also offers other use cases:
To implement our plans, we need an experimental WebAssembly module from LLVM version 5 (current stable) or older.
We will use the LLVM Webassembly chain backend -> LLVM bytecode -> text representation LLVM-IR -> Binaryen s2wasm -> Binaryen wasm-as
The build takes from 15 minutes to an hour and requires a lot of memory (especially, with make -j8
)
# download LLVM-5 sources wget http://releases.llvm.org/5.0.0/llvm-5.0.0.src.tar.xz tar -xJf llvm-5.0.0.src.tar.xz llvm-5.0.0.src mv llvm-5.0.0.src llvm rm llvm-5.0.0.src.tar.xz cd llvm/tools # download clang sources wget http://releases.llvm.org/5.0.0/cfe-5.0.0.src.tar.xz tar -xJf cfe-5.0.0.src.tar.xz cfe-5.0.0.src mv cfe-5.0.0.src clang rm cfe-5.0.0.src.tar.xz cd - WORKDIR=`pwd` INSTALLDIR=`pwd` rm -rf llvm-build mkdir llvm-build cd llvm-build # For Debug build: # cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Debug $WORKDIR/llvm cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm make
git clone https://github.com/WebAssembly/binaryen.git cd binaryen cmake . make
git clone https://github.com/WebAssembly/wabt.git cd wabt git submodule update --init make
curl https://sh.rustup.rs -sSf | sh source $HOME/.cargo/env rustup toolchain install nightly rustup target add wasm32-unknown-unknown rustup default nightly
C / C ++ Build Example with makefile
rustc <source_file> --target=wasm32-unknown-unknown --crate-type=cdylib -C panic=abort -o <wasm_output>
As a proof of concept you can use an interpreter from WABT. To confirm the work, we will call a function from WebAssembly, which calls the environment function. You can add imported functions to WABT, for example, like this .
extern void import_function(int); int export_function(int i_test) { import_function(i_test * 3); return ++i_test; }
#![no_std] #![no_main] #![feature(lang_items)] #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} } mod wasm { pub fn _import_function(i: isize) -> isize { unsafe { import_function(i) } } extern { fn import_function(i: isize) -> isize; } } #[no_mangle] pub fn export_function(i_test: isize) -> isize { wasm::_import_function(i_test*2); let result = i_test+1; result }
You can start the module like this:
<wasm-interp> <wasm-file> -E export_function
The same modules can be used in the web, if you implement the required imported functions. For example, like this .
rust_begin_unwind
to imported functions (although -C panic=abort
ensures that this function will not be called). Potentially, the problem can be corrected at the rustc level, at the WebAssembly optimization level (through the removal of unused parameters). As a temporary solution, we added rust_begin_unwind
to the import list as a function that does nothing.Vec2 makeVec2(float x, float y) {...}
to (func (; 2 ;) (param $0 i32) (param $1 f32) (param $2 f32)
. The return value was converted to a pointer (type i32
) to a block of memory that will store the finished object. That is, the compiler performed an RVO. To work with such functions, you must first allocate the required block from the module’s memory, and call the function with the pointer as the first argument --- a/src/s2wasm.h +++ b/src/s2wasm.h @@ -1320,7 +1320,7 @@ class S2WasmBuilder { } skipWhitespace(); Address align = 4; // XXX default? - if (match(".globl")) { + if (match(".globl") || match(".weak")) { mustMatch(name.str); skipWhitespace(); }
WebAssembly modules can import and export functions, but they have to create the library themselves: the standard does not define any standard library.
A standard library is created for the interpreter and compiled with the interpreter. If the task requires wasm to be executed natively, and in the browser, you will need to port your standard Javascript library for compatibility. For example, for an interactive graphics task, write a cmath-compatible wrapper for both the interpreter and javascript.
What to include in the standard library is a separate complex issue. In the case of scripting languages, you are given a ready-made universal library. From which some functions you will be forced to turn off (for example, direct access to the file system). In the case of wasm, you can create a strict, dedicated API to which scripts will be limited in their sandbox.
WebAssembly is a powerful technology that can be used outside the web environment. So far, we are only taking the first steps and are learning to use new tools and design systems according to the new rules. In the future, WebAssembly may become one of the standards for portable executable packages.
The current (as of November 2017) condition of the instruments is rather weak, but they are already suitable for use. Identified problems are corrected quickly enough. In this article we wanted to show the possibility of a separate use of WebAssembly. And where to dig further - in the survey.
Co-authored with strelok2010
All code is here .
Source: https://habr.com/ru/post/344246/
All Articles