% !TEX program = XeLaTeX
\documentclass[aspectratio=169]{beamer}
\mode<presentation>
\usepackage{tikz}
\usepackage{pgfpages} % notes
\usepackage{graphicx}
\usepackage{color} % for syntax highlighting definitions
\usepackage{fontspec} % for custom firacode setup
\usepackage{listings} % for formatting codeblocks
\usepackage[T1]{fontenc}
\usetheme{AnnArbor}
\usecolortheme{spruce}
\usecolortheme{rose}
\setbeamertemplate{navigation symbols}{}
\setbeamertemplate{enumerate items}[default]
\setbeamercolor{item projected}{bg=green!40!black,fg=white}
\setbeamercolor{section in toc}{fg=black}
%\setbeameroption{show notes on second screen}
%% code syntax highlighting
\definecolor{lightgray}{rgb}{.9,.9,.9}
\definecolor{darkgray}{rgb}{.4,.4,.4}
\definecolor{purple}{rgb}{0.65, 0.12, 0.82}
\definecolor{gruv-red}{RGB}{204,36,29}
\definecolor{gruv-yellow}{RGB}{215,153,33}
\definecolor{gruv-aqua}{RGB}{104,157,106}
\definecolor{gruv-green}{RGB}{69,133,136}
\lstdefinelanguage{JavaScript}{
keywords={break, case, then, catch, continue, debugger, default, delete, do, else, false, finally, for, function, if, in, instanceof, new, null, return, switch, this, throw, true, try, typeof, var, void, while, with},
morecomment=[l]{//},
morecomment=[s]{/*}{*/},
morestring=[b]',
morestring=[b]",
ndkeywords={class, export, boolean, throw, implements, import, this},
keywordstyle=\color{gruv-green}\ttfamily,
ndkeywordstyle=\color{darkgray}\ttfamily,
identifierstyle=\color{black}\ttfamily,
stringstyle=\color{darkgray}\ttfamily,
frame=none,
sensitive=true
}
\lstdefinelanguage{Rust}{
keywordstyle=\color{gruv-yellow}\ttfamily,
keywordstyle=[1]{\color{gruv-aqua}\ttfamily},
keywordstyle=[2]{\color{gruv-yellow}\ttfamily},
keywordstyle=[3]{\color{gruv-red}\ttfamily},
morestring=[b]",
morestring=[b]',
stringstyle=\color{gray}\ttfamily,
otherkeywords = {\&Display, \&str, \#\[wasm\_bindgen\]},
morekeywords=[1]{derive, \#\[wasm\_bindgen\], wasm\_bindgen, js\_namespace, console},
morekeywords=[2]{Serialize, KoreanInteger, Deserialize, String, i128, i32, char, \&str, \&Display},
morekeywords=[3]{use, pub, fn, extern, struct, self, impl},
frame=none,
sensitive=true
}
\lstdefinelanguage{WASM}{
keywords=[1]{module, type, func, table, memory, export, param, result},
keywordstyle=\color{gruv-green}\ttfamily,
frame=none,
sensitive=true
}
\lstset{%
basicstyle = \fontfamily{pcr}\fontsize{10pt}{12pt}\selectfont,
numberstyle = \small,
numbersep = 10pt,
frame=none,
}
%% behavior modifications
\newenvironment{wideitemize}{\itemize\addtolength{\itemsep}{10pt}}{\enditemize}
\AtBeginSection[]
{
\begin{frame}
\frametitle{Journey}
\tableofcontents[currentsection]
\end{frame}
}
%% metadata
\title[WASM!]{Web Assembly: What does it do? Does it do things? Let's find out!}
\author[]{Andrew Zah \texttt{<zah@andrewzah.com>}}
\institute[Rust Meetup Seoul]{Rust Meetup Seoul}
\date{May 28, 2019}
%% preamble over
\begin{document}
\maketitle
\section*{Journey}
\begin{frame}
\tableofcontents
\end{frame}
%%%%%%%%%%%%%%%%%%%
\section{What is WASM?}
\begin{frame}
\frametitle{Web Assembly's Definition}
\begin{block}{from webassembly.org (emphasis mine)}
WebAssembly (abbreviated Wasm) is a \alert{binary instruction format} for a \alert{stack-based virtual machine}. Wasm is designed as a \alert{portable target} for compilation of high-level languages like C/C++/Rust, enabling \alert{deployment on the web} for client and server applications.
\end{block}
\end{frame}
\begin{frame}
\frametitle{What WASM is not}
\begin{wideitemize}
\item WASM is not a programming language, though you can write by hand
\item<2-> WASM isn't standalone: it needs a host
\item<3-> WASM is not intended to replace javascript
\end{wideitemize}
\end{frame}
\begin{frame}
\frametitle{what is it actually, though?}
\begin{wideitemize}
\item WASM's format isn't coupled to any OS or architecture
\item<2-> Very similar to Java's bytecode or C\#'s CLR
\item<3-> Name and definition is a misnomer
\item<4-> It can run \alert{anywhere} you can build a \alert{host}
\end{wideitemize}
\end{frame}
\begin{frame}
\frametitle{WASM's specification}
\begin{wideitemize}
\item WASM is \alert{stack-based}, not register-based
\item<2-> WASM 1.0 only has 4 primitives
\item<3-> `i32`, `i64`, `f32`, `f64`
\item<4-> No arrays
\item<5-> no \alert{jmp} instruction
\end{wideitemize}
\note[item]{Forth and retro are just about the only somewhat-mainline language that are stack-based.}
\note[item]{RPL also exists but\ldots}
\end{frame}
\begin{frame}
\frametitle{memory}
\begin{columns}
\begin{column}{0.5\textwidth}
\begin{wideitemize}
\item WASM has no \alert{new::()} operator or \alert{heap}
\item<2-> There are no objects or or garbage collection
\item<3-> Instead, WASM has \alert{linear memory}
\item<4-> this causes a need for linearization and bitmasking, etc
\end{wideitemize}
\end{column}
\begin{column}{0.5\textwidth}
\begin{center}
\uncover<3-> {
\begin{tikzpicture}
\draw [gray] (0,0) rectangle (4,1) node[pos=.5] {unused};
\draw [teal] (0,1) rectangle (4,2) node[pos=.5] {var3 [80\ldots119]};
\draw [gray] (0,2) rectangle (4,3) node[pos=.5] {var2 [40\ldots79]};
\draw [teal] (0,3) rectangle (4,4) node[pos=.5] {var1 [0\ldots39]};
\end{tikzpicture}
}
\end{center}
\end{column}
\end{columns}
\end{frame}
\begin{frame}
\frametitle{anyone can be a WASM host!}
\begin{alertblock}{The Host needs to:}
\begin{enumerate}
\item Load and validate the WASM binary (the file, not the logic)
\item<2-> Expose Exports
\item<3-> Satisfy Imports
\item<4-> Interpret \& Execute Modules
\item<5-> Isolate Modules
\end{enumerate}
\end{alertblock}
\end{frame}
\begin{frame}
\frametitle{infinity and beyond?}
\begin{wideitemize}
\item WebAssembly modules are hotswappable
\item<2-> PLCs (Programmable Logic Controllers) could adhere to a well-known contract
\item<2-> This would let us program for hardware controllers in \alert{any language}!
\item<3-> \alert{wasmi} is an rust open-source wasm interpreter
\item<4-> \alert{serverless-wasm} does indeed exist
\end{wideitemize}
\end{frame}
\begin{frame}
\frametitle{security}
\begin{wideitemize}
\item WASM binaries can always be converted back to plaintext
\item<2-> Do not put secrets in WASM modules
\item<3-> \alert{Message handoffs} are not always secure!
\item<4-> Accordingly, \alert{sign} and \alert{encrypt} modules!
\end{wideitemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{add example: rust side}
\begin{block}{main.rs}
\begin{lstlisting}[language=rust]
#[no_mangle]
pub extern "C" fn add_one(x: i32) -> i32 {
x + 1
}
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{add example: generated WASM}
\begin{block}{main.wasm}
\begin{lstlisting}[language=wasm]
(module
(type $t0 (func (param i32) (result i32)))
(func $add_one
(export "add_one") (type $t0) (param $p0 i32) (result i32)
get_local $p0
i32.const 1
i32.add)
(table $T0 1 1 anyfunc)
(memory $memory (export "memory") 17))
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}
\frametitle{summary}
\begin{wideitemize}
\item WASM is simply a instruction format that's portable
\item WASM can run anywhere so long as a host exists
\item Just because you can write WASM doesn't mean you should
\end{wideitemize}
\end{frame}
%%%%%%%%%%%%%%%%%%%
\section{Applications of WASM in Rust}
\begin{frame}
\frametitle{wasm-bindgen}
\begin{wideitemize}
\item CLI tool to generate bindings for the wasm code to work
\item<2-> can be run manually but \alert{wasm-pack} simplifies things
\item<3-> \alert{automates} linearization, strings, complex types bindings
\end{wideitemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{configuring cargo}
\begin{block}{Cargo.toml}
\begin{lstlisting}
[lib]
crate-type = ["cdylib"]
[build]
target = "wasm32-unknown-unknown"
[dependencies]
wasm-bindgen = "0.2.45"
[dependencies.rand]
features = ["wasm-bindgen"]
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{rust wasm: functions}
\begin{block}{main.rs}
\begin{lstlisting}[language=rust]
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
#[wasm_bindgen(method, structural, js_namespace = ROT)]
fn draw(this: &Display, x: i32, y: i32, ch: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
log(&format!("Hello, {}!", name));
}
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{js\_sys and web\_sys provide bindings}
\begin{block}{main.rs}
\begin{lstlisting}[language=rust]
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
use web_sys::console::log_1;
#[wasm_bindgen]
pub fn hi() {
log_1(JsValue::from_str("hi"));
}
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{rust wasm: structs and impls}
\begin{block}{main.rs}
\begin{lstlisting}[language=rust]
#[wasm_bindgen]
pub struct Counter { count: i32, }
#[wasm_bindgen]
impl Counter {
pub fn get(&self) -> char {
log(format!("Count: {}", self.count));
self.count
}
}
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}
\frametitle{wasm-pack}
\begin{wideitemize}
\item<1-> higher level wrapper for \alert{wasm-bindgen}
\item<2-> commands: \alert{build}, \alert{test}, \alert{pack}, \alert{publish}, \alert{login}
\item<3-> \alert{wasm-bindgen} is still a dependency
\end{wideitemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{wasm-pack output in /pkg}
\begin{block}{exa -T -L1 pkg/}
\begin{lstlisting}
pkg/
package.json
wasm_pack_test.d.ts
wasm_pack_test.js
wasm_pack_test_bg.d.ts
wasm_pack_test_bg.wasm
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{wasm-pack output}
\begin{block}{main.js}
\begin{lstlisting}[language=javascript]
const wasm = import('./pkg/hello_world');
wasm
.then(m => m.greet('World!'))
.catch(console.error);
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}
\frametitle{extensions and alternatives}
\begin{wideitemize}
\item \alert{web-sys} and \alert{js-sys} provide raw js/web API bindings
\item<2-> \alert{std-web} has a similar goal but provides more JS interop + APIs
\item<3-> \alert{rust-neon} (external tool) generates \alert{Node.js} modules
\item<4-> \alert{yew} is a web framework that compiles to WASM
\end{wideitemize}
\end{frame}
\begin{frame}
\frametitle{optimizing the WASM output}
\begin{columns}
\begin{column}{0.6\textwidth}
\begin{wideitemize}
\item \alert{wasm-opt} can significantly reduce binary size
\item<2-> \alert{wasm2wat} can be used to confirm
\item<3-> \alert{twiggy} is a wasm profiler that analyzes call graphs
\item<4-> set \alert{lto = true} in Cargo.toml, but limit to release only
\end{wideitemize}
\end{column}
\begin{column}{0.4\textwidth}
\uncover<3->{
\includegraphics[scale=0.34]{twiggy.png}
}
\end{column}
\end{columns}
\end{frame}
%%%%%%%%%%%%%%%%%%%
\section{A Real, Non-Trivial WASM App}
\begin{frame}
\frametitle{korean apps}
\begin{wideitemize}
\item Initially I wrote a cargo crate, \alert{korean-numbers}
\item<2-> I wanted a way to use this logic in a webapp with React
\item<3-> I went with \alert{wasm-bindgen} calls in \alert{package.json} scripts
\end{wideitemize}
\end{frame}
\begin{frame}[fragile]
\frametitle{project structure}
\begin{block}{exa -T -L2 .}
\begin{lstlisting}
dist/
frontend/
native/
node_modules/
package.json
webpack.config.js
yarn.lock
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{why wasm-pack may be better}
\begin{block}{package.json}
\begin{lstlisting}
"scripts": {
"build-debug": "cd native; cargo +nightly build
--target wasm32-unknown-unknown
&& wasm-bindgen
target/wasm32-unknown-unknown/debug/korean_wasm.wasm
--out-dir ../frontend/wasm; cd .."
}
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{rust side: glue code}
\begin{block}{native/src/lib.rs}
\begin{lstlisting}[language=rust]
use korean_nums::{ NumberSystem, ...}
#[wasm_bindgen]
struct KoreanInteger { number: i128, hangeul: String, }
#[wasm_bindgen]
pub fn random_korean_int(
lower_str: &str, upper_str: &str, num_system: &str)
-> KoreanInteger
{ ... }
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{frontend layout}
\begin{block}{exa -T -L2 frontend/}
\begin{lstlisting}
components/
korean_numbers/
index.html
index.js
wasm/
korean_wasm.d.ts
korean_wasm.js
korean_wasm_bg.d.ts
korean_wasm_bg.wasm
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{calling code from the frontend}
\begin{block}{frontend/components/korean\_numbers/index.js}
\begin{lstlisting}[language=javascript]
const { random_int } = require("../../wasm/korean_wasm");
const res = random_korean_int(0, 10, "sino");
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{non-trivial optimizations}
\begin{columns}
\begin{column}{0.45\textwidth}
\begin{block}{ls -lah | rg wasm | awk `{print \$5, \$9}' | sort}
\begin{lstlisting}
282K wasm-opt-Oz-flag.wasm
283K wasm-opt-Os-flag.wasm
306K wasm-opt-O3-flag.wasm
573K wasm-opt-default.wasm
695K bindgen-development.wasm
\end{lstlisting}
\end{block}
\end{column}
\begin{column}{0.45\textwidth}<2->
\begin{block}{release mode versions}
\begin{lstlisting}
126K wasm-opt-lto-Oz-flag.wasm
136K bindgen-release-lto.wasm
166K bindgen-release.wasm
\end{lstlisting}
\end{block}
\end{column}
\end{columns}
\end{frame}
\begin{frame}[fragile]
\frametitle{inspecting with twiggy}
\begin{block}{twiggy top wasm-bindgen-default.wasm}
\begin{lstlisting}
Shallow Bytes │ Shallow % │ Item
124493 | 17.50% | "function names" subsection
57598 | 8.10% | rand_hc::hc128::Hc128Core::sixteen_steps
50394 | 7.09% | <rand_hc::hc128::Hc128Core>...::generate
24781 | 3.48% | data[1]
22978 | 3.23% | data[2]
7624 | 1.07% | <rand::rngs::entropy::EntropyRng>...::try_fill_bytes
6928 | 0.97% | korean_nums::parse::parse_hangeul_sino
4918 | 0.69% | core::num::flt2dec::strategy::dragon::mul_pow10
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}[fragile]
\frametitle{inspecting release mode with twiggy}
\begin{block}{twiggy top wasm-opt-Oz-release-lto.wasm}
\begin{lstlisting}
Shallow Bytes │ Shallow % │ Item
9753 | 7.55% | data[0]
8556 | 6.62% | code[33]
8457 | 6.54% | data[1]
7012 | 5.42% | code[76]
6156 | 4.76% | code[127]
6145 | 4.75% | code[75]
\end{lstlisting}
\end{block}
\end{frame}
\begin{frame}
\begin{center}
{\huge Thank you} \\
Andrew Zah
\end{center}
\end{frame}
%%%%%%%%%%%%%%%%%%%
\section*{Appendix}
\begin{frame}[plain]
\includegraphics[scale=0.34]{webassembly-studio.png}
\end{frame}
\begin{frame}
\frametitle{further reading}
\begin{itemize}
\item \alert{WASM Homepage} \texttt{https://webassembly.org}
\item \alert{WASM Spec} \texttt{https://webassembly.github.io/spec/}
\item \alert{wasm-bindgen docs} \texttt{https://rustwasm.github.io/docs/wasm-bindgen/}
\item \alert{stdweb} \texttt{https://github.com/koute/stdweb}
\item \alert{twiggy profiler} \texttt{https://github.com/rustwasm/twiggy}
\item \alert{wat2wasm, wasm2wat, and more} \texttt{https://github.com/WebAssembly/wabt}
\item \alert{websys} \texttt{https://rustwasm.github.io/wasm-bindgen/api/web\_sys/}
\item \alert{neon-bindings} \texttt{https://github.com/neon-bindings/neon}
\item \alert{optimizing emscriptem} \texttt{https://emscripten.org/docs/optimizing/Optimizing-Code.html}
\item \alert{wasmi: rust wasm interpreter} \texttt{https://github.com/paritytech/wasmi}
\end{itemize}
\end{frame}
\begin{frame}
\frametitle{bibliography}
\begin{thebibliography}{Dijkstra, 1982}
\bibitem[Hoffman, 2019]{Hoffman2019}
K.~Hoffman.
\newblock{\em Programming WebAssembly with Rust \\
\small Unified Development for Web, Mobile, and Embedded Applications }
\newblock{The Pragmatic Programmers, LLC}
\newblock{ISBN-13: 978-1-68050-636-5}
\end{thebibliography}
\end{frame}
\end{document}