7 पॉइंट द्वारा GN⁺ 2025-12-24 | 2 टिप्पणियां | WhatsApp पर शेयर करें
  • MicroQuickJS(MQuickJS) एम्बेडेड सिस्टम्स के लिए डिज़ाइन किया गया एक अति-हल्का JavaScript इंजन है, जो लगभग 10kB RAM और 100kB ROM पर चल सकता है
  • QuickJS जैसी गति बनाए रखते हुए मेमोरी उपयोग कम करने के लिए इसमें tracing garbage collector और UTF-8 string storage अपनाया गया है
  • समर्थित भाषा ES5 के क़रीब JavaScript का सीमित subset है, और केवल strict mode की अनुमति है, जो त्रुटि-प्रवण syntax को प्रतिबंधित करता है
  • REPL टूल mqjs के ज़रिए script execution, bytecode save करना, और memory limit सेट करना संभव है, तथा बना हुआ bytecode सीधे ROM से चलाया जा सकता है
  • पूरा इंजन और standard library ROM में resident रहते हैं, जिससे तेज़ initialization और कम memory consumption हासिल होता है और एम्बेडेड वातावरण में JavaScript execution efficiency बढ़ती है

परिचय

  • MicroQuickJS(MQuickJS) एम्बेडेड सिस्टम्स को ध्यान में रखकर बनाया गया JavaScript इंजन है, जो 10kB RAM और 100kB ROM (ARM Thumb-2 code सहित) पर काम करता है
    • इसकी गति QuickJS के समान है
  • यह केवल ES5 के क़रीब subset को सपोर्ट करता है, और सिर्फ़ strict mode में चलता है, जो अप्रभावी या त्रुटि-प्रवण syntax को प्रतिबंधित करता है
  • यह QuickJS के साथ कुछ code साझा करता है, लेकिन इसकी internal structure मेमोरी बचाने के लिए पूरी तरह अलग ढंग से डिज़ाइन की गई है
    • इसमें tracing garbage collector, CPU stack का उपयोग न करना, और UTF-8 string storage का उपयोग किया गया है

REPL

  • REPL command mqjs है, जो script execution, evaluation, interactive mode, memory limit setting, और bytecode save करने को सपोर्ट करता है
    • उदाहरण: ./mqjs --memory-limit 10k tests/mandelbrot.js
  • -o option के साथ compiled bytecode को फ़ाइल में सेव किया जा सकता है
    • सेव किया गया bytecode ./mqjs mandelbrot.bin से चलाया जा सकता है
  • bytecode CPU के endianness और word length (32/64-bit) के अनुसार अलग होता है, और -m32 option से 32-bit bytecode बनाया जा सकता है
  • --no-column option से debug information के column number हटाए जा सकते हैं

strict mode

  • केवल strict mode की अनुमति है; with keyword का उपयोग नहीं किया जा सकता, और global variables को अनिवार्य रूप से var से declare करना होगा
  • array holes की अनुमति नहीं है
    • उदाहरण: a[10] = 2 पर TypeError होगा
    • यदि holes वाला array चाहिए, तो सामान्य object का उपयोग करें
  • केवल global eval समर्थित है; local variables तक पहुँच नहीं है
  • value boxing समर्थित नहीं है (new Number(1) आदि)

JavaScript subset

  • strict mode आधारित, ES5 compatibility पर केंद्रित
  • Array object में holes नहीं होते, और range के बाहर index access करने पर error होता है
  • for in object की own properties पर ही iterate करता है, और for of केवल arrays को सपोर्ट करता है
  • global object मौजूद है, लेकिन getter/setter की अनुमति नहीं है, और सीधे बनाई गई properties global variables के रूप में expose नहीं होतीं
  • regular expressions (Regexp) में uppercase/lowercase matching केवल ASCII तक सीमित है, और /./ UTF-16 के बजाय Unicode code points के आधार पर match करता है
  • string functions केवल ASCII को संभालते हैं (toLowerCase, toUpperCase)
  • Date में केवल Date.now() समर्थित है
  • अतिरिक्त समर्थित सुविधाएँ:
    • for of, Typed arrays, \u{hex} string literals
    • Math functions: imul, clz32, fround, trunc, log2, log10
    • exponentiation operator, regexp flags (s, y, u), string functions (replaceAll, trimStart, trimEnd), globalThis

