WebAssembly - Panduan Cepat

WebAssembly adalah bahasa pemrograman komputer baru untuk web. Kode WebAssembly adalah format biner tingkat rendah, yang kompatibel dengan web dan dapat dengan mudah dijalankan di browser web modern. Ukuran file yang dihasilkan kecil dan dimuat serta dijalankan lebih cepat. Anda sekarang dapat mengkompilasi bahasa seperti C, C ++, Rust, dll. Ke format biner dan dapat berjalan di web seperti javascript.

Definisi WebAssembly

Sesuai situs web resmi WebAssembly, yang tersedia di https://webassembly.org/, itu didefinisikan sebagai WebAssembly (disingkat Wasm) adalah format instruksi biner untuk mesin virtual berbasis stack. Wasm dirancang sebagai target portabel untuk kompilasi bahasa tingkat tinggi seperti C / C ++ / Rust, memungkinkan penerapan di web untuk aplikasi klien dan server.

Perakitan Web bukanlah sesuatu yang harus ditulis oleh pengembang, tetapi kodenya ditulis dalam bahasa seperti C, C ++, Rust dan dapat dikompilasi ke WebAssembly (wasm). Kode yang sama dapat dijalankan di dalam browser web.

Web Assembly adalah bahasa baru, kodenya adalah bahasa assembly tingkat rendah, tetapi dengan fitur format teksnya, kode dapat dibaca dan debugging dimungkinkan, jika perlu.

Sasaran WebAssembly

Standar terbuka untuk WebAssembly dikembangkan dalam Kelompok Komunitas W3C yang mencakup perwakilan dari semua browser utama serta Kelompok Kerja W3C.

Tujuan utama WebAssembly disebutkan di bawah -

  • Faster, Efficient and Portable - Kode WebAssembly dimaksudkan untuk berjalan lebih cepat pada platform yang berbeda dengan memanfaatkan perangkat keras yang tersedia.

  • Easy to read and debug - WebAssembly, sebagai bahasa assembly tingkat rendah, memiliki dukungan format teks, yang memungkinkan Anda men-debug kode untuk masalah apa pun dan juga menulis ulang kode, jika perlu.

  • Security - WebAssembly aman untuk dijalankan di browser web, karena menangani izin dan kebijakan asal yang sama.

Keuntungan dari WebAssembly

Berikut ini adalah keuntungan dari WebAssembly -

  • Run is Modern Browsers - WebAssembly dapat dijalankan tanpa masalah apa pun di browser web modern yang tersedia.

  • Multiple Language support- Bahasa seperti C, C ++, Rust, Go sekarang dapat mengkompilasi kode ke WebAssembly dan menjalankannya di browser web. Jadi, bahasa yang tadinya tidak dapat dijalankan di browser kini dapat melakukannya.

  • Faster, Efficient and Portable - Karena ukuran kode yang kecil, ia memuat dan mengeksekusi lebih cepat.

  • Easy to understand- Pengembang tidak perlu terlalu stres dalam memahami pengkodean WebAssembly, karena mereka tidak perlu menulis kode di WebAssembly. Sebagai gantinya, kompilasi kode di WebAssembly dan jalankan hal yang sama di web.

  • Easy to Debug - Meskipun kode terakhir dalam bahasa assembly tingkat rendah, Anda juga bisa mendapatkannya dalam format teks, yang mudah dibaca dan di-debug.

Kekurangan WebAssembly

Berikut ini adalah kerugian dari WebAssembly -

  • WebAssembly masih dikerjakan dan masih terlalu dini untuk memutuskan masa depannya.

  • WebAssembly bergantung pada javascript untuk berinteraksi dengan Document Object Model (DOM).

WebAssembly juga disebut WASM yang pertama kali diperkenalkan pada tahun 2017. Perusahaan teknologi besar di balik asal-usul WebAssembly adalah Google, Apple, Microsoft, Mozilla dan W3C.

Kabar baiknya adalah bahwa WebAssembly akan menggantikan Javascript karena eksekusinya yang lebih cepat, tetapi bukan itu masalahnya. WebAssembly dan Javascript dimaksudkan untuk bekerja sama untuk memecahkan masalah yang kompleks.

Kebutuhan WebAssembly

Sejauh ini, kami hanya memiliki Javascript yang dapat berfungsi dengan baik di dalam browser. Ada tugas yang sangat berat yang sulit dilakukan di browser menggunakan javascript.

Beberapa di antaranya adalah Pengenalan gambar, aplikasi Computer-Aided Design (CAD), augmentasi video langsung, VR dan augmented reality, Aplikasi musik, Visualisasi dan simulasi ilmiah, Game, Pengeditan gambar / video, dll.

WebAssembly adalah bahasa baru dengan instruksi biner yang dapat memuat dan mengeksekusi lebih cepat. Tugas yang disebutkan di atas, dapat dengan mudah dilakukan dalam bahasa tingkat tinggi seperti C, C ++, Rust dll. Kita membutuhkan cara agar kode yang kita miliki di C, C ++, Rust dapat dikompilasi dan dapat digunakan di browser web. Hal yang sama dapat dicapai dengan menggunakan WebAssembly.

Ketika kode WebAssembly dimuat di dalam browser. Kemudian, browser menangani pengubahan ke dalam format mesin yang dapat dipahami oleh prosesor.

Untuk javascript, kode harus diunduh, diurai, dan diubah ke format mesin. Banyak waktu yang dihabiskan untuk itu dan untuk tugas berat seperti yang kami sebutkan sebelumnya bisa sangat lambat.

Bekerja dari WebAssembly

Bahasa tingkat tinggi seperti C, C ++ dan Rust dikompilasi ke dalam format biner, yaitu, .wasm dan format teks .wat.

Kode sumber yang ditulis dalam C, C ++ dan Rust dikompilasi ke .wasmmenggunakan kompiler. Anda dapat menggunakan Emscripten SDK untuk mengompilasi C / C ++ ke.wasm.

Alurnya adalah sebagai berikut -

Kode C / C ++ dapat dikompilasi ke .wasmmenggunakan Emscripten SDK. Kemudian,.wasm kode dapat digunakan dengan bantuan javascript di file html Anda untuk menampilkan output.

Konsep Utama WebAssembly

Konsep utama dijelaskan di bawah ini -

Modul

Modul adalah objek yang dikompilasi oleh browser menjadi kode mesin yang dapat dieksekusi. Sebuah modul dikatakan stateless dan dapat dibagi antara windows dan web worker.

Penyimpanan

Memori dalam WebAssembly, adalah sebuah arraybufferyang menyimpan data. Anda dapat mengalokasikan memori dengan menggunakan Javascript api WebAssembly.memory ().

Meja

Tabel di WebAssembly adalah array yang diketik, di luar memori WebAssembly dan sebagian besar memiliki referensi ke fungsi. Ini menyimpan alamat memori fungsi.

Contoh

Instance adalah objek yang akan memiliki, semua fungsi yang diekspor yang dapat dipanggil dari javascript untuk dijalankan di dalam browser.

WebAssembly juga disebut wasm, yang merupakan perbaikan Javascript. Ini dirancang untuk berjalan di dalam browser seperti javascript dan juga dengan nodejs. Anda kebetulan mendapatkan keluaran wasm, ketika bahasa tingkat tinggi seperti C, C ++, Rust dikompilasi.

Pertimbangkan program C berikut -

int factorial(int n) {
   if (n == 0) 
      return 1; 
   else 
      return n * factorial(n-1); 
}

Manfaatkan WasmExplorer, yang tersedia dihttps://mbebenita.github.io/WasmExplorer/ untuk mendapatkan kode yang dikompilasi seperti yang ditunjukkan di bawah ini -

Format teks WebAssembly untuk program faktorial adalah seperti yang dinyatakan di bawah ini -

(module 
   (table 0 anyfunc) 
   (memory $0 1) (export "memory" (memory $0)) (export "factorial" (func $factorial)) (func $factorial (; 0 ;) (param $0 i32) (result i32) (local $1 i32) 
      (local $2 i32) (block $label$0 (br_if $label$0 (i32.eqz (get_local $0) 
            )
         )
         (set_local $2 (i32.const 1) ) (loop $label$1 (set_local $2 
               (i32.mul 
                  (get_local $0) (get_local $2) 
               ) 
            ) 
            (set_local $0 (tee_local $1        (i32.add 
                  (get_local $0) (i32.const -1) ) ) ) (br_if $label$1 (get_local $1) 
            ) 
         ) 
         (return 
            (get_local $2)
         ) 
      ) 
      (i32.const 1) 
   )
)

Menggunakan alat Wat2Wasm, Anda dapat melihat kode WASM, seperti yang disebutkan di bawah ini -

