Is This the Next JAVA

Jul 13, 2020 • 8 minutes to read

In the post-Moore era, computer performance must come from more efficient software. Rust and WebAssembly provide Java-like memory safety, security, and portability to server-side applications while delivering high performance. Play with Rust functions in Node.js, and get recognized for your learning!

Back in 2005, I had the honor of being voted as one of the very first Java Champions for evangelizing Java on the server-side. It is hard to believe now, but back then, most people are doubtful that Java could even be used in server-side applications. Isn't Java a niche language invented to run silly games, known as Applets, inside the Netscape web browsers? Isn't Java very slow? Doesn't it consume a huge amount of memory? Well, those doubts were well founded. However, Java had one thing going for it. It is beloved by developers. The OOP language design, automatic memory safety, and cross platform runtime (JVM) were revolutionary at the time. Server side developers were just more productive in Java. The rest is history.

Since Java became the “king of the server side”, a challenger technology would emerge every a few years to “kill Java”. It was Ruby-on-Rails for a few years, and then Node.js for a few years. Yet, those challengers had the same playbook as Java — they focus on developer productivity. They are fundamentally managed runtimes with different front end languages. They are too similar to Java to kill Java.

Moore’s law

However, fast forward to 2020, a sea change is sweeping across the computer industry. It may finally bring a viable challenger to Java. In the past 50 years, the computer industry’s stunning success is driven by the Moore’s law.

Moore's Law refers to Moore's perception that the number of transistors on a microchip doubles every two years, though the cost of computers is halved.

That was why Java can trade performance for developer productivity with great success — Moore’s law dictates that today's performance will simply go away in 2 years with faster and cheaper hardware.

But in the past several years, semiconductor miniaturization has hit the quantum limit. The CPU speed is no longer going up. That threatens productivity improvements in many industries. The good news, as MIT professors Charles Leiserson et al. wrote in a recent paper published on Science, is that there are still room to squeeze at the top (of the stack, ie, software). In the post-Moore era, computer performance improvements will rely on software performance engineering.

That is causing profound changes in software. As Drs Leiserson et al. noted, we need a faster, less bloated, and close-to-hardware software stack. The compromises made by Java can no longer be taken granted in the post-Moore era. At the same time, we cannot just go back to the pre-Java era of C programming. We must imprice performance, and at the same time, preserve developer productivity and runtime safety gained from advances in software engineering in the past two decades. Leading the charge are the duo of Rust and WebAssembly.

Rust and WebAssembly to the rescue

The Rust programming language is designed to be a memory safe replacement for C. There is no bloated runtime for GC and memory management. It achieves memory safety through new programming concepts (ownership and borrowing of pointers) and a highly effective compiler toolchain. Developers love Rust. Xxx

WebAssembly pairs perfectly with Rust as a lightweight runtime. It is a sandbox for runtime memory safety. It also supports a capability-based security model for its contained applications to access system resources in a very controlled manner. Besides, just like the JVM, WebAssembly bytecode applications are portable across OS and hardware platforms.

Since WebAssembly was invented by web developers, it plays well with JavaScript, allowing JavaScript runtimes such as browsers and Node.js to embed high performance functions written in Rust.

We try to combine Rust's performance, WebAssembly's security and portability, and JavaScript's ease-of-use in a single solution.

Next, let's look into what a simple high performance web application looks like.

Solution

The host application is a Node.js web application written in JavaScript. It makes WebAssembly function call. The WebAssembly bytecode program is written in Rust. It runs inside the SSVM, and is called from the Node.js web application.

Rust and Wasm

Figure 1: Architecture of a high performance Node.js application

Without further ado, let's review a “hello world” example written in Rust but served as web application in Node.js. Please checkout the full source code for this example.

Prerequisites

Check out the complete setup instructions for Rust functions in Node.js.

The SSVM depends on the latest version of libstdc++. Ubuntu 20.04 LTS already has the latest libraries. If you are running an older Linux distribution, you have several options to upgrade.

On Ubuntu Linux 20.04, make sure that you have Rust and Node.js installed. We use the Second State Virtual Machine (SSVM), an open source WebAssembly runtime optimized for server-side applications, and the the ssvmup compiler toolchain. Both the SSVM and ssvumup can be installed with the NPM.

# Install ssvmup toolchain
$ npm install -g ssvmup # Append --unsafe-perm if permission denied

# OS dependencies for SSVM
$ sudo apt-get update
$ sudo apt-get -y upgrade
$ sudo apt install build-essential curl wget git vim libboost-all-dev

