Yann-Gaël Guéhéneuc
(/jan/, he/il)
Work licensed under Creative Commons
BY-NC-SA 4.0 International
WASM or
Realising the Dream of
Write Once, Run Anywhere?
Version 0.7
25/09/24
2/204
Outline
 History
 Problem and Solutions
– HTML + JavaScript + CSS
– Java Applets
– C/C++ + WebAssembly
– TeaVM
– TeaVM + WASI
– CheerpJ
 Conclusion
3/204
HISTORY
4/204
Computing Constraints
 Since the advent of computers,
multiple forces shaped computing
– Capability
• Proving needed xPU, RAM, screen resolutions
– Availability
• Providing computers where and when needed
– Diversity
• Providing many different features, i.e., software
– Affordability
• Having cheap hardware and software
5/204
Pre-history of Computers
ca. 205 BCE, https://en.wikipedia.org/wiki/Antikythera_mechanism
ca. 1620, https://en.wikipedia.org/wiki/Slide_rule
6/204
Pre-history of Programmable Computers
1804, https://ageofrevolution.org/200-object/jacquard-loom/
1837, https://en.wikipedia.org/wiki/Analytical_engine
7/204
First Programmable Computers
1943, https://en.wikipedia.org/wiki/Z3_(computer)
1943, https://en.wikipedia.org/wiki/Colossus_computer
8/204
First Computers
 Capability █
 Availability █
 Diversity █
 Affordability ~$84.106*
1948, https://en.wikipedia.org/wiki/Manchester_Baby
* All prices for 2025, adjusted for inflation
9/204
First Computers
 Capability █
 Availability █
 Diversity █
 Affordability ~$8.106
1949–1958, https://en.wikipedia.org/wiki/EDSAC
10/204
First Shared Computers
https://www.pcmag.com/news/the-forgotten-world-of-dumb-terminals
https://beginnerscsharp.wordpress.com/introduction-to-net/
11/204
First GUI Computers
 Capability ██
 Availability █
 Diversity █
 Affordability ~$76,780
1970s–1990s, https://en.wikipedia.org/wiki/PERQ
12/204
First Popular Computers
 Capability ██
 Availability ██
 Diversity ██
 Affordability ~$5,500
1981–1987, https://en.wikipedia.org/wiki/IBM_Personal_Computer
13/204
First Popular Computers
 Capability ██
 Availability ████
 Diversity ███
 Affordability ~$1,990
1982–1994, https://en.wikipedia.org/wiki/Commodore_64
14/204
First Popular Computers
 Capability ██
 Availability ███
 Diversity ███
 Affordability ~$7,750
1984–1985, https://en.wikipedia.org/wiki/Macintosh_128K
15/204
First Popular GUI Computers
 Capability ███
 Availability ███
 Diversity ███
 Affordability ~$1,987
1985–1998, https://en.wikipedia.org/wiki/Amiga
16/204
The OSs Takeover
 Capability ████
 Availability ███
 Diversity ███
 Affordability ~$5,000
ca. 1992, https://en.wikipedia.org/wiki/Windows_3.1 and
https://www.reddit.com/r/retrobattlestations/comments/10cr6ko/
windows_311_with_tabworks/#lightbox
17/204
The OSs Takeover
 Capability █████
 Availability ████
 Diversity ████
 Affordability ~$30,000
ca. 1996, https://en.wikipedia.org/wiki/Windows_95 and
https://www.reddit.com/r/VintageComputers/comments/1mimbzj/
i_restored_this_dell_dimension_m233a_from_1997_i/#lightbox
18/204
The OSs Takeover
 Capability █████
 Availability ███
 Diversity ███
 Affordability ~$7,730
1998–2002, https://www.reddit.com/r/unixporn/comments/8a1k6m/
sun_ultra_5_cool_sun_workstation_with_a_boxed/
19/204
The OSs Takeover
 Capability █████
 Availability ██
 Diversity ██
 Affordability ~$3,000
ca. 1995, https://www.reddit.com/r/linuxmasterrace/comments/xwvbsv/pulled_out_the_pentium_133_today/#lightbox
20/204
The OSs Takeover (Almost)
 Capability ███
 Availability ██
 Diversity ███
 Affordability ~$4,120
ca. 1996, https://meiobit.com/413250/power-macintosh-610066-o-
curioso-caso-do-frankenstein-da-apple/
21/204
The Killer Apps
https://www.computerhistory.org/revolution/
personal-computers/17/305/1050
https://en.wikipedia.org/wiki/VisiCalc
22/204
The Killer Apps
https://en.wikipedia.org/wiki/Lotus_1-2-3
https://dfarq.homeip.net/lotus-second-largest-software-publisher-in-the-
world-in-1983/
23/204
The Killer Apps
https://www.sk.rs/arhiva/clanak/33263/deluxe-paint
https://peakd.com/retrocomputing/@darth-azrael/deluxepaint-i-amiga-
1568216269252
24/204
Computers in the 1990s
 Main branches
– Apple computers
– Super computers
– “Wintel” computers
– Other independents
– Joker: Linux!
 Killer Apps
– Office suites
– Publishing
– Art creation
• Graphics
• Audio
• Videos
– Joker: Games
25/204
Computers in the 1990s
 Main branches
– Apple computers
– Super computers
– “Wintel” computers
– Other independents
 Killer Apps
– Office suites
– Publishing
– Art creation
• Graphics
• Audio
• Videos
26/204
Computers in the 1990s
 Main branches
– Apple computers
– Super computers
– “Wintel” computers
– Other independents
– Joker: Linux!
 Killer Apps
– Office suites
– Publishing
– Art creation
• Graphics
• Audio
• Videos
– Joker: Games
27/204
Opportunities and Challenges
 Opportunities
– Cheaper hardware
– Fewer, better OSs
– The Internet
 Challenges
– Computers-specific killer applications
– Still a wide of hardware and software
28/204
Opportunities and Challenges
 Opportunities
– Cheaper hardware
– Fewer, better OSs
– The Internet
 Challenges
– Computers-specific killer applications
– Still a wide of hardware and software
29/204
Opportunities and Challenges
http://toastytech.com/guis/win313.html
https://www.reddit.com/r/nostalgia/comments/winvdz/netscape_navigator_browser/
https://www.macintoshrepository.org/18187-quarkxpress-3-3-international-english
30/204
Opportunities and Challenges
 Capability
– Proving needed xPU, RAM, screen resolutions
 Availability
– Providing computers where and when needed
 Diversity
– Providing many different features, i.e., software
 Affordability
– Having cheap hardware and software
31/204
PROBLEM AND SOLUTIONS
32/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
33/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
34/204
HTML + JavaScript + CSS
 In every (major) browser
– In 1995, the first interpreter by Brendan Eich
for Netscape Navigator was LiveScript
• Became SpiderMonkey in Mozilla Firefox
– With Trace-, Jäger-, Ion-, and OdinMonkey…
for debugging, JIT compilation, optimisations
35/204
HTML + JavaScript + CSS
 In every (major) browser (cont’d)
– In 2008, V8 in Google Chrome
• In 2009, used for Node.js
• In 2013, used for Electron
– In 2008, Nitro in Apple Safari
– In 2010, Carakan in Opera
– In 2011, Chakra in Microsoft Internet Explorer
36/204
HTML + JavaScript + CSS
 More than interpreters, engines!
– Optimisers
– JIT compilers
– Host APIs
– ...
37/204
HTML + JavaScript + CSS
 Target for other programming languages
– In 2010, Emscripten to transpile C/C++
 Specific optimisations
– In 2013, asm.js with OdinMonkey, Mozilla Firefox
• Efficient native code ahead-of-time for the JIT
 Optimised bytecodes
– In 2017, asm.js, NaCl became WebAssembly
38/204
HTML + JavaScript + CSS
 Target for other programming languages
– In 2010, Emscripten to transpile C/C++
 Specific optimisations
– In 2013, asm.js with OdinMonkey, Mozilla Firefox
• Efficient native code ahead-of-time for the JIT
 Optimised bytecodes
– In 2017, asm.js, NaCl became WebAssembly
39/204
HTML + JavaScript + CSS
 Available in Web browsers
 Access to the DOM
 Popular
40/204
HTML + JavaScript + CSS
 Limitations
– Performance
– Complexity
– Design
– Typing
– Ecosystem
https://blog.bitsrc.io/5-fundamental-limits-in-javascript-every-developer-should-know-11b507f7a7dc
https://dev.to/malikhaziq/the-limitations-of-javascript-as-a-programming-language-2fd7
https://www.geeksforgeeks.org/javascript/advantages-and-disadvantages-of-javascript/
41/204
HTML + JavaScript + CSS
 Limitations
– Performance
David Lion, Adrian Chiu, Michael Stumm, Ding Yuan ; Investigating Managed Language Runtime
Performance: Why JavaScript and Python are 8x and 29x Slower than C++, Yet Java and Go Can
Be Faster? ; USENIX Annual Technical Conference, 2022
42/204
HTML + JavaScript + CSS
 Limitations
– Complexity
https://github.com/denysdovhan/wtfjs
https://www.geeksforgeeks.org/javascript/explain-the-concept-of-truthy-falsy-values-in-javascript/
if
if
if
if ("") console.log
log
log
log("1");
if
if
if
if (" ") console.log
log
log
log("2");
if
if
if
if (0) console.log
log
log
log("3");
if
if
if
if (-1) console.log
log
log
log("4");
if
if
if
if ([]) console.log
log
log
log("5");
if
if
if
if ({}) console.log
log
log
log("6");
43/204
HTML + JavaScript + CSS
 Limitations
– Complexity
https://github.com/denysdovhan/wtfjs
https://www.geeksforgeeks.org/javascript/explain-the-concept-of-truthy-falsy-values-in-javascript/
2
4
5
6
if
if
if
if ("") console.log
log
log
log("1");
if
if
if
if (" ") console.log
log
log
log("2");
if
if
if
if (0) console.log
log
log
log("3");
if
if
if
if (-1) console.log
log
log
log("4");
if
if
if
if ([]) console.log
log
log
log("5");
if
if
if
if ({}) console.log
log
log
log("6");
44/204
HTML + JavaScript + CSS
 Limitations
– Design
• Type coercion
– The infamous == vs. ===
• Behaviour of this
– Context dependent
• Prototypes
– No classes
• No multi-threading
– Concurrency but callback hell
45/204
HTML + JavaScript + CSS
 Limitations
– Typing
• Dynamically, weakly typed
• With weird type coercion rules
https://dotat.at/@/2025-08-28-strongly-typed.html
46/204
HTML + JavaScript + CSS
 Limitations
– Typing
• Dynamically, weakly typed
• With weird type coercion rules
https://dotat.at/@/2025-08-28-strongly-typed.html
47/204
HTML + JavaScript + CSS
 Limitations
– Ecosystem
• Inconsistencies
– Different behaviour in
different Web browsers
• Debugging
– Also, dependency on
HTML, Web browsers…
• Dependency management
– NPM again…
• Toolchains
– Webpack
• Code is always
accessible
– Obfuscation
• “Vendor” lock-in
– But WebAssembly
may change that!
48/204
HTML + JavaScript + CSS
 Other concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
49/204
HTML + JavaScript + CSS
 Other concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
50/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
51/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
52/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
53/204
Opportunities and Challenges
 Java has a virtual machines
 Web browsers abstract OSs and hardware
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
54/204
(JavaStation)
 Capability
 Availability
 Diversity
 Affordability: ~$1,355
1996–2000, https://en.wikipedia.org/wiki/JavaStation
55/204
(JavaStation)
 Network Computers (NCs)
– Advantages
• Run any Java programs
• “Cheap”
– Disadvantages
• Require changing existing desktops
• Run only (?) Java programs
• PCs became (ever) cheaper
• Very slow
https://hackaday.com/2018/04/10/the-forgotten-workstation-sun-javastation/
https://www.cnet.com/tech/tech-industry/javastation-nostalgia/
56/204
Java Applets
https://web.deu.edu.tr/doc/oreily/java/javanut/ch01_02.htm
57/204
Java Applets
 Getting value from the HTML
<applet code="Simple" width=50 height=50>
<param name="UserName" value="yann">
</applet>
https://www.tutorialspoint.com/java/java_applet_basics.htm
58/204
Java Applets
 Getting value from the HTML