Pengembang tidak seharusnya menulis kode di wasm atau belajar membuat kode di dalamnya, karena sebagian besar dihasilkan saat Anda mengompilasi bahasa tingkat tinggi.

Model Mesin Stack

Di WASM, semua instruksi didorong ke tumpukan. Argumen dimunculkan dan hasilnya didorong kembali ke tumpukan.

Pertimbangkan format Teks WebAssembly berikut yang menambahkan 2 angka -

(module
   (func $add (param $a i32) (param $b i32) (result i32) 
      get_local $a get_local $b 
      i32.add
   )
   (export "add" (func $add))
)

Nama fungsinya adalah $add, dibutuhkan dalam 2 param $a and $b. Hasilnya adalah tipe integer 32-bit. Variabel lokal diakses menggunakan get_local dan operasi penambahan dilakukan menggunakan i32.add.

Representasi stack untuk menambahkan 2 angka sedangkan eksekusinya adalah sebagai berikut -

Di step 1 - Eksekusi get_local $a instruction, the first parameters i.e., $a didorong pada tumpukan.

Di step 2 - Selama eksekusi get_local $b instruction, the second parameters i.e., $b didorong ke atas tumpukan.

Di step 3- Eksekusi i32.add akan memunculkan elemen dari tumpukan dan akan mendorong hasilnya kembali ke tumpukan. Nilai yang tersisa di akhir tumpukan adalah hasil dari fungsi $ add.

Pada bab ini, akan belajar bagaimana menginstal Emscripten SDK untuk mengkompilasi C / C ++. Emscripten adalah mesin virtual tingkat rendah (LLVM) yang mengambil bytecode yang dihasilkan dari C / C ++ dan mengkompilasinya menjadi JavaScript yang dapat dengan mudah dijalankan di dalam browser.

Untuk mengkompilasi C / C ++ ke WebAssembly, pertama-tama kita harus menginstal Emscripten sdk.

Pasang Emscripten sdk

Langkah-langkah untuk menginstal Emscripten sdk adalah sebagai berikut -

Step 1 - Kloning repo emsdk: git clone https://github.com/emscripten-core/emsdk.git.

E:\wa>git clone https://github.com/emscripten-core/emsdk.git 
Cloning into 'emsdk'... 
remote: Enumerating objects: 14, done. 
remote: Counting objects: 100% (14/14), done. 
remote: Compressing objects: 100% (12/12), done. 
remote: Total 1823 (delta 4), reused 4 (delta 2), pack-reused 1809 receiving obje 
cts: 99% (1819/1823), 924.01 KiB | 257.00 KiB/s 
Receiving objects: 100% (1823/1823), 1.01 MiB | 257.00 KiB/s, done. 
Resolving deltas: 100% (1152/1152), done.

Step 2 - Masuk ke dalam direktori emsdk.

cd emsdk

Step 3 - Untuk windows: Jalankan perintah berikut.

emsdk install latest

For linux, perintah ini akan membutuhkan waktu untuk menginstal alat yang diperlukan seperti java, python dll. Ikuti kode yang disebutkan di bawah ini -

./emsdk install latest

Step 4 - Untuk mengaktifkan SDK terbaru, jalankan perintah berikut di terminal Anda.

For windows, jalankan perintah berikut -

emsdk activate latest

For linux, jalankan perintah yang disebutkan di bawah ini -

./emsdk activate latest

Step 5 - Untuk mengaktifkan PATH dan variabel lingkungan lainnya, jalankan perintah berikut di terminal Anda.

For windows, jalankan perintah -

emsdk_env.bat

For linux, jalankan perintah berikut -

source ./emsdk_env.sh

Kami selesai menginstal emsdk dan sekarang dapat mengkompilasi kode C atau C ++. Kompilasi C / C ++ akan dilakukan di bab-bab selanjutnya.

Untuk mengkompilasi kode C atau C ++ apa pun berikut ini adalah perintah -

emcc source.c or source.cpp -s WASM=1 -o source.html

Outputnya akan memberi Anda file source.html, source.js dan file source.wasm. Js akan memiliki api yang akan mengambil source.wasm dan Anda dapat melihat hasilnya, ketika Anda menekan source.html di browser.

Untuk mendapatkan file wasm Anda dapat menggunakan perintah berikut. Perintah ini hanya akan memberi Anda file source.wasm.

emcc source.c or source.cpp -s STANDALONE_WASM

Bab ini akan membahas beberapa alat yang mudah digunakan yang sangat membantu, saat bekerja dengan WebAssembly. Mari kita mulai dengan mempelajari alat WebAssembly.studio.

WebAssembly.studio

Alat ini memungkinkan Anda untuk mengkompilasi C, Rust, Wat ke Wasm dll.

Untuk memulai, Anda dapat mengklik Proyek C Kosong, Proyek Karat Kosong, Proyek Wat Kosong untuk mengkompilasi C dan Rust ke WASM. 5.

Ini memiliki Build, Run untuk membangun kode dan memeriksa hasilnya. Tombol unduh memungkinkan Anda mengunduh.wasmfile, yang dapat digunakan untuk menguji di dalam browser. Alat ini sangat membantu untuk mengkompilasi kode C dan Rust dan memeriksa hasilnya.

WebAssembly Explorer

WebAssembly Explorer memungkinkan Anda untuk mengkompilasi kode C dan C ++. Lihat tautannyahttps://mbebenita.github.io/WasmExplorer/untuk lebih jelasnya. Layar yang akan muncul setelah mengklik link ditunjukkan di bawah ini -

Anda dapat memilih versi C dan C ++. Kode sumber C atau C ++ ditulis di sini -

Sekali, Anda mengklik tombol Compile, itu memberikan format teks WebAssembly (WAT) dan kode Perakitan Firefox x86 di blok di bawah ini -

Anda dapat mengunduh .wasm kode untuk mengujinya di dalam browser.

WASMFiddle

Wasmfiddle membantu Anda mengompilasi kode C ke WebAssembly dan juga menguji hasilnya. Setelah mengklik link tersebuthttps://wasdk.github.io/WasmFiddle/, Anda akan melihat halaman berikut -

Klik Build untuk mengompilasi kode. Anda dapat mengunduh kode Wat dan Wasm dengan mengklik Wat dan Wasm. Untuk menguji output, klik tombol Run.

WASM ke WAT

Alat wat2wasmakan memberi Anda kode wasm saat Anda memasukkan format teks WebAssembly. Anda dapat mengklik link tersebuthttps://webassembly.github.io/wabt/demo/wat2wasm/ untuk demo dan layar yang akan muncul diberikan di bawah ini -

Anda dapat menggunakan tombol unggah untuk mengunggah .wasm dan textarea akan menampilkan format teks.

WAT untuk WASM

Alat wat2wasm akan memberi Anda kode wasm saat Anda memasukkan format teks WebAssembly. Anda dapat mengklik link tersebuthttps://webassembly.github.io/wabt/demo/wat2wasm/ untuk demo dan layar yang akan muncul diberikan di bawah ini -

Alat ini sangat membantu, karena membantu untuk mendapatkan keluaran juga diuji. Anda dapat memasukkan kode WAT dan melihat kode .wasm dan juga menjalankan kode untuk melihat hasilnya.

WebAssembly, juga disebut WASM, adalah format biner kode tingkat rendah yang dikembangkan untuk dijalankan di dalam browser dengan cara yang paling efisien. Kode WebAssembly disusun dengan konsep-konsep berikut -

  • Values
  • Types
  • Instructions

Mari kita pelajari secara detail sekarang.

Nilai

Nilai dalam WebAssembly dimaksudkan untuk menyimpan data kompleks seperti teks, string, dan vektor. WebAssembly mendukung berikut ini -

  • Bytes
  • Integers
  • Titik apung
  • Names

Byte

Bytes adalah bentuk nilai paling sederhana yang didukung di WebAssembly. Nilainya dalam format heksadesimal.

For example

Byte direpresentasikan sebagai b , juga dapat mengambil bilangan asli n, di mana n <256.

byte ::= 0x00| .... |0xFF

Bilangan bulat

Di WebAssembly, integer yang didukung seperti yang diberikan di bawah ini -

  • i32: integer 32-bit
  • i64: bilangan bulat 64-bit

Titik Mengambang

Dalam nomor floating point WebAssembly yang didukung adalah sebagai berikut -

  • f32: titik mengambang 32-bit
  • f64: titik mengambang 64-bit

Nama

Nama adalah urutan karakter, dengan nilai skalar yang ditentukan oleh Unicode, yang tersedia di tautan http://www.unicode.org/versions/Unicode12.1.0/ diberikan bersama ini.

Jenis

