Join our Discord Server
Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).

Wasm: Explained to a 5 years old

4 min read

WebAssembly (abbreviated Wasm) is like a special language that helps computers understand and run programs really fast on the internet. It’s like having a translator that makes sure your program can work on any computer, even if they speak different languages.

WebAssembly is a powerful technology because it allows you to write code in different languages like C++, Rust, or even Python, and then compile that code into WebAssembly format. Once in WebAssembly format, the code can be executed efficiently by different computers on the internet, making programs run faster and more reliably.

A Bytecode format??

WebAssembly can be described as a “bytecode” format that compilers can use to translate programs into an efficient and platform-independent representation. Bytecode format is a compact, platform-independent representation of instructions that can be executed by a virtual machine or interpreter. It is a low-level representation of code that is designed to be efficient and easily interpreted by a runtime environment.

Bytecode serves as an intermediate representation between the high-level programming language and the machine code specific to a particular hardware architecture. It allows programs to be executed on different platforms without the need for recompilation, as long as the virtual machine or interpreter is available for that platform.



Explanation:

  • High-level Code: This represents the code written in a high-level programming language, such as Java, C#, or JavaScript.
  • Compiler/Interpreter: The code is passed through a compiler or interpreter, which translates the high-level code into a bytecode format. The compiler may perform optimizations and generate the bytecode representation, while an interpreter may directly interpret and execute the code.
  • Bytecode Format: The bytecode format is a platform-independent representation of the code. It consists of a series of instructions and possibly operands or arguments. This format is designed to be efficiently executed by a virtual machine.
  • Virtual Machine: The virtual machine is responsible for executing the bytecode. It understands the bytecode instructions and performs the corresponding operations. The virtual machine is specific to the target platform and can efficiently interpret or compile the bytecode into machine code for execution.
  • Machine Code: The virtual machine translates the bytecode into machine code, which is the low-level instructions understood by the specific hardware architecture. The machine code is executed directly by the processor.

Who doesn’t love LEGO bricks??!!

Imagine you have a box of LEGO bricks. Each brick represents a different part of a program. With normal languages, you have to take those LEGO bricks and build something using the instructions in that language. But with WebAssembly, you can put those LEGO bricks in a special box that can be opened by any computer.

Let me show you an example using some code. Pretend these LEGO bricks are like lines of code:

add 2 and 3 and store the result in a variable called 'sum'

In a normal language, you might write it like this:

let sum = 2 + 3;

But in WebAssembly, it would look like this:

(module
  (func (export "add") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add)
)

See how it looks a little different? That’s because WebAssembly uses a different format that computers can understand very quickly. So when you want to run your program on a computer, you send that special box with the WebAssembly code inside. The computer can open the box, understand the WebAssembly code, and run your program super fast.

Additionally, in Wasm, all the instructions are pushed on to the stack. The arguments are popped and the result is pushed back to the stack. That’s how WebAssembly helps make programs work on the internet, no matter what kind of computer you’re using. This code is written in a special language that WebAssembly understands. It tells the computer to add two numbers together and store the result.

Let’s break it down:

  • (module tells the computer that this is a WebAssembly module, like a special box containing the code.
  • (func (export “add”) (param i32 i32) (result i32) means we are defining a function called “add” that takes two parameters of type i32 (32-bit integer) and returns an i32 result.
  • local.get 0 and local.get 1 fetch the values of the first and second parameters, respectively.
  • i32.add adds the two values together.

So when you send this WebAssembly code to the computer, it knows how to run it and perform the addition. It’s like giving the computer a set of instructions that it can follow quickly.

WebAssembly is used for many things on the internet, like running complex games, editing photos, or even running programs that help with scientific calculations. It makes programs run faster and more efficiently on different types of computers.

Rust

Rust is a popular programming language that has excellent support for WebAssembly. Here’s an example of a simple Rust function that adds two numbers:

#[no_mangle]
pub fn add_numbers(a: i32, b: i32) -> i32 {
    return a + b;
}

This Rust code defines a function named add_numbers that takes two i32 (32-bit integer) parameters and returns an i32 result. The #[no_mangle] attribute ensures that the function name remains the same in the generated WebAssembly module.

To compile this Rust code to WebAssembly, you would typically use the wasm32-unknown-unknown target and the –target flag:

rustc --target wasm32-unknown-unknown example.rs

This command compiles the Rust code into a WebAssembly module (example.wasm).

After compiling, you can use the resulting WebAssembly module in JavaScript to invoke the Rust function add_numbers:

const wasmModule = new WebAssembly.Module(/* load the compiled WebAssembly module */);
const wasmInstance = new WebAssembly.Instance(wasmModule);

const addNumbers = wasmInstance.exports.add_numbers;

const result = addNumbers(5, 7);
console.log(result); // Output: 12

In this JavaScript code, we load the WebAssembly module, obtain a reference to the exported add_numbers function from the module, and then invoke it with the desired arguments.

Rust’s strong memory safety guarantees and its seamless integration with WebAssembly make it a popular choice for leveraging the benefits of WebAssembly in performance-critical applications.

Complex Example

Here’s another example in Rust that showcases a more complex computation using WebAssembly. Let’s calculate the factorial of a number:

#[no_mangle]
pub fn factorial(n: u32) -> u32 {
    if n <= 1 {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

In this Rust code, we define a function named factorial that takes an unsigned 32-bit integer n as input and returns an unsigned 32-bit integer as the result. The function recursively calculates the factorial of n using the formula n * factorial(n – 1). The base case is when n is less than or equal to 1, in which case it returns 1.

To compile this Rust code to WebAssembly, you can use the wasm32-unknown-unknown target:

rustc --target wasm32-unknown-unknown example.rs

Once compiled, you can interact with the WebAssembly module from JavaScript:

const wasmModule = new WebAssembly.Module(/* load the compiled WebAssembly module */);
const wasmInstance = new WebAssembly.Instance(wasmModule);

const factorial = wasmInstance.exports.factorial;

const result = factorial(5);
console.log(result); // Output: 120

In the JavaScript code, we load the WebAssembly module, obtain a reference to the exported factorial function from the module, and then invoke it with the desired argument (5 in this case). The result is the factorial of 5, which is 120.

This example demonstrates how you can leverage the power of WebAssembly to perform computationally intensive tasks like factorial calculations efficiently, even when executed within a web browser or any other WebAssembly-compatible environment.

Further References:

Have Queries? Join https://launchpass.com/collabnix

Ajeet Raina Ajeet Singh Raina is a former Docker Captain, Community Leader and Distinguished Arm Ambassador. He is a founder of Collabnix blogging site and has authored more than 700+ blogs on Docker, Kubernetes and Cloud-Native Technology. He runs a community Slack of 9800+ members and discord server close to 2600+ members. You can follow him on Twitter(@ajeetsraina).
Join our Discord Server
Index