<applet code="Simple" width=50 height=50>
<param name="UserName" value="yann">
</applet>
public class Simple extends Applet {
private String userName;
@Override
public void init() {
super.init();
this.userName = super.getParameter("UserName");
https://www.tutorialspoint.com/java/java_applet_basics.htm
59/204
Java Applets
 Manipulating the DOM
@Override
public void start() {
super.start();
try {
final Class<?> c = Class.forName("com.sun.java.browser.plugin2.DOM");
final Method m = c.getMethod("getDocument",
new Class[] { java.applet.Applet.class });
final HTMLDocument doc = (HTMLDocument) m.invoke(null, new Object[] { this });
final HTMLBodyElement body = (HTMLBodyElement) doc.getBody();
// ...
https://docs.oracle.com/javase/tutorial/deployment/applet/examplesIndex.html
60/204
Java Applets
 Manipulating the DOM
@Override
public void start() {
super.start();
try {
final Class<?> c = Class.forName("com.sun.java.browser.plugin2.DOM");
final Method m = c.getMethod("getDocument",
new Class[] { java.applet.Applet.class });
final HTMLDocument doc = (HTMLDocument) m.invoke(null, new Object[] { this });
final HTMLBodyElement body = (HTMLBodyElement) doc.getBody();
// ...
Must duplicate
the whole DOM
https://docs.oracle.com/javase/tutorial/deployment/applet/examplesIndex.html
61/204
Java Applets
 JavaScript to Applet
– LiveConnect
• Netscape Plugin API
– NPAPI
https://en.wikipedia.org/wiki/NPAPI#LiveConnect
62/204
Java Applets
 JavaScript to Applet
– LiveConnect
• Netscape Plugin API
– NPAPI
https://en.wikipedia.org/wiki/NPAPI#LiveConnect
63/204
Java Applets
 JavaScript to Applet
https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript
https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html
64/204
Java Applets
 JavaScript to Applet
https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript
https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html
public class MathApplet extends Applet {
public String userName = null;
// ...
65/204
Java Applets
 JavaScript to Applet
https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript
https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html
public class MathApplet extends Applet {
public String userName = null;
// ...
<script src="https://www.java.com/js/deployJava.js"/>
<script>
var attributes = { id:'mathApplet’,
code:'net.ptidej.teavm.MathApplet', ...};
var parameters = { jnlp_href: 'math_applet.jnlp’};
deployJava.runApplet(attributes, parameters, '1.6');
</script>
66/204
Java Applets
 JavaScript to Applet
https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript
https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html
public class MathApplet extends Applet {
public String userName = null;
// ...
<script language="javascript">
function enterNums(){
// set applet's public variable
mathApplet.userName = "yann";
// ...
<script src="https://www.java.com/js/deployJava.js"/>
<script>
var attributes = { id:'mathApplet’,
code:'net.ptidej.teavm.MathApplet', ...};
var parameters = { jnlp_href: 'math_applet.jnlp’};
deployJava.runApplet(attributes, parameters, '1.6');
</script>
67/204
Java Applets
 Applet to JavaScript
https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript
<html>
<body>
<center>
<applet id="testApplet"
code="TestApplet.class"
width="200" height="80"/>
</center>
</body>
<script type="text/javascript">
var coop = "Ooops!";
this[1] = "Slot 1";
function foo() {
return "This is from foo()";
}
function bar(firstName, lastName) {
return "Greeting " +
firstName + " " + lastName;
}
</script>
</html>
public class Java2JavaScript extends Applet {
public void init() {
// ...
}
private void testLiveConnect() throws JSException {
final JSObject jso = JSObject.getWindow(this);
String result = (String) jso.call("foo", null);
label.setText(result);
// ...
result = (String) jso.call(
"bar", new String[] { "Alice", "Alisa" });
label.setText(result);
// ...
final String expression = "alert('Hi!');";
jso.eval(expression);
// ...
result = (String) jso.getMember("coop");
label.setText(result);
// ...
result = (String) jso.getSlot(1);
label.setText(result);
68/204
Java Applets
 Limitations
– Java Applets
• Depend on a JRE + the plug-in for the Web browser
– May require to be root to install!
• No standard for screen readers
• Security restrictions and holes
– LiveConnect
• Tied to the JRE embedded within the Web browser
• Obsolete JNI
– JRI
https://en.wikipedia.org/wiki/Java_applet#Disadvantages
69/204
Java Applets
 Removal and total removal
– “By late 2015, many browser vendors had either
removed or announced timelines for the removal
of standards based plugin support, while some
are introducing proprietary browser-specific
extension APIs. […], Oracle is planning to
deprecate the Java browser plugin in JDK 9.”
https://stackoverflow.com/questions/45535112/why-were-applets-deprecated-in-jdk-9
70/204
Java Applets
 Inception, removal, and total removal
– 1996: Applets introduced in Java 1
– 2002: Java Web Start introduced in Java 1.4
– 2017: All deprecated in Java 9
– 2018: appletviewer and Java Web Start
removed from Java 11
– 2021: API deprecated for removal with Java 17
– 2026: total removal of all things Applet
https://stackoverflow.com/questions/45535112/why-were-applets-deprecated-in-jdk-9
https://openjdk.org/jeps/504
71/204
Java Applets
 Still runnable with older JDKs
 Still runnable with different implementations
of the JDK
– Azul Platform Core
– https://www.azul.com/blog/keeping-java-applets-
alive-with-azul-platform-core/
72/204
Java Applets
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
73/204
Java Applets
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
74/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
75/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
76/204
C/C++ + WebAssembly
 Browsers as universal computing platform
77/204
C/C++ + WebAssembly
 Browsers as universal computing platform

78/204
C/C++ + WebAssembly
 Browsers as universal computing platform
 WebAssembly
– Portable binary-code format (.wasm)
• And a corresponding text format (.wat)
– API with host environment
– Implemented in all major Web browsers
• In their respective JavaScript engine
79/204
C/C++ + WebAssembly
 WebAssembly in a nutshell
https://en.wikipedia.org/wiki/WebAssembly#Code_representation
int factorial
factorial
factorial
factorial(int n) {
if
if
if
if (n == 0)
return
return
return
return 1;
else
else
else
else return
return
return
return n * factorial(n-1);
}
80/204
C/C++ + WebAssembly
 WebAssembly in a nutshell
https://en.wikipedia.org/wiki/WebAssembly#Code_representation
int factorial
factorial
factorial
factorial(int n) {
if
if
if
if (n == 0)
return
return
return
return 1;
else
else
else
else return
return
return
return n * factorial(n-1);
}
(func
func
func
func (param
param
param
param i64) (result
result
result
result i64)
local.get 0
i64.eqz
if
if
if
if (result
result
result
result i64)
i64.const 1
else
else
else
else
local.get 0
local.get 0
i64.const 1
i64.sub
call 0
i64.mul
end
end
end
end)
81/204
C/C++ + WebAssembly
 WebAssembly in a nutshell
https://en.wikipedia.org/wiki/WebAssembly#Code_representation
int factorial
factorial
factorial
factorial(int n) {
if
if
if
if (n == 0)
return
return
return
return 1;
else
else
else
else return
return
return
return n * factorial(n-1);
}
(func
func
func
func (param
param
param
param i64) (result
result
result
result i64)
local.get 0
i64.eqz
if
if
if
if (result
result
result
result i64)
i64.const 1
else
else
else
else
local.get 0
local.get 0
i64.const 1
i64.sub
call 0
i64.mul
end
end
end
end)
(module
module
module
module
(type
type
type
type $t0 (func
func
func
func (param
param
param
param i64) (result
result
result
result i64)))
(func
func
func
func $f0 (type
type
type
type $t0) (param
param
param
param $p0 i64) (result
result
result
result i64)
(if
if
if
if $I0 (result
result
result
result i64) ;; $I0 is unused
(i64.eqz
(local.get $p0)) ;; $p0 is same as 0
(then
then
then
then
(i64.const 1))
(else
else
else
else
(i64.mul
(local.get $p0)
(call $f0 ;; $f0 is same as 0
(i64.sub
(local.get $p0)
(i64.const 1))))))))
82/204
C/C++ + WebAssembly
 WebAssembly in a nutshell
https://en.wikipedia.org/wiki/WebAssembly#Code_representation
int factorial
factorial
factorial
factorial(int n) {
if
if
if
if (n == 0)
return
return
return
return 1;
else
else
else
else return
return
return
return n * factorial(n-1);
}
(func
func
func
func (param
param
param
param i64) (result
result
result
result i64)
local.get 0
i64.eqz
if
if
if
if (result
result
result
result i64)
i64.const 1
else
else
else
else
local.get 0
local.get 0
i64.const 1
i64.sub
call 0
i64.mul
end
end
end
end)
(module
module
module
module
(type
type
type
type $t0 (func
func
func
func (param
param
param
param i64) (result
result
result
result i64)))
(func
func
func
func $f0 (type
type
type
type $t0) (param
param
param
param $p0 i64) (result
result
result
result i64)
(if
if
if
if $I0 (result
result
result
result i64) ;; $I0 is unused
(i64.eqz
(local.get $p0)) ;; $p0 is same as 0
(then
then
then
then
(i64.const 1))
(else
else
else
else
(i64.mul
(local.get $p0)
(call $f0 ;; $f0 is same as 0
(i64.sub
(local.get $p0)
(i64.const 1))))))))
Stack machine
83/204
C/C++ + WebAssembly
 WebAssembly in a nutshell
https://en.wikipedia.org/wiki/WebAssembly#Code_representation
int factorial
factorial
factorial
factorial(int n) {
if
if
if
if (n == 0)
return
return
return
return 1;
else
else
else
else return
return
return
return n * factorial(n-1);
}
(func
func
func
func (param
param
param
param i64) (result
result
result
result i64)
local.get 0
i64.eqz
if
if
if
if (result
result
result
result i64)
i64.const 1
else
else
else
else
local.get 0
local.get 0
i64.const 1
i64.sub
call 0
i64.mul
end
end
end
end)
(module
module
module
module
(type
type
type
type $t0 (func
func
func
func (param
param
param
param i64) (result
result
result
result i64)))
(func
func
func
func $f0 (type
type
type
type $t0) (param
param
param
param $p0 i64) (result
result
result
result i64)
(if
if
if
if $I0 (result
result
result
result i64) ;; $I0 is unused
(i64.eqz
(local.get $p0)) ;; $p0 is same as 0
(then
then
then
then
(i64.const 1))
(else
else
else
else
(i64.mul
(local.get $p0)
(call $f0 ;; $f0 is same as 0
(i64.sub
(local.get $p0)
(i64.const 1))))))))
Stack machine
S-expression
84/204
C/C++ + WebAssembly
 WebAssembly in Web browsers
https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly
const
const
const
const supported = (() => {
try
try
try
try {
if
if
if
if (typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly === "object“ &&
typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly.instantiate === "function") {
const
const
const
const module = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module
Module
Module
Module(
Uint8Array
Uint8Array
Uint8Array
Uint8Array.of
of
of
of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if
if
if
if (module instanceof
instanceof
instanceof
instanceof WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module)
return
return
return
return new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance
Instance
Instance
Instance(module) instanceof
instanceof
instanceof
instanceof
WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance;
}
}
catch
catch
catch
catch (e) { }
return
return
return
return false;
})();
console.log
log
log
log(supported ?
"WebAssembly is supported" :
"WebAssembly is not supported");
85/204
C/C++ + WebAssembly
 WebAssembly in Web browsers
https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly
const
const
const
const supported = (() => {
try
try
try
try {
if
if
if
if (typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly === "object“ &&
typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly.instantiate === "function") {
const
const
const
const module = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module
Module
Module
Module(
Uint8Array
Uint8Array
Uint8Array
Uint8Array.of
of
of
of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if
if
if
if (module instanceof
instanceof
instanceof
instanceof WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module)
return
return
return
return new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance
Instance
Instance
Instance(module) instanceof
instanceof
instanceof
instanceof
WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance;
}
}
catch
catch
catch
catch (e) { }
return
return
return
return false;
})();
console.log
log
log
log(supported ?
"WebAssembly is supported" :
"WebAssembly is not supported");
Stateful, executable a
WebAssembly.Module
86/204
C/C++ + WebAssembly
 WebAssembly in Web browsers
https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly
const
const
const
const supported = (() => {
try
try
try
try {
if
if
if
if (typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly === "object“ &&
typeof
typeof
typeof
typeof WebAssembly
WebAssembly
WebAssembly
WebAssembly.instantiate === "function") {
const
const
const
const module = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module
Module
Module
Module(
Uint8Array
Uint8Array
Uint8Array
Uint8Array.of
of
of
of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00));
if
if
if
if (module instanceof
instanceof
instanceof
instanceof WebAssembly
WebAssembly
WebAssembly
WebAssembly.Module)
return
return
return
return new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance
Instance
Instance
Instance(module) instanceof
instanceof
instanceof
instanceof
WebAssembly
WebAssembly
WebAssembly
WebAssembly.Instance;
}
}
catch
catch
catch
catch (e) { }
return
return
return
return false;
})();
console.log
log
log
log(supported ?
"WebAssembly is supported" :
"WebAssembly is not supported");
Stateful, executable a
WebAssembly.Module
Smallest possible program
in WebAssembly: 0asm1
87/204
C/C++ + WebAssembly
 WebAssembly outside of Web browsers
– Enarx
– wasm3
– Wasmer
– WAMR
– Wasmtime
– WAVM
88/204
C/C++ + WebAssembly
 WebAssembly outside of Web browsers
– Enarx
– wasm3
– Wasmer
– WAMR
– Wasmtime
– WAVM
Embedder is the term for host
environments in which WASM
modules are executed
89/204
C/C++ + WebAssembly
 Longer example
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
90/204
C/C++ + WebAssembly
 Longer example
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
91/204
92/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
93/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
94/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(loop $L5
(if $I6
(i32.rem_u
(local.get $p0)
(local.get $l2))
(then
(br_if $L5
(i32.gt_s
(local.get $p0)
(i32.mul
(local.tee $l2
(i32.add
(local.get $l2)
(i32.const 1)))
(local.get $l2))))
(br $B1))))
(local.set $l1
(i32.const 0)))
(return
(local.get $l1))))
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
95/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(loop $L5
(if $I6
(i32.rem_u
(local.get $p0)
(local.get $l2))
(then
(br_if $L5
(i32.gt_s
(local.get $p0)
(i32.mul
(local.tee $l2
(i32.add
(local.get $l2)
(i32.const 1)))
(local.get $l2))))
(br $B1))))
(local.set $l1
(i32.const 0)))
(return
(local.get $l1))))
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
S-expression
96/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(loop $L5
(if $I6
(i32.rem_u
(local.get $p0)
(local.get $l2))
(then
(br_if $L5
(i32.gt_s
(local.get $p0)
(i32.mul
(local.tee $l2
(i32.add
(local.get $l2)
(i32.const 1)))
(local.get $l2))))
(br $B1))))
(local.set $l1
(i32.const 0)))
(return
(local.get $l1))))
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
Host environment
S-expression
97/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(loop $L5
(if $I6
(i32.rem_u
(local.get $p0)
(local.get $l2))
(then
(br_if $L5
(i32.gt_s
(local.get $p0)
(i32.mul
(local.tee $l2
(i32.add
(local.get $l2)
(i32.const 1)))
(local.get $l2))))
(br $B1))))
(local.set $l1
(i32.const 0)))
(return
(local.get $l1))))
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
Host environment
Export to host
S-expression
98/204
(module
(type $t0 (func (param i32 i32 i32 i32)))
(type $t1 (func))
(type $t2 (func (param i32) (result i32)))
(import "env" "__assert_fail" (func $env.__assert_fail (type $t0)))
(import "env" "__memory_base" (global $env.__memory_base i32))
(import "env" "memory" (memory $env.memory 1))
(func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1)
(nop))
(func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32)
(local $l1 i32) (local $l2 i32)
(if $I0
(i32.ge_s
(local.get $p0)
(i32.const 0))
(then
(block $B1
...
...
(loop $L5
(if $I6
(i32.rem_u
(local.get $p0)
(local.get $l2))
(then
(br_if $L5
(i32.gt_s
(local.get $p0)
(i32.mul
(local.tee $l2
(i32.add
(local.get $l2)
(i32.const 1)))
(local.get $l2))))
(br $B1))))
(local.set $l1
(i32.const 0)))
(return
(local.get $l1))))
...
...
(call $env.__assert_fail
(i32.add
(local.tee $p0
(global.get $env.__memory_base))
(i32.const 33))
(i32.add
(local.get $p0)
(i32.const 9))
(i32.const 11)
(local.get $p0))
(unreachable))
(data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
Host environment
Export to host
S-expression
Host function
99/204
C/C++ + WebAssembly
 Support
– C and C++: via Emscripten or Clang
– Rust: via rustc with Wasm target
– Go: native support introduced in v1.11
– .NET languages: C# and F# via Blazor
– Python: dedicated implementations, Pyodide
– Java and JVM languages: CheerpJ, TeaVM…
– …
– GraalWasm et al.
https://en.wikipedia.org/wiki/WebAssembly#Language_Support
100/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
#include
include
include
include <cstdlib>
#include
include
include
include <iostream>
#include
include
include
include "prime_calculator.h“
int main
main
main
main() {
std::cout << "Prime numbers between;
std::cout << "2 and 100:"
std::cout << std::endl;
for
for
for
for (int number = 2;
number <= 100; number++) {
if
if
if
if (is_prime(number)) {
std::cout << number << " ";
}
}
std::cout << std::endl;
}
101/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
#include
include
include
include <cstdlib>
#include
include
include
include <iostream>
#include
include
include
include "prime_calculator.h“
int main
main
main
main() {
std::cout << "Prime numbers between;
std::cout << "2 and 100:"
std::cout << std::endl;
for
for
for
for (int number = 2;
number <= 100; number++) {
if
if
if
if (is_prime(number)) {
std::cout << number << " ";
}
}
std::cout << std::endl;
}
102/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
103/204
C/C++ + WebAssembly
 Emscripten
CXX := emcc
INCLUDE_DIR := src
SRC_DIR := src
BUILD_DIR := build
all:
all:
all:
all: $(CXX) ${SRC_DIR}prime_calculator.cc
-o $(BUILD_DIR)prime_calculator.wasm
-I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1
clean:
clean:
clean:
clean: del /F /S /Q $(BUILD_DIR)
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
104/204
C/C++ + WebAssembly
 Emscripten
CXX := emcc
INCLUDE_DIR := src
SRC_DIR := src
BUILD_DIR := build
all:
all:
all:
all: $(CXX) ${SRC_DIR}prime_calculator.cc
-o $(BUILD_DIR)prime_calculator.wasm
-I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1
clean:
clean:
clean:
clean: del /F /S /Q $(BUILD_DIR)
WASM
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
105/204
C/C++ + WebAssembly
 Emscripten
CXX := emcc
INCLUDE_DIR := src
SRC_DIR := src
BUILD_DIR := build
all:
all:
all:
all: $(CXX) ${SRC_DIR}prime_calculator.cc
-o $(BUILD_DIR)prime_calculator.wasm
-I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1
clean:
clean:
clean:
clean: del /F /S /Q $(BUILD_DIR)
WASM
#include
include
include
include <cassert>
#include
include
include
include "prime_calculator.h“
int is_prime
is_prime
is_prime
is_prime(int number) {
if
if
if
if (number < 0) {
assert(0 && “Not a natural number");
}
else
else
else
else if
if
if
if (number == 1) {
return
return
return
return 0;
}
else
else
else
else if
if
if
if (number == 2) {
return
return
return
return 1;
}
else
else
else
else {
for
for
for
for (int i = 3; i * i < number; i++) {
if
if
if
if (number % i == 0) {
return
return
return
return 0;
}
}
return
return
return
return 1;
}
}
No main()
106/204
C/C++ + WebAssembly
 Emscripten
<!doctype html
html
html
html>
<html
html
html
html lang="en-ca">
<head
head
head
head>
<meta
meta
meta
meta charset="utf-8">
<meta
meta
meta
meta name="viewport" content="width=device-width, initial-scale=1.0">
<title
title
title
title>Emscripten Manual Example</title
title
title
title>
</head
head
head
head>
<body
body
body
body>
Prime calculator in WASM with Emscripten<br
br
br
br/>
See the Console for the output...
<script
script
script
script type="text/javascript" src="prime_calculator.js"/>
</body
body
body
body>
</html
html
html
html>
107/204
C/C++ + WebAssembly
 Emscripten
const
const
const
const memory = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Memory
Memory
Memory
Memory({ initial: 1, maximum: 10 });
const
const
const
const stack_pointer = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Global
Global
Global
Global({ value: "i32", mutable: true }, 0);
const
const
const
const importObject = {
env: {
memory: memory,
__memory_base: 0,
__table_base: 0,
__stack_pointer: stack_pointer,
__assert_fail: function
function
function
function(condition, filename, line, func) { },
}
}
WebAssembly
WebAssembly
WebAssembly
WebAssembly.instantiateStreaming
instantiateStreaming
instantiateStreaming
instantiateStreaming(fetch
fetch
fetch
fetch("build/prime_calculator.wasm"), importObject)
.then
then
then
then(result => {
for
for
for
for (let
let
let
let i = 2; i <= 100; i++) {
if
if
if
if (result.instance.exports.is_prime
is_prime
is_prime
is_prime(i) == 1) {
console.log
log
log
log(i.toString
toString
toString
toString());
}
}
});
108/204
C/C++ + WebAssembly
 Emscripten
const
const
const
const memory = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Memory
Memory
Memory
Memory({ initial: 1, maximum: 10 });
const
const
const
const stack_pointer = new
new
new
new WebAssembly
WebAssembly
WebAssembly
WebAssembly.Global
Global
Global
Global({ value: "i32", mutable: true }, 0);
const
const
const
const importObject = {
env: {
memory: memory,
__memory_base: 0,
__table_base: 0,
__stack_pointer: stack_pointer,
__assert_fail: function
function
function
function(condition, filename, line, func) { },
}
}
WebAssembly
WebAssembly
WebAssembly
WebAssembly.instantiateStreaming
instantiateStreaming
instantiateStreaming
instantiateStreaming(fetch
fetch
fetch
fetch("build/prime_calculator.wasm"), importObject)
.then
then
then
then(result => {
for
for
for
for (let
let
let
let i = 2; i <= 100; i++) {
if
if
if
if (result.instance.exports.is_prime
is_prime
is_prime
is_prime(i) == 1) {
console.log
log
log
log(i.toString
toString
toString
toString());
}
}
});
Host environment
109/204
C/C++ + WebAssembly
 Emscripten
110/204
C/C++ + WebAssembly
 Emscripten
emrun prime_calculator.html
111/204
C/C++ + WebAssembly
 Emscripten
emrun prime_calculator.html
112/204
C/C++ + WebAssembly
 WebAssembly System Interface (WASI)
– Version 2
• wasi-io
• wasi-clocks
• wasi-random
• wasi-filesystem
• wasi-sockets
• wasi-cli
• wasi-http
https://atamel.dev/posts/2023/06-20_explore_wasm_outside_browser/
113/204
C/C++ + WebAssembly
 WebAssembly System Interface (WASI)
– Version 2
• wasi-io
• wasi-clocks
• wasi-random
• wasi-filesystem
• wasi-sockets
• wasi-cli
• wasi-http
https://atamel.dev/posts/2023/06-20_explore_wasm_outside_browser/
114/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <stdio.h>
#include
include
include
include <stdlib.h>
#include
include
include
include <string.h>
#include
include
include
include <errno.h>
int main
main
main
main() {
printf("Writing a filen");
FILE *fp; fp = fopen("hello.txt", "w");
if
if
if
if (NULL == fp) {
fprintf(
stderr,
"Error opening file: %sn",
strerror(errno));
exit(1);
}
fputs("Hello, world!n", fp);
fclose(fp);
return
return
return
return 0;
}
https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9
115/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <stdio.h>
#include
include
include
include <stdlib.h>
#include
include
include
include <string.h>
#include
include
include
include <errno.h>
int main
main
main
main() {
printf("Writing a filen");
FILE *fp; fp = fopen("hello.txt", "w");
if
if
if
if (NULL == fp) {
fprintf(
stderr,
"Error opening file: %sn",
strerror(errno));
exit(1);
}
fputs("Hello, world!n", fp);
fclose(fp);
return
return
return
return 0;
}
https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9
POSIX function
116/204
C/C++ + WebAssembly
 Emscripten
#include
include
include
include <stdio.h>
#include
include
include
include <stdlib.h>
#include
include
include
include <string.h>
#include
include
include
include <errno.h>
int main
main
main
main() {
printf("Writing a filen");
FILE *fp; fp = fopen("hello.txt", "w");
if
if
if
if (NULL == fp) {
fprintf(
stderr,
"Error opening file: %sn",
strerror(errno));
exit(1);
}
fputs("Hello, world!n", fp);
fclose(fp);
return
return
return
return 0;
}
https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9
POSIX function
117/204
C/C++ + WebAssembly
 Emscripten
https://github.com/emscripten-core/emscripten/issues/12094
118/204
C/C++ + WebAssembly
 Emscripten
“POSIX provides source code portability. You can
compile the same source code with different
versions of libc to target different machines. But
WebAssembly needs to go one step beyond this.
We need to be able to compile once and run
across a whole bunch of different machines. We
need portable binaries.”
— Lin Clark
https://danielmangum.com/posts/wasm-wasi-clang-17/
119/204
C/C++ + WebAssembly
 Emscripten
“POSIX provides source code portability. You can
compile the same source code with different
versions of libc to target different machines. But
WebAssembly needs to go one step beyond this.
We need to be able to compile once and run
across a whole bunch of different machines. We
need portable binaries.”
— Lin Clark
https://danielmangum.com/posts/wasm-wasi-clang-17/
120/204
C/C++ + WebAssembly
 Emscripten
https://github.com/WebAssembly/wasi-libc
121/204
C/C++ + WebAssembly
https://blog.stackademic.com/write-once-run-everywhere-still-a-joke-in-2025-bd273d0e3224?gi=24ef682243ac
122/204
C/C++ + WebAssembly
https://adriancitu.com/2024/01/15/introduction-to-web-assembly-for-java-engineers/
123/204
Java Bytecode vs. WASM
 Polyglot compilation target
– Not Java
– WASM!
 Just stack-based languages
– Java bytecode is unstructured (goto )
– WASM is structured, with nested operations
• Scheme
• But no exceptions!
 Memory Management
– Java hides stack vs. heap allocations, with GC
– WASM sees a linear memory, must implement GC (!)
• Object layouts in memory
https://www.javaadvent.com/2022/12/webassembly-for-the-java-geek.html
124/204
Java Bytecode vs. WASM
 Lessons learned from Java bytecode and Applets,
WebAssembly was designed
– To have rapid compilation times with very simple
validation rules compared to Java
– With the concept of a host environment, i.e., the browser
– To be secure and simple, minimising the attack surface
– To support many languages (C, C++, Rust, ...), whereas
the JVM was initially designed for a single language
https://stackoverflow.com/questions/58131892/why-the-jvm-cannot-be-used-in-place-of-webassembly
125/204
C/C++ + WebAssembly
 Limitations
– No direct manipulation of the DOM
– Limited WebAssembly System Interface (WASI)
– Limited debugging support
– Limited integration with JavaScript
– Inconsistent integration with browser APIs
– Complex and inconsistent build tools
126/204
C/C++ + WebAssembly
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
127/204
C/C++ + WebAssembly
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
128/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
129/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
130/204
https://www.javaadvent.com/2022/12/webassembly-for-the-java-geek.html
131/204
TeaVM
 “[A]n ahead-of-time compiler for Java bytecode
that emits JavaScript and WebAssembly”
– You are a Java developer, and you are going to write a
web front-end from scratch
– You already have a Java-based backend and want to
integrate front-end code tightly
– You have some Java back-end code you want to reuse
in the front end
– You are ready to rewrite your code for TeaVM
https://teavm.org/docs/intro/overview.html
132/204
TeaVM
 “[A]n ahead-of-time compiler for Java bytecode
that emits JavaScript and WebAssembly”
– You are a Java developer, and you are going to write a
web front-end from scratch
– You already have a Java-based backend and want to
integrate front-end code tightly
– You have some Java back-end code you want to reuse
in the front end
– You are ready to rewrite your code for TeaVM
https://teavm.org/docs/intro/overview.html
133/204
TeaVM
 Inspired by Google Web Toolkit (GWT)
– GWT takes source code, limited to Java only
– TeaVM relies on existing compilers, such as
javac, kotlinc, and scalac
134/204
TeaVM
 Features
– Ahead-of-time compiler
of Java bytecode to
JavaScript code
– Original structure of a
method, so in most
cases it produces
“natural” JavaScript
– Green threads
– Optimisations
• Dead code
• Devirtualisation
• Local variables reuse
• Method renaming
– Java JavaScript
interoperability API
– Source maps
• Debugging
135/204
TeaVM
Example
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
136/204
TeaVM
Example
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
137/204
TeaVM
Example
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
138/204
TeaVM
Example
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
139/204
TeaVM
Example
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
140/204
TeaVM
Transpiled JavaScript
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
let Bl = (a, b) => BigInt.asIntN(64, a + b);
let CZ = (b, c) => {
let d, e, $$je;
// ...
a: {
try {
e = Bl(BE(L(c.value)), BE(L(d.value)));
c = S();
Cx(H(c, F(3)), e);
b.textContent = Bv(R(c));
break a;
}
catch ($$e) {
$$je = CB($$e);
if ($$je instanceof I) {
}
else {
throw $$e;
}
}
c = "Invalid numbers";
b.textContent = c;
}
};
141/204
TeaVM
Transpiled JavaScript
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
let Bl = (a, b) => BigInt.asIntN(64, a + b);
let CZ = (b, c) => {
let d, e, $$je;
// ...
a: {
try {
e = Bl(BE(L(c.value)), BE(L(d.value)));
c = S();
Cx(H(c, F(3)), e);
b.textContent = Bv(R(c));
break a;
}
catch ($$e) {
$$je = CB($$e);
if ($$je instanceof I) {
}
else {
throw $$e;
}
}
c = "Invalid numbers";
b.textContent = c;
}
};
142/204
TeaVM
Transpiled JavaScript
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
let Bl = (a, b) => BigInt.asIntN(64, a + b);
let CZ = (b, c) => {
let d, e, $$je;
// ...
a: {
try {
e = Bl(BE(L(c.value)), BE(L(d.value)));
c = S();
Cx(H(c, F(3)), e);
b.textContent = Bv(R(c));
break a;
}
catch ($$e) {
$$je = CB($$e);
if ($$je instanceof I) {
}
else {
throw $$e;
}
}
c = "Invalid numbers";
b.textContent = c;
}
};
143/204
TeaVM
Transpiled JavaScript
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
let Bl = (a, b) => BigInt.asIntN(64, a + b);
let CZ = (b, c) => {
let d, e, $$je;
// ...
a: {
try {
e = Bl(BE(L(c.value)), BE(L(d.value)));
c = S();
Cx(H(c, F(3)), e);
b.textContent = Bv(R(c));
break a;
}
catch ($$e) {
$$je = CB($$e);
if ($$je instanceof I) {
}
else {
throw $$e;
}
}
c = "Invalid numbers";
b.textContent = c;
}
};
144/204
TeaVM
Transpiled JavaScript
final HTMLDocument document = HTMLDocument.current();
final HTMLElement h1 = document.createElement("h1");
h1.appendChild(document.createTextNode("TeaVM Example"));
document.getBody().appendChild(h1);
final HTMLElement div = document.createElement("div");
div.setAttribute("id", "calculator-container");
document.getBody().appendChild(div);
final HTMLElement container = document.
getElementById("calculator-container");
final HTMLInputElement input1 = (HTMLInputElement)
document.createElement("input");
input1.setType("number");
container.appendChild(input1);
final HTMLInputElement input2 = (HTMLInputElement)
document.createElement("input");
input2.setType("number");
container.appendChild(input2);
final HTMLButtonElement button = (HTMLButtonElement)
document.createElement("button");
button.appendChild(document.createTextNode("Sum"));
container.appendChild(button);
final HTMLElement resultDiv =
document.createElement("div");
container.appendChild(resultDiv);
button.addEventListener("click", (evt) -> {
try {
final long num1 = Long.parseLong(
input1.getValue());
final long num2 = Long.parseLong(
input2.getValue());
final long sum = num1 + num2;
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.setTextContent("Invalid numbers");
}
});
let Bl = (a, b) => BigInt.asIntN(64, a + b);
let CZ = (b, c) => {
let d, e, $$je;
// ...
a: {
try {
e = Bl(BE(L(c.value)), BE(L(d.value)));
c = S();
Cx(H(c, F(3)), e);
b.textContent = Bv(R(c));
break a;
}
catch ($$e) {
$$je = CB($$e);
if ($$je instanceof I) {
}
else {
throw $$e;
}
}
c = "Invalid numbers";
b.textContent = c;
}
};
“Natural” JavaScript
145/204
TeaVM
@JSExport HTML/JavaScript
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int sum = Client.sum(num1, num2);
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent(“Invalid numbers");
}
});
// ...
@JSExport
public static int sum(
final int l1, final int l2) {
return l1 + l2;
}
<head>
<script type="text/javascript“
src="classes.js"></script>
<script type="text/javascript">
document.
addEventListener('DOMContentLoaded',
function() {
let result = sum(51, 72);
console.log("Sum result: " + result);
main();
});
</script>
</head>
<body>
</body>
146/204
TeaVM
@JSExport HTML/JavaScript
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int sum = Client.sum(num1, num2);
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent(“Invalid numbers");
}
});
// ...
@JSExport
public static int sum(
final int l1, final int l2) {
return l1 + l2;
}
<head>
<script type="text/javascript“
src="classes.js"></script>
<script type="text/javascript">
document.
addEventListener('DOMContentLoaded',
function() {
let result = sum(51, 72);
console.log("Sum result: " + result);
main();
});
</script>
</head>
<body>
</body>
147/204
TeaVM
@JSExport HTML/JavaScript
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int sum = Client.sum(num1, num2);
resultDiv.setTextContent("Result: " + sum);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent(“Invalid numbers");
}
});
// ...
@JSExport
public static int sum(
final int l1, final int l2) {
return l1 + l2;
}
<head>
<script type="text/javascript“
src="classes.js"></script>
<script type="text/javascript">
document.
addEventListener('DOMContentLoaded',
function() {
let result = sum(51, 72);
console.log("Sum result: " + result);
main();
});
</script>
</head>
<body>
</body>
148/204
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int mul = Client.mul(num1, num2);
resultDiv.setTextContent("Result: " + mul);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent("Invalid numbers");
}
});
// ...
@JSBody(params = { "v1", "v2" },
script = "return v1 * v2;")
public static native int mul(
final int l1, final int l2);
TeaVM
@JSBody HTML/JavaScript
export function foo() {
console.log("foo called");
}
@JSBody(
script = "return testModule.foo();",
imports = @JSBodyImport(
alias = "testModule",
fromModule = "testModule.js"))
149/204
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int mul = Client.mul(num1, num2);
resultDiv.setTextContent("Result: " + mul);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent("Invalid numbers");
}
});
// ...
@JSBody(params = { "v1", "v2" },
script = "return v1 * v2;")
public static native int mul(
final int l1, final int l2);
TeaVM
@JSBody HTML/JavaScript
export function foo() {
console.log("foo called");
}
@JSBody(
script = "return testModule.foo();",
imports = @JSBodyImport(
alias = "testModule",
fromModule = "testModule.js"))
150/204
// Add click event listener to the button
button.onClick((evt) -> {
try {
final int num1 =
Integer.parseInt(input1.getValue());
final int num2 =
Integer.parseInt(input2.getValue());
final int mul = Client.mul(num1, num2);
resultDiv.setTextContent("Result: " + mul);
}
catch (final NumberFormatException e) {
resultDiv.
setTextContent("Invalid numbers");
}
});
// ...
@JSBody(params = { "v1", "v2" },
script = "return v1 * v2;")
public static native int mul(
final int l1, final int l2);
TeaVM
@JSBody HTML/JavaScript
export function foo() {
console.log("foo called");
}
@JSBody(
script = "return testModule.foo();",
imports = @JSBodyImport(
alias = "testModule",
fromModule = "testModule.js"))
151/204
TeaVM
 Coroutines to emulate Threads together with