Entitas dalam WebAssembly diklasifikasikan sebagai tipe. Jenis yang didukung adalah seperti yang dinyatakan di bawah -

  • Jenis Nilai
  • Jenis Hasil
  • Jenis Fungsi
  • Limits
  • Jenis Memori
  • Jenis Tabel
  • Tipe Global
  • Jenis Eksternal

Let us study them one by one.

Value Types

The values type supported by WebAssembly are as mentioned below −

  • i32: 32-bit integer
  • i64: 64-bit integer
  • f32: 32-bit floating point
  • f64: 64-bit floating point
valtype ::= i32|i64|f32|f64

Result Types

The values written inside brackets are executed and stored inside result types. The result type is the output of the execution of a block of code made up of values.

resulttype::=[valtype?]

Function Types

A function type will take in vector of parameters returns a vector of results.

functype::=[vec(valtype)]--> [vec(valtype)]

Limits

Limits are the storage range linked with memory and table types.

limits ::= {min u32, max u32}

Memory Types

Memory types deal with linear memories and the size range.

memtype ::= limits

Table Types

Table Types are classified by the element type assigned to it.

tabletype ::= limits elemtype
elemtype ::= funcref

Table type is dependent on the limit for the minimum and maximum size assigned to it.

Global Types

Global Type holds the global variables that have the value, that can change or remain the same.

globaltype ::= mut valtype
mut ::= const|var

External Types

External Types deals with imports and external values.

externtype ::= func functype | table tabletype | mem memtype | global globaltype

Instructions

WebAssembly code is a sequence of instructions that follows a stack machine model. As WebAssembly follows a stack machine model, the instructions are pushed on the stack.

The argument values for a function, for example, are popped from stack and the result is pushed back on the stack. In the end, there will be only one value in the stack and that is the result.

Some of the commonly used Instructions are as follows −

  • Numeric Instructions
  • Variable Instructions

Numeric Instructions

Numeric Instructions are operations, which are performed on numeric value.

For example
nn, mm ::= 32|64
ibinop ::= add|sub|mul|div_sx|rem_sx|and|or|xor
irelop ::= eq | ne | lt_sx | gt_sx | le_sx | ge_sx
frelop ::= eq | ne | lt | gt | le | ge

Variable Instructions

Variable instructions are about accessing the local and global variables.

For example

To access local variables −

get_local $a
get_local $b

To set local variables −

set_local $a
set_local $b

To access global variables −

get_global $a
get_global $b

To set global variables −

set_global $a
set_global $b

This chapter will list out the comparison between WebAssembly and Javascript.

Javascript is a language, that we have used a lot inside the browser. Now, with WebAssembly release, we can also use WebAssembly inside the browser.

The reason for WebAssembly to come into existence is not to replace javascript, but to take care of certain things, that are difficult to handle with javascript.

For example

It is difficult to get the tasks such as Image recognition, CAD applications, Live video augmentation, VR and augmented reality, Music applications, Scientific visualization and simulation, Games, Image / video editing etc. to be done with javascript.

Using high level languages like C/C++, Rust, which now can be compiled to WebAssembly, it is easy to get the task mentioned above to be done. WebAssembly generates a binary code that is easy to execute inside the browser.

So here, is the list of comparison done between Javascript and WebAssembly.

Parameters Javascript WebAssembly

Coding

You can easily write code in Javascript. The code written is human readable and saved as .js. When used inside the browser you need to use a <script> tag.

The code can be written in text format in WebAssembly and it is saved as .wat. It is difficult to write the code in .wat format. It is best to compile the code from some other high level language instead of writing from start in .wat.

You cannot execute the .wat file inside the browser and has to convert to .wasm using the compilers or online tools available.

Execution

The code written in javascript when used inside the browser has to be downloaded, parsed, compiled and optimized.

We have WebAssembly code in .wasm already compiled and in binary format.

Memory Management

Javascript assigns memory when, variables are created and the memory is released when not used and are added to garbage collection.

Memory in WebAssembly is an arraybuffer that holds the data. You can allocate memory by using the Javascript API WebAssembly.memory().

WebAssembly memory is stored in an array format i.e. a flat memory model that is easy to understand and perform the execution.

The disadvantage of memory model in WebAssembly is −

  • Complex calculation takes time.

  • Webassembly does not support garbage collection that does not allow reuse of the memory and the memory is wasted.

Load Time & Performance

In case of javascript, when called inside the browser, the javascript file has to be downloaded, and parsed. Later, the parser converts the source code to bytecode that the javascript engine executes the code in the browser.

The Javascript engine is very powerful and hence, the load time and performance of javascript is very fast in comparison to WebAssembly.

A most important goal of WebAssembly is to be faster than JavaScript.Wasm code generated from high-level languages is smaller in size and hence, the load time is faster.

But, languages like GO, when compiled to wasm produce a big file size for a small piece of code.

WebAssembly is designed in such a way that it is faster in compilation, and can run across all the major browsers. WebAssembly still has to add lots of improvements in terms of performance in comparison to javascript.

Debugging

Javascript is human-readable and can be debugged easily. Adding breakpoints to your javascript code inside the browser allows you to easily debug the code.

WebAssembly provides the code in text format, that is readable but, still very difficult to debug. Firefox does allow you to view the wasm code in .wat format inside the browser.

You cannot add breakpoints in .wat and that is something that will be available in the future.

Browser Support

Javascript works well in all browsers.

All major web browsers have support for WebAssembly.

In this chapter, we will understand how to load the wasm code and execute them in the browser using the help of javascript webassembly API.

Here are some important API's, we are going to make use throughout the tutorial to execute wasm code.

  • fetch() Browser API
  • WebAssembly.compile
  • WebAssembly.instance
  • WebAssembly.instantiate
  • WebAssembly.instantiateStreaming

Before we discuss the WebAssembly javascript API's, to test the API and the output we are going to use the following C program and the .wasm code generated from the c program using wasm explorer.

An example for C Program is as follows −

#include<stdio.h>
int square(int n) { 
   return n*n; 
}

We will make use of WASM explorer, to get the wasm code −

Download WASM code and use it to test the API's.

fetch() Browser API

fetch() API is meant to load .wasm network resource.

<script>
   var result = fetch("findsquare.wasm");
   console.log(result);
</script>

It returns a promise as shown below −

You can also make use of XMLHttpRequest method to fetch the wasm network resource.

WebAssembly.compile()

The api responsibility is to compile the module details that are fetched from .wasm.

Syntax

The syntax is as given below −

WebAssembly.compile(buffer);

Parameters

Buffer − This code from .wasm has to be converted to a typed array or arraybuffer, before giving as input to compile.

Return value

It will return a promise that will have the compiled module.

Example

Let us see one example, that gives the output as a compiled module using webAssembly.compile().

<script> 
   fetch("findsquare.wasm") .then(bytes => bytes.arrayBuffer()) 
   .then(mod => {
      var compiledmod = WebAssembly.compile(mod);
      compiledmod.then(test=> {
         console.log(test); 
      })
   })
</script>

Output

The console.log, when checked in the browser, will give you the compiled module details −

The module has a constructor object with imports, exports, and customSections. Let us see the next API, to get more details of the compiled module.

WebAssembly.instance

Using the WebAssembly.instance, API will give you the executable instance of the compiled module that can be further executed to get the output.

Syntax

The syntax is as given below −

new WebAssembly.Instance(compiled module)

Return value

The return value will be an object with the array of exports function that can be executed.

Example

<script> 
   fetch("findsquare.wasm") 
      .then(bytes => bytes.arrayBuffer())
      .then(mod => WebAssembly.compile(mod)).then(module => {
         let instance = new WebAssembly.Instance(module); 
         console.log(instance); 
      })
</script>

Output

The output will give us an array of exports function as shown below −

You can see the square function, that we got from the C code that is compiled.

To execute the square function, you can do the following −

<script>
   fetch("findsquare.wasm") 
   .then(bytes => bytes.arrayBuffer()) 
   .then(mod => WebAssembly.compile(mod)) 
   .then(module => { 
      let instance = new WebAssembly.Instance(module);
      console.log(instance.exports.square(15));
   })
</script>

The output will be −

225

WebAssembly.instantiate

This API takes care of compiling and instantiating the module together.

Syntax

The syntax is as follows −

WebAssembly.instantiate(arraybuffer, importObject)

Parameters

arraybuffer − The code from .wasm has to be converted to typed array or arraybuffer before giving as input to instantiate.

importObject − The import object has to have details of the memory, imported functions to be used inside the module. It can be an empty module object, in case, there is nothing to be shared.

Return value

It will return a promise, that will have module and instance details.

Example

<script type="text/javascript">
   const importObj = {
      module: {}
   };
   fetch("findsquare.wasm")
      .then(bytes => bytes.arrayBuffer())
      .then(module => WebAssembly.instantiate(module, importObj)) 
      .then(finalcode => { 
         console.log(finalcode); console.log(finalcode.instance.exports.square(25)); 
      }); 
