Home

Web Assembly: What is it? Does it do things? Let's find out!

— at Seoul Rust Meetup —

Download PDF
% !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{<[email protected]>}}
\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}