a few simple synchronisation primitives
 No support for reflection
– Would increase complexity, size
– Would prevent optimisations
– But metaprogramming API
152/204
TeaVM
 Coroutines to emulate Threads together with
a few simple synchronisation primitives
 No support for reflection
– Would increase complexity, size
– Would prevent optimisations
– But metaprogramming API
Not all tested!
153/204
TeaVM
 Metaprogramming API
public class Client {
public static Object getFoo(final Object obj) {
return Client.getFooImpl(obj.getClass(), obj);
}
@Meta
private static native Object getFooImpl(final Class<?> cls, final Object obj);
private static void getFooImpl(final ReflectClass<Object> cls, final Value<Object> obj) {
final ReflectField field = cls.getField("foo");
if (field != null) {
Metaprogramming.exit(() -> field.get(obj));
}
else {
Metaprogramming.exit(() -> null);
}
}
public static void main(final String[] args) {
// ...
resultDiv.setTextContent(
"Client.getFoo(new A("")): " + Client.getFoo(new A("")) +
"<br>Client.getFoo(new B()): " + Client.getFoo(new B()));
}
}
Doesn’t compile
154/204
TeaVM
 Java/JavaScript Objects (JSO) library
– Overlay types
– Properties mapping
– Constructors mapping
– Extension methods
– Static methods
– Indexer wrappers
Not all tested!
155/204
TeaVM
 Java/JavaScript Objects (JSO) library
