2 पॉइंट द्वारा GN⁺ 2024-11-11 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Jawsm Rust में लिखा गया JavaScript→WebAssembly compiler है, एक experimental tool जो interpreter के बिना चलने वाली standalone WASM binaries बनाता है
  • porffor की तरह यह standalone WASM बनाता है, लेकिन implementation approach अलग है; यह आधुनिक WASM GC, exception handling, और tail call optimization proposal के instructions का उपयोग करके JavaScript syntax को WASM instructions में बदलता है
  • अभी यह test262 test suite के लगभग 25% tests pass करता है, और viability की पुष्टि के लिए महत्वपूर्ण माने गए scopes/closures, try/catch, async/await, generators implement हो चुके हैं
  • यह अभी production-ready नहीं है; कई language features और built-in types गायब या अधूरे हैं, और RegExp, ज़्यादातर builtins, BigInt arithmetic भी मौजूद नहीं हैं
  • generated binaries की runtime portability कम है, क्योंकि वे नए WASM proposals पर निर्भर हैं; फिलहाल इन्हें V8-based Chromium या Node में WASIp2 polyfill के साथ चलाया जाता है

Jawsm का लक्ष्य और स्थिति

  • Jawsm एक JavaScript to WebAssembly compiler है, जिसका उच्चारण “awesome” जैसा है
  • यह Rust में लिखा गया है, और इसका लक्ष्य JavaScript code को interpreter के बिना चलने वाली standalone WASM binary में बदलना है
  • यह porffor जैसे output बनाता है, लेकिन implementation approach अलग है
  • अभी यह एक experimental tool है और production में इस्तेमाल के लिए तैयार नहीं है
    • कई JavaScript language features गायब या अधूरे हैं
    • कई built-in types और methods भी गायब या अधूरे हैं
  • long-term goal JavaScript language features का 100% support देना है

Jawsm क्यों बनाया गया

  • यह project WebAssembly scenarios चलाने वाले stress test tool Crows पर काम करते समय शुरू हुआ
  • Crows फिलहाल केवल Rust से WASM में compile किए गए code को support करता है
  • छोटे tests अक्सर interpreted language में लिखना आसान होता है, लेकिन WASM पर scripting language चलाने का मौजूदा तरीका ideal नहीं है
    • interpreter शामिल करने पर binary size कम से कम कुछ MB हो जाता है और memory usage भी बढ़ जाता है
    • या TinyGo, AssemblyScript जैसे target language के variant का उपयोग करना पड़ता है
  • आधुनिक WASM proposals का उपयोग करके, compiled interpreter के बिना भी JavaScript features का 100% implementation संभव हो सकता है—यही लक्ष्य है
  • यह मानकर चला गया है कि WASM runtime खुद पहले से ही एक interpreter है

अभी काम करने वाले features

  • Jawsm फिलहाल test262 test suite के लगभग 25% tests pass करता है
  • project viability की पुष्टि के लिए 4 core features सभी implement हो चुके हैं
    • scopes/closures
    • try/catch
    • async/await
    • generators
  • इसके अलावा जिन features के काम करने की उम्मीद है, वे हैं
    • var, let, const declarations और assignment
    • do..while, while, for, for..in, for..of loops
    • switch statement
    • break, continue का limited support
    • string literals और string literal concatenation
    • numbers और basic operators +, -, *, /
    • boolean और basic boolean operators
    • arrays और Array से जुड़े ज़्यादातर functions
    • object literals
    • new keyword
    • async, await
    • Promise API का limited support
    • generator functions
    • try/catch
    • बहुत basic BigInt support

अभी missing features

  • फिलहाल missing मुख्य items ये हैं
    • ज़्यादातर builtins
    • मौजूदा builtins के ज़्यादातर methods
    • RegExp expressions
    • BigInt arithmetic
  • अगले चरण की योजना इन features के implementation पर केंद्रित है
    • basic regexp support
      • RegExp literals
      • RegExp object के बहुत basic functions
    • BigInt literals और basic BigInt support
    • equality checks या कई operators का उपयोग करते समय बेहतर automatic casting
    • arrays, strings आदि basic builtins के और functions