C API

  • C library dependencies न्यूनतम रखी गई हैं; malloc, free, printf का उपयोग नहीं होता
  • memory buffer सीधे प्रदान करना होता है, और इंजन उसी buffer के भीतर memory allocate करता है
    • उदाहरण: ctx = JS_NewContext(mem_buf, sizeof(mem_buf), &js_stdlib)
  • garbage collection method के कारण JS_FreeValue() कॉल करने की आवश्यकता नहीं है
  • object address हर allocation पर बदल सकता है, इसलिए JSValue pointer का उपयोग करने की सिफ़ारिश की जाती है
    • JS_PushGCRef() / JS_PopGCRef() से सुरक्षित reference management संभव है
  • standard library को ऐसे C structures के रूप में compile किया जाता है जिन्हें ROM में रखा जा सकता है, जिससे तेज़ initialization और कम RAM usage मिलता है
  • bytecode execution ROM से संभव है, और JS_RelocateBytecode() से relocate करने के बाद JS_LoadBytecode() और JS_Run() से चलाया जा सकता है
  • math library (libm.c) और floating-point emulator अंतर्निहित हैं

आंतरिक संरचना और QuickJS से तुलना

  • garbage collection: reference counting के बजाय tracing और compaction GC का उपयोग
    • इससे memory fragmentation रुकती है और object size कम होता है
  • value representation: CPU word size (32/64-bit) के अनुरूप डिज़ाइन
    • इसमें 31-bit integers, Unicode code points, floating point values, और memory block pointers स्टोर किए जा सकते हैं
  • strings UTF-8 में store की जाती हैं, जो QuickJS की 8/16-bit array approach से अधिक efficient है
  • C functions को single value के रूप में store किया जा सकता है, लेकिन उनमें properties जोड़ी नहीं जा सकतीं
  • standard library ROM में resident रहती है, और RAM objects को न्यूनतम रखकर तेज़ engine initialization संभव बनाती है
  • bytecode stack-based है और indirect reference table के माध्यम से read-only बनाया जाता है
    • Golomb code से line और column numbers compress किए जाते हैं
  • compiler QuickJS जैसा है, लेकिन C stack usage सीमित रखने के लिए non-recursive parser का उपयोग करता है
    • parse tree के बिना single-pass bytecode generation

टेस्ट और बेंचमार्क

  • बेसिक टेस्ट: make test
  • QuickJS micro benchmark: make microbench
  • Octane benchmark (strict mode के लिए संशोधित संस्करण) अलग से डाउनलोड किया जा सकता है
    • चलाने के लिए: make octane

लाइसेंस

  • MIT लाइसेंस के तहत वितरित
  • source code का copyright Fabrice Bellard और Charlie Gordon के पास है