– Passing Java objects to JavaScript
– Passing Java objects as functions
– Passing Java arrays without copying
– Passing NIO buffers to JavaScript
– Defining top-level functions and properties
– Importing declarations from a module
Not all tested!
156/204
TeaVM
 Limitations
– TeaVM must know how
to transpile every
method of every class of
the Java Class Library
• Based on Apache
Harmony of 2011 (!?)
– AWT (?)
– Reflection
https://teavm.org/jcl-report/recent/jcl.html
157/204
TeaVM
 Limitations
– Implementation
– Documentation
– No WASM?
158/204
TeaVM
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java but without JavaScript…
159/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
160/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
161/204
TeaVM + WASI
 Fermyon Technologies, Inc.
– https://developer.fermyon.com/wasm-
languages/java
– https://github.com/fermyon
 Friendly fork of TeaVM to support WASI
and the WebAssembly Component Model
162/204
TeaVM + WASI
Java WASM
 WASM 190 KB
 WAT 47 KLOC
package wasi;
public class Fibonacci {
public static void main(final String[] args) {
final int n = Integer.parseInt(args[0]);
System.out.println(Fibonacci.fib(n));
}
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Fibonacci.fib(n - 1) +
Fibonacci.fib(n - 2);
}
}
(func $__start__ (type $t2)
(call $initclass_otbw_WasmHeap)
(call $meth_otbw_WasmHeap_initHeap
(i32.const 102820)
(i32.const 4194304)
(i32.const 134217728)
(i32.const 262144))
(call $initclass_otr_GC)
(call $initclass_otr_EventQueue)
(call $initclass_otr_Fiber))
(func $teavm_start
(export "_start") (type $t2)
(call $meth_otr_WasiMain_startMain))
GC
Events
“Threads”
163/204
(Fibers and Enarx)
 Fibers
– Cooperatively scheduled, user-space green
threads / stackful coroutines
 Enarx