execution environment और constraints

  • Jawsm कुछ अपेक्षाकृत नए WASM proposals का उपयोग करता है, इसलिए generated binaries अभी runtimes के बीच ज्यादा portable नहीं हैं
  • target implementation WASIp2 को ध्यान में रखकर है
  • Wasmtime ऐसा runtime है जो components और WASIp2 चला सकता है, लेकिन Jawsm जिन चीज़ों का उपयोग करता है, जैसे WASM GC के कुछ हिस्से या exception handling, उन्हें support नहीं करता
  • runtimes के standardized proposals के साथ catch up करने तक development आसान रखने के लिए V8 का उपयोग किया जाता है
    • V8 को Chromium या Node के जरिए उपयोग किया जाता है
    • जरूरी WASIp2 features को JavaScript polyfill से supplement किया जाता है
  • repository में Jawsm द्वारा generated binaries चलाने के लिए run.js script है
  • अंततः लक्ष्य यह है कि यह WASM GC, exception handling, और WASIp2 API implement करने वाले सभी runtimes में चल सके
    • या WASIp2 polyfill का उपयोग करने वाला तरीका भी इसमें शामिल है

उपयोग का तरीका

  • अगर उद्देश्य contribution नहीं है, तो फिलहाल इसके उपयोग की सिफारिश नहीं की जाती
  • repository clone करने के बाद execute.sh को इस तरह इस्तेमाल किया जा सकता है
./execute.sh --cargo-run path/to/script.js
  • यह command WAT file बनाता है, उसे binary में compile करता है, और फिर Node.js से चलाता है
  • जरूरी tools ये हैं
    • Rust का cargo
    • wasm-tools का अपेक्षाकृत नया version
    • Node.js v23.0.0 या उससे ऊपर
  • --cargo-run option देने पर पहले cargo run से project compile किया जाता है, फिर execute किया जाता है
  • --cargo-run के बिना चलाने पर यह release build run करने की कोशिश करता है, इसलिए पहले cargo build --release चलाना होगा

internal working

  • Jawsm JavaScript syntax को WASM instructions में बदलता है
  • conversion process में इन WASM proposals के instructions का उपयोग होता है
    • WASM GC

      • exception handling
      • tail call optimizations
      • Rust code script को transform करता है, और JavaScript semantics को WASM में ले जाने के लिए types और functions का एक set साथ में उपयोग होता है
      • ज़्यादातर WASM instructions tarnik का उपयोग करके generate किए जाते हैं
      • tarnik एक Rust macro है जो Rust-like syntax के आधार पर WASM instructions generate करता है

scope और closure handling का example

  • WASM function references, structs, arrays को support करता है, लेकिन JavaScript की scope semantics सीधे provide नहीं करता
  • Jawsm JavaScript scope behavior की नकल करने के लिए extra WASM code generate करता है
  • example JavaScript code इस प्रकार है
let a = "foo";

function bar() {
  console.log(a);
}

bar();
  • JavaScript में function definition अपने define हुए scope को inherit करती है, इसलिए bar() को variable a access कर पाना चाहिए
  • conversion flow मोटे तौर पर इस प्रकार है
    • बिना parent वाला global scope बनाता है
    • current scope में variable a को "foo" के रूप में declare करता है
    • bar function object बनाते समय, function जिस scope में define हुआ था उसका reference भी साथ store करता है
    • function के अंदर execute करते समय नया scope बनाता है, लेकिन parentScope reference बनाए रखता है
    • retrieve(scope, "a") current scope और सभी parent scopes में a को search करता है
    • current scope से bar लेकर call करता है

license

  • code Apache 2.0 license के तहत distribute किया गया है