</script>

Output

When you execute the code, you will get the below mentioned output.

WebAssembly.instantiateStreaming

This API takes care of compiling as well as instantiating the WebAssembly module from the .wasm code given.

Syntax

The syntax is as given below −

WebAssembly.instantiateStreaming(wasmcode, importObject);

Parameters

wasmcode − Response from fetch or any other API that gives the wasm code and returns a promise.

importObject − The import object has to have details of the memory, imported functions to be used inside the module. It can be an empty module object in case there is nothing to be shared.

Return Value

It will return a promise, that will have module and instance details.

Example

An example is discussed below −

<script type="text/javascript">     
   const importObj = { 
      module: {} 
   };
   WebAssembly.instantiateStreaming(fetch("findsquare.wasm"), importObj).then(obj => {
      console.log(obj); 
   }); 
</script>

When you test it in the browser, you will see an error −

To make it work at your server end, you will have to add the mime type application/wasm or else make use of WebAssembly.instantiate(arraybuffer, importObject).

WebAssembly support is added to all the latest browsers available with you today like Chrome, Firefox. The Firefox version 54+ onwards gives you a special feature to debug your wasm code.

To do that, execute your code inside Firefox browsers that call wasm. For example, consider following C code that finds the square of the number.

An example for the C Program is as follows −

#include<stdio.h>
int square(int n) {
   return n*n;
}

We will make use of WASM explorer to get the wasm code −

Download WASM code and use it to see the output in the browser.

The html file that loads the wasm is as follows −

!doctype html> 
<html>
   <head>
      <meta charset="utf-8"> 
      <title>WebAssembly Square function</title> 
      <style> 
         div { 
            font-size : 30px; text-align : center; color:orange; 
         } 
      </style> 
   </head> 
   <body> 
      <div id="textcontent"></div> 
      <script> 
         let square; 
         fetch("findsquare.wasm").then(bytes => bytes.arrayBuffer()) 
            .then(mod => WebAssembly.compile(mod)) 
            .then(module => {return new WebAssembly.Instance(module) }) 
            .then(instance => {  
            square = instance.exports.square(13);
            console.log("The square of 13 = " +square);           
            document.getElementById("textcontent").innerHTML = "The square of 13 = " +square; 
         }); 
      </script> 
   </body> 
</html>

Open your Firefox browser and load the above html file and open the debugger tool.

You should see wasm:// entry in the debugger tool. Click on wasm:// and it shows the wasm code converted to .wat format as shown above.

You can take a look at the code of the exported function and can debug the code, if any issue comes up. Firefox also intends to add breakpoints, so that you can debug the code and check the execution flow.

In this chapter we are going to write a simple program in C and convert it into .wasm and execute the same in the browser to get the text "Hello World".

Will make use of wasm explorer tool that will convert the C program to .wasm and will make use of the .wasm inside our .html file.

The Wasm explorer tool which is available at https://mbebenita.github.io/WasmExplorer/ looks as follows −

The C code that we are going to use is as follows −

#include <stdio.h>
char *c_hello() {
   return "Hello World"; 
}

Update the first block in wasm explorer with the C code as shown below −

Click on COMPILE Button to compile to WASM and WAT and Firefox x86 Web Assembly as shown below −

Use the DOWNLOAD to get the .wasm file and save it as firstprog.wasm.

Create a .html file called firstprog.html as shown below −

<!doctype html>
<html>
   <head>
      <meta charset="utf-8"> 
      <title>WebAssembly Hello World</title> 
   </head> 
   <body>
      <div id="textcontent"></div>     
      <script type="text/javascript"> 
         //Your code from webassembly here
      </script> 
   </body>
</html>

Let us now use firstprog.wasm to read the helloworld from the C function c_hello().

Step 1

Use fetch() api to read the firstprog.wasm code.

Step 2

The .wasm code has to be converted into arraybuffer by using ArrayBuffer. The ArrayBuffer object will return you a fixed length binary data buffer.

The code so far will be as follows −

<script type="text/javascript"> 
   fetch("firstprog.wasm") .then(bytes => bytes.arrayBuffer()) 
</script>

Step 3

The bytes from ArrayBuffer have to be compiled into a module by using WebAssembly.compile(buffer) function.

The code will look like below −

<script type="text/javascript">
   fetch("firstprog.wasm")
   .then(bytes => bytes.arrayBuffer())
   .then(mod => WebAssembly.compile(mod))
</script>

Step 4

To get the module we have to call the webassembly.instance constructor as shown below −

<script type="text/javascript">     
   fetch("firstprog.wasm") 
   .then(bytes => bytes.arrayBuffer())
   .then(mod => WebAssembly.compile(mod))
   .then(module => {return new WebAssembly.Instance(module) }) 
</script>

Step 5

Let us now console the instance to see the details in the browser.

<script type="text/javascript"> 
   fetch("firstprog.wasm") .then(bytes => bytes.arrayBuffer()) 
   .then(mod => WebAssembly.compile(mod)) .then(module => {
      return new WebAssembly.Instance(module) 
   }) 
   .then(instance => {
      console.log(instance);
   }); 
</script>

The console.log details are shown below −

To get the string “Hello World” from the function c_hello(), we need to add some code in javascript.

First, get the memory buffer details as shown below −

let buffer = instance.exports.memory.buffer;;

The buffer value has to be converted to a typed array so that we can read the values from it. The buffer has the string Hello World in it.

To convert to typed call the constructor Uint8Array as shown below −

let buffer = new Uint8Array(instance.exports.memory.buffer);

Now, we can read the value from the buffer in a for - loop.

Let us now get the start point to read the buffer, by calling the function we wrote as shown below −

let test = instance.exports.c_hello();

Now, the test variable has the start point to read our string. WebAssembly does not have anything for string values, everything is stored as integers.

So when, we read the value from the buffer, they will be an integer value and we need to convert it into a string using fromCharCode() in javascript.

The code is as follows −

let mytext = ""; 
for (let i=test; buffer[i]; i++){ 
   mytext += String.fromCharCode(buffer[i]);
}

Now, when you console mytext you should see the string “Hello World”.

Example

The complete code is as follows −

<!doctype html> 
<html> 
   <head> 
      <meta charset="utf-8"> 
      <title>WebAssembly Add Function</title>
      <style>
         div { 
            font-size : 30px; text-align : center; color:orange; 
         } 
      </style>
   </head>
   <body>
      <div id="textcontent"></div>
      <script> 
         fetch("firstprog.wasm")
         .then(bytes => bytes.arrayBuffer())
         .then(mod => WebAssembly.compile(mod))
         .then(module => {return new WebAssembly.Instance(module)})
         .then(instance => {   
            console.log(instance); 
            let buffer = new Uint8Array(instance.exports.memory.buffer); 
            let test = instance.exports.c_hello(); 
            let mytext = ""; 
            for (let i=test; buffer[i]; i++) {
               mytext += String.fromCharCode(buffer[i]);
            }
            console.log(mytext); document.getElementById("textcontent").innerHTML = mytext; 
         });
      </script>
   </body>
</html>

We have added a div and the content is added to the div, so the string is displayed on the browser.

Output

The output is mentioned below −

We have seen how to get a .wasm file from c /c++ code. In this chapter, we will convert the wasm into a WebAssembly module and execute the same in the browser.

Let us use the C++ Factorial code as shown below −

int fact(int n) {
   if ((n==0)||(n==1))
      return 1;
   else
      return n*fact(n-1);
}

Open Wasm Explorer which is available at https://mbebenita.github.io/WasmExplorer/ as shown below −

The first column has the C++ factorial function, the 2nd column has the WebAssembly text format and the last column has x86 Assembly code.

The WebAssembly Text format −

(module
   (table 0 anyfunc)
   (memory $0 1)
   (export "memory" (memory $0)) (export "_Z4facti" (func $_Z4facti))
   (func $_Z4facti (; 0 ;) (param $0 i32) (result i32)
      (local $1 i32) (set_local $1
         (i32.const 1)
      )
      (block $label$0
         (br_if $label$0
            (i32.eq
               (i32.or
                  (get_local $0) (i32.const 1) ) (i32.const 1) ) ) (set_local $1
            (i32.const 1)
         )
         (loop $label$1
            (set_local $1 (i32.mul (get_local $0)
                  (get_local $1) ) ) (br_if $label$1 (i32.ne (i32.or (tee_local $0
                        (i32.add
                           (get_local $0) (i32.const -1) ) ) (i32.const 1) ) (i32.const 1) ) ) ) ) (get_local $1)
   )
)

The C++ function fact has been exported as “_Z4facti” in WebAssembly Text format.

Click on the download button to download the wasm code and save the file as factorial.wasm.