– Trusted Execution Environments (TEE)
– Run-time TEE based on WebAssembly
• Uses wasmtime as a runtime
enarx run --wasmcfgfile Fibonacci.enarx.toml
target/generated/wasm/teavm-wasm/classes.wasm
https://blog.enarx.dev/language-support-for-wasi-2/
164/204
TeaVM + WASI
Java
(func $meth_w_Fibonacci_main
(type $t0) (param $p0 i32)
...
(block $B0 (local.set $l5
(call $meth_otbw_WasmRuntime_allocStack
(i32.const 1)))
...
(i32.store offset=4
(local.get $l5) (local.get $l2))
(i32.store
(local.get $l5) (i32.const 495))
(local.set $l3
(call $meth_jl_Integer_parseInt_0
(local.get $l2)))
(if $I3
(i32.eq
(i32.load (local.get $l5))
(i32.const 495))
(then (i32.store offset=4
(local.get $l5) (i32.const 0))
(i32.store (local.get $l5)
(i32.const 496))
(local.set $l2
(call $meth_jl_System_out))
(if $I4
(i32.eq
(i32.load (local.get $l5))
(i32.const 496))
(then (i32.store offset=4
(local.get $l5)
(local.get $l2))
(i32.store (local.get $l5)
(i32.const 497))
(local.set $l4
(call $meth_w_Fibonacci_fib
(local.get $l3)))
...
package wasi;
public class Fibonacci {
public static void main(final String[] args) {
final int n = Integer.parseInt(args[0]);
System.out.println(Fibonacci.fib(n));
}
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Fibonacci.fib(n - 1) +
Fibonacci.fib(n - 2);
}
}
165/204
TeaVM + WASI
Java
package wasi;
public class Fibonacci {
public static void main(final String[] args) {
final int n = Integer.parseInt(args[0]);
System.out.println(Fibonacci.fib(n));
}
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Fibonacci.fib(n - 1) +
Fibonacci.fib(n - 2);
}
}
(func $meth_w_Fibonacci_fib
...
(call $meth_otbw_WasmRuntime_allocStack
(i32.const 0)))
(block $B1
...
(then
(local.set $l1
(i32.sub
sub
sub
sub
(local.get $p0)
(i32.const 1)))
(i32.store
(local.get $l3)
(i32.const 501))
(local.set $l2
(call $meth_w_Fibonacci_fib
(local.get $l1)))
(if $I3
(i32.eq
(i32.load
(local.get $l3))
(i32.const 501))
(then
(local.set $l1
(i32.sub
sub
sub
sub
(local.get $p0)
(i32.const 2)))
(i32.store
(local.get $l3)
(i32.const 502))
(local.set $l1
(call $meth_w_Fibonacci_fib
(local.get $l1)))
...
(return (local.get $p0))))
166/204
TeaVM + WASI
Java WASM
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
167/204
TeaVM + WASI
Java WASM
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
168/204
TeaVM + WASI
Java WASM
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
[INFO
INFO
INFO
INFO] Running TeaVM
[INFO
INFO
INFO
INFO] Output file built with errors
[INFO
INFO
INFO
INFO] Classes compiled: 121
[INFO
INFO
INFO
INFO] Methods compiled: 1166
[ERROR
ERROR
ERROR
ERROR] Class java.awt.Frame was not found
at wasi.AWT.main(AWT.java:18)
[ERROR
ERROR
ERROR
ERROR] Class ....WindowAdapter was not found
at wasi.AWT$1.<init>(AWT.java:25)
at wasi.AWT.main(AWT.java:25)
169/204
TeaVM + WASI
Java WASM
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
[INFO
INFO
INFO
INFO] Running TeaVM
[INFO
INFO
INFO
INFO] Output file built with errors
[INFO
INFO
INFO
INFO] Classes compiled: 121
[INFO
INFO
INFO
INFO] Methods compiled: 1166
[ERROR
ERROR
ERROR
ERROR] Class java.awt.Frame was not found
at wasi.AWT.main(AWT.java:18)
[ERROR
ERROR
ERROR
ERROR] Class ....WindowAdapter was not found
at wasi.AWT$1.<init>(AWT.java:25)
at wasi.AWT.main(AWT.java:25)
No GUI
170/204
TeaVM + WASI
Java WASM
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
171/204
TeaVM + WASI
Java WASM
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
55
172/204
TeaVM + WASI
Java WASM
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
55
[INFO
INFO
INFO
INFO] Running TeaVM
[INFO
INFO
INFO
INFO] Output file built with errors
[INFO
INFO
INFO
INFO] Classes compiled: 147
[INFO
INFO
INFO
INFO] Methods compiled: 1351
[ERROR
ERROR
ERROR
ERROR] Method
org.teavm.classlib.impl.reflection.Converter
.toJava(Lorg/teavm/platform/PlatformObject;)
Ljava/lang/Object; is native but has no
org.teavm.interop.Import annotation on it
...
[ERROR
ERROR
ERROR
ERROR] Method
org.teavm.classlib.impl.reflection.Converter
.arrayFromJava([Ljava/lang/Object;)Lorg/teav
m/platform/PlatformSequence; is native but
has no org.teavm.interop.Import annotation
on it
...
173/204
TeaVM + WASI
Java WASM
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
55
[INFO
INFO
INFO
INFO] Running TeaVM
[INFO
INFO
INFO
INFO] Output file built with errors
[INFO
INFO
INFO
INFO] Classes compiled: 147
[INFO
INFO
INFO
INFO] Methods compiled: 1351
[ERROR
ERROR
ERROR
ERROR] Method
org.teavm.classlib.impl.reflection.Converter
.toJava(Lorg/teavm/platform/PlatformObject;)
Ljava/lang/Object; is native but has no
org.teavm.interop.Import annotation on it
...
[ERROR
ERROR
ERROR
ERROR] Method
org.teavm.classlib.impl.reflection.Converter
.arrayFromJava([Ljava/lang/Object;)Lorg/teav
m/platform/PlatformSequence; is native but
has no org.teavm.interop.Import annotation
on it
...
Incomplete
implementation?
174/204
TeaVM + WASI
 Limitations
– Same as TeaVM?
• Must know how to transpile every method of every
class of the Java Class Library
– Based on Apache Harmony of 2011 (?)
• AWT
• Reflection
• Implementation
• Documentation
175/204
TeaVM + WASI
 Still a concern
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java but without JavaScript…
176/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
177/204
Opportunities and Challenges
Problem: Run the exact same programs on
widely different hardware and OSs
Solution: Running code in the Web browsers
178/204
CheerpJ
 Leaning Technologies Inc.
– “CheerpJ is a JVM and a distribution of
OpenJDK for the browser in WebAssembly
and JavaScript”
– Java 17 (preview), 11, 8…
– Swing, AWT, and most frameworks
– Fully within the browser sandbox
– Clipboard, networking, files, native methods
https://cheerpj.com/
179/204
CheerpJ
 2018: Java 8
 2025: Java 11
 2025: Java 17
 2026: Java 21
 2027: Java 26
– LTS parity
180/204
CheerpJ
181/204
CheerpJ
Java (cf. TeaVM) CheerpJ
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
182/204
CheerpJ
Java (cf. TeaVM) CheerpJ
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
183/204
CheerpJ
Java (cf. TeaVM) CheerpJ
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
184/204
CheerpJ
Java (cf. TeaVM) CheerpJ
public static void main(final String[] args) {
final int n;
if (args.length == 0) {
n = 10;
}
else {
n = Integer.parseInt(args[0]);
}
final Frame frame = new Frame("Fibonacci");
final Label label = new Label(
"F(" + n + ") = " + fib(n));
label.setAlignment(Label.CENTER);
frame.add(label);
frame.setSize(300, 300);
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(
final WindowEvent e) {
System.exit(0);
}
});
}
GUI!
185/204
CheerpJ
Java CheerpJ
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
186/204
CheerpJ
Java CheerpJ
55
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
187/204
CheerpJ
Java CheerpJ
55
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
188/204
CheerpJ
Java CheerpJ
55
public class Reflection {
public static void main(final String[] args)
throws ... {
final int n = Integer.parseInt(args[0]);
final Class<?> thisClass =
Class.forName("wasi.Reflection");
final Method fibMethod =
thisClass.getDeclaredMethod(
"fib", int.class);
System.out.println(
fibMethod.invoke(null, n));
}
@SuppressWarnings("unused")
private static int fib(final int n) {
if (n <= 1) {
return n;
}
return Reflection.fib(n - 1) +
Reflection.fib(n - 2);
}
}
Reflection
Console
189/204
CheerpJ
 WebAssembly-based Java Virtual Machine
– Works directly with Java byte code/JARs
– Uses Cheerp
• C and C++ compiler to WebAssembly and JavaScript
to run in the browser or Node.js
• Compiled full Java SE 8, 11 and 17 runtimes, based
on OpenJDK
– Provides interpreter + JIT compiler to JavaScript
• Inline and devirtualise calls
https://cheerpj.com/docs/explanation/architecture
190/204
CheerpJ
 Virtual window manager
– AWT/Swing to a hierarchy of HTML5 elements
 Virtual file system
– Server-hosted files and persistent local storage
 Networking support
– fetch() for same-origin HTTP/HTTPS requests
– Tailscale for general networking
• VPN technology using WebSocket as transport layer
191/204
CheerpJ
 Notes
– Like super Java Applets
• But can manipulate the DOM?
– VM rather than transpiler
• No (little?) change to the Java code
• No access to JavaScript / WASM?
• Performance?
• Compatibility?
192/204
CheerpJ
 Not a concern anymore
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
193/204
CONCLUSION
194/204
Conclusion
 Computers
– Capability
• Proving needed xPU, RAM, screen resolutions
– Availability
• Providing computers where and when needed
– Diversity
• Providing many different features, i.e., software
– Affordability
• Having cheap hardware and software
195/204
Conclusion
 What to do with the billions of lines of
already code written in other programming
languages?
196/204
Conclusion
 Write Once, Run Anywhere
https://blog.stackademic.com/write-once-run-everywhere-still-a-joke-in-2025-bd273d0e3224
197/204
Conclusion
 Not a concern anymore
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
198/204
Conclusion
 Not a concern anymore
– What to do with the billions of lines of already
code written in other programming languages?
• C/C++, Java…
Emscripten
TeaVM (+ WASM)
CheerpJ
199/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs
200/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs
201/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs
202/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs
203/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs
204/204
Conclusion
 Rewrite
 Framework
 Compile or
 Transpile
 VMs

WASM or Realising the Dream of Write Once, Run Anywhere?

  • 1.
    Yann-Gaël Guéhéneuc (/jan/, he/il) Worklicensed under Creative Commons BY-NC-SA 4.0 International WASM or Realising the Dream of Write Once, Run Anywhere? Version 0.7 25/09/24
  • 2.
    2/204 Outline  History  Problemand Solutions – HTML + JavaScript + CSS – Java Applets – C/C++ + WebAssembly – TeaVM – TeaVM + WASI – CheerpJ  Conclusion
  • 3.
  • 4.
    4/204 Computing Constraints  Sincethe advent of computers, multiple forces shaped computing – Capability • Proving needed xPU, RAM, screen resolutions – Availability • Providing computers where and when needed – Diversity • Providing many different features, i.e., software – Affordability • Having cheap hardware and software
  • 5.
    5/204 Pre-history of Computers ca.205 BCE, https://en.wikipedia.org/wiki/Antikythera_mechanism ca. 1620, https://en.wikipedia.org/wiki/Slide_rule
  • 6.
    6/204 Pre-history of ProgrammableComputers 1804, https://ageofrevolution.org/200-object/jacquard-loom/ 1837, https://en.wikipedia.org/wiki/Analytical_engine
  • 7.
    7/204 First Programmable Computers 1943,https://en.wikipedia.org/wiki/Z3_(computer) 1943, https://en.wikipedia.org/wiki/Colossus_computer
  • 8.
    8/204 First Computers  Capability█  Availability █  Diversity █  Affordability ~$84.106* 1948, https://en.wikipedia.org/wiki/Manchester_Baby * All prices for 2025, adjusted for inflation
  • 9.
    9/204 First Computers  Capability█  Availability █  Diversity █  Affordability ~$8.106 1949–1958, https://en.wikipedia.org/wiki/EDSAC
  • 10.
  • 11.
    11/204 First GUI Computers Capability ██  Availability █  Diversity █  Affordability ~$76,780 1970s–1990s, https://en.wikipedia.org/wiki/PERQ
  • 12.
    12/204 First Popular Computers Capability ██  Availability ██  Diversity ██  Affordability ~$5,500 1981–1987, https://en.wikipedia.org/wiki/IBM_Personal_Computer
  • 13.
    13/204 First Popular Computers Capability ██  Availability ████  Diversity ███  Affordability ~$1,990 1982–1994, https://en.wikipedia.org/wiki/Commodore_64
  • 14.
    14/204 First Popular Computers Capability ██  Availability ███  Diversity ███  Affordability ~$7,750 1984–1985, https://en.wikipedia.org/wiki/Macintosh_128K
  • 15.
    15/204 First Popular GUIComputers  Capability ███  Availability ███  Diversity ███  Affordability ~$1,987 1985–1998, https://en.wikipedia.org/wiki/Amiga
  • 16.
    16/204 The OSs Takeover Capability ████  Availability ███  Diversity ███  Affordability ~$5,000 ca. 1992, https://en.wikipedia.org/wiki/Windows_3.1 and https://www.reddit.com/r/retrobattlestations/comments/10cr6ko/ windows_311_with_tabworks/#lightbox
  • 17.
    17/204 The OSs Takeover Capability █████  Availability ████  Diversity ████  Affordability ~$30,000 ca. 1996, https://en.wikipedia.org/wiki/Windows_95 and https://www.reddit.com/r/VintageComputers/comments/1mimbzj/ i_restored_this_dell_dimension_m233a_from_1997_i/#lightbox
  • 18.
    18/204 The OSs Takeover Capability █████  Availability ███  Diversity ███  Affordability ~$7,730 1998–2002, https://www.reddit.com/r/unixporn/comments/8a1k6m/ sun_ultra_5_cool_sun_workstation_with_a_boxed/
  • 19.
    19/204 The OSs Takeover Capability █████  Availability ██  Diversity ██  Affordability ~$3,000 ca. 1995, https://www.reddit.com/r/linuxmasterrace/comments/xwvbsv/pulled_out_the_pentium_133_today/#lightbox
  • 20.
    20/204 The OSs Takeover(Almost)  Capability ███  Availability ██  Diversity ███  Affordability ~$4,120 ca. 1996, https://meiobit.com/413250/power-macintosh-610066-o- curioso-caso-do-frankenstein-da-apple/
  • 21.
  • 22.
  • 23.
  • 24.
    24/204 Computers in the1990s  Main branches – Apple computers – Super computers – “Wintel” computers – Other independents – Joker: Linux!  Killer Apps – Office suites – Publishing – Art creation • Graphics • Audio • Videos – Joker: Games
  • 25.
    25/204 Computers in the1990s  Main branches – Apple computers – Super computers – “Wintel” computers – Other independents  Killer Apps – Office suites – Publishing – Art creation • Graphics • Audio • Videos
  • 26.
    26/204 Computers in the1990s  Main branches – Apple computers – Super computers – “Wintel” computers – Other independents – Joker: Linux!  Killer Apps – Office suites – Publishing – Art creation • Graphics • Audio • Videos – Joker: Games
  • 27.
    27/204 Opportunities and Challenges Opportunities – Cheaper hardware – Fewer, better OSs – The Internet  Challenges – Computers-specific killer applications – Still a wide of hardware and software
  • 28.
    28/204 Opportunities and Challenges Opportunities – Cheaper hardware – Fewer, better OSs – The Internet  Challenges – Computers-specific killer applications – Still a wide of hardware and software
  • 29.
  • 30.
    30/204 Opportunities and Challenges Capability – Proving needed xPU, RAM, screen resolutions  Availability – Providing computers where and when needed  Diversity – Providing many different features, i.e., software  Affordability – Having cheap hardware and software
  • 31.
  • 32.
    32/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 33.
    33/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 34.
    34/204 HTML + JavaScript+ CSS  In every (major) browser – In 1995, the first interpreter by Brendan Eich for Netscape Navigator was LiveScript • Became SpiderMonkey in Mozilla Firefox – With Trace-, Jäger-, Ion-, and OdinMonkey… for debugging, JIT compilation, optimisations
  • 35.
    35/204 HTML + JavaScript+ CSS  In every (major) browser (cont’d) – In 2008, V8 in Google Chrome • In 2009, used for Node.js • In 2013, used for Electron – In 2008, Nitro in Apple Safari – In 2010, Carakan in Opera – In 2011, Chakra in Microsoft Internet Explorer
  • 36.
    36/204 HTML + JavaScript+ CSS  More than interpreters, engines! – Optimisers – JIT compilers – Host APIs – ...
  • 37.
    37/204 HTML + JavaScript+ CSS  Target for other programming languages – In 2010, Emscripten to transpile C/C++  Specific optimisations – In 2013, asm.js with OdinMonkey, Mozilla Firefox • Efficient native code ahead-of-time for the JIT  Optimised bytecodes – In 2017, asm.js, NaCl became WebAssembly
  • 38.
    38/204 HTML + JavaScript+ CSS  Target for other programming languages – In 2010, Emscripten to transpile C/C++  Specific optimisations – In 2013, asm.js with OdinMonkey, Mozilla Firefox • Efficient native code ahead-of-time for the JIT  Optimised bytecodes – In 2017, asm.js, NaCl became WebAssembly
  • 39.
    39/204 HTML + JavaScript+ CSS  Available in Web browsers  Access to the DOM  Popular
  • 40.
    40/204 HTML + JavaScript+ CSS  Limitations – Performance – Complexity – Design – Typing – Ecosystem https://blog.bitsrc.io/5-fundamental-limits-in-javascript-every-developer-should-know-11b507f7a7dc https://dev.to/malikhaziq/the-limitations-of-javascript-as-a-programming-language-2fd7 https://www.geeksforgeeks.org/javascript/advantages-and-disadvantages-of-javascript/
  • 41.
    41/204 HTML + JavaScript+ CSS  Limitations – Performance David Lion, Adrian Chiu, Michael Stumm, Ding Yuan ; Investigating Managed Language Runtime Performance: Why JavaScript and Python are 8x and 29x Slower than C++, Yet Java and Go Can Be Faster? ; USENIX Annual Technical Conference, 2022
  • 42.
    42/204 HTML + JavaScript+ CSS  Limitations – Complexity https://github.com/denysdovhan/wtfjs https://www.geeksforgeeks.org/javascript/explain-the-concept-of-truthy-falsy-values-in-javascript/ if if if if ("") console.log log log log("1"); if if if if (" ") console.log log log log("2"); if if if if (0) console.log log log log("3"); if if if if (-1) console.log log log log("4"); if if if if ([]) console.log log log log("5"); if if if if ({}) console.log log log log("6");
  • 43.
    43/204 HTML + JavaScript+ CSS  Limitations – Complexity https://github.com/denysdovhan/wtfjs https://www.geeksforgeeks.org/javascript/explain-the-concept-of-truthy-falsy-values-in-javascript/ 2 4 5 6 if if if if ("") console.log log log log("1"); if if if if (" ") console.log log log log("2"); if if if if (0) console.log log log log("3"); if if if if (-1) console.log log log log("4"); if if if if ([]) console.log log log log("5"); if if if if ({}) console.log log log log("6");
  • 44.
    44/204 HTML + JavaScript+ CSS  Limitations – Design • Type coercion – The infamous == vs. === • Behaviour of this – Context dependent • Prototypes – No classes • No multi-threading – Concurrency but callback hell
  • 45.
    45/204 HTML + JavaScript+ CSS  Limitations – Typing • Dynamically, weakly typed • With weird type coercion rules https://dotat.at/@/2025-08-28-strongly-typed.html
  • 46.
    46/204 HTML + JavaScript+ CSS  Limitations – Typing • Dynamically, weakly typed • With weird type coercion rules https://dotat.at/@/2025-08-28-strongly-typed.html
  • 47.
    47/204 HTML + JavaScript+ CSS  Limitations – Ecosystem • Inconsistencies – Different behaviour in different Web browsers • Debugging – Also, dependency on HTML, Web browsers… • Dependency management – NPM again… • Toolchains – Webpack • Code is always accessible – Obfuscation • “Vendor” lock-in – But WebAssembly may change that!
  • 48.
    48/204 HTML + JavaScript+ CSS  Other concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 49.
    49/204 HTML + JavaScript+ CSS  Other concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 50.
    50/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 51.
    51/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 52.
    52/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 53.
    53/204 Opportunities and Challenges Java has a virtual machines  Web browsers abstract OSs and hardware Problem: Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 54.
    54/204 (JavaStation)  Capability  Availability Diversity  Affordability: ~$1,355 1996–2000, https://en.wikipedia.org/wiki/JavaStation
  • 55.
    55/204 (JavaStation)  Network Computers(NCs) – Advantages • Run any Java programs • “Cheap” – Disadvantages • Require changing existing desktops • Run only (?) Java programs • PCs became (ever) cheaper • Very slow https://hackaday.com/2018/04/10/the-forgotten-workstation-sun-javastation/ https://www.cnet.com/tech/tech-industry/javastation-nostalgia/
  • 56.
  • 57.
    57/204 Java Applets  Gettingvalue from the HTML <applet code="Simple" width=50 height=50> <param name="UserName" value="yann"> </applet> https://www.tutorialspoint.com/java/java_applet_basics.htm
  • 58.
    58/204 Java Applets  Gettingvalue from the HTML <applet code="Simple" width=50 height=50> <param name="UserName" value="yann"> </applet> public class Simple extends Applet { private String userName; @Override public void init() { super.init(); this.userName = super.getParameter("UserName"); https://www.tutorialspoint.com/java/java_applet_basics.htm
  • 59.
    59/204 Java Applets  Manipulatingthe DOM @Override public void start() { super.start(); try { final Class<?> c = Class.forName("com.sun.java.browser.plugin2.DOM"); final Method m = c.getMethod("getDocument", new Class[] { java.applet.Applet.class }); final HTMLDocument doc = (HTMLDocument) m.invoke(null, new Object[] { this }); final HTMLBodyElement body = (HTMLBodyElement) doc.getBody(); // ... https://docs.oracle.com/javase/tutorial/deployment/applet/examplesIndex.html
  • 60.
    60/204 Java Applets  Manipulatingthe DOM @Override public void start() { super.start(); try { final Class<?> c = Class.forName("com.sun.java.browser.plugin2.DOM"); final Method m = c.getMethod("getDocument", new Class[] { java.applet.Applet.class }); final HTMLDocument doc = (HTMLDocument) m.invoke(null, new Object[] { this }); final HTMLBodyElement body = (HTMLBodyElement) doc.getBody(); // ... Must duplicate the whole DOM https://docs.oracle.com/javase/tutorial/deployment/applet/examplesIndex.html
  • 61.
    61/204 Java Applets  JavaScriptto Applet – LiveConnect • Netscape Plugin API – NPAPI https://en.wikipedia.org/wiki/NPAPI#LiveConnect
  • 62.
    62/204 Java Applets  JavaScriptto Applet – LiveConnect • Netscape Plugin API – NPAPI https://en.wikipedia.org/wiki/NPAPI#LiveConnect
  • 63.
    63/204 Java Applets  JavaScriptto Applet https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html
  • 64.
    64/204 Java Applets  JavaScriptto Applet https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html public class MathApplet extends Applet { public String userName = null; // ...
  • 65.
    65/204 Java Applets  JavaScriptto Applet https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html public class MathApplet extends Applet { public String userName = null; // ... <script src="https://www.java.com/js/deployJava.js"/> <script> var attributes = { id:'mathApplet’, code:'net.ptidej.teavm.MathApplet', ...}; var parameters = { jnlp_href: 'math_applet.jnlp’}; deployJava.runApplet(attributes, parameters, '1.6'); </script>
  • 66.
    66/204 Java Applets  JavaScriptto Applet https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript https://docs.oracle.com/javase/tutorial/deployment/applet/invokingAppletMethodsFromJavaScript.html public class MathApplet extends Applet { public String userName = null; // ... <script language="javascript"> function enterNums(){ // set applet's public variable mathApplet.userName = "yann"; // ... <script src="https://www.java.com/js/deployJava.js"/> <script> var attributes = { id:'mathApplet’, code:'net.ptidej.teavm.MathApplet', ...}; var parameters = { jnlp_href: 'math_applet.jnlp’}; deployJava.runApplet(attributes, parameters, '1.6'); </script>
  • 67.
    67/204 Java Applets  Appletto JavaScript https://www.codejava.net/java-se/applet/liveconnect-the-api-for-communication-between-java-applet-and-javascript <html> <body> <center> <applet id="testApplet" code="TestApplet.class" width="200" height="80"/> </center> </body> <script type="text/javascript"> var coop = "Ooops!"; this[1] = "Slot 1"; function foo() { return "This is from foo()"; } function bar(firstName, lastName) { return "Greeting " + firstName + " " + lastName; } </script> </html> public class Java2JavaScript extends Applet { public void init() { // ... } private void testLiveConnect() throws JSException { final JSObject jso = JSObject.getWindow(this); String result = (String) jso.call("foo", null); label.setText(result); // ... result = (String) jso.call( "bar", new String[] { "Alice", "Alisa" }); label.setText(result); // ... final String expression = "alert('Hi!');"; jso.eval(expression); // ... result = (String) jso.getMember("coop"); label.setText(result); // ... result = (String) jso.getSlot(1); label.setText(result);
  • 68.
    68/204 Java Applets  Limitations –Java Applets • Depend on a JRE + the plug-in for the Web browser – May require to be root to install! • No standard for screen readers • Security restrictions and holes – LiveConnect • Tied to the JRE embedded within the Web browser • Obsolete JNI – JRI https://en.wikipedia.org/wiki/Java_applet#Disadvantages
  • 69.
    69/204 Java Applets  Removaland total removal – “By late 2015, many browser vendors had either removed or announced timelines for the removal of standards based plugin support, while some are introducing proprietary browser-specific extension APIs. […], Oracle is planning to deprecate the Java browser plugin in JDK 9.” https://stackoverflow.com/questions/45535112/why-were-applets-deprecated-in-jdk-9
  • 70.
    70/204 Java Applets  Inception,removal, and total removal – 1996: Applets introduced in Java 1 – 2002: Java Web Start introduced in Java 1.4 – 2017: All deprecated in Java 9 – 2018: appletviewer and Java Web Start removed from Java 11 – 2021: API deprecated for removal with Java 17 – 2026: total removal of all things Applet https://stackoverflow.com/questions/45535112/why-were-applets-deprecated-in-jdk-9 https://openjdk.org/jeps/504
  • 71.
    71/204 Java Applets  Stillrunnable with older JDKs  Still runnable with different implementations of the JDK – Azul Platform Core – https://www.azul.com/blog/keeping-java-applets- alive-with-azul-platform-core/
  • 72.
    72/204 Java Applets  Stilla concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 73.
    73/204 Java Applets  Stilla concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 74.
    74/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 75.
    75/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 76.
    76/204 C/C++ + WebAssembly Browsers as universal computing platform
  • 77.
    77/204 C/C++ + WebAssembly Browsers as universal computing platform 
  • 78.
    78/204 C/C++ + WebAssembly Browsers as universal computing platform  WebAssembly – Portable binary-code format (.wasm) • And a corresponding text format (.wat) – API with host environment – Implemented in all major Web browsers • In their respective JavaScript engine
  • 79.
    79/204 C/C++ + WebAssembly WebAssembly in a nutshell https://en.wikipedia.org/wiki/WebAssembly#Code_representation int factorial factorial factorial factorial(int n) { if if if if (n == 0) return return return return 1; else else else else return return return return n * factorial(n-1); }
  • 80.
    80/204 C/C++ + WebAssembly WebAssembly in a nutshell https://en.wikipedia.org/wiki/WebAssembly#Code_representation int factorial factorial factorial factorial(int n) { if if if if (n == 0) return return return return 1; else else else else return return return return n * factorial(n-1); } (func func func func (param param param param i64) (result result result result i64) local.get 0 i64.eqz if if if if (result result result result i64) i64.const 1 else else else else local.get 0 local.get 0 i64.const 1 i64.sub call 0 i64.mul end end end end)
  • 81.
    81/204 C/C++ + WebAssembly WebAssembly in a nutshell https://en.wikipedia.org/wiki/WebAssembly#Code_representation int factorial factorial factorial factorial(int n) { if if if if (n == 0) return return return return 1; else else else else return return return return n * factorial(n-1); } (func func func func (param param param param i64) (result result result result i64) local.get 0 i64.eqz if if if if (result result result result i64) i64.const 1 else else else else local.get 0 local.get 0 i64.const 1 i64.sub call 0 i64.mul end end end end) (module module module module (type type type type $t0 (func func func func (param param param param i64) (result result result result i64))) (func func func func $f0 (type type type type $t0) (param param param param $p0 i64) (result result result result i64) (if if if if $I0 (result result result result i64) ;; $I0 is unused (i64.eqz (local.get $p0)) ;; $p0 is same as 0 (then then then then (i64.const 1)) (else else else else (i64.mul (local.get $p0) (call $f0 ;; $f0 is same as 0 (i64.sub (local.get $p0) (i64.const 1))))))))
  • 82.
    82/204 C/C++ + WebAssembly WebAssembly in a nutshell https://en.wikipedia.org/wiki/WebAssembly#Code_representation int factorial factorial factorial factorial(int n) { if if if if (n == 0) return return return return 1; else else else else return return return return n * factorial(n-1); } (func func func func (param param param param i64) (result result result result i64) local.get 0 i64.eqz if if if if (result result result result i64) i64.const 1 else else else else local.get 0 local.get 0 i64.const 1 i64.sub call 0 i64.mul end end end end) (module module module module (type type type type $t0 (func func func func (param param param param i64) (result result result result i64))) (func func func func $f0 (type type type type $t0) (param param param param $p0 i64) (result result result result i64) (if if if if $I0 (result result result result i64) ;; $I0 is unused (i64.eqz (local.get $p0)) ;; $p0 is same as 0 (then then then then (i64.const 1)) (else else else else (i64.mul (local.get $p0) (call $f0 ;; $f0 is same as 0 (i64.sub (local.get $p0) (i64.const 1)))))))) Stack machine
  • 83.
    83/204 C/C++ + WebAssembly WebAssembly in a nutshell https://en.wikipedia.org/wiki/WebAssembly#Code_representation int factorial factorial factorial factorial(int n) { if if if if (n == 0) return return return return 1; else else else else return return return return n * factorial(n-1); } (func func func func (param param param param i64) (result result result result i64) local.get 0 i64.eqz if if if if (result result result result i64) i64.const 1 else else else else local.get 0 local.get 0 i64.const 1 i64.sub call 0 i64.mul end end end end) (module module module module (type type type type $t0 (func func func func (param param param param i64) (result result result result i64))) (func func func func $f0 (type type type type $t0) (param param param param $p0 i64) (result result result result i64) (if if if if $I0 (result result result result i64) ;; $I0 is unused (i64.eqz (local.get $p0)) ;; $p0 is same as 0 (then then then then (i64.const 1)) (else else else else (i64.mul (local.get $p0) (call $f0 ;; $f0 is same as 0 (i64.sub (local.get $p0) (i64.const 1)))))))) Stack machine S-expression
  • 84.
    84/204 C/C++ + WebAssembly WebAssembly in Web browsers https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly const const const const supported = (() => { try try try try { if if if if (typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly === "object“ && typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly.instantiate === "function") { const const const const module = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Module Module Module Module( Uint8Array Uint8Array Uint8Array Uint8Array.of of of of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); if if if if (module instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Module) return return return return new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Instance Instance Instance Instance(module) instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Instance; } } catch catch catch catch (e) { } return return return return false; })(); console.log log log log(supported ? "WebAssembly is supported" : "WebAssembly is not supported");
  • 85.
    85/204 C/C++ + WebAssembly WebAssembly in Web browsers https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly const const const const supported = (() => { try try try try { if if if if (typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly === "object“ && typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly.instantiate === "function") { const const const const module = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Module Module Module Module( Uint8Array Uint8Array Uint8Array Uint8Array.of of of of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); if if if if (module instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Module) return return return return new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Instance Instance Instance Instance(module) instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Instance; } } catch catch catch catch (e) { } return return return return false; })(); console.log log log log(supported ? "WebAssembly is supported" : "WebAssembly is not supported"); Stateful, executable a WebAssembly.Module
  • 86.
    86/204 C/C++ + WebAssembly WebAssembly in Web browsers https://stackoverflow.com/questions/47879864/how-can-i-check-if-a-browser-supports-webassembly const const const const supported = (() => { try try try try { if if if if (typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly === "object“ && typeof typeof typeof typeof WebAssembly WebAssembly WebAssembly WebAssembly.instantiate === "function") { const const const const module = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Module Module Module Module( Uint8Array Uint8Array Uint8Array Uint8Array.of of of of(0x0, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00)); if if if if (module instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Module) return return return return new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Instance Instance Instance Instance(module) instanceof instanceof instanceof instanceof WebAssembly WebAssembly WebAssembly WebAssembly.Instance; } } catch catch catch catch (e) { } return return return return false; })(); console.log log log log(supported ? "WebAssembly is supported" : "WebAssembly is not supported"); Stateful, executable a WebAssembly.Module Smallest possible program in WebAssembly: 0asm1
  • 87.
    87/204 C/C++ + WebAssembly WebAssembly outside of Web browsers – Enarx – wasm3 – Wasmer – WAMR – Wasmtime – WAVM
  • 88.
    88/204 C/C++ + WebAssembly WebAssembly outside of Web browsers – Enarx – wasm3 – Wasmer – WAMR – Wasmtime – WAVM Embedder is the term for host environments in which WASM modules are executed
  • 89.
    89/204 C/C++ + WebAssembly Longer example #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } }
  • 90.
    90/204 C/C++ + WebAssembly Longer example #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } }
  • 91.
  • 92.
    92/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ...
  • 93.
    93/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
  • 94.
    94/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (loop $L5 (if $I6 (i32.rem_u (local.get $p0) (local.get $l2)) (then (br_if $L5 (i32.gt_s (local.get $p0) (i32.mul (local.tee $l2 (i32.add (local.get $l2) (i32.const 1))) (local.get $l2)))) (br $B1)))) (local.set $l1 (i32.const 0))) (return (local.get $l1)))) ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200"))
  • 95.
    95/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (loop $L5 (if $I6 (i32.rem_u (local.get $p0) (local.get $l2)) (then (br_if $L5 (i32.gt_s (local.get $p0) (i32.mul (local.tee $l2 (i32.add (local.get $l2) (i32.const 1))) (local.get $l2)))) (br $B1)))) (local.set $l1 (i32.const 0))) (return (local.get $l1)))) ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200")) S-expression
  • 96.
    96/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (loop $L5 (if $I6 (i32.rem_u (local.get $p0) (local.get $l2)) (then (br_if $L5 (i32.gt_s (local.get $p0) (i32.mul (local.tee $l2 (i32.add (local.get $l2) (i32.const 1))) (local.get $l2)))) (br $B1)))) (local.set $l1 (i32.const 0))) (return (local.get $l1)))) ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200")) Host environment S-expression
  • 97.
    97/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (loop $L5 (if $I6 (i32.rem_u (local.get $p0) (local.get $l2)) (then (br_if $L5 (i32.gt_s (local.get $p0) (i32.mul (local.tee $l2 (i32.add (local.get $l2) (i32.const 1))) (local.get $l2)))) (br $B1)))) (local.set $l1 (i32.const 0))) (return (local.get $l1)))) ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200")) Host environment Export to host S-expression
  • 98.
    98/204 (module (type $t0 (func(param i32 i32 i32 i32))) (type $t1 (func)) (type $t2 (func (param i32) (result i32))) (import "env" "__assert_fail" (func $env.__assert_fail (type $t0))) (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "memory" (memory $env.memory 1)) (func $__wasm_call_ctors (export "__wasm_call_ctors") (type $t1) (nop)) (func $is_prime (export "is_prime") (type $t2) (param $p0 i32) (result i32) (local $l1 i32) (local $l2 i32) (if $I0 (i32.ge_s (local.get $p0) (i32.const 0)) (then (block $B1 ... ... (loop $L5 (if $I6 (i32.rem_u (local.get $p0) (local.get $l2)) (then (br_if $L5 (i32.gt_s (local.get $p0) (i32.mul (local.tee $l2 (i32.add (local.get $l2) (i32.const 1))) (local.get $l2)))) (br $B1)))) (local.set $l1 (i32.const 0))) (return (local.get $l1)))) ... ... (call $env.__assert_fail (i32.add (local.tee $p0 (global.get $env.__memory_base)) (i32.const 33)) (i32.add (local.get $p0) (i32.const 9)) (i32.const 11) (local.get $p0)) (unreachable)) (data $d0 (global.get $env.__memory_base) "is_prime00...000 && 22tNot a natural number2200")) Host environment Export to host S-expression Host function
  • 99.
    99/204 C/C++ + WebAssembly Support – C and C++: via Emscripten or Clang – Rust: via rustc with Wasm target – Go: native support introduced in v1.11 – .NET languages: C# and F# via Blazor – Python: dedicated implementations, Pyodide – Java and JVM languages: CheerpJ, TeaVM… – … – GraalWasm et al. https://en.wikipedia.org/wiki/WebAssembly#Language_Support
  • 100.
    100/204 C/C++ + WebAssembly Emscripten #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } } #include include include include <cstdlib> #include include include include <iostream> #include include include include "prime_calculator.h“ int main main main main() { std::cout << "Prime numbers between; std::cout << "2 and 100:" std::cout << std::endl; for for for for (int number = 2; number <= 100; number++) { if if if if (is_prime(number)) { std::cout << number << " "; } } std::cout << std::endl; }
  • 101.
    101/204 C/C++ + WebAssembly Emscripten #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } } #include include include include <cstdlib> #include include include include <iostream> #include include include include "prime_calculator.h“ int main main main main() { std::cout << "Prime numbers between; std::cout << "2 and 100:" std::cout << std::endl; for for for for (int number = 2; number <= 100; number++) { if if if if (is_prime(number)) { std::cout << number << " "; } } std::cout << std::endl; }
  • 102.
    102/204 C/C++ + WebAssembly Emscripten #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } }
  • 103.
    103/204 C/C++ + WebAssembly Emscripten CXX := emcc INCLUDE_DIR := src SRC_DIR := src BUILD_DIR := build all: all: all: all: $(CXX) ${SRC_DIR}prime_calculator.cc -o $(BUILD_DIR)prime_calculator.wasm -I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1 clean: clean: clean: clean: del /F /S /Q $(BUILD_DIR) #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } }
  • 104.
    104/204 C/C++ + WebAssembly Emscripten CXX := emcc INCLUDE_DIR := src SRC_DIR := src BUILD_DIR := build all: all: all: all: $(CXX) ${SRC_DIR}prime_calculator.cc -o $(BUILD_DIR)prime_calculator.wasm -I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1 clean: clean: clean: clean: del /F /S /Q $(BUILD_DIR) WASM #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } }
  • 105.
    105/204 C/C++ + WebAssembly Emscripten CXX := emcc INCLUDE_DIR := src SRC_DIR := src BUILD_DIR := build all: all: all: all: $(CXX) ${SRC_DIR}prime_calculator.cc -o $(BUILD_DIR)prime_calculator.wasm -I $(INCLUDE_DIR) -Os -s SIDE_MODULE=1 clean: clean: clean: clean: del /F /S /Q $(BUILD_DIR) WASM #include include include include <cassert> #include include include include "prime_calculator.h“ int is_prime is_prime is_prime is_prime(int number) { if if if if (number < 0) { assert(0 && “Not a natural number"); } else else else else if if if if (number == 1) { return return return return 0; } else else else else if if if if (number == 2) { return return return return 1; } else else else else { for for for for (int i = 3; i * i < number; i++) { if if if if (number % i == 0) { return return return return 0; } } return return return return 1; } } No main()
  • 106.
    106/204 C/C++ + WebAssembly Emscripten <!doctype html html html html> <html html html html lang="en-ca"> <head head head head> <meta meta meta meta charset="utf-8"> <meta meta meta meta name="viewport" content="width=device-width, initial-scale=1.0"> <title title title title>Emscripten Manual Example</title title title title> </head head head head> <body body body body> Prime calculator in WASM with Emscripten<br br br br/> See the Console for the output... <script script script script type="text/javascript" src="prime_calculator.js"/> </body body body body> </html html html html>
  • 107.
    107/204 C/C++ + WebAssembly Emscripten const const const const memory = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Memory Memory Memory Memory({ initial: 1, maximum: 10 }); const const const const stack_pointer = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Global Global Global Global({ value: "i32", mutable: true }, 0); const const const const importObject = { env: { memory: memory, __memory_base: 0, __table_base: 0, __stack_pointer: stack_pointer, __assert_fail: function function function function(condition, filename, line, func) { }, } } WebAssembly WebAssembly WebAssembly WebAssembly.instantiateStreaming instantiateStreaming instantiateStreaming instantiateStreaming(fetch fetch fetch fetch("build/prime_calculator.wasm"), importObject) .then then then then(result => { for for for for (let let let let i = 2; i <= 100; i++) { if if if if (result.instance.exports.is_prime is_prime is_prime is_prime(i) == 1) { console.log log log log(i.toString toString toString toString()); } } });
  • 108.
    108/204 C/C++ + WebAssembly Emscripten const const const const memory = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Memory Memory Memory Memory({ initial: 1, maximum: 10 }); const const const const stack_pointer = new new new new WebAssembly WebAssembly WebAssembly WebAssembly.Global Global Global Global({ value: "i32", mutable: true }, 0); const const const const importObject = { env: { memory: memory, __memory_base: 0, __table_base: 0, __stack_pointer: stack_pointer, __assert_fail: function function function function(condition, filename, line, func) { }, } } WebAssembly WebAssembly WebAssembly WebAssembly.instantiateStreaming instantiateStreaming instantiateStreaming instantiateStreaming(fetch fetch fetch fetch("build/prime_calculator.wasm"), importObject) .then then then then(result => { for for for for (let let let let i = 2; i <= 100; i++) { if if if if (result.instance.exports.is_prime is_prime is_prime is_prime(i) == 1) { console.log log log log(i.toString toString toString toString()); } } }); Host environment
  • 109.
  • 110.
    110/204 C/C++ + WebAssembly Emscripten emrun prime_calculator.html
  • 111.
    111/204 C/C++ + WebAssembly Emscripten emrun prime_calculator.html
  • 112.
    112/204 C/C++ + WebAssembly WebAssembly System Interface (WASI) – Version 2 • wasi-io • wasi-clocks • wasi-random • wasi-filesystem • wasi-sockets • wasi-cli • wasi-http https://atamel.dev/posts/2023/06-20_explore_wasm_outside_browser/
  • 113.
    113/204 C/C++ + WebAssembly WebAssembly System Interface (WASI) – Version 2 • wasi-io • wasi-clocks • wasi-random • wasi-filesystem • wasi-sockets • wasi-cli • wasi-http https://atamel.dev/posts/2023/06-20_explore_wasm_outside_browser/
  • 114.
    114/204 C/C++ + WebAssembly Emscripten #include include include include <stdio.h> #include include include include <stdlib.h> #include include include include <string.h> #include include include include <errno.h> int main main main main() { printf("Writing a filen"); FILE *fp; fp = fopen("hello.txt", "w"); if if if if (NULL == fp) { fprintf( stderr, "Error opening file: %sn", strerror(errno)); exit(1); } fputs("Hello, world!n", fp); fclose(fp); return return return return 0; } https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9
  • 115.
    115/204 C/C++ + WebAssembly Emscripten #include include include include <stdio.h> #include include include include <stdlib.h> #include include include include <string.h> #include include include include <errno.h> int main main main main() { printf("Writing a filen"); FILE *fp; fp = fopen("hello.txt", "w"); if if if if (NULL == fp) { fprintf( stderr, "Error opening file: %sn", strerror(errno)); exit(1); } fputs("Hello, world!n", fp); fclose(fp); return return return return 0; } https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9 POSIX function
  • 116.
    116/204 C/C++ + WebAssembly Emscripten #include include include include <stdio.h> #include include include include <stdlib.h> #include include include include <string.h> #include include include include <errno.h> int main main main main() { printf("Writing a filen"); FILE *fp; fp = fopen("hello.txt", "w"); if if if if (NULL == fp) { fprintf( stderr, "Error opening file: %sn", strerror(errno)); exit(1); } fputs("Hello, world!n", fp); fclose(fp); return return return return 0; } https://itnext.io/final-report-webassembly-wasi-support-in-ruby-4aface7d90c9 POSIX function
  • 117.
    117/204 C/C++ + WebAssembly Emscripten https://github.com/emscripten-core/emscripten/issues/12094
  • 118.
    118/204 C/C++ + WebAssembly Emscripten “POSIX provides source code portability. You can compile the same source code with different versions of libc to target different machines. But WebAssembly needs to go one step beyond this. We need to be able to compile once and run across a whole bunch of different machines. We need portable binaries.” — Lin Clark https://danielmangum.com/posts/wasm-wasi-clang-17/
  • 119.
    119/204 C/C++ + WebAssembly Emscripten “POSIX provides source code portability. You can compile the same source code with different versions of libc to target different machines. But WebAssembly needs to go one step beyond this. We need to be able to compile once and run across a whole bunch of different machines. We need portable binaries.” — Lin Clark https://danielmangum.com/posts/wasm-wasi-clang-17/
  • 120.
    120/204 C/C++ + WebAssembly Emscripten https://github.com/WebAssembly/wasi-libc
  • 121.
  • 122.
  • 123.
    123/204 Java Bytecode vs.WASM  Polyglot compilation target – Not Java – WASM!  Just stack-based languages – Java bytecode is unstructured (goto ) – WASM is structured, with nested operations • Scheme • But no exceptions!  Memory Management – Java hides stack vs. heap allocations, with GC – WASM sees a linear memory, must implement GC (!) • Object layouts in memory https://www.javaadvent.com/2022/12/webassembly-for-the-java-geek.html
  • 124.
    124/204 Java Bytecode vs.WASM  Lessons learned from Java bytecode and Applets, WebAssembly was designed – To have rapid compilation times with very simple validation rules compared to Java – With the concept of a host environment, i.e., the browser – To be secure and simple, minimising the attack surface – To support many languages (C, C++, Rust, ...), whereas the JVM was initially designed for a single language https://stackoverflow.com/questions/58131892/why-the-jvm-cannot-be-used-in-place-of-webassembly
  • 125.
    125/204 C/C++ + WebAssembly Limitations – No direct manipulation of the DOM – Limited WebAssembly System Interface (WASI) – Limited debugging support – Limited integration with JavaScript – Inconsistent integration with browser APIs – Complex and inconsistent build tools
  • 126.
    126/204 C/C++ + WebAssembly Still a concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 127.
    127/204 C/C++ + WebAssembly Still a concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 128.
    128/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 129.
    129/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 130.
  • 131.
    131/204 TeaVM  “[A]n ahead-of-timecompiler for Java bytecode that emits JavaScript and WebAssembly” – You are a Java developer, and you are going to write a web front-end from scratch – You already have a Java-based backend and want to integrate front-end code tightly – You have some Java back-end code you want to reuse in the front end – You are ready to rewrite your code for TeaVM https://teavm.org/docs/intro/overview.html
  • 132.
    132/204 TeaVM  “[A]n ahead-of-timecompiler for Java bytecode that emits JavaScript and WebAssembly” – You are a Java developer, and you are going to write a web front-end from scratch – You already have a Java-based backend and want to integrate front-end code tightly – You have some Java back-end code you want to reuse in the front end – You are ready to rewrite your code for TeaVM https://teavm.org/docs/intro/overview.html
  • 133.
    133/204 TeaVM  Inspired byGoogle Web Toolkit (GWT) – GWT takes source code, limited to Java only – TeaVM relies on existing compilers, such as javac, kotlinc, and scalac
  • 134.
    134/204 TeaVM  Features – Ahead-of-timecompiler of Java bytecode to JavaScript code – Original structure of a method, so in most cases it produces “natural” JavaScript – Green threads – Optimisations • Dead code • Devirtualisation • Local variables reuse • Method renaming – Java JavaScript interoperability API – Source maps • Debugging
  • 135.
    135/204 TeaVM Example final HTMLDocument document= HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } });
  • 136.
    136/204 TeaVM Example final HTMLDocument document= HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } });
  • 137.
    137/204 TeaVM Example final HTMLDocument document= HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } });
  • 138.
    138/204 TeaVM Example final HTMLDocument document= HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } });
  • 139.
    139/204 TeaVM Example final HTMLDocument document= HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } });
  • 140.
    140/204 TeaVM Transpiled JavaScript final HTMLDocumentdocument = HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } }); let Bl = (a, b) => BigInt.asIntN(64, a + b); let CZ = (b, c) => { let d, e, $$je; // ... a: { try { e = Bl(BE(L(c.value)), BE(L(d.value))); c = S(); Cx(H(c, F(3)), e); b.textContent = Bv(R(c)); break a; } catch ($$e) { $$je = CB($$e); if ($$je instanceof I) { } else { throw $$e; } } c = "Invalid numbers"; b.textContent = c; } };
  • 141.
    141/204 TeaVM Transpiled JavaScript final HTMLDocumentdocument = HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } }); let Bl = (a, b) => BigInt.asIntN(64, a + b); let CZ = (b, c) => { let d, e, $$je; // ... a: { try { e = Bl(BE(L(c.value)), BE(L(d.value))); c = S(); Cx(H(c, F(3)), e); b.textContent = Bv(R(c)); break a; } catch ($$e) { $$je = CB($$e); if ($$je instanceof I) { } else { throw $$e; } } c = "Invalid numbers"; b.textContent = c; } };
  • 142.
    142/204 TeaVM Transpiled JavaScript final HTMLDocumentdocument = HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } }); let Bl = (a, b) => BigInt.asIntN(64, a + b); let CZ = (b, c) => { let d, e, $$je; // ... a: { try { e = Bl(BE(L(c.value)), BE(L(d.value))); c = S(); Cx(H(c, F(3)), e); b.textContent = Bv(R(c)); break a; } catch ($$e) { $$je = CB($$e); if ($$je instanceof I) { } else { throw $$e; } } c = "Invalid numbers"; b.textContent = c; } };
  • 143.
    143/204 TeaVM Transpiled JavaScript final HTMLDocumentdocument = HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } }); let Bl = (a, b) => BigInt.asIntN(64, a + b); let CZ = (b, c) => { let d, e, $$je; // ... a: { try { e = Bl(BE(L(c.value)), BE(L(d.value))); c = S(); Cx(H(c, F(3)), e); b.textContent = Bv(R(c)); break a; } catch ($$e) { $$je = CB($$e); if ($$je instanceof I) { } else { throw $$e; } } c = "Invalid numbers"; b.textContent = c; } };
  • 144.
    144/204 TeaVM Transpiled JavaScript final HTMLDocumentdocument = HTMLDocument.current(); final HTMLElement h1 = document.createElement("h1"); h1.appendChild(document.createTextNode("TeaVM Example")); document.getBody().appendChild(h1); final HTMLElement div = document.createElement("div"); div.setAttribute("id", "calculator-container"); document.getBody().appendChild(div); final HTMLElement container = document. getElementById("calculator-container"); final HTMLInputElement input1 = (HTMLInputElement) document.createElement("input"); input1.setType("number"); container.appendChild(input1); final HTMLInputElement input2 = (HTMLInputElement) document.createElement("input"); input2.setType("number"); container.appendChild(input2); final HTMLButtonElement button = (HTMLButtonElement) document.createElement("button"); button.appendChild(document.createTextNode("Sum")); container.appendChild(button); final HTMLElement resultDiv = document.createElement("div"); container.appendChild(resultDiv); button.addEventListener("click", (evt) -> { try { final long num1 = Long.parseLong( input1.getValue()); final long num2 = Long.parseLong( input2.getValue()); final long sum = num1 + num2; resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv.setTextContent("Invalid numbers"); } }); let Bl = (a, b) => BigInt.asIntN(64, a + b); let CZ = (b, c) => { let d, e, $$je; // ... a: { try { e = Bl(BE(L(c.value)), BE(L(d.value))); c = S(); Cx(H(c, F(3)), e); b.textContent = Bv(R(c)); break a; } catch ($$e) { $$je = CB($$e); if ($$je instanceof I) { } else { throw $$e; } } c = "Invalid numbers"; b.textContent = c; } }; “Natural” JavaScript
  • 145.
    145/204 TeaVM @JSExport HTML/JavaScript // Addclick event listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int sum = Client.sum(num1, num2); resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv. setTextContent(“Invalid numbers"); } }); // ... @JSExport public static int sum( final int l1, final int l2) { return l1 + l2; } <head> <script type="text/javascript“ src="classes.js"></script> <script type="text/javascript"> document. addEventListener('DOMContentLoaded', function() { let result = sum(51, 72); console.log("Sum result: " + result); main(); }); </script> </head> <body> </body>
  • 146.
    146/204 TeaVM @JSExport HTML/JavaScript // Addclick event listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int sum = Client.sum(num1, num2); resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv. setTextContent(“Invalid numbers"); } }); // ... @JSExport public static int sum( final int l1, final int l2) { return l1 + l2; } <head> <script type="text/javascript“ src="classes.js"></script> <script type="text/javascript"> document. addEventListener('DOMContentLoaded', function() { let result = sum(51, 72); console.log("Sum result: " + result); main(); }); </script> </head> <body> </body>
  • 147.
    147/204 TeaVM @JSExport HTML/JavaScript // Addclick event listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int sum = Client.sum(num1, num2); resultDiv.setTextContent("Result: " + sum); } catch (final NumberFormatException e) { resultDiv. setTextContent(“Invalid numbers"); } }); // ... @JSExport public static int sum( final int l1, final int l2) { return l1 + l2; } <head> <script type="text/javascript“ src="classes.js"></script> <script type="text/javascript"> document. addEventListener('DOMContentLoaded', function() { let result = sum(51, 72); console.log("Sum result: " + result); main(); }); </script> </head> <body> </body>
  • 148.
    148/204 // Add clickevent listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int mul = Client.mul(num1, num2); resultDiv.setTextContent("Result: " + mul); } catch (final NumberFormatException e) { resultDiv. setTextContent("Invalid numbers"); } }); // ... @JSBody(params = { "v1", "v2" }, script = "return v1 * v2;") public static native int mul( final int l1, final int l2); TeaVM @JSBody HTML/JavaScript export function foo() { console.log("foo called"); } @JSBody( script = "return testModule.foo();", imports = @JSBodyImport( alias = "testModule", fromModule = "testModule.js"))
  • 149.
    149/204 // Add clickevent listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int mul = Client.mul(num1, num2); resultDiv.setTextContent("Result: " + mul); } catch (final NumberFormatException e) { resultDiv. setTextContent("Invalid numbers"); } }); // ... @JSBody(params = { "v1", "v2" }, script = "return v1 * v2;") public static native int mul( final int l1, final int l2); TeaVM @JSBody HTML/JavaScript export function foo() { console.log("foo called"); } @JSBody( script = "return testModule.foo();", imports = @JSBodyImport( alias = "testModule", fromModule = "testModule.js"))
  • 150.
    150/204 // Add clickevent listener to the button button.onClick((evt) -> { try { final int num1 = Integer.parseInt(input1.getValue()); final int num2 = Integer.parseInt(input2.getValue()); final int mul = Client.mul(num1, num2); resultDiv.setTextContent("Result: " + mul); } catch (final NumberFormatException e) { resultDiv. setTextContent("Invalid numbers"); } }); // ... @JSBody(params = { "v1", "v2" }, script = "return v1 * v2;") public static native int mul( final int l1, final int l2); TeaVM @JSBody HTML/JavaScript export function foo() { console.log("foo called"); } @JSBody( script = "return testModule.foo();", imports = @JSBodyImport( alias = "testModule", fromModule = "testModule.js"))
  • 151.
    151/204 TeaVM  Coroutines toemulate Threads together with a few simple synchronisation primitives  No support for reflection – Would increase complexity, size – Would prevent optimisations – But metaprogramming API
  • 152.
    152/204 TeaVM  Coroutines toemulate Threads together with a few simple synchronisation primitives  No support for reflection – Would increase complexity, size – Would prevent optimisations – But metaprogramming API Not all tested!
  • 153.
    153/204 TeaVM  Metaprogramming API publicclass Client { public static Object getFoo(final Object obj) { return Client.getFooImpl(obj.getClass(), obj); } @Meta private static native Object getFooImpl(final Class<?> cls, final Object obj); private static void getFooImpl(final ReflectClass<Object> cls, final Value<Object> obj) { final ReflectField field = cls.getField("foo"); if (field != null) { Metaprogramming.exit(() -> field.get(obj)); } else { Metaprogramming.exit(() -> null); } } public static void main(final String[] args) { // ... resultDiv.setTextContent( "Client.getFoo(new A("")): " + Client.getFoo(new A("")) + "<br>Client.getFoo(new B()): " + Client.getFoo(new B())); } } Doesn’t compile
  • 154.
    154/204 TeaVM  Java/JavaScript Objects(JSO) library – Overlay types – Properties mapping – Constructors mapping – Extension methods – Static methods – Indexer wrappers Not all tested!
  • 155.
    155/204 TeaVM  Java/JavaScript Objects(JSO) library – Passing Java objects to JavaScript – Passing Java objects as functions – Passing Java arrays without copying – Passing NIO buffers to JavaScript – Defining top-level functions and properties – Importing declarations from a module Not all tested!
  • 156.
    156/204 TeaVM  Limitations – TeaVMmust know how to transpile every method of every class of the Java Class Library • Based on Apache Harmony of 2011 (!?) – AWT (?) – Reflection https://teavm.org/jcl-report/recent/jcl.html
  • 157.
  • 158.
    158/204 TeaVM  Still aconcern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java but without JavaScript…
  • 159.
    159/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 160.
    160/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 161.
    161/204 TeaVM + WASI Fermyon Technologies, Inc. – https://developer.fermyon.com/wasm- languages/java – https://github.com/fermyon  Friendly fork of TeaVM to support WASI and the WebAssembly Component Model
  • 162.
    162/204 TeaVM + WASI JavaWASM  WASM 190 KB  WAT 47 KLOC package wasi; public class Fibonacci { public static void main(final String[] args) { final int n = Integer.parseInt(args[0]); System.out.println(Fibonacci.fib(n)); } private static int fib(final int n) { if (n <= 1) { return n; } return Fibonacci.fib(n - 1) + Fibonacci.fib(n - 2); } } (func $__start__ (type $t2) (call $initclass_otbw_WasmHeap) (call $meth_otbw_WasmHeap_initHeap (i32.const 102820) (i32.const 4194304) (i32.const 134217728) (i32.const 262144)) (call $initclass_otr_GC) (call $initclass_otr_EventQueue) (call $initclass_otr_Fiber)) (func $teavm_start (export "_start") (type $t2) (call $meth_otr_WasiMain_startMain)) GC Events “Threads”
  • 163.
    163/204 (Fibers and Enarx) Fibers – Cooperatively scheduled, user-space green threads / stackful coroutines  Enarx – Trusted Execution Environments (TEE) – Run-time TEE based on WebAssembly • Uses wasmtime as a runtime enarx run --wasmcfgfile Fibonacci.enarx.toml target/generated/wasm/teavm-wasm/classes.wasm https://blog.enarx.dev/language-support-for-wasi-2/
  • 164.
    164/204 TeaVM + WASI Java (func$meth_w_Fibonacci_main (type $t0) (param $p0 i32) ... (block $B0 (local.set $l5 (call $meth_otbw_WasmRuntime_allocStack (i32.const 1))) ... (i32.store offset=4 (local.get $l5) (local.get $l2)) (i32.store (local.get $l5) (i32.const 495)) (local.set $l3 (call $meth_jl_Integer_parseInt_0 (local.get $l2))) (if $I3 (i32.eq (i32.load (local.get $l5)) (i32.const 495)) (then (i32.store offset=4 (local.get $l5) (i32.const 0)) (i32.store (local.get $l5) (i32.const 496)) (local.set $l2 (call $meth_jl_System_out)) (if $I4 (i32.eq (i32.load (local.get $l5)) (i32.const 496)) (then (i32.store offset=4 (local.get $l5) (local.get $l2)) (i32.store (local.get $l5) (i32.const 497)) (local.set $l4 (call $meth_w_Fibonacci_fib (local.get $l3))) ... package wasi; public class Fibonacci { public static void main(final String[] args) { final int n = Integer.parseInt(args[0]); System.out.println(Fibonacci.fib(n)); } private static int fib(final int n) { if (n <= 1) { return n; } return Fibonacci.fib(n - 1) + Fibonacci.fib(n - 2); } }
  • 165.
    165/204 TeaVM + WASI Java packagewasi; public class Fibonacci { public static void main(final String[] args) { final int n = Integer.parseInt(args[0]); System.out.println(Fibonacci.fib(n)); } private static int fib(final int n) { if (n <= 1) { return n; } return Fibonacci.fib(n - 1) + Fibonacci.fib(n - 2); } } (func $meth_w_Fibonacci_fib ... (call $meth_otbw_WasmRuntime_allocStack (i32.const 0))) (block $B1 ... (then (local.set $l1 (i32.sub sub sub sub (local.get $p0) (i32.const 1))) (i32.store (local.get $l3) (i32.const 501)) (local.set $l2 (call $meth_w_Fibonacci_fib (local.get $l1))) (if $I3 (i32.eq (i32.load (local.get $l3)) (i32.const 501)) (then (local.set $l1 (i32.sub sub sub sub (local.get $p0) (i32.const 2))) (i32.store (local.get $l3) (i32.const 502)) (local.set $l1 (call $meth_w_Fibonacci_fib (local.get $l1))) ... (return (local.get $p0))))
  • 166.
    166/204 TeaVM + WASI JavaWASM public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); }
  • 167.
    167/204 TeaVM + WASI JavaWASM public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); }
  • 168.
    168/204 TeaVM + WASI JavaWASM public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); } [INFO INFO INFO INFO] Running TeaVM [INFO INFO INFO INFO] Output file built with errors [INFO INFO INFO INFO] Classes compiled: 121 [INFO INFO INFO INFO] Methods compiled: 1166 [ERROR ERROR ERROR ERROR] Class java.awt.Frame was not found at wasi.AWT.main(AWT.java:18) [ERROR ERROR ERROR ERROR] Class ....WindowAdapter was not found at wasi.AWT$1.<init>(AWT.java:25) at wasi.AWT.main(AWT.java:25)
  • 169.
    169/204 TeaVM + WASI JavaWASM public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); } [INFO INFO INFO INFO] Running TeaVM [INFO INFO INFO INFO] Output file built with errors [INFO INFO INFO INFO] Classes compiled: 121 [INFO INFO INFO INFO] Methods compiled: 1166 [ERROR ERROR ERROR ERROR] Class java.awt.Frame was not found at wasi.AWT.main(AWT.java:18) [ERROR ERROR ERROR ERROR] Class ....WindowAdapter was not found at wasi.AWT$1.<init>(AWT.java:25) at wasi.AWT.main(AWT.java:25) No GUI
  • 170.
    170/204 TeaVM + WASI JavaWASM public class Reflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } }
  • 171.
    171/204 TeaVM + WASI JavaWASM public class Reflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } } 55
  • 172.
    172/204 TeaVM + WASI JavaWASM public class Reflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } } 55 [INFO INFO INFO INFO] Running TeaVM [INFO INFO INFO INFO] Output file built with errors [INFO INFO INFO INFO] Classes compiled: 147 [INFO INFO INFO INFO] Methods compiled: 1351 [ERROR ERROR ERROR ERROR] Method org.teavm.classlib.impl.reflection.Converter .toJava(Lorg/teavm/platform/PlatformObject;) Ljava/lang/Object; is native but has no org.teavm.interop.Import annotation on it ... [ERROR ERROR ERROR ERROR] Method org.teavm.classlib.impl.reflection.Converter .arrayFromJava([Ljava/lang/Object;)Lorg/teav m/platform/PlatformSequence; is native but has no org.teavm.interop.Import annotation on it ...
  • 173.
    173/204 TeaVM + WASI JavaWASM public class Reflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } } 55 [INFO INFO INFO INFO] Running TeaVM [INFO INFO INFO INFO] Output file built with errors [INFO INFO INFO INFO] Classes compiled: 147 [INFO INFO INFO INFO] Methods compiled: 1351 [ERROR ERROR ERROR ERROR] Method org.teavm.classlib.impl.reflection.Converter .toJava(Lorg/teavm/platform/PlatformObject;) Ljava/lang/Object; is native but has no org.teavm.interop.Import annotation on it ... [ERROR ERROR ERROR ERROR] Method org.teavm.classlib.impl.reflection.Converter .arrayFromJava([Ljava/lang/Object;)Lorg/teav m/platform/PlatformSequence; is native but has no org.teavm.interop.Import annotation on it ... Incomplete implementation?
  • 174.
    174/204 TeaVM + WASI Limitations – Same as TeaVM? • Must know how to transpile every method of every class of the Java Class Library – Based on Apache Harmony of 2011 (?) • AWT • Reflection • Implementation • Documentation
  • 175.
    175/204 TeaVM + WASI Still a concern – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java but without JavaScript…
  • 176.
    176/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 177.
    177/204 Opportunities and Challenges Problem:Run the exact same programs on widely different hardware and OSs Solution: Running code in the Web browsers
  • 178.
    178/204 CheerpJ  Leaning TechnologiesInc. – “CheerpJ is a JVM and a distribution of OpenJDK for the browser in WebAssembly and JavaScript” – Java 17 (preview), 11, 8… – Swing, AWT, and most frameworks – Fully within the browser sandbox – Clipboard, networking, files, native methods https://cheerpj.com/
  • 179.
    179/204 CheerpJ  2018: Java8  2025: Java 11  2025: Java 17  2026: Java 21  2027: Java 26 – LTS parity
  • 180.
  • 181.
    181/204 CheerpJ Java (cf. TeaVM)CheerpJ public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); }
  • 182.
    182/204 CheerpJ Java (cf. TeaVM)CheerpJ public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); }
  • 183.
    183/204 CheerpJ Java (cf. TeaVM)CheerpJ public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); }
  • 184.
    184/204 CheerpJ Java (cf. TeaVM)CheerpJ public static void main(final String[] args) { final int n; if (args.length == 0) { n = 10; } else { n = Integer.parseInt(args[0]); } final Frame frame = new Frame("Fibonacci"); final Label label = new Label( "F(" + n + ") = " + fib(n)); label.setAlignment(Label.CENTER); frame.add(label); frame.setSize(300, 300); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing( final WindowEvent e) { System.exit(0); } }); } GUI!
  • 185.
    185/204 CheerpJ Java CheerpJ public classReflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } }
  • 186.
    186/204 CheerpJ Java CheerpJ 55 public classReflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } }
  • 187.
    187/204 CheerpJ Java CheerpJ 55 public classReflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } }
  • 188.
    188/204 CheerpJ Java CheerpJ 55 public classReflection { public static void main(final String[] args) throws ... { final int n = Integer.parseInt(args[0]); final Class<?> thisClass = Class.forName("wasi.Reflection"); final Method fibMethod = thisClass.getDeclaredMethod( "fib", int.class); System.out.println( fibMethod.invoke(null, n)); } @SuppressWarnings("unused") private static int fib(final int n) { if (n <= 1) { return n; } return Reflection.fib(n - 1) + Reflection.fib(n - 2); } } Reflection Console
  • 189.
    189/204 CheerpJ  WebAssembly-based JavaVirtual Machine – Works directly with Java byte code/JARs – Uses Cheerp • C and C++ compiler to WebAssembly and JavaScript to run in the browser or Node.js • Compiled full Java SE 8, 11 and 17 runtimes, based on OpenJDK – Provides interpreter + JIT compiler to JavaScript • Inline and devirtualise calls https://cheerpj.com/docs/explanation/architecture
  • 190.
    190/204 CheerpJ  Virtual windowmanager – AWT/Swing to a hierarchy of HTML5 elements  Virtual file system – Server-hosted files and persistent local storage  Networking support – fetch() for same-origin HTTP/HTTPS requests – Tailscale for general networking • VPN technology using WebSocket as transport layer
  • 191.
    191/204 CheerpJ  Notes – Likesuper Java Applets • But can manipulate the DOM? – VM rather than transpiler • No (little?) change to the Java code • No access to JavaScript / WASM? • Performance? • Compatibility?
  • 192.
    192/204 CheerpJ  Not aconcern anymore – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 193.
  • 194.
    194/204 Conclusion  Computers – Capability •Proving needed xPU, RAM, screen resolutions – Availability • Providing computers where and when needed – Diversity • Providing many different features, i.e., software – Affordability • Having cheap hardware and software
  • 195.
    195/204 Conclusion  What todo with the billions of lines of already code written in other programming languages?
  • 196.
    196/204 Conclusion  Write Once,Run Anywhere https://blog.stackademic.com/write-once-run-everywhere-still-a-joke-in-2025-bd273d0e3224
  • 197.
    197/204 Conclusion  Not aconcern anymore – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java…
  • 198.
    198/204 Conclusion  Not aconcern anymore – What to do with the billions of lines of already code written in other programming languages? • C/C++, Java… Emscripten TeaVM (+ WASM) CheerpJ
  • 199.
    199/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs
  • 200.
    200/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs
  • 201.
    201/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs
  • 202.
    202/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs
  • 203.
    203/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs
  • 204.
    204/204 Conclusion  Rewrite  Framework Compile or  Transpile  VMs