- PVSM.RU - https://www.pvsm.ru -
Представлять WebAssembly не нужно — поддержка уже есть в современных браузерах. Но технология годится не только для них.
WebAssembly — кроссплатформенный байткод. Значит, этот байткод можно запустить на любой платформе, где есть его виртуальная машина. И для этого вовсе не нужен браузер и Javascript-движок.
Далее — проверка концепции на прочность, инструментарий и первый скриптовый модуль.
Wasm-модули можно использовать в тех же случаях, что и скриптовые языки: для исполнения динамически загружаемой логики. Там, где используется Lua и Javascript. Но затраты на интерпретацию wasm меньше, чем у скриптовых языков, и на wasm можно применить больше оптимизаций. Ибо оптимизации эти делаются во время компиляции на исходной машине, а не интерпретации или JIT-компиляции на клиенте.
WebAssembly потенциально независим от исходного языка. В перспективе, скриптёр (тот, кто будет писать скрипты) может делать это на удобном для него языке, не привязываться к конкретному языку.
Кроме скриптовых языков технологию можно сравнить с LLVM-байткодом и Java-машиной.
Сравнение с LLVM-IR сделано [1] уже в ходе разработки WebAssembly. Авторы аргументируют свой отказ ещё на этапе MVP так:
По сравнению с Java и её виртуальной машиной:
WebAssembly может занять в инфраструктуре портируемого кода собственную нишу, где ни скриптовые языки, ни LLVM-IR, ни JVM не решают задачи эффективно.
Идея использовать WebAssembly без web-окружения возникла из конкретной задачи. Необходимо создать модули с интерактивными графиками, которые бы работали на веб-сайте и в мобильном приложении. Первоначальный вариант решения: встроить Javascript-движок в мобильное приложение и передавать логику javascript-кодом. Но движки оказались достаточно массивными и сложными в устройстве (за исключением, пожалуй, JerryScript [2]). Использование движка для одной небольшой задачи выглядело серьёзным оверинжинирингом. В этот момент мы пришли к выводу, что аналогичные модули на WebAssembly будут лучше из-за малого размера интерпретатора и более быстрой интерпретации.
Другой вариант использования: компилировать в WebAssembly шаблоны для веб-страниц. Для этого достаточно создать backend к любимому шаблонизатору. Такие шаблоны достаточно просто запускать как на сервере через интерпретатор, так и в браузере стандартными средствами. Создать backend к шаблонизатору проще, чем портировать любимый шаблонизатор на любимую систему. Формально, backend проще сделать для кода на C, который после будет компилироваться в wasm.
На сайте WebAssembly [3] предлагаются [4] и другие варианты использования:
Для реализации задуманного нам нужен экспериментальный модуль WebAssembly из LLVM версии 5 (текущей стабильной) или старше.
Будем использовать цепочку LLVM Webassembly backend -> LLVM байткод -> текстовое представление LLVM-IR -> Binaryen s2wasm -> Binaryen wasm-as
Сборка занимает от 15 минут до часа и требует много памяти (особенно, при 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++ с помощью makefile [6]
rustc <source_file> --target=wasm32-unknown-unknown --crate-type=cdylib -C panic=abort -o <wasm_output>
В качестве proof of concept можно использовать интерпретатор из WABT. Для подтверждения работы будем вызывать функцию из WebAssembly, которая вызывает функцию среды. Добавить импортируемые функции в WABT можно, например, вот так [7].
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
}
Запустить модуль можно так:
<wasm-interp> <wasm-file> -E export_function
Эти же модули можно использовать и в вебе, если реализовать требуемые импортируемые функции. Например, вот так [8].
rust_begin_unwind
(хотя -C panic=abort
гарантирует, что эта функция не будет вызвана). Потенциально проблему можно исправить на уровне rustc, на уровне оптимизации WebAssembly (через удаление неиспользуемых параметров). Как временное решение мы добавили rust_begin_unwind
в список импорта в виде функции, которая не делает ничего.Vec2 makeVec2(float x, float y) {...}
в (func (; 2 ;) (param $0 i32) (param $1 f32) (param $2 f32)
. Возвращаемое значение было преобразовано в указатель (тип i32
) на блок памяти, который будет хранить готовый объект. То есть, компилятор выполнил RVO. Для работы с такими функциями нужно предварительно распределить из памяти модуля требуемый блок, и вызывать функцию с указателем в качестве первого аргумента--- 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 модули умеют импортировать и экспортировать функции, но создать библиотеку предстоит самостоятельно: стандарт не определяет никакой стандартной библиотеки.
Стандартная библиотека создается для интерпретатора и компилируется вместе с интерпретатором. Если задача требует исполнения wasm и нативно, и в браузере, вам нужно будет портировать вашу стандартную библиотеку на Javascript для совместимости. Например, для задачи интерактивных графиков написать cmath-совместимую обёртку и для интерпретатора, и для javascript.
Что включать в стандартную библиотеку — отдельный сложный вопрос. В случае со скриптовыми языками, вам дают уже готовую универсальную библиотеку. Из которой некоторые функции вы будете вынуждены выключить (например, прямой доступ к файловой системе). В случае с wasm вы можете создать строгий специальный API, которым скрипты будут ограничены в их песочнице.
WebAssembly — мощная технология, которую можно использовать и вне веб-окружения. Пока мы делаем только первые шаги и учимся использовать новые инструменты, проектировать системы по новым правилам. В будущем WebAssembly может стать одним из стандартов для портируемых исполняемых пакетов.
Текущее (на ноябрь 2017 года) состояние инструментов довольно слабое, но они уже пригодны для использования. Выявленные проблемы исправляются достаточно быстро. В этой статье мы хотели показать возможность отдельного применения WebAssembly. А куда копать дальше — в опросе.
В соавторстве с strelok2010 [9]
Весь код здесь [10].
Автор: Роман Катунцев
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/c-3/270266
Ссылки в тексте:
[1] сделано: http://webassembly.org/docs/faq/
[2] JerryScript: https://github.com/jerryscript-project/jerryscript
[3] На сайте WebAssembly: http://webassembly.org/docs/non-web/
[4] предлагаются: http://webassembly.org/docs/use-cases/
[5] cocos2d-js: https://github.com/cocos2d/cocos2d-js
[6] Пример сборки C/C++ с помощью makefile: https://github.com/strelok2012/WASMScript/blob/master/wasm/cpp/Makefile
[7] вот так: https://github.com/strelok2012/WASMScript/blob/master/interp/exec/ImportDelegate.cc
[8] Например, вот так: https://github.com/strelok2012/WASMScript/blob/master/index.html
[9] strelok2010: https://habrahabr.ru/users/strelok2010/
[10] здесь: https://github.com/strelok2012/WASMScript
[11] Источник: https://habrahabr.ru/post/344246/?utm_source=habrahabr&utm_medium=rss&utm_campaign=344246
Нажмите здесь для печати.