Now to convert the .wasm code to the module we have to do the following −

Step 1

Convert the .wasm into arraybuffer by using ArrayBuffer. The ArrayBuffer object will return you a fixed-length binary data buffer.

Step 2

The bytes from ArrayBuffer have to be compiled into a module by using WebAssembly.compile(buffer) function.

The WebAssembly.compile() function compiles and returns a WebAssembly.Module from the bytes given.

Here, is the Javascript code that is discussed in Step 1 and 2.

<script type="text/javascript">
   let factorial;
   fetch("factorial.wasm")
      .then(bytes => bytes.arrayBuffer())
      .then(mod => WebAssembly.compile(mod))
      .then(module => {return new WebAssembly.Instance(module) })
      .then(instance => {
      
      factorial = instance.exports._Z4facti;
      console.log('Test the output in Brower Console by using factorial(n)');
   });
</script>

Code Explanation

  • Javascript browser API fetch is used to get the contents of factorial.wasm.

  • The content is converted to bytes using arrayBuffer().

  • The module is created from bytes by calling WebAssembly.compile(mod).

  • The instance of a module is created using new

    WebAssembly.Instance(module)

  • The factorial function export _Z4facti is assigned to variable factorial by using WebAssembly.Module.exports().

Example

Here, is the module.html along with the javascript code −

module.html

<!doctype html>
<html>
   <head>
      <meta charset="utf-8">
      <title>WebAssembly Module</title>
   </head>
   <body>
      <script>
      let factorial;
      fetch("factorial.wasm")
      .then(bytes => bytes.arrayBuffer())
      .then(mod => WebAssembly.compile(mod))
      .then(module => {return new WebAssembly.Instance(module) })
      .then(instance => {
         factorial = instance.exports._Z4facti;
         console.log('Test the output in Browser Console by using factorial(n)');
      });
      </script>
   </body>
</html>

Output

Execute module.html in the browser to see the output −

In this chapter, we are going to discuss the webassembly.validate() function that will validate the .wasm output. The .wasm is available when we compile C, C++ or rust code.

You can make use of the following tools to get the wasm code.

  • Wasm Fiddler,which is available at https://wasdk.github.io/WasmFiddle/

  • WebAssembly Explorer, which is available at https://mbebenita.github.io/WasmExplorer/.

Syntax

The syntax is as given below −

WebAssembly.validate(bufferSource);

Parameters

bufferSource − The bufferSource has the binary code that comes from either C, C++ or Rust program. It is in the form of typedarray or ArrayBuffer.

Return Value

The function will return true if the .wasm code is valid and false if not.

Let us try one example. Go to Wasm fiddler, which is available at https://wasdk.github.io/WasmFiddle/, enter C code of your choice and down the wasm code.

The block marked in red is the C code. Click on the Build button at the center to execute the code.

Click on the Wasm , button to download the .wasm code. Save the .wasm at your end and let us use the same for validating.

Example

For Example: validate.html

<!doctype html>
<html>
   <head> 
      <meta charset="utf-8">
      <title>Testing WASM validate()</title>
   </head>
   <body>
      <script> 
         fetch('program.wasm').then(res => res.arrayBuffer() ).then(function(testbytes) {
         var valid = WebAssembly.validate(testbytes); 
            if (valid) {
               console.log("Valid Wasm Bytes!"); 
            } else {
               console.log("Invalid Wasm Code!"); 
            }
         }); 
      </script> 
   </body>
</html>

I have hosted the above .html file in wamp server along with the download .wasm file. Here, is the output when you test it in the browser.

Output

The output is the mentioned below −

WebAssembly has the code in a binary format called WASM. You can also get the text format in WebAssembly and it is called WAT (WebAssembly Text format). As a developer you are not supposed to write code in WebAssembly, instead, you have to compile high-level languages like C, C++ and Rust to WebAssembly.

WAT Code

Let us write WAT code stepwise.

Step 1 − The starting point in a WAT is to declare the module.

(module)

Step 2 − Let us now, add some functionality to it in the form of function.

The function is declared as shown below −

(func <parameters/result> <local variables> <function body>)

The function starts with func keyword which is followed by parameters or result.

Parameters/Result

The parameters and the return value as a result.

The parameters can have the following type supported by wasm −

  • i32: 32-bit integer
  • i64: 64-bit integer
  • f32: 32-bit float
  • f64: 64-bit float

The params for the functions are written as given below −

  • (param i32)
  • (param i64)
  • (param f32)
  • (param f64)

The result will be written as follows −

  • (result i32)
  • (result i64)
  • (result f32)
  • (result f64)

The function with parameters and return value will be defined as follows −

(func (param i32) (param i32) (result i64) <function body>)

Variabel Lokal

Variabel lokal adalah variabel yang Anda butuhkan dalam fungsi Anda. Nilai lokal untuk fungsi tersebut akan ditentukan sebagai berikut -

(func (param i32) (param i32) (local i32) (result i64) <function body>)

Fungsi Tubuh

Badan fungsi adalah logika yang harus dilakukan. Program terakhir akan terlihat seperti ini -

(module (func (param i32) (param i32) (local i32) (result i64) <function body>) )

Step 3 - Untuk membaca dan mengatur parameter dan variabel lokal.

Untuk membaca parameter dan variabel lokal, gunakan get_local dan set_local perintah.

Example

(module 
   (func (param i32) (param i32) (local i32) (result i64) get_local 0 
      get_local 1 
      get_local 2 
   ) 
)

Sesuai tanda tangan fungsi,

  • get_local 0 akan memberikan param i32

  • get_local 1 akan memberikan parameter selanjutnya param i32

  • get_local 2 akan memberi local value i32

Alih-alih mengacu pada parameter dan penduduk setempat menggunakan nilai numerik seperti 0,1,2, Anda juga dapat menggunakan nama sebelum parameter, mengawali nama dengan tanda dolar.

Contoh berikut menunjukkan, bagaimana menggunakan nama dengan parameter dan lokal.

Example

(module 
   (func 
      (param $a i32) (param $b i32) 
      (local $c i32) (result i64) get_local $a get_local $b get_local $c 
   ) 
)

Step 4 - Instruksi dalam tubuh Fungsi dan eksekusi.

Eksekusi di wasm mengikuti strategi stack. Instruksi yang dijalankan dikirim satu per satu di tumpukan. Misalnya, instruksi get_local $ a akan mendorong nilai, terbaca di tumpukan.

Instruksi seperti i32.add yang akan menambah kemauan memunculkan elemen dari tumpukan.

(func (param $a i32) (param $b i32) get_local $a 
   get_local $b 
   i32.add
)

Instruksi untuk i32.add adalah ($a+$b). Nilai akhir i32.add, akan didorong ke tumpukan dan itu akan ditetapkan ke hasilnya.

Jika tanda tangan fungsi memiliki hasil yang dideklarasikan, seharusnya ada satu nilai dalam tumpukan di akhir eksekusi. Jika tidak ada parameter hasil, tumpukan harus kosong di akhir.

Jadi, kode terakhir bersama dengan function body adalah sebagai berikut -

(module 
   (func (param $a i32) (param $b i32) (result i32) get_local $a
      get_local $b 
      i32.add
   )
)

Step 5 - Melakukan panggilan ke fungsi tersebut.

Kode terakhir dengan badan fungsi seperti yang ditunjukkan pada langkah 4. Sekarang, untuk memanggil fungsi, kita perlu mengekspornya.

Untuk mengekspor fungsi bisa dilakukan dengan nilai indeks seperti 0,1, tapi kita juga bisa memberi nama. Nama akan diawali dengan $ dan akan ditambahkan setelah kata kunci func.

Example

(module 
   (func $add (param $a i32) (param $b i32) (result i32) get_local $a 
      get_local $b i32.add
   ) 
)

Fungsi $ add harus diekspor, menggunakan kata kunci ekspor seperti yang ditunjukkan di bawah ini -

(module 
   (func $add (param $a i32) 
      (param $b i32) (result i32) get_local $a get_local $b i32.add ) (export "add" (func $add))
)

Untuk menguji kode di atas di browser, Anda harus mengubahnya menjadi bentuk biner (.wasm). Mengaculah ke bab berikutnya yang menunjukkan bagaimana mengonversi.WAT to .WASM.

Pada bab sebelumnya, kita telah melihat bagaimana menulis kode .watyaitu, format teks WebAssembly. Format teks WebAssembly tidak akan langsung bekerja di dalam browser dan Anda perlu mengubahnya menjadi format biner, misalnya WASM untuk bekerja di dalam browser.

WAT untuk WASM

Mari kita ubah .WAT menjadi .WASM.

Kode yang akan kita gunakan adalah sebagai berikut -