2 टिप्पणियां

 
GN⁺ 2025-12-24
Hacker News की राय
  • अगर 2010 में यह मौजूद होता, तो लगता है Redis की scripting language Lua नहीं बल्कि JavaScript होती
    Lua को भाषाई कारणों से नहीं, बल्कि implementation constraints (छोटी, तेज़, ANSI-C आधारित) की वजह से चुना गया था
    Lua के कुछ ideas अच्छे हैं, लेकिन निजी तौर पर मुझे Algol-शैली के व्याकरण से हटना बेवजह लगा
    SmallTalk या FORTH की तरह नए abstraction concepts सीखने की कीमत पर जो भ्रम पैदा होता है, वह सार्थक हो सकता है, लेकिन Lua के बदलाव के लिए उतनी ठोस वजह नहीं लगती

    • मुझे Lua की syntax खास पसंद नहीं, लेकिन developers ने उसे क्यों चुना, यह पूरी तरह समझ में आता है
      Lua इकलौती lightweight language है जो tail call optimization(TCO) सपोर्ट करती है, और इसकी वजह से loops के बिना सिर्फ recursion से program लिखे जा सकते हैं
      JavaScript में यह optimization नहीं है, इसलिए उसी तरीके से यह संभव नहीं
      Lua compiler writing के लिए भी खास तौर पर उपयुक्त है, क्योंकि उसमें recursive structures बहुत होते हैं
      Redis scripting के लिए JS शायद ज़्यादा फिट हो, लेकिन Lua को कमतर बताना ठीक नहीं लगता
    • यह देखते हुए कि Lua पहली बार 1993 में आई थी, उस समय के हिसाब से इसकी traditional syntax काफ़ी सामान्य थी
      ब्राज़ील में C से ज़्यादा Pascal और Ada इस्तेमाल होते थे, इसलिए उसी का असर था
      Ruby और Perl भी लगभग उसी दौर में आए, लेकिन उन्होंने syntax में कहीं ज़्यादा radical बदलाव किए
    • पहले मैं यह कहने वाला था कि मैंने 13 साल की उम्र में Lua आसानी से सीख ली थी, लेकिन फिर देखकर हैरानी हुई कि comment लिखने वाला खुद antirez है
    • इससे syntax की समस्या हल नहीं होगी, लेकिन “language skins” का विचार दिलचस्प है
      parser और lexer को अलग रखते हुए भी, {} की जगह then/end जैसे tokens बदलकर लगाने की कोशिशें लगभग नहीं हुई हैं
      संबंधित चर्चा: HN thread, Reddit चर्चा
    • सोच रहा हूँ कि Redis scripting language के लिए Tcl पर कभी विचार किया गया था या नहीं, क्योंकि वह मूल embedded language मानी जाती है
  • यह engine JS को उसी तरह restrict करता है जैसा मैं पहले JSC पर काम करते समय चाहता था
    web पर compatibility की वजह से ऐसी सीमाएँ संभव नहीं, लेकिन embedded environments में यही सीमाएँ उल्टा खुशी देने वाला design बन सकती हैं

    • हमारे पास पहले से ऐसा JS engine है जिसमें ये restrictions नहीं हैं
    • जानना चाहूँगा कि JSC में चल रहा multithreading work क्या हुआ। Apple छोड़ने के बाद वह रुक गया, या code अभी भी कहीं मौजूद है
  • मैंने एक playground बनाया है जहाँ browser में सीधे MicroQuickJS चलाकर देखा जा सकता है
    MicroQuickJS WebAssembly version
    संदर्भ के लिए मूल QuickJS version भी है
    QuickJS 2.28MB है, जबकि MicroQuickJS सिर्फ 303KB, यानी काफ़ी हल्का

    • लगता है build में name information वगैरह शामिल होने से size बढ़ गया है
      emcc -O3 option या --closure 1 जोड़ने से शायद और कम हो सकता है
      QuickJS पहले से optimized है, और सुधार की गुंजाइश सिर्फ MicroQuickJS में दिखती है
  • Jeff Atwood के मशहूर कथन की तरह, “हर वह app जो JavaScript में लिखा जा सकता है, अंततः JavaScript में लिखा जाएगा
    अब लगता है यह बात embedded systems पर भी लागू हो रही है
    Jeff Atwood wiki

    • सहमत। संबंधित talk: The Birth and Death of JavaScript
    • Fabrice Bellard ने browser के भीतर Linux चला सकने वाला JS-आधारित VM भी बनाया था
      JSLinux लिंक
    • यह लगभग इंटरनेट के Rule 35 जैसा लगता है
  • यह थोड़ा अफ़सोसजनक है कि इसे commit history के बिना upload किया गया
    मैं देखना चाहता था कि इस स्तर का developer किसी project को कितनी तेज़ी से पूरा करता है
    वैसे भी यह QuickJS आधारित है, इसलिए तुलना का ज़्यादा मतलब शायद नहीं

    • “public repository of…” जैसी wording देखकर लगता है कि असली work history किसी private repository में हो सकती है
    • शायद उसने इसे बस one-shot में पूरा कर दिया हो
  • सोच रहा हूँ कि क्या यह yt-dlp की YouTube JS challenge को हल करने का सबसे हल्का तरीका हो सकता है
    yt-dlp EJS docs देखें
    QuickJS पहले से supported है

    • संभावना कम है। यह सिर्फ ES5 स्तर की partial implementation सपोर्ट करता है
      YouTube की JS puzzles इतनी जटिल हैं कि Python में बना JS emulator भी उन्हें संभालना छोड़ चुका है
    • सिर्फ ES5 implemented होने की वजह से, व्यावहारिक रूप से यह मुश्किल लगता है
  • embedded systems की मुझे ज़्यादा जानकारी नहीं, लेकिन सोच रहा हूँ कि क्या ऐसा engine ESP32 या Arduino को JavaScript से program करने लायक बना सकता है
    कुछ MicroPython जैसा

    • ऐसे मिलते-जुलते projects पहले से हैं
    • Moddable/Kinoma का XS engine ES6 और उससे ऊपर सपोर्ट करता है
      MicroQuickJS में सिर्फ ES5 का कुछ हिस्सा implemented है, और यह environment bindings भी नहीं देता
    • पहले Tessel नाम का एक JS programming board हुआ करता था
      वह JS code को Lua VM bytecode में बदलकर चलाता था, और यह काफ़ी चतुर तरीका था
      हाल में मैंने उस पुराने Node 0.8 CLI को Rust में फिर से लिखने की कोशिश भी की, लेकिन आखिरकार hardware फिर दराज़ में लौट गया
    • असली बात यह है कि इसकी संरचना malloc() के बिना काम करती है। यही इसकी संभावनाएँ खोलती है
  • timing सच में बहुत अहम है। कल रात इसे पोस्ट किया था तो कोई प्रतिक्रिया नहीं मिली

    • शायद यह सिर्फ किस्मत की बात हो
    • किसी और ने भी कोशिश की थी लेकिन कोई प्रतिक्रिया नहीं मिली
      एक रणनीति यह है कि अमेरिकी सुबह के समय फिर से पोस्ट करो, या समय-समय पर दोबारा पोस्ट करते रहो
  • Fabrice Bellard मौजूदा समय के सबसे उत्पादक और बहुमुखी programmers में से एक हैं
    प्रमुख काम: FFmpeg, QEMU, JSLinux, TCC, QuickJS
    सचमुच एक दिग्गज हस्ती

    • जितनी उनकी प्रशंसा होती है, उतने लोग उनके development style में दिलचस्पी नहीं लेते
      बहुत कम dependencies और tools के साथ complete programs बनाने का उनका तरीका प्रभावशाली है
    • अब तो कभी-कभी लगता है कि वह एक व्यक्ति नहीं बल्कि अनुभवी hackers के समूह का codename हैं
      क्योंकि अगर वह सचमुच एक ही इंसान हैं, तो उन्हें सोना भी पड़ता होगा
    • उन्होंने खुद LLM inference engine भी बनाया है, और उसे GPT-2 के दौर से maintain कर रहे हैं
      ts_server, TextSynth
    • दिलचस्प बात यह है कि उनके ज़्यादातर programs GUI-केंद्रित user interfaces पर केंद्रित नहीं होते
      लगता है वे ऐसी संरचना पसंद करते हैं जहाँ user parameters सेट करे और program अपने आप पूरा चल जाए
    • वे International Obfuscated C Code Contest(IOCCC) तीन बार जीत चुके हैं
      IOCCC winners list
  • यह बात प्रभावशाली है कि “10kB RAM में भी JS को compile और run किया जा सकता है”
    आजकल जब RAM फिर महँगी हो रही है, यह बिल्कुल सही समय पर आया लगता है
    सोच रहा हूँ कि क्या इसे Chromium या Electron में डाला जा सकता है

    • web compatibility की वजह से यह मुश्किल होगा, लेकिन वैसे भी Chromium में memory reduction effect बहुत बड़ा शायद नहीं होगा
 
xguru 2025-12-24

Fabrice Bellard के बारे में परिचय के लिए मैंने पहले जो कमेंट लिखा था, उसे देखें। यह शख्स वाकई लगातार कमाल करने वाला अद्भुत दिग्गज है..
https://hi.news.hada.io/topic?id=59#cid51