1 टिप्पणियां

 
GN⁺ 2024-11-11
Hacker News की राय
  • WASM GC proposal का वाकई बहुत चतुर इस्तेमाल किया गया है
    अब तक JS→WASM compilers असल में पूरा JS engine साथ लोड करने वाले तरीके अपनाते थे, लेकिन JS structures को सीधे WASM के primitive features पर map करने की कोशिश पहली बार देखी है

    • Porffor https://porffor.dev/ और Static Hermes https://hermesengine.dev/ भी compilation approach अपनाते लगते हैं
      Jaws से तुलना करना दिलचस्प होगा
    • सही है। हालांकि ईमानदारी से कहूं तो यह चतुर उपयोग कुछ हद तक इसलिए निकला क्योंकि मैं WASM के ऊपर पूरा interpreter लिखने जितना होशियार नहीं था
  • पहले मैंने TypeScript के काफ़ी करीब एक भाषा को embedded ARM compiler के रूप में बनाया था
    वह AssemblyScript की तुलना में TypeScript के कहीं ज़्यादा करीब थी, और तब इस्तेमाल की गई कुछ techniques मददगार हो सकती हैं
    https://www.microsoft.com/en-us/research/uploads/prod/2019/09/static-typescript-draft2.pdf

  • “Rust इस्तेमाल करना मुझे वाकई पसंद है, लेकिन मैं यह भी जानता हूं कि यह व्यापक रूप से लोकप्रिय भाषा नहीं है” — क्या यह बात सही है?
    Rust को बहुत ज़्यादा hype किया जा रहा है और आजकल यह हर जगह इस्तेमाल होती दिखती है

    • मुझे अभी तक crypto से असंबंधित Rust jobs नहीं मिलीं
      मेरे देश Estonia में, लोग जिस local job board का इस्तेमाल करते हैं उसके आधार पर local jobs 0 हैं, इसलिए असल मायने में इसे बिल्कुल भी लोकप्रिय कहना मुश्किल है
    • social पर hype होना और बहुत दिखाई देना ज़रूरी नहीं कि व्यापक रूप से इस्तेमाल होने का मतलब हो
      यह इस पर निर्भर करता है कि “व्यापक” को कैसे define करते हैं, लेकिन StackOverflow, PyPL जैसे indices और GitHub stats देखें तो Rust का usage JavaScript या Python का करीब 5~10% लगता है
  • अगर “आखिरकार JavaScript spec का 100% cover कर पाएंगे, इसका काफ़ी भरोसा है,” तो क्या test262_runner.rb results हैं?
    Porffor के लेखक की presentation से test262 के बारे में पता चला, और README में https://github.com/CanadaHonk/porffor?tab=readme-ov-file#test262 जैसी progress indicator हो तो अच्छा होगा
    अच्छा project है

    • अभी tests के करीब 12% pass हो रहे हैं, लेकिन implement करने में आसान बहुत से हिस्से अभी बचे हैं
      खासकर यह देखते हुए कि project शुरू हुए सिर्फ़ 2 हफ्ते हुए हैं; और हां, इसका मतलब यह नहीं कि 100% तक progress linear होगी
      built-in types और functions की लंबी tail बची है, लेकिन “मुश्किल हिस्सों” से implementation शुरू करने की वजह से कुछ आसान हिस्से अभी नहीं किए गए हैं
      उदाहरण के लिए, test262 harness चलाने के लिए जितनी ज़रूरत थी उतनी ही syntax implement की है—conditional statements और while loops—और for, for in, for of, do while तथा switch जैसी condition expressions अभी implement नहीं हुई हैं
      इन्हें मौजूदा if/else और while implementation की तरह ही काफ़ी आसानी से जोड़ा जा सकता है

      await और generators की implementation खत्म कर लेने पर, आखिरी मुश्किल semantic concepts भी हल हो जाएंगे, इसलिए उसके बाद ऐसे आसान हिस्सों को implement करने का इरादा है
      coverage कितनी बढ़ेगी कहना मुश्किल है, लेकिन उदाहरण के लिए अभी object["foo"] syntax implement नहीं है, इसलिए 1200 tests fail हो रहे हैं
      object.foo काम करता है, लेकिन object["foo"] नहीं चलता
      इसका मतलब यह नहीं कि वे 1200 अपने-आप सभी pass हो जाएंगे, लेकिन इस तरह की अपेक्षाकृत simple syntax omissions की वजह से अक्सर सैकड़ों tests fail होते हैं

      Porffor जैसा शानदार graph भी ज़रूर जोड़ना चाहता हूं

  • project README.md पढ़ने के बाद भी अभी साफ़ नहीं है कि expected usage pattern क्या है?
    generated WASM code किस runtime के साथ और कैसे interact करता है, यह जानना चाहता हूं
    क्या यह browser और दूसरे WASM runtimes दोनों के साथ compatible tool है, या केवल project से linked runtime में ही चलता है?

    इससे जुड़ा सवाल: JavaScript code में web APIs या किसी specific environment में ही defined global identifiers—जैसे modern browser या Node.js के global identifiers—मिलें तो यह कैसे react करता है?
    अगर ऐसे environment को target नहीं कर रहे, तो I/O कैसे करना चाहिए?

    • अच्छे सवाल हैं, और README में और detail जोड़ूंगा
      यह project मुख्य रूप से server पर WebAssembly usage को target करता है
      JavaScript के अंदर WebAssembly से JavaScript चलाने का ज़्यादा मतलब नहीं दिखता, लेकिन समय के साथ यह frontend plugin sandboxing में उपयोगी हो सकता है

      चाहे browser में चलाएं या WasmTime/WasmEdge जैसे backend runtime में, फिलहाल WebAssembly के अंदर JavaScript execute करना ideal नहीं है
      या तो V8/SpiderMonkey जैसे JS engines को WASM में compile करके उनके ऊपर scripts चलानी पड़ती हैं, या AssemblyScript जैसी “लगभग JavaScript” language से संतुष्ट होना पड़ता है
      यही server workloads चलाने में limiting factor बनता है
      उदाहरण के लिए Fastly WASM workers में SpiderMonkey इस्तेमाल करता है, और सिर्फ़ hello world भी हर instance पर 5~10MB memory लेता है
      इसके उलट Shopify store की server-side customization के लिए WASM इस्तेमाल करता है और WASM binary को 250KB से कम तक limit करता है; इस size में कोई भी interpreter डालना मुश्किल है
      इसलिए “recommended” language AssemblyScript बनी, और वजह यहां समझाई गई है: https://shopify.engineering/shopify-webassembly

      यह स्थिति ऐतिहासिक रूप से इसलिए रही क्योंकि WASM बहुत simple runtime था
      C code को machine code में compile करने की तरह WASM में compile करना अपेक्षाकृत आसान था, लेकिन WebAssembly खुद एक तरह का interpreter होने के बावजूद, उसके ऊपर higher-level languages interpret करना आसान नहीं था

      अब garbage collection support और exception handling support जैसे नए proposals standardize हो रहे हैं, जिससे WebAssembly structs, arrays और function references जैसी capabilities वाला कहीं ज़्यादा powerful interpreter बन रहा है