(module 
   (func $add (param $a i32) (param $b i32) (result i32) get_local $a 
      get_local $b i32.add ) (export "add" (func $add)) 
)

Sekarang pergi ke WebAssembly Studio, yang tersedia di https://webassembly.studio/.

Anda akan melihat sesuatu seperti ini, ketika Anda menekan tautan -

Klik pada proyek Empty Wat dan klik tombol Buat di bagian bawah.

Ini akan membawa Anda ke proyek kosong seperti yang ditunjukkan di bawah ini -

Klik main.wat dan ganti kode yang ada dengan milik Anda dan klik tombol simpan.

Setelah disimpan, klik pada build untuk diubah menjadi .wasm -

Jika build berhasil, Anda akan melihat file .wasm dibuat seperti yang ditunjukkan di bawah ini -

Turunkan file main.wasm dan gunakan di dalam file .html Anda untuk melihat output seperti yang ditunjukkan di bawah ini.

Sebagai Contoh - add.html

<!doctype html>
<html>
   <head>
      <meta charset="utf-8">
      <title>WebAssembly Add Function</title>
   </head>
   <body>
      <script> 
         let sum; 
         fetch("main.wasm")
            .then(bytes => bytes.arrayBuffer()) 
            .then(mod => WebAssembly.compile(mod)) .then(module => {
            
            return new WebAssembly.Instance(module) 
         })
         .then(instance => {
            sum = instance.exports.add(10,40); 
            console.log("The sum of 10 and 40 = " +sum); 
         }); 
      </script>
   </body>
</html>

Penambahan fungsi diekspor seperti yang ditunjukkan dalam kode. Parameter yang dilewati adalah 2 nilai integer 10 dan 40 dan mengembalikan jumlah itu.

Keluaran

Outputnya ditampilkan di browser.

Tautan dinamis adalah proses di mana dua atau lebih modul akan ditautkan bersama selama runtime.

Untuk mendemonstrasikan cara kerja penautan dinamis, kita akan menggunakan program C dan mengkompilasinya menjadi wasm menggunakan Ecmascript sdk.

Jadi di sini kita punya -

test1.c

int test1(){ 
   return 100; 
}

test2.c

int test2(){ 
   return 200; 
}

main.c

#include <stdio.h>

int test1(); 
int test2();
int main() { 
   int result = test1() + test2(); 
   return result; 
}

Dalam kode main.c, itu menggunakan test1 () dan test2 (), yang didefinisikan di dalam test1.c dan test2.c. Mari kita periksa bagaimana menghubungkan modul-modul ini di WebAssembly.

Perintah untuk mengkompilasi kode di atas adalah sebagai berikut: gunakan SIDE_MODULE = 1 untuk penautan dinamis seperti yang ditunjukkan pada perintah.

emcc test1.c test2.c main.c -s SIDE_MODULE=1 -o maintest.wasm

Menggunakan WasmtoWat, yang tersedia di https://webassembly.github.io/wabt/demo/wasm2wat/, akan mendapatkan format teks WebAssembly dari maintest.wasm.