# Install the nodejs addon for SSVM
$ npm install ssvm

WebAssembly program in Rust

In this example, our Rust program appends the input string after “hello”. Below is the content of the Rust program src/lib.rs. You can define multiple external functions in this library file, and all of them will be available to the host JavaScript app via WebAssembly. Just remember to annotate each function with #[wasm_bindgen] so that ssvmup knows to generate the correct JavaScript to Rust interface for it when you build it.

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn say(s: String) -> String {
let r = String::from("hello ");
  return r + &s;
}

Next, you can compile the Rust source code into WebAssembly bytecode and generate the accompanying JavaScript module for the Node.js host environment.

$ ssvmup build

The result are files in the pkg/ directory. the .wasm file is the WebAssembly bytecode program, and the .js files are for the JavaScript module.

The Node.js host application

Next, go to the node folder and examine the JavaScript program app.js. With the generated hello_lib.js module, it is very easy to write JavaScript to call WebAssembly functions. Below is the node application app.js. It simply imports the say() function from the generated module. The node application takes the name parameter from incoming an HTTP GET request, and responds with “hello name”.

const { say } = require('../pkg/hello_lib.js');

const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 8080;

const server = http.createServer((req, res) => {
const queryObject = url.parse(req.url,true).query;
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(say(queryObject['name']));
});

server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});

Start the Node.js application server as follows.

$ node app.js
Server running at http://127.0.0.1:8080/

Then, you can test it.

$ curl http://127.0.0.1:8080/?name=Wasm
hello Wasm

The hello world example is very simple. It demonstrates how various components of the application work together in the simplest terms. Next, let’s review a Node.js ExpressJS web application that does some useful work!

Passing complex data between Rust and JavaScript

The next example shows how to pass multiple data types and arguments between the Rust functions in SSVM and the JavaScript function in the Node.js host. The example is a web applications that computes the roots for quadratic equations. Please checkout the full source code here.

The user enters the values for a, b, c on the web form, and the web application calls the web service at /solve to compute the roots for the quadratic equation.

a*X^2 + b*X + c = 0

The roots for X are displayed in the area below the input form.

Figure 2: The web app to teach quadratic equation

The HTML file contains the client side JavaScript to submit the web form to /solve, and put result into the #roots HTML element on the page.

$(function() {
    var options = {
      target: '#roots',
      url: "/solve",
      type: "post"
    };
    $('#solve').ajaxForm(options);
});

The Node.js application behind the /solve URL endpoint is as follows. It reads the data from the input form, passes them into the solve function as an array, and puts the return value in the HTTP response.

app.post('/solve', function (req, res) {
  var a = parseFloat(req.body.a);
  var b = parseFloat(req.body.b);
  var c = parseFloat(req.body.c);
  res.send(solve([a, b, c]))
})

Thesolve function is written in Rust and runs inside the SSVM. While the call arguments in the JavaScript side is an array of values, the Rust function receives a JSON object that encapsulates the array. In the Rust code, we first decode the JSON, perform the computation, and return the result values in a JSON string.

#[wasm_bindgen]
pub fn solve(params: &str) -> String {
  let ps: (f32, f32, f32) = serde_json::from_str(&params).unwrap();
  let discriminant: f32 = (ps.1 * ps.1) - (4. * ps.0 * ps.2);
  let mut solution: (f32, f32) = (0., 0.);
  if discriminant >= 0. {
    solution.0 = (((-1.) * ps.1) + discriminant.sqrt()) / (2. * ps.0);
    solution.1 = (((-1.) * ps.1) - discriminant.sqrt()) / (2. * ps.0);
    return serde_json::to_string(&solution).unwrap();
  } else {
    return String::from("not real numbers");
  }
}

That’s it for the quadratic equation example. You can see more examples, including computationally intensive artificial intelligence and machine learning examples from the Second State WebAssembly VM web site.

Next steps

If you are a Node.js or JavaScript developer, fork the hello world template project and add your own Rust code. After that, you will get a blockchain-based certificate and a FREE Raspberry Pi. Check out this article for more details.

To learn more about the Rust programming language, check out the learning resources on the official Rust web site. You could check out the previous article on learning Rust in your browser without installing any software.

The SSVM web site has a lot of example code, use cases, and tutorials on Rust functions in Node.js.

RustWebAssemblyJavaserver-sidevirtual-machineperformance
A high-performance, extensible, and hardware optimized WebAssembly Virtual Machine for automotive, cloud, AI, and blockchain applications