WebAssembly - คู่มือฉบับย่อ
WebAssembly เป็นภาษาโปรแกรมคอมพิวเตอร์ใหม่สำหรับเว็บ รหัส WebAssembly เป็นรูปแบบไบนารีระดับต่ำซึ่งเข้ากันได้กับเว็บและสามารถเรียกใช้ในเว็บเบราว์เซอร์สมัยใหม่ได้อย่างง่ายดาย ขนาดไฟล์ที่สร้างขึ้นมีขนาดเล็กและโหลดและดำเนินการได้เร็วขึ้น ตอนนี้คุณสามารถรวบรวมภาษาเช่น C, C ++, Rust และอื่น ๆ เป็นรูปแบบไบนารีและสามารถทำงานบนเว็บได้เช่นเดียวกับจาวาสคริปต์
ความหมายของ WebAssembly
ตามเว็บไซต์อย่างเป็นทางการของ WebAssembly ซึ่งมีอยู่ที่ https://webassembly.org/ซึ่งถูกกำหนดให้เป็น WebAssembly (ย่อว่า Wasm) เป็นรูปแบบคำสั่งไบนารีสำหรับเครื่องเสมือนแบบสแต็ก Wasm ได้รับการออกแบบให้เป็นเป้าหมายแบบพกพาสำหรับการรวบรวมภาษาระดับสูงเช่น C / C ++ / Rust ทำให้สามารถปรับใช้บนเว็บสำหรับไคลเอ็นต์และเซิร์ฟเวอร์ได้
Web Assembly ไม่ใช่สิ่งที่นักพัฒนาจะต้องเขียน แต่โค้ดจะเขียนด้วยภาษาเช่น C, C ++, Rust และสามารถคอมไพล์ไปยัง WebAssembly (wasm) ได้ รหัสเดียวกันสามารถเรียกใช้ภายในเว็บเบราว์เซอร์
Web Assembly เป็นภาษาใหม่รหัสเป็นภาษาแอสเซมบลีระดับต่ำ แต่ด้วยคุณสมบัติรูปแบบข้อความทำให้โค้ดสามารถอ่านได้และแก้ไขจุดบกพร่องได้หากจำเป็น
เป้าหมายของ WebAssembly
มาตรฐานแบบเปิดสำหรับ WebAssembly ได้รับการพัฒนาใน W3C Community Group ซึ่งรวมถึงตัวแทนจากเบราว์เซอร์หลักทั้งหมดรวมทั้ง W3C Working Group
เป้าหมายหลักของ WebAssembly มีดังต่อไปนี้ -
Faster, Efficient and Portable - รหัส WebAssembly มีขึ้นเพื่อให้ทำงานได้เร็วขึ้นบนแพลตฟอร์มต่างๆโดยใช้ประโยชน์จากฮาร์ดแวร์ที่มีอยู่
Easy to read and debug - WebAssembly ซึ่งเป็นภาษาแอสเซมบลีระดับต่ำมีการรองรับรูปแบบข้อความซึ่งช่วยให้คุณสามารถดีบักโค้ดสำหรับปัญหาใด ๆ และยังเขียนโค้ดใหม่ได้หากจำเป็น
Security - WebAssembly ปลอดภัยที่จะทำงานบนเว็บเบราว์เซอร์เนื่องจากดูแลสิทธิ์และนโยบายที่มาเดียวกัน
ข้อดีของ WebAssembly
ต่อไปนี้เป็นข้อดีของ WebAssembly -
Run is Modern Browsers - WebAssembly สามารถดำเนินการได้โดยไม่มีปัญหาใด ๆ กับเว็บเบราว์เซอร์สมัยใหม่ที่มีอยู่
Multiple Language support- ภาษาเช่น C, C ++, Rust, Go สามารถคอมไพล์โค้ดไปยัง WebAssembly และเรียกใช้แบบเดียวกันในเว็บเบราว์เซอร์ ดังนั้นภาษาที่ไม่สามารถทำงานในเบราว์เซอร์ได้ในขณะนี้จะสามารถทำได้
Faster, Efficient and Portable - เนื่องจากโค้ดมีขนาดเล็กจึงโหลดและดำเนินการได้เร็วขึ้น
Easy to understand- นักพัฒนาไม่ต้องเครียดมากในการทำความเข้าใจกับการเข้ารหัส WebAssembly เนื่องจากไม่ต้องเขียนโค้ดใน WebAssembly แทนที่จะคอมไพล์โค้ดใน WebAssembly และดำเนินการเดียวกันบนเว็บ
Easy to Debug - แม้ว่าโค้ดสุดท้ายจะอยู่ในภาษาแอสเซมบลีระดับต่ำ แต่คุณยังสามารถใช้งานได้ในรูปแบบข้อความซึ่งง่ายต่อการอ่านและแก้ไขข้อบกพร่อง
ข้อเสียของ WebAssembly
ต่อไปนี้เป็นข้อเสียของ WebAssembly -
WebAssembly ยังคงทำงานอยู่และยังเร็วเกินไปที่จะตัดสินใจอนาคตของมัน
WebAssembly ขึ้นอยู่กับจาวาสคริปต์ในการโต้ตอบกับ Document Object Model (DOM)
WebAssembly เรียกอีกอย่างว่า WASM ซึ่งเปิดตัวครั้งแรกในปี 2017 บริษัท เทคโนโลยีขนาดใหญ่ที่อยู่เบื้องหลังการกำเนิด WebAssembly ได้แก่ Google, Apple, Microsoft, Mozilla และ W3C
ข่าวลือคือ WebAssembly จะเข้ามาแทนที่ Javascript เนื่องจากมีการดำเนินการที่เร็วกว่า แต่ก็ไม่เป็นเช่นนั้น WebAssembly และ Javascript มีไว้เพื่อทำงานร่วมกันเพื่อแก้ปัญหาที่ซับซ้อน
ต้องการ WebAssembly
จนถึงตอนนี้เรามี Javascript เท่านั้นที่สามารถทำงานได้สำเร็จภายในเบราว์เซอร์ มีงานที่หนักมากซึ่งทำได้ยากในเบราว์เซอร์โดยใช้จาวาสคริปต์
ในการตั้งชื่อไม่กี่อย่าง ได้แก่ การจดจำภาพแอปพลิเคชันการออกแบบโดยใช้คอมพิวเตอร์ช่วย (CAD) การเพิ่มวิดีโอสด VR และความเป็นจริงที่เพิ่มขึ้นแอปพลิเคชันเพลงการสร้างภาพและจำลองทางวิทยาศาสตร์เกมการตัดต่อภาพ / วิดีโอเป็นต้น
WebAssembly เป็นภาษาใหม่ที่มีคำสั่งไบนารีที่สามารถโหลดและดำเนินการได้เร็วขึ้น งานที่ระบุไว้ข้างต้นสามารถทำได้อย่างง่ายดายในภาษาระดับสูงเช่น C, C ++, Rust เป็นต้นเราต้องการวิธีที่สามารถคอมไพล์โค้ดที่เรามีใน C, C ++, Rust ได้และสามารถใช้ในเว็บเบราว์เซอร์ได้ ทำได้เช่นเดียวกันโดยใช้ WebAssembly
เมื่อโหลดโค้ด WebAssembly ภายในเบราว์เซอร์ จากนั้นเบราว์เซอร์จะดูแลการแปลงเป็นรูปแบบเครื่องที่โปรเซสเซอร์สามารถเข้าใจได้
สำหรับจาวาสคริปต์จะต้องดาวน์โหลดรหัสแยกวิเคราะห์และแปลงเป็นรูปแบบเครื่อง เวลาผ่านไปนานมากและสำหรับงานหนักเช่นที่เรากล่าวถึงก่อนหน้านี้อาจช้ามาก
การทำงานของ WebAssembly
ภาษาระดับสูงเช่น C, C ++ และ Rust ถูกคอมไพล์เป็นรูปแบบไบนารีนั่นคือ .wasm และรูปแบบข้อความ .wat.
ซอร์สโค้ดที่เขียนด้วย C, C ++ และ Rust ถูกคอมไพล์เป็น .wasmโดยใช้คอมไพเลอร์ คุณสามารถใช้ Emscripten SDK สำหรับการคอมไพล์ C / C ++ ถึง.wasm.
กระแสมีดังนี้ -
สามารถคอมไพล์โค้ด C / C ++ เป็นไฟล์ .wasmโดยใช้ Emscripten SDK ต่อมา.wasm รหัสสามารถใช้ด้วยความช่วยเหลือของจาวาสคริปต์ในไฟล์ html ของคุณเพื่อแสดงผลลัพธ์
แนวคิดหลักของ WebAssembly
แนวคิดหลักมีคำอธิบายด้านล่าง -
โมดูล
โมดูลคือออบเจ็กต์ที่ถูกคอมไพล์โดยเบราว์เซอร์ไปยังรหัสเครื่องที่เรียกใช้ โมดูลถูกกล่าวว่าไร้สัญชาติและสามารถใช้ร่วมกันระหว่าง Windows และ Web Workers
หน่วยความจำ
หน่วยความจำใน WebAssembly คือไฟล์ arraybufferที่เก็บข้อมูล คุณสามารถจัดสรรหน่วยความจำโดยใช้ Javascript api WebAssembly.memory ()
ตาราง
ตารางใน WebAssembly คืออาร์เรย์ที่พิมพ์ซึ่งอยู่นอกหน่วยความจำ WebAssembly และส่วนใหญ่มีการอ้างอิงถึงฟังก์ชัน จะเก็บที่อยู่หน่วยความจำของฟังก์ชัน
ตัวอย่าง
อินสแตนซ์คือออบเจ็กต์ที่จะมีฟังก์ชันที่ส่งออกทั้งหมดซึ่งสามารถเรียกใช้จากจาวาสคริปต์เพื่อเรียกใช้งานภายในเบราว์เซอร์
WebAssembly เรียกอีกอย่างว่า wasm ซึ่งเป็นการปรับปรุง Javascript มันถูกออกแบบมาให้ทำงานในเบราว์เซอร์เช่นเดียวกับจาวาสคริปต์และกับ nodejs คุณได้รับเอาต์พุต wasm เมื่อมีการคอมไพล์ภาษาระดับสูงเช่น C, C ++, Rust
พิจารณาโปรแกรม C ต่อไปนี้ -
int factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
ใช้ WasmExplorer ซึ่งมีอยู่ที่https://mbebenita.github.io/WasmExplorer/ เพื่อรับโค้ดที่คอมไพล์แล้วดังแสดงด้านล่าง -
รูปแบบข้อความ WebAssembly สำหรับโปรแกรมแฟกทอเรียลมีดังที่ระบุไว้ด้านล่าง -
(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)
)
)
เมื่อใช้เครื่องมือ Wat2Wasm คุณสามารถดูรหัส WASM ได้เช่นเดียวกับที่ระบุไว้ด้านล่าง -
นักพัฒนาไม่ควรเขียนโค้ดเป็น wasm หรือเรียนรู้การเขียนโค้ดเนื่องจากส่วนใหญ่สร้างขึ้นเมื่อคุณรวบรวมภาษาระดับสูง
เครื่องสแต็ค
ใน WASM คำแนะนำทั้งหมดจะถูกผลักไปที่สแต็ก อาร์กิวเมนต์จะปรากฏขึ้นและผลลัพธ์จะถูกผลักกลับไปที่สแต็ก
พิจารณารูปแบบ WebAssembly Text ต่อไปนี้ที่เพิ่มตัวเลข 2 ตัว -
(module
(func $add (param $a i32) (param $b i32) (result i32)
get_local $a get_local $b
i32.add
)
(export "add" (func $add))
)
ชื่อของฟังก์ชันคือ $addใช้เวลาใน 2 params $a and $ข. ผลลัพธ์คือประเภทจำนวนเต็ม 32 บิต ตัวแปรโลคัลเข้าถึงได้โดยใช้ get_local และการดำเนินการเพิ่มจะดำเนินการโดยใช้ i32.add
การแสดงสแต็กเพื่อเพิ่มตัวเลข 2 ตัวในขณะที่การดำเนินการจะเป็นดังนี้ -
ใน step 1 - การดำเนินการของ get_local $a instruction, the first parameters i.e., $a ถูกผลักลงบนสแต็ก
ใน step 2 - ระหว่างดำเนินการ get_local $b instruction, the second parameters i.e., $b ถูกผลักลงบนสแต็ก
ใน step 3- การเรียกใช้ i32.add จะดึงองค์ประกอบจากสแต็กและจะผลักผลลัพธ์กลับไปที่สแต็ก ค่าที่ยังคงอยู่ท้ายสุดในสแตกเป็นผลลัพธ์ของฟังก์ชัน $ add
ในบทนี้จะเรียนรู้วิธีการติดตั้ง Emscripten SDK เพื่อคอมไพล์ C / C ++ Emscripten เป็นเครื่องเสมือนระดับต่ำ (LLVM) ที่ใช้ bytecode ที่สร้างจาก C / C ++ และรวบรวมเป็น JavaScript ที่สามารถเรียกใช้งานภายในเบราว์เซอร์ได้อย่างง่ายดาย
ในการคอมไพล์ C / C ++ ไปยัง WebAssembly เราต้องติดตั้ง Emscripten sdk ก่อน
ติดตั้ง Emscripten sdk
ขั้นตอนในการติดตั้ง Emscripten sdk มีดังนี้ -
Step 1 - โคลน 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 - เข้าสู่ภายในไดเร็กทอรี emsdk
cd emsdk
Step 3 - สำหรับ windows: ดำเนินการคำสั่งต่อไปนี้
emsdk install latest
For linuxคำสั่งนี้จะใช้เวลาสักครู่ในการติดตั้งเครื่องมือที่จำเป็นเช่น java, python เป็นต้นทำตามรหัสที่กล่าวถึงด้านล่าง -
./emsdk install latest
Step 4 - เพื่อเปิดใช้งาน SDK ล่าสุดให้รันคำสั่งต่อไปนี้ในเทอร์มินัลของคุณ
For windowsดำเนินการคำสั่งต่อไปนี้ -
emsdk activate latest
For linuxดำเนินการตามคำสั่งที่กล่าวถึงด้านล่าง -
./emsdk activate latest
Step 5 - ในการเปิดใช้งาน PATH และตัวแปรสภาพแวดล้อมอื่น ๆ ให้รันคำสั่งต่อไปนี้ในเทอร์มินัลของคุณ
For windowsดำเนินการคำสั่ง -
emsdk_env.bat
For linuxดำเนินการคำสั่งต่อไปนี้ -
source ./emsdk_env.sh
เราติดตั้ง emsdk เสร็จแล้วและสามารถคอมไพล์รหัส C หรือ C ++ ได้แล้ว การคอมไพล์ C / C ++ จะทำในบทถัดไป
ในการคอมไพล์โค้ด C หรือ C ++ ต่อไปนี้คือคำสั่ง -
emcc source.c or source.cpp -s WASM=1 -o source.html
ผลลัพธ์จะให้ไฟล์ source.html, source.js และไฟล์ source.wasm js จะมี api ที่จะดึง source.wasm และคุณจะเห็นผลลัพธ์เมื่อคุณกด source.html ในเบราว์เซอร์
ในการรับไฟล์ wasm คุณสามารถใช้คำสั่งต่อไปนี้ คำสั่งนี้จะให้ไฟล์ source.wasm แก่คุณเท่านั้น
emcc source.c or source.cpp -s STANDALONE_WASM
บทนี้จะกล่าวถึงเครื่องมือที่ใช้งานง่ายซึ่งมีประโยชน์มากในขณะที่ทำงานกับ WebAssembly เริ่มต้นด้วยการเรียนรู้เกี่ยวกับเครื่องมือ WebAssembly.studio
WebAssembly.studio
เครื่องมือนี้ช่วยให้คุณสามารถรวบรวม C, Rust, Wat to Wasm เป็นต้น
ในการเริ่มต้นคุณสามารถคลิกที่ Empty C Project, Empty Rust Project, Empty Wat Project เพื่อรวบรวม C และ Rust เป็น WASM 5.
มี Build, Run เพื่อสร้างโค้ดและตรวจสอบผลลัพธ์ ปุ่มดาวน์โหลดช่วยให้คุณดาวน์โหลด.wasmไฟล์ที่สามารถใช้ทดสอบภายในเบราว์เซอร์ เครื่องมือนี้มีประโยชน์มากในการรวบรวมรหัส C และ Rust และตรวจสอบผลลัพธ์
WebAssembly Explorer
WebAssembly Explorer ช่วยให้คุณสามารถคอมไพล์โค้ด C และ C ++ อ้างอิงลิงค์https://mbebenita.github.io/WasmExplorer/สำหรับรายละเอียดเพิ่มเติม หน้าจอที่จะปรากฏขึ้นหลังจากคลิกที่ลิงค์ดังแสดงด้านล่าง -
คุณสามารถเลือกเวอร์ชัน C และ C ++ ซอร์สโค้ดของ C หรือ C ++ เขียนไว้ที่นี่ -
เมื่อคุณคลิกที่ปุ่ม Compile มันจะให้รูปแบบข้อความ WebAssembly (WAT) และรหัสประกอบ Firefox x86 ในบล็อกด้านล่าง -
คุณสามารถดาวน์โหลดไฟล์ .wasm รหัสเพื่อทดสอบภายในเบราว์เซอร์
WASMFiddle
Wasmfiddleช่วยให้คุณสามารถคอมไพล์โค้ด C ไปยัง WebAssembly และทดสอบเอาต์พุต หลังจากคลิกที่ลิงค์https://wasdk.github.io/WasmFiddle/, คุณจะเห็นหน้าต่อไปนี้ -
คลิกที่สร้างเพื่อคอมไพล์โค้ด คุณสามารถดาวน์โหลดรหัส Wat and Wasm ได้โดยคลิกที่ Wat and Wasm ในการทดสอบผลลัพธ์ให้คลิกที่ปุ่ม Run
WASM เป็น WAT
เครื่องมือ wat2wasmจะให้รหัส wasm แก่คุณเมื่อคุณป้อนรูปแบบข้อความ WebAssembly คุณสามารถคลิกที่ลิงค์https://webassembly.github.io/wabt/demo/wat2wasm/ สำหรับการสาธิตและหน้าจอที่จะปรากฏขึ้นมีดังต่อไปนี้ -
คุณสามารถใช้ปุ่มอัพโหลดเพื่ออัพโหลด. wasm และ textarea จะแสดงรูปแบบข้อความ
WAT เป็น WASM
เครื่องมือ wat2wasm จะให้รหัส wasm แก่คุณเมื่อคุณป้อนรูปแบบข้อความ WebAssembly คุณสามารถคลิกที่ลิงค์https://webassembly.github.io/wabt/demo/wat2wasm/ สำหรับการสาธิตและหน้าจอที่จะปรากฏขึ้นมีดังต่อไปนี้ -
เครื่องมือนี้มีประโยชน์มากเนื่องจากช่วยในการทดสอบผลลัพธ์ด้วย คุณสามารถป้อนรหัส WAT และดูที่รหัส. wasm และรันโค้ดเพื่อดูผลลัพธ์
WebAssembly หรือที่เรียกว่า WASM เป็นรูปแบบไบนารีโค้ดระดับต่ำที่พัฒนาขึ้นเพื่อเรียกใช้งานภายในเบราว์เซอร์ด้วยวิธีที่มีประสิทธิภาพสูงสุด รหัส WebAssembly มีโครงสร้างตามแนวคิดต่อไปนี้ -
- Values
- Types
- Instructions
ให้เราเรียนรู้โดยละเอียดตอนนี้
ค่า
ค่าใน WebAssembly มีขึ้นเพื่อจัดเก็บข้อมูลที่ซับซ้อนเช่นข้อความสตริงและเวกเตอร์ WebAssembly รองรับสิ่งต่อไปนี้ -
- Bytes
- Integers
- จุดลอยตัว
- Names
ไบต์
ไบต์เป็นรูปแบบที่ง่ายที่สุดของค่าที่รองรับใน WebAssembly ค่าอยู่ในรูปแบบเลขฐานสิบหก
For exampleไบต์แสดงเป็นbสามารถรับจำนวนธรรมชาติ n โดยที่ n <256
byte ::= 0x00| .... |0xFF
จำนวนเต็ม
ใน WebAssembly จำนวนเต็มที่รองรับมีดังต่อไปนี้ -
- i32: จำนวนเต็ม 32 บิต
- i64: จำนวนเต็ม 64 บิต
จุดลอยน้ำ
ใน WebAssembly หมายเลขลอยตัวที่รองรับมีดังต่อไปนี้ -
- f32: จุดลอยตัว 32 บิต
- f64: จุดลอยตัว 64 บิต
ชื่อ
ชื่อคือลำดับของอักขระโดยมีค่าสเกลาร์ที่กำหนดโดย Unicode ซึ่งมีอยู่ที่ลิงค์ http://www.unicode.org/versions/Unicode12.1.0/ ให้ไว้ ณ ที่นี้
ประเภท
เอนทิตีใน WebAssembly ถูกจัดประเภทเป็นประเภท ประเภทที่รองรับมีดังที่ระบุไว้ด้านล่าง -
- ประเภทมูลค่า
- ประเภทผลลัพธ์
- ประเภทฟังก์ชัน
- Limits
- ประเภทหน่วยความจำ
- ประเภทตาราง
- ประเภททั่วโลก
- ประเภทภายนอก
ให้เราศึกษาทีละคน
ประเภทมูลค่า
ประเภทค่าที่ WebAssembly รองรับมีดังต่อไปนี้ -
- i32: จำนวนเต็ม 32 บิต
- i64: จำนวนเต็ม 64 บิต
- f32: จุดลอยตัว 32 บิต
- f64: จุดลอยตัว 64 บิต
valtype ::= i32|i64|f32|f64
ประเภทผลลัพธ์
ค่าที่เขียนไว้ในวงเล็บจะถูกเรียกใช้และเก็บไว้ในประเภทผลลัพธ์ ประเภทผลลัพธ์คือผลลัพธ์ของการเรียกใช้บล็อกโค้ดที่ประกอบด้วยค่า
resulttype::=[valtype?]
ประเภทฟังก์ชัน
ประเภทฟังก์ชันจะใช้เวกเตอร์ของพารามิเตอร์ส่งกลับเวกเตอร์ของผลลัพธ์
functype::=[vec(valtype)]--> [vec(valtype)]
ขีด จำกัด
ขีด จำกัด คือช่วงการจัดเก็บที่เชื่อมโยงกับหน่วยความจำและประเภทตาราง
limits ::= {min u32, max u32}
ประเภทหน่วยความจำ
ประเภทหน่วยความจำจัดการกับความทรงจำเชิงเส้นและช่วงขนาด
memtype ::= limits
ประเภทตาราง
ประเภทตารางแบ่งตามประเภทองค์ประกอบที่กำหนดให้
tabletype ::= limits elemtype
elemtype ::= funcref
ประเภทตารางขึ้นอยู่กับขีด จำกัด ของขนาดต่ำสุดและสูงสุดที่กำหนดให้
ประเภททั่วโลก
Global Type เก็บตัวแปรส่วนกลางที่มีค่าซึ่งสามารถเปลี่ยนแปลงหรือคงเดิมได้
globaltype ::= mut valtype
mut ::= const|var
ประเภทภายนอก
ประเภทภายนอกเกี่ยวข้องกับการนำเข้าและค่าภายนอก
externtype ::= func functype | table tabletype | mem memtype | global globaltype
คำแนะนำ
รหัส WebAssembly คือลำดับของคำสั่งที่เป็นไปตามรูปแบบเครื่องสแต็ก เนื่องจาก WebAssembly เป็นไปตามรุ่นของเครื่องสแต็กคำแนะนำจะถูกผลักลงบนสแต็ก
ตัวอย่างเช่นค่าอาร์กิวเมนต์สำหรับฟังก์ชันถูกดึงออกมาจากสแต็กและผลลัพธ์จะถูกผลักกลับไปที่สแต็ก ในท้ายที่สุดจะมีเพียงค่าเดียวในสแตกและนั่นคือผลลัพธ์
คำแนะนำที่ใช้กันทั่วไปมีดังนี้ -
- คำแนะนำเกี่ยวกับตัวเลข
- คำแนะนำตัวแปร
คำแนะนำเกี่ยวกับตัวเลข
คำแนะนำตัวเลขคือการดำเนินการซึ่งดำเนินการกับค่าตัวเลข
For examplenn, 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
คำแนะนำตัวแปร
คำแนะนำตัวแปรเกี่ยวกับการเข้าถึงตัวแปรภายในและทั่วโลก
For example
ในการเข้าถึงตัวแปรท้องถิ่น -
get_local $a
get_local $b
ถึง set ตัวแปรท้องถิ่น -
set_local $a
set_local $b
ถึง access ตัวแปรทั่วโลก -
get_global $a
get_global $b
ถึง set ตัวแปรทั่วโลก -
set_global $a
set_global $b
บทนี้จะแสดงการเปรียบเทียบระหว่าง WebAssembly และ Javascript
Javascript เป็นภาษาที่เราใช้กันมากในเบราว์เซอร์ ขณะนี้ด้วยการเปิดตัว WebAssembly เรายังสามารถใช้ WebAssembly ภายในเบราว์เซอร์
เหตุผลที่ทำให้ WebAssembly ไม่ได้มาแทนที่ javascript แต่เพื่อดูแลบางสิ่งซึ่งยากที่จะจัดการกับ javascript
For example
เป็นเรื่องยากที่จะทำงานเช่นการจดจำภาพ, แอปพลิเคชัน CAD, การเพิ่มวิดีโอสด, VR และความเป็นจริงที่เพิ่มขึ้น, แอปพลิเคชั่นเพลง, การสร้างภาพและจำลองทางวิทยาศาสตร์, เกม, การตัดต่อรูปภาพ / วิดีโอเป็นต้นโดยใช้จาวาสคริปต์
การใช้ภาษาระดับสูงเช่น C / C ++, Rust ซึ่งตอนนี้สามารถคอมไพล์ไปยัง WebAssembly ได้ทำให้งานที่กล่าวถึงข้างต้นทำได้ง่ายขึ้น WebAssembly สร้างรหัสไบนารีที่ง่ายต่อการเรียกใช้งานภายในเบราว์เซอร์
นี่คือรายการการเปรียบเทียบระหว่าง Javascript และ WebAssembly
พารามิเตอร์ | Javascript | WebAssembly |
---|---|---|
การเข้ารหัส |
คุณสามารถเขียนโค้ดใน Javascript ได้อย่างง่ายดาย โค้ดที่เขียนขึ้นนั้นมนุษย์สามารถอ่านได้และบันทึกเป็น. js เมื่อใช้ภายในเบราว์เซอร์คุณต้องใช้แท็ก <script> |
สามารถเขียนโค้ดในรูปแบบข้อความใน WebAssembly และบันทึกเป็น .wat เป็นการยากที่จะเขียนโค้ดในรูปแบบ. wat ที่ดีที่สุดคือรวบรวมโค้ดจากภาษาระดับสูงอื่น ๆ แทนที่จะเขียนตั้งแต่เริ่มต้นใน. คุณไม่สามารถเรียกใช้ไฟล์ .wat ภายในเบราว์เซอร์และต้องแปลงเป็น. wasm โดยใช้คอมไพเลอร์หรือเครื่องมือออนไลน์ที่มีให้ |
การดำเนินการ |
โค้ดที่เขียนด้วย javascript เมื่อใช้ภายในเบราว์เซอร์จะต้องดาวน์โหลดแยกวิเคราะห์รวบรวมและปรับให้เหมาะสม |
เรามีโค้ด WebAssembly ใน. wasm ที่คอมไพล์แล้วและอยู่ในรูปแบบไบนารี |
การจัดการหน่วยความจำ |
Javascript กำหนดหน่วยความจำเมื่อมีการสร้างตัวแปรและหน่วยความจำจะถูกปล่อยออกมาเมื่อไม่ได้ใช้งานและเพิ่มลงในการรวบรวมขยะ |
หน่วยความจำใน WebAssembly คืออาร์เรย์บัฟเฟอร์ที่เก็บข้อมูล คุณสามารถจัดสรรหน่วยความจำโดยใช้ Javascript API WebAssembly.memory () หน่วยความจำ WebAssembly ถูกจัดเก็บในรูปแบบอาร์เรย์เช่นรูปแบบหน่วยความจำแบบแบนที่เข้าใจง่ายและดำเนินการ ข้อเสียของโมเดลหน่วยความจำใน WebAssembly คือ -
|
โหลดเวลาและประสิทธิภาพ |
ในกรณีของ javascript เมื่อเรียกใช้ภายในเบราว์เซอร์ไฟล์ javascript จะต้องถูกดาวน์โหลดและแยกวิเคราะห์ ต่อมาตัวแยกวิเคราะห์จะแปลงซอร์สโค้ดเป็น bytecode ซึ่งเอ็นจิ้นจาวาสคริปต์จะเรียกใช้โค้ดในเบราว์เซอร์ เอ็นจิ้น Javascript มีประสิทธิภาพมากดังนั้นเวลาในการโหลดและประสิทธิภาพของ javascript จึงเร็วมากเมื่อเทียบกับ WebAssembly |
เป้าหมายที่สำคัญที่สุดของ WebAssembly คือต้องเร็วกว่า JavaScript รหัส WAT ที่สร้างจากภาษาระดับสูงมีขนาดเล็กกว่าและด้วยเหตุนี้เวลาในการโหลดจึงเร็วกว่า แต่ภาษาเช่น GO เมื่อคอมไพล์เป็น wasm จะทำให้ไฟล์มีขนาดใหญ่สำหรับโค้ดชิ้นเล็ก ๆ WebAssembly ได้รับการออกแบบมาเพื่อให้รวบรวมได้เร็วขึ้นและสามารถทำงานบนเบราว์เซอร์หลัก ๆ ทั้งหมดได้ WebAssembly ยังคงต้องเพิ่มการปรับปรุงมากมายในแง่ของประสิทธิภาพเมื่อเทียบกับจาวาสคริปต์ |
การแก้จุดบกพร่อง |
Javascript สามารถอ่านได้โดยมนุษย์และสามารถแก้จุดบกพร่องได้อย่างง่ายดาย การเพิ่มเบรกพอยต์ลงในโค้ดจาวาสคริปต์ของคุณภายในเบราว์เซอร์ทำให้คุณสามารถดีบักโค้ดได้อย่างง่ายดาย |
WebAssembly จัดเตรียมโค้ดในรูปแบบข้อความซึ่งสามารถอ่านได้ แต่ก็ยังแก้ไขจุดบกพร่องได้ยากมาก Firefox อนุญาตให้คุณดูรหัส wasm ในรูปแบบ .wat ภายในเบราว์เซอร์ คุณไม่สามารถเพิ่มเบรกพอยต์ใน .wat ได้และนั่นคือสิ่งที่จะพร้อมใช้งานในอนาคต |
รองรับเบราว์เซอร์ |
Javascript ทำงานได้ดีในทุกเบราว์เซอร์ |
เว็บเบราว์เซอร์หลัก ๆ ทั้งหมดรองรับ WebAssembly |
ในบทนี้เราจะเข้าใจวิธีการโหลดรหัส wasm และเรียกใช้งานในเบราว์เซอร์โดยใช้ javascript webassembly API
นี่คือ API ที่สำคัญบางส่วนเราจะใช้ตลอดทั้งบทช่วยสอนในการรันโค้ด wasm
- fetch () Browser API
- WebAssembly.compile
- WebAssembly.instance
- WebAssembly.instantiate
- WebAssembly.instantiateStreaming
ก่อนที่เราจะพูดถึง WebAssembly javascript API เพื่อทดสอบ API และเอาต์พุตเราจะใช้โปรแกรม C ต่อไปนี้และรหัส. wasm ที่สร้างจากโปรแกรม c โดยใช้ wasm explorer
ตัวอย่างโปรแกรม C มีดังต่อไปนี้ -
#include<stdio.h>
int square(int n) {
return n*n;
}
เราจะใช้ประโยชน์จาก WASM explorer เพื่อรับรหัส wasm -
ดาวน์โหลดรหัส WASM และใช้เพื่อทดสอบ API
fetch () Browser API
fetch () API มีไว้เพื่อโหลดทรัพยากรเครือข่าย. wasm
<script>
var result = fetch("findsquare.wasm");
console.log(result);
</script>
มันคืนสัญญาดังที่แสดงด้านล่าง -
คุณยังสามารถใช้เมธอด XMLHttpRequest เพื่อดึงทรัพยากรเครือข่าย wasm
WebAssembly.compile ()
ความรับผิดชอบของ api คือการรวบรวมรายละเอียดโมดูลที่ดึงมาจาก. wasm
ไวยากรณ์
ไวยากรณ์เป็นไปตามที่ระบุด้านล่าง -
WebAssembly.compile(buffer);
พารามิเตอร์
Buffer - รหัสจาก. wasm นี้จะต้องถูกแปลงเป็นอาร์เรย์ที่พิมพ์หรืออาร์เรย์บัฟเฟอร์ก่อนที่จะให้เป็นอินพุตในการคอมไพล์
ส่งคืนค่า
มันจะส่งคืนสัญญาว่าจะมีโมดูลที่คอมไพล์
ตัวอย่าง
ให้เราดูตัวอย่างหนึ่งที่ให้ผลลัพธ์เป็นโมดูลที่คอมไพล์โดยใช้ webAssembly.compile ()
<script>
fetch("findsquare.wasm") .then(bytes => bytes.arrayBuffer())
.then(mod => {
var compiledmod = WebAssembly.compile(mod);
compiledmod.then(test=> {
console.log(test);
})
})
</script>
เอาต์พุต
console.log เมื่อตรวจสอบในเบราว์เซอร์จะให้รายละเอียดโมดูลที่คอมไพล์ -
โมดูลมีอ็อบเจ็กต์คอนสตรัคเตอร์พร้อมอิมพอร์ตเอ็กซ์พอร์ตและ customSections ให้เราดู API ถัดไปเพื่อรับรายละเอียดเพิ่มเติมของโมดูลที่คอมไพล์
WebAssembly.instance
เมื่อใช้ WebAssembly.instance API จะให้อินสแตนซ์ที่สามารถเรียกใช้งานได้ของโมดูลที่คอมไพล์แล้วซึ่งสามารถเรียกใช้งานเพิ่มเติมเพื่อรับเอาต์พุตได้
ไวยากรณ์
ไวยากรณ์เป็นไปตามที่ระบุด้านล่าง -
new WebAssembly.Instance(compiled module)
ส่งคืนค่า
ค่าที่ส่งคืนจะเป็นวัตถุที่มีฟังก์ชันการส่งออกอาร์เรย์ที่สามารถเรียกใช้งานได้
ตัวอย่าง
<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>
เอาต์พุต
ผลลัพธ์จะทำให้เรามีฟังก์ชันการส่งออกอาร์เรย์ดังที่แสดงด้านล่าง -
คุณสามารถดูฟังก์ชันสี่เหลี่ยมที่เราได้จากโค้ด C ที่คอมไพล์
ในการเรียกใช้ฟังก์ชันกำลังสองคุณสามารถทำสิ่งต่อไปนี้ -
<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>
ผลลัพธ์จะเป็น -
225
WebAssembly.instantiate
API นี้ดูแลการคอมไพล์และอินสแตนซ์โมดูลเข้าด้วยกัน
ไวยากรณ์
ไวยากรณ์มีดังนี้ -
WebAssembly.instantiate(arraybuffer, importObject)
พารามิเตอร์
arraybuffer - รหัสจาก. wasm จะต้องถูกแปลงเป็นอาร์เรย์ที่พิมพ์หรืออาร์เรย์บัฟเฟอร์ก่อนที่จะให้เป็นอินพุตเพื่อสร้างอินสแตนซ์
importObject- วัตถุนำเข้าจะต้องมีรายละเอียดของหน่วยความจำฟังก์ชันที่นำเข้าเพื่อใช้ภายในโมดูล อาจเป็นอ็อบเจ็กต์โมดูลว่างในกรณีที่ไม่มีสิ่งใดที่จะแชร์
ส่งคืนค่า
มันจะกลับคำสัญญาซึ่งจะมีรายละเอียดโมดูลและอินสแตนซ์
ตัวอย่าง
<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>
เอาต์พุต
เมื่อคุณรันโค้ดคุณจะได้รับผลลัพธ์ที่กล่าวถึงด้านล่าง
WebAssembly.instantiateStreaming
API นี้ดูแลการคอมไพล์และการสร้างอินสแตนซ์โมดูล WebAssembly จากรหัส. wasm ที่กำหนด
ไวยากรณ์
ไวยากรณ์เป็นไปตามที่ระบุด้านล่าง -
WebAssembly.instantiateStreaming(wasmcode, importObject);
พารามิเตอร์
wasmcode - การตอบสนองจากการดึงข้อมูลหรือ API อื่น ๆ ที่ให้รหัส wasm และส่งคืนสัญญา
importObject- วัตถุนำเข้าจะต้องมีรายละเอียดของหน่วยความจำฟังก์ชันที่นำเข้าเพื่อใช้ภายในโมดูล อาจเป็นอ็อบเจ็กต์โมดูลว่างในกรณีที่ไม่มีอะไรจะแชร์
ส่งคืนค่า
มันจะกลับคำสัญญาซึ่งจะมีรายละเอียดโมดูลและอินสแตนซ์
ตัวอย่าง
ตัวอย่างจะกล่าวถึงด้านล่าง -
<script type="text/javascript">
const importObj = {
module: {}
};
WebAssembly.instantiateStreaming(fetch("findsquare.wasm"), importObj).then(obj => {
console.log(obj);
});
</script>
เมื่อคุณทดสอบในเบราว์เซอร์คุณจะเห็นข้อผิดพลาด -
เพื่อให้มันทำงานที่ส่วนท้ายเซิร์ฟเวอร์ของคุณคุณจะต้องเพิ่มแอปพลิเคชั่นประเภท mime / wasm หรือใช้ประโยชน์จาก WebAssembly.instantiate (arraybuffer, importObject)
มีการเพิ่มการสนับสนุน WebAssembly ในเบราว์เซอร์ล่าสุดทั้งหมดที่มีให้คุณในวันนี้เช่น Chrome, Firefox Firefox เวอร์ชัน 54+ เป็นต้นไปให้คุณสมบัติพิเศษในการดีบักรหัส wasm ของคุณ
ในการทำเช่นนั้นให้รันโค้ดของคุณในเบราว์เซอร์ Firefox ที่เรียกว่า wasm ตัวอย่างเช่นพิจารณาตามรหัส C ที่ค้นหากำลังสองของตัวเลข
ตัวอย่างโปรแกรม C มีดังต่อไปนี้ -
#include<stdio.h>
int square(int n) {
return n*n;
}
เราจะใช้ WASM explorer เพื่อรับรหัส wasm -
ดาวน์โหลดรหัส WASM และใช้เพื่อดูผลลัพธ์ในเบราว์เซอร์
ไฟล์ html ที่โหลด wasm มีดังนี้ -
!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>
เปิดเบราว์เซอร์ Firefox และโหลดไฟล์ html ด้านบนและเปิดเครื่องมือดีบักเกอร์
คุณควรเห็นรายการ wasm: // ในเครื่องมือดีบั๊ก คลิกที่ wasm: // และจะแสดงรหัส wasm ที่แปลงเป็นรูปแบบ. wat ดังที่แสดงด้านบน
คุณสามารถดูรหัสของฟังก์ชันที่ส่งออกและแก้ไขข้อบกพร่องของรหัสได้หากมีปัญหาเกิดขึ้น Firefox ยังตั้งใจที่จะเพิ่มเบรกพอยต์เพื่อให้คุณสามารถดีบักโค้ดและตรวจสอบขั้นตอนการดำเนินการได้
ในบทนี้เราจะเขียนโปรแกรมง่ายๆในภาษา C และแปลงเป็น. wasm และดำเนินการเหมือนกันในเบราว์เซอร์เพื่อรับข้อความ "Hello World"
จะใช้ประโยชน์จาก wasm explorer tool ที่จะแปลงโปรแกรม C เป็น. wasm และจะใช้ประโยชน์จาก. wasm ในไฟล์. html ของเรา
เครื่องมือ Wasm explorer ซึ่งมีให้ที่ https://mbebenita.github.io/WasmExplorer/ looks as follows −
รหัส C ที่เราจะใช้มีดังนี้ -
#include <stdio.h>
char *c_hello() {
return "Hello World";
}
อัปเดตบล็อกแรกใน wasm explorer ด้วยรหัส C ดังที่แสดงด้านล่าง -
คลิกที่ปุ่ม COMPILE เพื่อคอมไพล์เป็น WASM และ WAT และ Firefox x86 Web Assembly ดังที่แสดงด้านล่าง -
ใช้ DOWNLOAD เพื่อรับไฟล์. wasm และบันทึกเป็นไฟล์ firstprog.wasm.
สร้างไฟล์. html ชื่อ firstprog.html ดังภาพด้านล่าง -
<!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>
ให้เราใช้ firstprog.wasm เพื่ออ่าน helloworld จากฟังก์ชัน C c_hello ()
ขั้นตอนที่ 1
ใช้ fetch () api เพื่ออ่านโค้ด firstprog.wasm
ขั้นตอนที่ 2
รหัส. wasm จะต้องถูกแปลงเป็น arraybuffer โดยใช้ ArrayBuffer. วัตถุ ArrayBuffer จะส่งคืนบัฟเฟอร์ข้อมูลไบนารีที่มีความยาวคงที่
รหัสจนถึงตอนนี้จะเป็นดังนี้ -
<script type="text/javascript">
fetch("firstprog.wasm") .then(bytes => bytes.arrayBuffer())
</script>
ขั้นตอนที่ 3
ไบต์จาก ArrayBuffer จะต้องรวบรวมลงในโมดูลโดยใช้ WebAssembly.compile(buffer) ฟังก์ชัน
โค้ดจะมีลักษณะดังนี้ -
<script type="text/javascript">
fetch("firstprog.wasm")
.then(bytes => bytes.arrayBuffer())
.then(mod => WebAssembly.compile(mod))
</script>
ขั้นตอนที่ 4
ในการรับโมดูลเราต้องเรียกตัวสร้าง webassembly.instance ดังที่แสดงด้านล่าง -
<script type="text/javascript">
fetch("firstprog.wasm")
.then(bytes => bytes.arrayBuffer())
.then(mod => WebAssembly.compile(mod))
.then(module => {return new WebAssembly.Instance(module) })
</script>
ขั้นตอนที่ 5
ตอนนี้ให้เราคอนโซลอินสแตนซ์เพื่อดูรายละเอียดในเบราว์เซอร์
<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>
รายละเอียด console.log แสดงไว้ด้านล่าง -
ในการรับสตริง“ Hello World” จากฟังก์ชัน c_hello () เราต้องเพิ่มโค้ดในจาวาสคริปต์
ขั้นแรกรับรายละเอียดบัฟเฟอร์หน่วยความจำดังที่แสดงด้านล่าง -
let buffer = instance.exports.memory.buffer;;
ค่าบัฟเฟอร์จะต้องถูกแปลงเป็นอาร์เรย์ที่พิมพ์เพื่อให้เราสามารถอ่านค่าจากมันได้ บัฟเฟอร์มีสตริง Hello World อยู่ในนั้น
หากต้องการแปลงเป็นพิมพ์ให้เรียกตัวสร้าง Uint8Array ดังที่แสดงด้านล่าง -
let buffer = new Uint8Array(instance.exports.memory.buffer);
ตอนนี้เราสามารถอ่านค่าจากบัฟเฟอร์ใน for - loop
ตอนนี้ให้เราได้รับจุดเริ่มต้นในการอ่านบัฟเฟอร์โดยเรียกใช้ฟังก์ชันที่เราเขียนตามที่แสดงด้านล่าง -
let test = instance.exports.c_hello();
ตอนนี้ตัวแปรทดสอบมีจุดเริ่มต้นในการอ่านสตริงของเรา WebAssembly ไม่มีค่าสตริงทุกอย่างจะถูกจัดเก็บเป็นจำนวนเต็ม
ดังนั้นเมื่อเราอ่านค่าจากบัฟเฟอร์ค่าเหล่านี้จะเป็นค่าจำนวนเต็มและเราต้องแปลงเป็นสตริงโดยใช้ fromCharCode () ใน javascript
รหัสมีดังนี้ -
let mytext = "";
for (let i=test; buffer[i]; i++){
mytext += String.fromCharCode(buffer[i]);
}
ตอนนี้เมื่อคุณคอนโซล mytext คุณจะเห็นสตริง“ Hello World”
ตัวอย่าง
รหัสที่สมบูรณ์มีดังนี้ -
<!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>
เราได้เพิ่ม div และเนื้อหาจะถูกเพิ่มเข้าไปใน div ดังนั้นสตริงจึงแสดงบนเบราว์เซอร์
เอาต์พุต
ผลลัพธ์จะกล่าวถึงด้านล่าง -
เราได้เห็นวิธีรับไฟล์. wasm จากรหัส c / c ++ ในบทนี้เราจะแปลง wasm เป็นโมดูล WebAssembly และดำเนินการเดียวกันในเบราว์เซอร์
ให้เราใช้รหัส C ++ Factorial ดังที่แสดงด้านล่าง -
int fact(int n) {
if ((n==0)||(n==1))
return 1;
else
return n*fact(n-1);
}
เปิด Wasm Explorer ซึ่งมีอยู่ที่ https://mbebenita.github.io/WasmExplorer/ as shown below −
คอลัมน์แรกมีฟังก์ชันแฟกทอเรียล C ++ คอลัมน์ที่ 2 มีรูปแบบข้อความ WebAssembly และคอลัมน์สุดท้ายมีรหัส x86 Assembly
รูปแบบ WebAssembly Text -
(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)
)
)
ฟังก์ชัน C ++ fact ได้รับการส่งออกเป็น“_Z4facti” ในรูปแบบ WebAssembly Text
คลิกที่ปุ่มดาวน์โหลดเพื่อดาวน์โหลดรหัส wasm และบันทึกไฟล์เป็น factorial.wasm
ตอนนี้ในการแปลงรหัส. wasm เป็นโมดูลเราต้องทำสิ่งต่อไปนี้ -
ขั้นตอนที่ 1
แปลง. wasm เป็น arraybuffer โดยใช้ ArrayBuffer. วัตถุ ArrayBuffer จะส่งคืนบัฟเฟอร์ข้อมูลไบนารีที่มีความยาวคงที่
ขั้นตอนที่ 2
ไบต์จาก ArrayBuffer จะต้องรวบรวมลงในโมดูลโดยใช้ WebAssembly.compile(buffer) ฟังก์ชัน
WebAssembly.compile() ฟังก์ชันคอมไพล์และส่งคืน WebAssembly.Module จากไบต์ที่กำหนด
นี่คือโค้ด Javascript ที่กล่าวถึงในขั้นตอนที่ 1 และ 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>
คำอธิบายรหัส
Javascript browser API fetch ใช้เพื่อรับเนื้อหาของ factorial.wasm
เนื้อหาถูกแปลงเป็นไบต์โดยใช้ arrayBuffer ()
โมดูลถูกสร้างขึ้นจากไบต์โดยเรียก WebAssembly.compile (mod)
อินสแตนซ์ของโมดูลถูกสร้างขึ้นโดยใช้ new
WebAssembly.Instance(module)
ฟังก์ชันแฟกทอเรียลเอ็กซ์พอร์ต _Z4facti ถูกกำหนดให้กับตัวแปรแฟกทอเรียลโดยใช้ WebAssembly.Module.exports ()
ตัวอย่าง
นี่คือ module.html พร้อมกับรหัสจาวาสคริปต์ -
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>
เอาต์พุต
ดำเนินการ module.html ในเบราว์เซอร์เพื่อดูผลลัพธ์ -
ในบทนี้เราจะพูดถึงฟังก์ชัน webassembly.validate () ที่จะตรวจสอบเอาต์พุต. wasm .wasm สามารถใช้ได้เมื่อเราคอมไพล์ C, C ++ หรือรหัสสนิม
คุณสามารถใช้เครื่องมือต่อไปนี้เพื่อรับรหัส wasm
Wasm Fiddler ซึ่งมีอยู่ที่ https://wasdk.github.io/WasmFiddle/
WebAssembly Explorer ซึ่งมีอยู่ที่ https://mbebenita.github.io/WasmExplorer/.
ไวยากรณ์
ไวยากรณ์เป็นไปตามที่ระบุด้านล่าง -
WebAssembly.validate(bufferSource);
พารามิเตอร์
bufferSource- bufferSource มีรหัสไบนารีที่มาจากโปรแกรม C, C ++ หรือ Rust มันอยู่ในรูปแบบของ typedarray หรือ ArrayBuffer
ส่งคืนค่า
ฟังก์ชันจะคืนค่าเป็นจริงหากรหัส. wasm ถูกต้องและเป็นเท็จถ้าไม่
ให้เราลองดูตัวอย่าง ไปที่Wasm fiddlerซึ่งมีให้ที่https://wasdk.github.io/WasmFiddle/, ป้อนรหัส C ที่คุณเลือกและลงรหัส wasm
บล็อกที่มีเครื่องหมายสีแดงคือรหัส C คลิกที่ปุ่มสร้างตรงกลางเพื่อรันโค้ด
คลิกที่ปุ่ม Wasm เพื่อดาวน์โหลดรหัส. wasm บันทึก. wasm ในตอนท้ายของคุณและให้เราใช้สิ่งเดียวกันนี้เพื่อตรวจสอบความถูกต้อง
ตัวอย่าง
ตัวอย่างเช่น: 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>
ฉันได้โฮสต์ไฟล์. html ข้างต้นในเซิร์ฟเวอร์ wamp พร้อมกับไฟล์ดาวน์โหลด. wasm นี่คือผลลัพธ์เมื่อคุณทดสอบในเบราว์เซอร์
เอาต์พุต
ผลลัพธ์มีดังต่อไปนี้ -
WebAssembly มีรหัสในรูปแบบไบนารีที่เรียกว่า WASM คุณยังสามารถรับรูปแบบข้อความใน WebAssembly และเรียกว่า WAT (รูปแบบ WebAssembly Text) ในฐานะนักพัฒนาคุณไม่ควรเขียนโค้ดใน WebAssembly แทนคุณต้องรวบรวมภาษาระดับสูงเช่น C, C ++ และ Rust เป็น WebAssembly
รหัส WAT
ให้เราเขียนรหัส WAT ตามลำดับ
Step 1 - จุดเริ่มต้นใน WAT คือการประกาศโมดูล
(module)
Step 2 - ให้เราเพิ่มฟังก์ชั่นบางอย่างในรูปแบบของฟังก์ชัน
มีการประกาศฟังก์ชันดังที่แสดงด้านล่าง -
(func <parameters/result> <local variables> <function body>)
ฟังก์ชันเริ่มต้นด้วยคีย์เวิร์ด func ซึ่งตามด้วยพารามิเตอร์หรือผลลัพธ์
พารามิเตอร์ / ผลลัพธ์
พารามิเตอร์และค่าที่ส่งคืนเป็นผลลัพธ์
พารามิเตอร์สามารถมีประเภทต่อไปนี้ที่รองรับโดย wasm -
- i32: จำนวนเต็ม 32 บิต
- i64: จำนวนเต็ม 64 บิต
- f32: โฟลต 32 บิต
- f64: ลอย 64 บิต
พารามิเตอร์สำหรับฟังก์ชันถูกเขียนตามที่ระบุด้านล่าง -
- (พารามิเตอร์ i32)
- (พารามิเตอร์ i64)
- (พารามิเตอร์ f32)
- (พารามิเตอร์ f64)
ผลลัพธ์จะถูกเขียนดังนี้ -
- (ผลลัพธ์ i32)
- (ผลลัพธ์ i64)
- (ผลลัพธ์ f32)
- (ผลลัพธ์ f64)
ฟังก์ชันที่มีพารามิเตอร์และค่าส่งกลับจะถูกกำหนดดังนี้ -
(func (param i32) (param i32) (result i64) <function body>)
ตัวแปรท้องถิ่น
ตัวแปรท้องถิ่นคือตัวแปรที่คุณต้องการในฟังก์ชันของคุณ ค่าท้องถิ่นของฟังก์ชันจะถูกกำหนดดังนี้ -
(func (param i32) (param i32) (local i32) (result i64) <function body>)
ฟังก์ชั่นร่างกาย
เนื้อความของฟังก์ชันคือตรรกะที่จะดำเนินการ โปรแกรมสุดท้ายจะมีลักษณะดังนี้ -
(module (func (param i32) (param i32) (local i32) (result i64) <function body>) )
Step 3 - เพื่ออ่านและตั้งค่าพารามิเตอร์และตัวแปรท้องถิ่น
หากต้องการอ่านพารามิเตอร์และตัวแปรภายในให้ใช้ get_local และ set_local คำสั่ง
Example
(module
(func (param i32) (param i32) (local i32) (result i64) get_local 0
get_local 1
get_local 2
)
)
ตามลายเซ็นของฟังก์ชัน
get_local 0 จะให้ param i32
get_local 1 จะให้พารามิเตอร์ถัดไป param i32
get_local 2 จะให้ local value i32
แทนที่จะอ้างถึงพารามิเตอร์และภาษาท้องถิ่นโดยใช้ค่าตัวเลขเช่น 0,1,2 คุณยังสามารถใช้ชื่อนำหน้าพารามิเตอร์โดยนำหน้าชื่อด้วยเครื่องหมายดอลลาร์
ตัวอย่างต่อไปนี้แสดงวิธีใช้ชื่อกับพารามิเตอร์และภาษาท้องถิ่น
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 - คำสั่งในตัวฟังก์ชันและการดำเนินการ
การดำเนินการใน wasm เป็นไปตามกลยุทธ์สแต็ก คำสั่งที่ดำเนินการจะถูกส่งไปทีละสแต็ก ตัวอย่างเช่นคำสั่ง get_local $ a จะพุชค่ามันอ่านบนสแต็ก
คำสั่งเช่น i32.add ที่จะเพิ่มองค์ประกอบจะปรากฏจากสแต็ก
(func (param $a i32) (param $b i32) get_local $a
get_local $b
i32.add
)
คำแนะนำสำหรับ i32.add คือ ($a+$b). ค่าสุดท้ายของ i32.add จะถูกพุชบนสแต็กและจะถูกกำหนดให้กับผลลัพธ์
หากลายเซ็นของฟังก์ชันมีการประกาศผลลัพธ์ควรมีค่าหนึ่งในสแต็กเมื่อสิ้นสุดการเรียกใช้งาน หากไม่มีพารามิเตอร์ผลลัพธ์สแต็กจะต้องว่างเปล่าในตอนท้าย
ดังนั้นรหัสสุดท้ายพร้อมกับเนื้อหาของฟังก์ชันจะเป็นดังนี้ -
(module
(func (param $a i32) (param $b i32) (result i32) get_local $a
get_local $b
i32.add
)
)
Step 5 - การโทรไปยังฟังก์ชัน
รหัสสุดท้ายที่มีเนื้อความของฟังก์ชันดังแสดงในขั้นตอนที่ 4 ตอนนี้ในการเรียกใช้ฟังก์ชันเราจำเป็นต้องส่งออก
ในการส่งออกฟังก์ชันสามารถทำได้โดยใช้ค่าดัชนีเช่น 0,1 แต่เราสามารถตั้งชื่อได้ด้วย ชื่อจะนำหน้าด้วย $ และจะถูกเพิ่มหลังคำหลัก func
Example
(module
(func $add (param $a i32) (param $b i32) (result i32) get_local $a
get_local $b i32.add
)
)
ฟังก์ชัน $ add จะต้องถูกส่งออกโดยใช้คำสำคัญการส่งออกดังที่แสดงด้านล่าง -
(module
(func $add (param $a i32)
(param $b i32) (result i32) get_local $a get_local $b i32.add ) (export "add" (func $add))
)
ในการทดสอบโค้ดด้านบนในเบราว์เซอร์คุณจะต้องแปลงเป็นรูปแบบไบนารี (.wasm) อ้างถึงบทถัดไปที่แสดงวิธีการแปลง.WAT to .WASM.
ในบทที่แล้วเราได้เห็นวิธีการเขียนโค้ดใน .watนั่นคือรูปแบบข้อความ WebAssembly รูปแบบข้อความ WebAssembly จะไม่ทำงานโดยตรงในเบราว์เซอร์และคุณต้องแปลงเป็นรูปแบบไบนารีเช่น WASM เพื่อทำงานภายในเบราว์เซอร์
WAT เป็น WASM
ให้เราแปลง. WAT เป็น. WASM
รหัสที่เราจะใช้มีดังนี้ -
(module
(func $add (param $a i32) (param $b i32) (result i32) get_local $a
get_local $b i32.add ) (export "add" (func $add))
)
ตอนนี้ไปที่ WebAssembly Studioซึ่งมีอยู่ที่ https://webassembly.studio/.
คุณควรเห็นสิ่งนี้เมื่อคุณกดลิงก์ -
คลิกที่โครงการ Empty Wat และคลิกที่ปุ่มสร้างที่ด้านล่าง
จะนำคุณไปยังโครงการที่ว่างเปล่าดังที่แสดงด้านล่าง -
คลิกที่ main.wat และแทนที่รหัสที่มีอยู่ด้วยรหัสของคุณแล้วคลิกที่ปุ่มบันทึก
เมื่อบันทึกแล้วให้คลิกที่บิลด์เพื่อแปลงเป็น. wasm -
หากการสร้างสำเร็จคุณจะเห็นไฟล์. wasm ที่สร้างขึ้นดังที่แสดงด้านล่าง -
ลงไฟล์ main.wasm และใช้ในไฟล์. html ของคุณเพื่อดูผลลัพธ์ตามที่แสดงด้านล่าง
ตัวอย่างเช่น - 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>
ฟังก์ชันเพิ่มจะถูกส่งออกตามที่แสดงในโค้ด พารามิเตอร์ที่ส่งผ่านคือ 2 ค่าจำนวนเต็ม 10 และ 40 และจะส่งกลับผลรวมของมัน
เอาต์พุต
ผลลัพธ์จะแสดงในเบราว์เซอร์
การลิงก์แบบไดนามิกคือกระบวนการที่โมดูลสองโมดูลขึ้นไปจะถูกเชื่อมโยงเข้าด้วยกันระหว่างรันไทม์
เพื่อแสดงให้เห็นว่าการเชื่อมโยงแบบไดนามิกทำงานอย่างไรเราจะใช้โปรแกรม C และรวบรวมเป็น wasm โดยใช้ Ecmascript sdk
ที่นี่เรามี -
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;
}
ในรหัส main.c จะใช้ test1 () และ test2 () ซึ่งกำหนดไว้ใน test1.c และ test2.c ให้เราตรวจสอบวิธีการเชื่อมโยงโมดูลเหล่านี้ใน WebAssembly
คำสั่งในการคอมไพล์โค้ดด้านบนมีดังนี้: ใช้ SIDE_MODULE = 1 สำหรับการลิงก์แบบไดนามิกดังที่แสดงในคำสั่ง
emcc test1.c test2.c main.c -s SIDE_MODULE=1 -o maintest.wasm
ใช้ WasmtoWat ซึ่งมีอยู่ที่ https://webassembly.github.io/wabt/demo/wasm2wat/จะได้รูปแบบข้อความ WebAssembly ของ 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))
)
รูปแบบข้อความ WebAssembly มีการนำเข้าบางส่วนที่กำหนดดังที่แสดงด้านล่าง -
(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))
สิ่งนี้ถูกเพิ่มในขณะที่รวบรวมโค้ดโดย emcc (emscripten sdk) และเกี่ยวข้องกับการจัดการหน่วยความจำใน WebAssembly
การทำงานกับการนำเข้าและส่งออก
ตอนนี้เพื่อดูผลลัพธ์เราจะต้องกำหนดการนำเข้าที่คุณสามารถเห็นได้ในรหัส.
(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))
คำศัพท์ข้างต้นอธิบายได้ดังนี้ -
env.stackSave - ใช้สำหรับการจัดการสแต็กซึ่งเป็นฟังก์ชันที่จัดทำโดยโค้ดที่คอมไพล์ emscripten
env.stackRestore - ใช้สำหรับการจัดการสแต็กซึ่งเป็นฟังก์ชันที่จัดทำโดยโค้ดที่คอมไพล์ emscripten
env.__memory_base- เป็นออฟเซ็ตสากล i32 ที่ไม่เปลี่ยนรูปซึ่งใช้ใน env.memory และสงวนไว้สำหรับโมดูล wasm โมดูลสามารถใช้ global นี้ในตัวเริ่มต้นของเซ็กเมนต์ข้อมูลเพื่อให้โหลดในที่อยู่ที่ถูกต้อง
env.__table_base- เป็นออฟเซ็ตสากล i32 ที่ไม่เปลี่ยนรูปซึ่งใช้ใน env.table และสงวนไว้สำหรับโมดูล wasm โมดูลสามารถใช้โกลบอลนี้ในตัวเริ่มต้นของเซกเมนต์องค์ประกอบตารางเพื่อให้โหลดในออฟเซ็ตที่ถูกต้อง
env.memory - จะมีรายละเอียดหน่วยความจำที่ต้องใช้ร่วมกันระหว่างโมดูล wasm
env.table - จะมีรายละเอียดตารางที่ต้องใช้ร่วมกันระหว่างโมดูล wasm
การนำเข้าจะต้องกำหนดไว้ในจาวาสคริปต์ดังนี้ -
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
}
};
ตัวอย่าง
ต่อไปนี้เป็นโค้ดจาวาสคริปต์ที่ใช้ importObj ภายใน 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>
เอาต์พุต
ผลลัพธ์มีดังนี้ -
ตามเว็บไซต์อย่างเป็นทางการของ WebAssembly.org ซึ่งมีอยู่ที่ https://webassembly.org/docs/security/ เป้าหมายหลักของ WebAssembly ในด้านความปลอดภัยมีดังนี้ -
รูปแบบการรักษาความปลอดภัยของ WebAssembly มีเป้าหมายสำคัญสองประการ -
ปกป้องผู้ใช้จากโมดูลที่มีข้อบกพร่องหรือเป็นอันตรายและ
มอบพื้นฐานและการบรรเทาที่เป็นประโยชน์แก่นักพัฒนาในการพัฒนาแอปพลิเคชันที่ปลอดภัยภายในข้อ จำกัด ของ (1)
โค้ดที่คอมไพล์เช่น WASM จาก C / C ++ / Rust ไม่ได้ถูกดำเนินการโดยตรงภายในเบราว์เซอร์และใช้ Javascript API รหัส WASM เป็นแบบแซนด์บ็อกซ์เช่นเรียกใช้ผ่าน Javascript API wrapper และเบราว์เซอร์พูดกับ WASM โดยใช้ API
นี่คือตัวอย่างของการใช้ไฟล์. wasm ในเบราว์เซอร์
ตัวอย่าง - C Program
#include<stdio.h>
int square(int n) {
return n*n;
}
เราจะใช้ WASM explorer เพื่อรับรหัส wasm -
ดาวน์โหลดรหัส WASM และใช้เพื่อทดสอบ api
ตัวอย่าง
<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>
เอาต์พุต
คุณจะได้รับผลลัพธ์ต่อไปนี้ -
อ็อบเจ็กต์การเอ็กซ์พอร์ตมีการอ้างอิงถึงฟังก์ชันที่จะเรียกใช้ ในการเรียกฟังก์ชันสแควร์คุณจะต้องทำดังนี้ -
console.log(finalcode.instance.exports.square(25));
ปัญหาเกี่ยวกับโค้ดที่คอมไพล์ WASM
ต่อไปนี้เป็นปัญหาเกี่ยวกับโค้ดที่คอมไพล์ WASM -
เป็นการยากที่จะตรวจสอบว่ามีการแทรกโค้ดที่เป็นอันตรายหรือไม่ในขณะที่รวบรวมโค้ดเป็น wasm ไม่มีเครื่องมือในขณะนี้เพื่อตรวจสอบความถูกต้องของรหัส
Wasm นั้นยากที่จะวิเคราะห์และสามารถเรียกใช้โค้ด buggy / malicious ภายในเบราว์เซอร์ได้อย่างง่ายดาย
ในบทนี้เราจะรวบรวมโปรแกรม C อย่างง่ายเพื่อใช้จาวาสคริปต์และเรียกใช้งานแบบเดียวกันในเบราว์เซอร์
ตัวอย่างเช่น - C Program
#include<stdio.h>
int square(int n) {
return n*n;
}
เราได้ทำการติดตั้ง emsdk ในโฟลเดอร์ wa /. ในโฟลเดอร์เดียวกันให้สร้างโฟลเดอร์อื่น cprog / และบันทึกโค้ดด้านบนเป็น square.c
เราได้ติดตั้ง emsdk ไปแล้วในบทที่แล้ว ที่นี่เราจะใช้ emsdk เพื่อรวบรวมรหัส c ด้านบน
คอมไพล์ test.c ใน command prompt ดังที่แสดงด้านล่าง -
emcc square.c -s STANDALONE_WASM –o findsquare.wasm
คำสั่ง emcc ดูแลการคอมไพล์โค้ดและให้รหัส. wasm เราได้ใช้ตัวเลือก STANDALONE_WASM ที่จะให้เฉพาะไฟล์. wasm
ตัวอย่าง - 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>
เอาต์พุต
ผลลัพธ์มีดังต่อไปนี้ -
ในบทนี้เราจะรวบรวมโปรแกรม C ++ อย่างง่ายเพื่อใช้จาวาสคริปต์และเรียกใช้งานแบบเดียวกันในเบราว์เซอร์
ตัวอย่าง
โปรแกรม C ++ - การย้อนกลับหมายเลขที่กำหนด
#include <iostream>
int reversenumber(int n) {
int reverse=0, rem;
while(n!=0) {
rem=n%10; reverse=reverse*10+rem; n/=10;
}
return reverse;
}
เราได้ทำการติดตั้ง emsdk ในโฟลเดอร์ wa /. ในโฟลเดอร์เดียวกันให้สร้างโฟลเดอร์อื่น cprog / และบันทึกโค้ดด้านบนเป็น reverse.cpp
เราได้ติดตั้ง emsdk ไปแล้วในบทที่แล้ว ที่นี่เราจะใช้ emsdk เพื่อรวบรวมรหัส c ด้านบน
คอมไพล์ test.c ใน command prompt ดังที่แสดงด้านล่าง -
emcc reverse.cpp -s STANDALONE_WASM –o reverse.wasm
คำสั่ง emcc ดูแลการคอมไพล์โค้ดและให้รหัส. wasm
ตัวอย่าง - 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>
เอาต์พุต
ผลลัพธ์มีดังนี้ -
ในการรับโค้ดคอมไพล์ RUST เราจะใช้เครื่องมือ WebAssembly.studio
ไปที่WebAssembly.studioซึ่งมีอยู่ที่ Go tohttps://webassembly.studio/ และจะแสดงหน้าจอดังที่แสดงด้านล่าง -
คลิกที่ Empty Rust Project เมื่อเสร็จแล้วคุณจะได้รับสามไฟล์ใน src / โฟลเดอร์ -
เปิดไฟล์ main.rs และเปลี่ยนรหัสที่คุณต้องการ
ฉันกำลังเพิ่มฟังก์ชั่นต่อไปนี้ที่จะเพิ่มตัวเลขที่กำหนดสองตัว -
fn add_ints(lhs: i32, rhs: i32) -> i32 {
lhs+rhs
}
รหัสที่มีอยู่ใน main.rs มีดังนี้ -
#[no_mangle]
pub extern "C" fn add_one(x: i32) -> i32 {
x + 1
}
แทนที่ fn add_one ด้วยของคุณดังที่แสดงด้านล่าง -
#[no_mangle]
pub extern "C" fn add_ints(lhs: i32, rhs: i32) -> i32 {
lhs+rhs
}
ใน main.js เปลี่ยนชื่อฟังก์ชันจาก add_one เป็น 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);
แทนที่ instance.exports.add_one เป็น 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);
คลิกที่ปุ่มสร้างที่มีอยู่บน UI ของ webassembly.studio เพื่อสร้างโค้ด
เมื่อสร้างเสร็จแล้วให้คลิกที่ปุ่ม Run ที่มีอยู่บน UI เพื่อดูผลลัพธ์ -
เราได้ผลลัพธ์เป็น 200 ขณะที่เราส่งผ่าน instance.exports.add_ints (100,100)
ในทำนองเดียวกันคุณสามารถเขียนโปรแกรมที่แตกต่างกันสำหรับสนิมและรวบรวมไว้ใน webassembly.studio
Go ได้เพิ่มการรองรับ WebAssembly ตั้งแต่เวอร์ชัน 1.1 เป็นต้นไป เพื่อทดสอบการดาวน์โหลดครั้งแรกไป
ไปที่เว็บไซต์ golang ซึ่งมีให้ที่ https://golang.org/dl/และคลิกที่ดาวน์โหลดไป ตามระบบปฏิบัติการของคุณดาวน์โหลดและติดตั้ง Go
เมื่อเสร็จแล้วให้เขียนโปรแกรมง่ายๆที่เพิ่มตัวเลขสองตัวเข้าไป
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
}
ในการรวบรวมโค้ดด้านบนเป็น wasm ขั้นแรกให้ตั้งค่าตัวแปรสภาพแวดล้อมใน Go
คุณจะต้องรันคำสั่งต่อไปนี้ -
Set GOOS=js
GOARCH=wasm
เมื่อเสร็จแล้วให้รันคำสั่งด้านล่าง -
go build -o testnum.wasm testnum.go
คุณควรได้รับไฟล์ testnum.wasm เมื่อดำเนินการคำสั่ง
ตอนนี้ให้เราทดสอบโค้ดในเบราว์เซอร์ ในการทำเช่นนั้นเราต้องได้รับ wasm_exec.js ซึ่งติดตั้งมาพร้อมกับ go
ไฟล์ wasm_exec.js จะอยู่ในโฟลเดอร์ misc / wasm / go
ตัวอย่าง
นี่คือรหัสสำหรับ testgo.html ที่ใช้ wasm_exec.js และ 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>
เอาต์พุต
ผลลัพธ์มีดังนี้ -
Javascript มี API มากมายที่สามารถทำงานกับรหัส wasm ได้ นอกจากนี้ยังรองรับ API ใน nodejs
ติดตั้ง NODEJS ในระบบของคุณ สร้างไฟล์ Factorialtest.js
ให้เราใช้รหัส C ++ Factorial ดังที่แสดงด้านล่าง -
int fact(int n) {
if ((n==0)||(n==1))
return 1;
else
return n*fact(n-1);
}
เปิด Wasm Explorer ซึ่งมีอยู่ที่ https://mbebenita.github.io/WasmExplorer/ ดังแสดงด้านล่าง -
คอลัมน์แรกมีฟังก์ชันแฟกทอเรียล C ++ คอลัมน์ที่ 2 มีรูปแบบข้อความ WebAssembly และคอลัมน์สุดท้ายมีรหัส x86 Assembly
รูปแบบ WebAssembly Text มีดังนี้ -
(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)
)
)
ฟังก์ชัน C ++ ถูกส่งออกเป็น "_Z4facti” ในรูปแบบ WebAssembly Text
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))
}
}
);
ในบรรทัดคำสั่งของคุณให้รันโหนดคำสั่ง factorialtest.js และผลลัพธ์จะเป็นดังนี้ -
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
บทนี้กล่าวถึงตัวอย่างที่เกี่ยวข้องกับ WebAssembly
ตัวอย่าง 1
ต่อไปนี้เป็นตัวอย่างของโปรแกรม C เพื่อรับองค์ประกอบสูงสุด -
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;
}
รวบรวมรหัสใน wasm fiddle และดาวน์โหลดรหัส. wasm และ .wat
Wat code
รหัสวัดมีดังนี้ -
(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)
)
)
ดาวน์โหลดรหัส. wasm และให้เราใช้ในไฟล์. html ตามที่แสดงด้านล่าง -
<!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>
เอาต์พุต
ผลลัพธ์มีดังนี้ -
ตัวอย่าง 2
ต่อไปนี้เป็นรหัส C ++ เพื่อรับชุด fibonacci ของหมายเลขที่กำหนด
#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;
}
ฉันใช้ wasm explorer เพื่อรวบรวมโค้ด ดาวน์โหลด Wat and Wasm และทดสอบสิ่งเดียวกันในเบราว์เซอร์
คุณสามารถใช้รหัสที่กล่าวถึงด้านล่าง -
<!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>
เอาต์พุต
ผลลัพธ์มีดังนี้ -
ตัวอย่างที่ 3
ต่อไปนี้เป็นรหัสสนิมเพื่อเพิ่มองค์ประกอบในอาร์เรย์ที่กำหนด
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
}
เราจะใช้ประโยชน์จาก WebAssembly Studio เพื่อรวบรวม RUST to wasm
สร้างรหัสและดาวน์โหลดไฟล์ wasm และดำเนินการแบบเดียวกันในเบราว์เซอร์
<!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>
เอาต์พุต
ผลลัพธ์จะเป็นไปตามที่ระบุด้านล่าง -