(module 
   (type $t0 (func (result i32))) (type $t1 (func)) 
   (type $t2 (func (param i32))) (type $t3 (func (param i32 i32) (result i32))) 
   (import "env" "stackSave" (func $env.stackSave (type $t0))) 
   (import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
   (import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "__table_base" (global $env.__table_base i32)) 
   (import "env" "memory" (memory $env.memory 0)) (import "env" "table" (table $env.table 0 funcref)) 
   (func $f2 (type $t1) 
      (call $__wasm_apply_relocs) ) (func $__wasm_apply_relocs (export "__wasm_apply_relocs") (type $t1)) (func $test1 (export "test1") (type $t0) (result i32) (local $l0 i32) 
      (local.set $l0 (i32.const 100) ) (return (local.get $l0)
      )
   )
   (func $test2 (export "test2") (type $t0) (result i32) 
      (local $l0 i32) (local.set $l0 
         (i32.const 200)) 
      (return 
         (local.get $l0) ) ) (func $__original_main 
      (export "__original_main") 
      (type $t0) (result i32) (local $l0 i32) 
      (local $l1 i32) (local $l2 i32) 
      (local $l3 i32) (local $l4 i32) 
      (local $l5 i32) (local $l6 i32) 
      (local $l7 i32) (local $l8 i32) 
      (local $l9 i32) (local.set $l0(call $env.stackSave)) (local.set $l1 (i32.const 16))
      (local.set $l2 (i32.sub (local.get $l0) (local.get $l1))) (call $env.stackRestore (local.get $l2) ) (local.set $l3(i32.const 0)) 
      (i32.store offset=12 (local.get $l2) (local.get $l3)) 
      (local.set $l4 (call $test1)) 
      (local.set $l5 (call $test2)) 
      (local.set $l6 (i32.add (local.get $l4) (local.get $l5))) (i32.store offset=8 (local.get $l2) (local.get $l6)) (local.set $l7 (i32.load offset=8 (local.get $l2))) (local.set $l8 (i32.const 16)) 
      (local.set $l9 (i32.add (local.get $l2) (local.get $l8))) (call $env.stackRestore (local.get $l9)) (return(local.get $l7))
   )
   (func $main (export "main") (type $t3) 
      (param $p0 i32) (param $p1 i32) 
      (result i32) 
      (local $l2 i32) (local.set $l2 
      (call $__original_main)) (return (local.get $l2))
   ) 
   (func $__post_instantiate (export "__post_instantiate") (type $t1) (call $f2)) (global $__dso_handle (export "__dso_handle") i32 (i32.const 0))
)

Format teks WebAssembly memiliki beberapa impor yang ditentukan seperti yang ditunjukkan di bawah ini -

(import "env" "stackSave" (func $env.stackSave (type $t0)))       
(import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
(import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "__table_base" (global $env.__table_base i32)) 
(import "env" "memory" (memory $env.memory 0)) (import "env" "table" (table $env.table 0 funcref))

Ini ditambahkan saat mengkompilasi kode oleh emcc (emscripten sdk) dan berhubungan dengan manajemen memori di WebAssembly.

Bekerja dengan Impor dan Ekspor

Sekarang untuk melihat hasilnya, kita harus menentukan impor yang dapat Anda lihat di kode .wat -

(import "env" "stackSave" (func $env.stackSave (type $t0)))       
(import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
(import "env" "__memory_base" (global $env.__memory_base i32)) (import "env" "__table_base" (global $env.__table_base i32)) 
(import "env" "memory" (memory $env.memory 0)) (import "env" "table" (table $env.table 0 funcref))

Istilah di atas dijelaskan sebagai berikut -

  • env.stackSave - Digunakan untuk manajemen tumpukan, sebuah fungsionalitas yang disediakan oleh kode yang dikompilasi emscripten.

  • env.stackRestore - Digunakan untuk manajemen tumpukan, sebuah fungsionalitas yang disediakan oleh kode yang dikompilasi emscripten.

  • env.__memory_base- Ini adalah offset global i32 yang tidak dapat diubah, digunakan di env.memory dan dicadangkan untuk modul wasm. Modul dapat menggunakan global ini dalam penginisialisasi segmen datanya, sehingga mereka dimuat di alamat yang benar.

  • env.__table_base- Ini adalah offset global i32 yang tidak dapat diubah, digunakan dalam env.table dan disediakan untuk modul wasm. Modul dapat menggunakan global ini dalam penginisialisasi segmen elemen tabelnya, sehingga mereka dimuat pada offset yang benar.

  • env.memory - Ini akan memiliki detail memori yang diperlukan untuk dibagi antara modul wasm.

  • env.table - Ini akan memiliki detail tabel yang diperlukan untuk dibagikan antara modul wasm.

Impor harus ditentukan dalam javascript sebagai berikut -

var wasmMemory = new WebAssembly.Memory({'initial': 256,'maximum': 65536}); 
const importObj = { 
   env: {
      stackSave: n => 2, stackRestore: n => 3, //abortStackOverflow: () => {
         throw new Error('overflow'); 
      }, 
      table: new WebAssembly.Table({ 
         initial: 0, maximum: 65536, element: 'anyfunc' 
      }), __table_base: 0,
      memory: wasmMemory, __memory_base: 256 
   } 
};

Contoh

Berikut ini adalah kode javascript yang menggunakan importObj di dalam WebAssembly.instantiate.

<!DOCTYPE html> 
<html>
   <head>
      <meta charset="UTF-8">
   </head>
   <body>
      <script>
         var wasmMemory = new WebAssembly.Memory({'initial': 256,'maximum': 65536}); 
         const importObj = {
            env: {
               stackSave: n => 2, stackRestore: n => 3, //abortStackOverflow: () => {
                  throw new Error('overflow'); 
               }, 
               table: new WebAssembly.Table({ 
                  initial: 0, maximum: 65536, element: 'anyfunc' 
               }), __table_base: 0,
               memory: wasmMemory, __memory_base: 256 
            } 
         };
         fetch("maintest.wasm") .then(bytes => bytes.arrayBuffer()) .then(
            module => WebAssembly.instantiate(module, importObj)
         )
         .then(finalcode => {        
            console.log(finalcode);     
            console.log(WebAssembly.Module.imports(finalcode.module)); 
            console.log(finalcode.instance.exports.test1());    
            console.log(finalcode.instance.exports.test2());   
            console.log(finalcode.instance.exports.main()); 
         });
      </script>
   </body>
</html>

Keluaran

Outputnya adalah sebagai berikut -

Sesuai situs web resmi WebAssembly.org, yang tersedia di https://webassembly.org/docs/security/ tujuan utama WebAssembly dalam hal keamanan adalah sebagai berikut -

Model keamanan WebAssembly memiliki dua tujuan penting -

  • Melindungi pengguna dari modul buggy atau berbahaya, dan

  • Memberi pengembang primitif dan mitigasi yang berguna untuk mengembangkan aplikasi yang aman, dalam batasan (1).

Kode yang dikompilasi yaitu WASM dari C / C ++ / Rust tidak langsung dieksekusi di dalam browser dan menggunakan API Javascript. Kode WASM di sandbox yaitu dieksekusi melalui Javascript API wrapper dan browser berbicara dengan WASM menggunakan API.

Berikut adalah contoh penggunaan file .wasm di dalam browser.

Contoh - C Program

#include<stdio.h> 
int square(int n) { 
   return n*n; 
}

Kami akan menggunakan penjelajah WASM untuk mendapatkan kode wasm -

Unduh kode WASM dan gunakan untuk menguji api.

Contoh

<script type="text/javascript"> 
   const importObj = {
      module: {}
   }; 
   fetch("findsquare.wasm")      
      .then(bytes => bytes.arrayBuffer())          
      .then(module => WebAssembly.instantiate(module,importObj))                 
      .then(finalcode => {
         
      console.log(finalcode); console.log(finalcode.instance.exports.square(25)); 
   }); 
</script>

Keluaran

Anda akan mendapatkan output berikut -

Objek ekspor memiliki referensi ke fungsi yang akan dipanggil. Untuk memanggil function square, Anda harus melakukannya sebagai berikut -

console.log(finalcode.instance.exports.square(25));

Masalah dengan kode yang dikompilasi WASM

Berikut adalah masalah dengan kode yang dikompilasi WASM -

  • Sulit untuk memeriksa, jika ada kode berbahaya yang dimasukkan, saat mengkompilasi kode ke wasm. Tidak ada alat yang tersedia saat ini untuk memvalidasi kode.

  • Wasm sulit untuk dianalisis dan kode buggy / malicious dapat dengan mudah dieksekusi di dalam browser.

Pada bab ini, kita akan mengkompilasi program C sederhana ke javascript dan menjalankannya di browser.

Sebagai Contoh - C Program

#include<stdio.h> 
int square(int n) { 
   return n*n; 
}

Kami telah melakukan instalasi emsdk di folder wa /. Di folder yang sama, buat folder lain cprog / dan simpan kode di atas sebagai square.c.

Kami telah menginstal emsdk di bab sebelumnya. Di sini, kita akan menggunakan emsdk untuk mengkompilasi kode c di atas.

Kompilasi test.c di command prompt Anda seperti yang ditunjukkan di bawah ini -

emcc square.c -s STANDALONE_WASM –o findsquare.wasm

Perintah emcc menangani kompilasi kode serta memberi Anda kode .wasm. Kami telah menggunakan opsi STANDALONE_WASM yang hanya akan memberikan file .wasm.

Contoh - findsquare.html

<!doctype html> 
<html>
   <head>
      <meta charset="utf-8">
      <title>WebAssembly Square function</title>
      <style>
         div { 
            font-size : 30px; text-align : center; color:orange; 
         } 
      </style>
   </head> 
   <body>
      <div id="textcontent"></div>
      <script> 
      let square; fetch("findsquare.wasm").then(bytes => bytes.arrayBuffer()) 
      .then(mod => WebAssembly.compile(mod)) .then(module => {
         return new WebAssembly.Instance(module) 
      }) 
      .then(instance => {
         square = instance.exports.square(13); 
         console.log("The square of 13 = " +square);         
         document.getElementById("textcontent").innerHTML = "The square of 13 = " +square; 
      }); 
      </script>
   </body>
</html>

Keluaran

Outputnya seperti yang disebutkan di bawah ini -

Pada bab ini, kita akan mengkompilasi program C ++ sederhana ke javascript dan menjalankannya di browser.

Contoh

Program C ++ - Membalik angka tertentu.

#include <iostream> 
int reversenumber(int n) { 
   int reverse=0, rem; 
   while(n!=0) { 
      rem=n%10; reverse=reverse*10+rem; n/=10; 
   } 
   return reverse; 
}

Kami telah melakukan instalasi emsdk di folder wa /. Di folder yang sama, buat folder lain cprog / dan simpan kode di atas sebagai reverse.cpp.

Kami telah menginstal emsdk di bab sebelumnya. Di sini, kita akan menggunakan emsdk untuk mengkompilasi kode c di atas.

Kompilasi test.c di command prompt Anda seperti yang ditunjukkan di bawah ini -

emcc reverse.cpp -s STANDALONE_WASM –o reverse.wasm

Perintah emcc menangani kompilasi kode serta memberi Anda kode .wasm.

Contoh - reversenumber.html

<!doctype html> 
<html>
   <head> 
      <meta charset="utf-8">
      <title>WebAssembly Reverse Number</title>
      <style>
         div { 
            font-size : 30px; text-align : center; color:orange; 
         } 
      </style>
   </head>
   <body>
      <div id="textcontent"></div>
      <script> 
         let reverse; 
         fetch("reverse.wasm")  
            .then(bytes => bytes.arrayBuffer()) 
            .then(mod => WebAssembly.compile(mod)) 
            .then(module => {return new WebAssembly.Instance(module) })
            .then(instance => { 
            
            console.log(instance); 
            reverse = instance.exports._Z13reversenumberi(1439898); 
            console.log("The reverse of 1439898 = " +reverse); 
            document.getElementById("textcontent")
               .innerHTML = "The reverse of 1439898 = " +reverse; 
         }); 
      </script>
   </body>
</html>

Keluaran

Outputnya adalah sebagai berikut -

Untuk mendapatkan kode kompilasi RUST kita akan menggunakan alat WebAssembly.studio.

Buka WebAssembly.studio yang tersedia di Go tohttps://webassembly.studio/ dan itu akan menampilkan layar Anda seperti yang ditunjukkan di bawah ini -

Klik pada Proyek Karat Kosong. Setelah selesai Anda akan mendapatkan tiga file di folder src / -

Buka file main.rs dan ubah kode pilihan Anda.

Saya menambahkan fungsi berikut yang akan menambahkan dua angka yang diberikan -

fn add_ints(lhs: i32, rhs: i32) -> i32 {
   lhs+rhs
}

Kode yang tersedia di main.rs adalah sebagai berikut -

#[no_mangle]
pub extern "C" fn add_one(x: i32) -> i32 {
   x + 1
}

Ganti fn add_one dengan milik Anda seperti yang ditunjukkan di bawah ini -

#[no_mangle]
pub extern "C" fn add_ints(lhs: i32, rhs: i32) -> i32 {
   lhs+rhs
}

Di main.js, ubah nama fungsi dari add_one menjadi add_ints

fetch('../out/main.wasm').then(
   response =>
   response.arrayBuffer()
).then(bytes => WebAssembly.instantiate(bytes)).then(results => {
   instance = results.instance;
   document.getElementById("container").textContent = instance.exports.add_one(41);
}).catch(console.error);

Ganti instance.exports.add_one ke instance.exports.add_ints (100.100)

fetch('../out/main.wasm').then(
   response =>
   response.arrayBuffer()
).then(bytes => WebAssembly.instantiate(bytes)).then(results => {
   instance = results.instance;
   document.getElementById("container").textContent = instance.exports.add_ints(100,100)
}).catch(console.error);

Klik pada tombol build yang tersedia di webassembly.studio UI untuk membuat kode.

Setelah build selesai, klik tombol Run yang tersedia di UI, untuk melihat hasilnya -

Kami mendapatkan output sebagai 200, saat kami melewati instance.exports.add_ints (100,100).

Demikian pula, Anda dapat menulis program lain untuk rust dan membuatnya dikompilasi di webassembly.studio.

Go telah menambahkan dukungan untuk WebAssembly dari versi 1.1 dan seterusnya. Untuk mengujinya download pertama, Go.

Kunjungi situs golang, yang tersedia di https://golang.org/dl/dan klik Download Go. Sesuai sistem operasi Anda, unduh dan instal Go.

Setelah selesai, tulis program sederhana yang menambahkan dua angka sekaligus.

testnum.go

package main
import "fmt"
func main() { 
   var a int = 100 
   var b int = 200 
   var ret int 
   ret = sum(a, b) 
   fmt.Printf( "Sum is : %d\n", ret ) 
}
 
/* function returning the max between two numbers */ 
func sum(num1, num2 int) int { 
   return num1+num2 
}

Untuk mengkompilasi kode di atas menjadi wasm, pertama-tama atur variabel lingkungan di Go.

Anda harus menjalankan perintah berikut -

Set GOOS=js
GOARCH=wasm

Setelah selesai, jalankan perintah di bawah ini -

go build -o testnum.wasm testnum.go

Anda harus mendapatkan file testnum.wasm setelah perintah dijalankan.

Sekarang mari kita uji kode di browser. Untuk melakukan itu, kita perlu mendapatkan wasm_exec.js, yang diinstal dengan go.

File wasm_exec.js akan tersedia di dalam folder misc / wasm /.

Contoh

Di sini, adalah kode untuk testgo.html yang menggunakan wasm_exec.js dan testnum.wasm.

<html> 
   <head> 
      <meta charset="utf-8"/>
      <script src="wasm_exec.js"></script>
   </head>
   <body>
      <script type="text/javascript"> 
         const importObj = {
            module: {} 
         };
         const go = new Go(); 
         async function fetchAndInstantiate() { 
            const response = await fetch("testnum.wasm"); 
            const buffer = await response.arrayBuffer(); 
            const obj = await WebAssembly.instantiate(buffer, go.importObject); 
            console.log(obj); 
            go.run(obj.instance); 
         } 
         fetchAndInstantiate(); 
      </script>
   </body>
</html>

Keluaran

Outputnya adalah sebagai berikut -

Javascript memiliki banyak API yang dapat bekerja dengan kode wasm. API juga didukung di nodejs.

Dapatkan NODEJS terinstal di sistem Anda. Buat file Factorialtest.js.

Mari kita gunakan kode Faktorial C ++ seperti yang ditunjukkan di bawah ini -

int fact(int n) {
   if ((n==0)||(n==1))
      return 1;
   else
      return n*fact(n-1);
}

Buka Wasm Explorer, yang tersedia di https://mbebenita.github.io/WasmExplorer/ seperti yang ditunjukkan di bawah ini -

Kolom pertama memiliki fungsi faktorial C ++, kolom kedua memiliki format teks WebAssembly dan kolom terakhir memiliki kode Assembly x86.

Format Teks WebAssembly adalah sebagai berikut -

(module
   (table 0 anyfunc)
   (memory $0 1) (export "memory" (memory $0))
   (export "_Z4facti" (func $_Z4facti)) (func $_Z4facti (; 0 ;) (param $0 i32) (result i32) (local $1 i32)
      (set_local $1(i32.const 1)) (block $label$0 (br_if $label$0 (i32.eq (i32.or (get_local $0)
                  (i32.const 1)
               )
               (i32.const 1)
            )
         )
         (set_local $1 (i32.const 1) ) (loop $label$1 (set_local $1
               (i32.mul
                  (get_local $0) (get_local $1)
               )
            )
            (br_if $label$1
               (i32.ne
                  (i32.or
                     (tee_local $0 (i32.add (get_local $0)
                           (i32.const -1)
                        )
                     )
                     (i32.const 1)
                  )
                  (i32.const 1)
               )
            )
         )
      )
      (get_local $1)
   )
)

Fakta fungsi C ++ telah diekspor sebagai "_Z4facti”Dalam format Teks WebAssembly.

Factorialtest.js

const fs = require('fs');
const buf = fs.readFileSync('./factorial.wasm');
const lib = WebAssembly.instantiate(new Uint8Array(buf)).
   then(res => {
      for (var i=1;i<=10;i++) {
         console.log("The factorial of "+i+" = "+res.instance.exports._Z4facti(i))
      }
   }
);

Di baris perintah Anda, jalankan perintah node factorialtest.js dan hasilnya adalah sebagai berikut -

C:\wasmnode>node factorialtest.js
The factorial of 1 = 1
The factorial of 2 = 2
The factorial of 3 = 6
The factorial of 4 = 24
The factorial of 5 = 120
The factorial of 6 = 720
The factorial of 7 = 5040
The factorial of 8 = 40320
The factorial of 9 = 362880
The factorial of 10 = 3628800

Bab ini membahas contoh-contoh yang berkaitan dengan WebAssembly.

Contoh 1

Berikut adalah contoh Program C untuk mendapatkan Elemen maksimal -

void displaylog(int n);
/* function returning the max between two numbers */ 
int max(int num1, int num2) {
   /* local variable declaration */ int result; 
   if (num1 > num2) 
      result = num1; 
   else result = num2;
      displaylog(result);
   return result; 
}

Kompilasi kode di biola wasm dan unduh kode .wasm dan .wat.

Wat code

Kode Wat adalah sebagai berikut -

(module 
   (type $FUNCSIG$vi (func (param i32))) (import "env" "displaylog" (func $displaylog (param i32))) 
   (table 0 anyfunc) 
   (memory $0 1) (export "memory" (memory $0)) 
   (export "max" (func $max)) (func $max (; 1 ;) (param $0 i32) (param $1 i32) (result i32) 
      (call $displaylog (tee_local $0 
            (select 
               (get_local $0) (get_local $1) 
               (i32.gt_s (get_local $0) (get_local $1)) 
            )
         )
      )
      (get_local $0) 
   )
)

Download kode .wasm dan mari kita gunakan di file .html seperti yang ditunjukkan di bawah ini -

<!DOCTYPE html> 
<html>
   <head>
      <meta charset="UTF-8">
   </head>
   <body>
      <script>
         const importObj = {
            env: { 
               displaylog: n => alert("The max of (400, 130) is " +n) 
            } 
         };
         fetch("testmax.wasm") .then(bytes => bytes.arrayBuffer()) 
            .then(module => WebAssembly.instantiate(module, importObj)) 
            .then(finalcode => { 
            console.log(finalcode); 
            console.log(finalcode.instance.exports.max(400,130)); 
         }); 
      </script> 
   </body>
</html>

Keluaran

Outputnya adalah sebagai berikut -

Contoh 2

Berikut ini adalah kode C ++ untuk mendapatkan rangkaian fibonacci dari nomor yang diberikan.

#include <iostream>>
void displaylog(int n); 
int fibonacciSeries(int number) {
   int n1=0,n2=1,n3,i; 
   for(i=2;i<number;++i) { 
      n3=n1+n2; displaylog(n); n1=n2; n2=n3;
   }
   return 0; 
}

Saya menggunakan wasm explorer untuk mengkompilasi kode. Unduh Wat dan Wasm dan uji yang sama di browser.

Anda dapat menggunakan kode yang disebutkan di bawah ini -

<!DOCTYPE html> 
<html>
   <head> 
      <meta charset="UTF-8">
   </head>
   <body>
      <script> 
         const importObj = { 
            env: { _Z10displaylogi: n => console.log(n) } 
         };
         fetch("fib.wasm") 
            .then(bytes => bytes.arrayBuffer()) 
            .then(module => WebAssembly.instantiate(module, importObj)) 
            .then(finalcode => { 
            console.log(finalcode); 
            console.log(finalcode.instance.exports._Z15fibonacciSeriesi(10)); 
         });
      </script> 
   </body>
</html>

Keluaran

Outputnya adalah sebagai berikut -

Contoh 3

Berikut adalah kode Rust untuk menambahkan elemen dalam array yang diberikan.

fn add_array(x: i32) -> i32 { 
   let mut sum = 0; 
   let mut numbers = [10,20,30]; for i in 0..3 { 
      sum += numbers[i]; 
   } 
   sum 
}

Kita akan menggunakan WebAssembly Studio untuk mengkompilasi RUST menjadi wasm.

Bangun kode dan unduh file wasm dan jalankan yang sama di browser.

<!DOCTYPE html> 
<html>
   <head> 
      <meta charset="UTF-8">
   </head>
      <body>
      <script> 
         const importObj = { 
            env: {
            } 
         };
         fetch("add_array.wasm") .then(bytes => bytes.arrayBuffer())
            .then(module => WebAssembly.instantiate(module, importObj)) 
            .then(finalcode => { 
            console.log(finalcode); 
            console.log(finalcode.instance.exports.add_array());
         }); 
      </script> 
   </body> 
</html>

Keluaran

Outputnya akan seperti yang diberikan di bawah ini -