Jaws इसी बात का फायदा उठाकर JS कोड को WASM कोड में बदलता है, और SpiderMonkey जैसे JS engine के बिना WASM से ही बने हुए code को interpret करवाता है
असल में Jaws से बना binary शायद 50KB से कम हो सकता है, जबकि SpiderMonkey को WASM में compile करके उसके ऊपर script चलाने वाले तरीके में यह 10MB के करीब होता है
memory usage भी काफी कम हो जाएगा
Fastly जैसी कंपनियों के लिए इसका मतलब memory usage और server cost को कई गुना घटा पाना है, और Shopify जैसी कंपनियों के लिए इसका मतलब मौजूदा JavaScript code, जैसे NPM packages और JavaScript ecosystem, को backend plugin authors के लिए उपलब्ध करा पाना है

project जिस runtime का इस्तेमाल करता है वह **सिर्फ WebAssembly** है  
generated code आम तौर पर इस file के करीब 3 हजार lines वाले WAT code [https://github.com/drogus/jaws/blob/main/src/wat/template.wat](<https://github.com/drogus/jaws/blob/main/src/wat/template.wat>;) और user के JS code से बदले गए हिस्से से बना होता है  
उदाहरण के लिए `"console.log('foo')"` जैसे बहुत simple program में पूरी “generated” part बस इतना ही है: [https://gist.github.com/drogus/1c49c25ed0b14804b2f27e10d2a79928/…](<https://gist.github.com/drogus/1c49c25ed0b14804b2f27e10d2a79928/…;)  
यह मोटे तौर पर arguments को `new_static_string` से तैयार करने के बाद `console.log` को call करता है  
अभी host side पर थोड़े glue code की जरूरत है, लेकिन आखिरकार ऐसे binary को WASIp2, WASM GC और exception handling proposals को support करने वाले किसी भी runtime में चलाया जा सकेगा

web API या environment-specific global identifiers का support अभी implement नहीं हुआ है, लेकिन यह कैसे काम करेगा, बताया जा सकता है  
**Node.js API** को WASI के जरिए support करने की योजना है  
WASI, WASM programs और बाहरी दुनिया के बीच communication के लिए एक standard है  
उदाहरण के लिए यह HTTP request भेजने, STDOUT में लिखने, files read/write करने आदि के लिए standard functions का set define करता है  
इसलिए `fetch` या `fs` जैसे API तक पहुंचने पर, WASI preview2 support करने वाले runtimes में इन्हें काम करना चाहिए  
browser भी polyfill से support कर सकते हैं, लेकिन इस case में I/O support ज्यादा custom होगा  
अगर WASM program को files read या write करने की अनुमति देनी है, तो उदाहरण के लिए localStorage में save करना, WASM में compiled SQLite database इस्तेमाल करना, या यहां तक कि S3 जैसी जगह पर भेजना—ऐसा कोई mechanism देना होगा
  • “browser runtime के बिना JS चलाना” करीब आता हुआ लग रहा है
    Porffor, Jaws, या किसी और project में से कोई न कोई आखिरकार सफल होगा लगता है

  • मुझे यह approach सच में पसंद है
    binary सीधे generate करने की कोशिश करने के बजाय सीधे WASM को target करके build करने पर, WASM GC और WASI 0.3 में शामिल होने वाली लग रही async support पर निर्भर किया जा सकता है

  • string encoding के फर्क और related utilities को कैसे handle करते हैं?
    मेरी धुंधली समझ के हिसाब से WASM UTF-8 support करता है और JS संभावित रूप से टूटे हुए UTF-16 को भी support करता है

    • CPU instruction set की तरह, WASM abstract machine में string या encoding की कोई concept नहीं है
      यह linear memory के अंदर बस bytes हैं, और जो encoding चाहिए उसे खुद implement किया जा सकता है

      WASM file format में names की encoding के लिए UTF-8 specify करता है, लेकिन इसका runtime virtual machine से कोई संबंध नहीं है

  • कुछ लोग उसे compiler भी कहते हैं
    खैर, अच्छा बनाया है

    • title लिखते समय मुझे बिल्कुल ध्यान नहीं आया कि wording थोड़ी अजीब है
  • क्या यह उसी code को JS में सीधे चलाने से तेज है, या यह दूसरे languages के साथ interop के लिए है?

    • इस stage पर कहना मुश्किल है, लेकिन मुझे लगता है कि JIT enabled SpiderMonkey या V8 से तेज होने की संभावना बहुत कम है
      modern JavaScript compilers JIT के जरिए frequently executed paths को काफी अच्छे से optimize करते हैं
      इस project का use case JavaScript को WebAssembly sandbox environment में चलाने लायक बनाना है
      उदाहरण के लिए Shopify WebAssembly से backend code extend करने देता है, लेकिन binary size को 250KB तक limit करता है
      उस size में अभी JavaScript इस्तेमाल करना मुश्किल है, क्योंकि QuickJS जैसा simple interpreter भी WASM में compile करने पर कुछ MB का हो जाता है