बाइनरी के साथ Wasm को कंपाइल और ऑप्टिमाइज़ करना

Binaryen, C++ में लिखी गई WebAssembly के लिए एक कंपाइलर और टूलचैन इंफ़्रास्ट्रक्चर लाइब्रेरी है. इसका मकसद, WebAssembly में कोड को आसानी से, तेज़ी से, और असरदार तरीके से कंपाइल करना है. इस पोस्ट में, ExampleScript नाम की सिंथेटिक टॉय लैंग्वेज के उदाहरण का इस्तेमाल करके, Binaryen.js API का इस्तेमाल करके JavaScript में WebAssembly मॉड्यूल लिखने का तरीका जानें. इस कोर्स में, मॉड्यूल बनाने, मॉड्यूल में फ़ंक्शन जोड़ने, और मॉड्यूल से फ़ंक्शन एक्सपोर्ट करने के बुनियादी तरीकों के बारे में बताया गया है. इससे आपको असली प्रोग्रामिंग लैंग्वेज को WebAssembly में कंपाइल करने के पूरे तरीके के बारे में जानकारी मिलेगी. इसके अलावा, आपको Binaryen.js और wasm-opt की मदद से, कमांड लाइन पर Wasm मॉड्यूल को ऑप्टिमाइज़ करने का तरीका भी पता चलेगा.

Binaryen के बारे में जानकारी

Binaryen में एक ही हेडर में, आसानी से इस्तेमाल किया जा सकने वाला C API होता है. साथ ही, इसका इस्तेमाल JavaScript से भी किया जा सकता है. यह WebAssembly फ़ॉर्मैट में इनपुट स्वीकार करता है. हालांकि, यह उन कंपाइलर के लिए सामान्य कंट्रोल फ़्लो ग्राफ़ भी स्वीकार करता है जो इस फ़ॉर्मैट का इस्तेमाल करना पसंद करते हैं.

इंटरमीडिएट रिप्रज़ेंटेशन (आईआर), डेटा स्ट्रक्चर या कोड होता है. इसका इस्तेमाल, सोर्स कोड को दिखाने के लिए, कंपाइलर या वर्चुअल मशीन के अंदर किया जाता है. Binaryen का इंटरनल आईआर, कॉम्पैक्ट डेटा स्ट्रक्चर का इस्तेमाल करता है. साथ ही, इसे सभी उपलब्ध सीपीयू कोर का इस्तेमाल करके, पूरी तरह से पैरलल कोड जनरेशन और ऑप्टिमाइज़ेशन के लिए डिज़ाइन किया गया है. Binaryen का आईआर, WebAssembly का सबसेट होने की वजह से, WebAssembly में कंपाइल हो जाता है.

Binaryen के ऑप्टिमाइज़र में कई पास होते हैं, जिनसे कोड के साइज़ और स्पीड को बेहतर बनाया जा सकता है. इन ऑप्टिमाइज़ेशन का मकसद, Binaryen को इतना बेहतर बनाना है कि इसे खुद ही कंपाइलर के बैकएंड के तौर पर इस्तेमाल किया जा सके. इसमें वेब असेंबली के हिसाब से ऑप्टिमाइज़ेशन शामिल होते हैं. ये ऐसे ऑप्टिमाइज़ेशन होते हैं जो शायद सामान्य काम के लिए इस्तेमाल होने वाले कंपाइलर न कर पाएं. इन्हें Wasm को छोटा करने के तौर पर देखा जा सकता है.

Binaryen के उदाहरण के तौर पर AssemblyScript

Binaryen का इस्तेमाल कई प्रोजेक्ट करते हैं. उदाहरण के लिए, AssemblyScript, जो TypeScript जैसी भाषा से सीधे WebAssembly में कंपाइल करने के लिए, Binaryen का इस्तेमाल करता है. AssemblyScript के प्लेग्राउंड में, उदाहरण आज़माएं.

AssemblyScript इनपुट:

export function add(a: i32, b: i32): i32 {
  return a + b;
}

Binaryen से जनरेट किया गया, टेक्स्ट फ़ॉर्मैट में मौजूद मिलता-जुलता WebAssembly कोड:

(module
 (type $0 (func (param i32 i32) (result i32)))
 (memory $0 0)
 (export "add" (func $module/add))
 (export "memory" (memory $0))
 (func $module/add (param $0 i32) (param $1 i32) (result i32)
  local.get $0
  local.get $1
  i32.add
 )
)

AssemblyScript का प्लेग्राउंड, जिसमें पिछले उदाहरण के आधार पर जनरेट किया गया WebAssembly कोड दिखाया गया है.

Binaryen टूलचेन

Binaryen टूलचेन, JavaScript डेवलपर और कमांड लाइन के उपयोगकर्ताओं, दोनों के लिए कई काम के टूल उपलब्ध कराता है. इन टूल का एक सबसेट यहां दिया गया है. प्रोजेक्ट की README फ़ाइल में, इसमें शामिल टूल की पूरी सूची उपलब्ध है.

  • binaryen.js: यह एक स्टैंडअलोन JavaScript लाइब्रेरी है, जो Wasm मॉड्यूल बनाने और उन्हें ऑप्टिमाइज़ करने के लिए, Binaryen के तरीकों को दिखाती है. बिल्ड के लिए, npm पर binaryen.js देखें (या इसे सीधे GitHub या unpkg से डाउनलोड करें).
  • wasm-opt: कमांड-लाइन टूल, जो WebAssembly को लोड करता है और उस पर Binaryen IR पास चलाता है.
  • wasm-as और wasm-dis: ये कमांड-लाइन टूल, WebAssembly को असेंबल और डिसअसेम्बल करते हैं.
  • wasm-ctor-eval: कमांड-लाइन टूल, जो कंपाइल करने के समय फ़ंक्शन (या फ़ंक्शन के कुछ हिस्सों) को चला सकता है.
  • wasm-metadce: कमांड-लाइन टूल, जिसका इस्तेमाल करके Wasm फ़ाइलों के कुछ हिस्सों को आसानी से हटाया जा सकता है. यह इस बात पर निर्भर करता है कि मॉड्यूल का इस्तेमाल कैसे किया जा रहा है.
  • wasm-merge: कमांड-लाइन टूल, जो कई Wasm फ़ाइलों को एक फ़ाइल में मर्ज करता है. साथ ही, ऐसा करते समय, उनसे जुड़े इंपोर्ट को एक्सपोर्ट से जोड़ता है. यह JavaScript के लिए बंडलर की तरह ही काम करता है, लेकिन Wasm के लिए.

WebAssembly में कंपाइल करना

आम तौर पर, एक भाषा से दूसरी भाषा में कॉन्टेंट को कंपाइल करने के लिए कई चरण पूरे करने पड़ते हैं. इनमें से सबसे अहम चरण नीचे दिए गए हैं:

  • लेक्सिकल विश्लेषण: सोर्स कोड को टोकन में बांटना.
  • सिंटैक्स का विश्लेषण: एब्स्ट्रैक्ट सिंटैक्स ट्री बनाएं.
  • सेमांटिक विश्लेषण: गड़बड़ियों की जांच करना और भाषा के नियमों को लागू करना.
  • इंटरमीडिएट कोड जनरेशन: ज़्यादा बेहतर तरीके से दिखाएं.
  • कोड जनरेट करना: टारगेट की भाषा में अनुवाद करें.
  • टारगेट के हिसाब से कोड ऑप्टिमाइज़ेशन: टारगेट के लिए ऑप्टिमाइज़ करें.

Unix में, कोड को कंपाइल करने के लिए अक्सर इस्तेमाल किए जाने वाले टूल, lex और yacc हैं:

  • lex (लेक्सिकल ऐनालाइज़र जनरेटर): lex एक ऐसा टूल है जो लेक्सिकल ऐनालाइज़र जनरेट करता है. इन्हें लेक्सर या स्कैनर भी कहा जाता है. यह इनपुट के तौर पर रेगुलर एक्सप्रेशन और उनसे जुड़ी कार्रवाइयों का एक सेट लेता है. साथ ही, लेक्सिकल ऐनालाइज़र के लिए कोड जनरेट करता है, जो इनपुट सोर्स कोड में पैटर्न की पहचान करता है.
  • yacc (Yet Another Compiler Compiler): yacc एक ऐसा टूल है जो सिंटैक्स विश्लेषण के लिए पार्सर जनरेट करता है. यह प्रोग्रामिंग भाषा के व्याकरण के बारे में जानकारी को इनपुट के तौर पर लेता है और पार्स करने वाले टूल के लिए कोड जनरेट करता है. आम तौर पर, पार्स करने वाले टूल, अब्स्ट्रैक्ट सिंटैक्स ट्री (एएसटी) जनरेट करते हैं. ये एएसटी, सोर्स कोड के हैरारकी वाले स्ट्रक्चर को दिखाते हैं.

काम करने का उदाहरण

इस पोस्ट में, पूरी प्रोग्रामिंग लैंग्वेज को कवर करना मुमकिन नहीं है. इसलिए, आसानी से समझने के लिए, ExampleScript नाम की एक बहुत सीमित और बेकार सिंथेटिक प्रोग्रामिंग लैंग्वेज पर विचार करें. यह लैंग्वेज, उदाहरणों के ज़रिए सामान्य ऑपरेशन को दिखाकर काम करती है.

  • add() फ़ंक्शन लिखने के लिए, किसी जोड़ के उदाहरण को कोड में लिखें, जैसे कि 2 + 3.
  • उदाहरण के लिए, multiply() फ़ंक्शन लिखने के लिए, 6 * 12 लिखें.

पहले से दी गई चेतावनी के मुताबिक, यह पूरी तरह से बेकार है. हालांकि, लेक्सिकल ऐनालाइज़र के लिए यह एक रेगुलर एक्सप्रेशन के तौर पर काफ़ी आसान है: /\d+\s*[\+\-\*\/]\s*\d+\s*/.

इसके बाद, पार्सर होना चाहिए. असल में, कैप्चरिंग ग्रुप के नाम वाले रेगुलर एक्सप्रेशन का इस्तेमाल करके, किसी ऐब्स्ट्रैक्ट सिंटैक्स ट्री का बहुत आसान वर्शन बनाया जा सकता है: /(?<first_operand>\d+)\s*(?<operator>[\+\-\*\/])\s*(?<second_operand>\d+)/.

ExampleScript के निर्देशों को एक लाइन में एक ही निर्देश लिखा जाता है. इसलिए, पार्स करने वाला टूल, कोड को लाइन के हिसाब से प्रोसेस कर सकता है. इसके लिए, वह नई लाइन के वर्णों के हिसाब से कोड को अलग करता है. इससे, बुलेट की सूची में दिए गए पहले तीन चरणों की जांच करने के लिए काफ़ी है. ये चरण हैं: लेक्सिकल विश्लेषण, सिंटैक्स विश्लेषण, और सेमांटिक विश्लेषण. इन चरणों का कोड, यहां दी गई लिस्टिंग में मौजूद है.

export default class Parser {
  parse(input) {
    input = input.split(/\n/);
    if (!input.every((line) => /\d+\s*[\+\-\*\/]\s*\d+\s*/gm.test(line))) {
      throw new Error('Parse error');
    }

    return input.map((line) => {
      const { groups } =
        /(?<first_operand>\d+)\s*(?<operator>[\+\-\*\/])\s*(?<second_operand>\d+)/gm.exec(
          line,
        );
      return {
        firstOperand: Number(groups.first_operand),
        operator: groups.operator,
        secondOperand: Number(groups.second_operand),
      };
    });
  }
}

इंटरमीडिएट कोड जनरेशन

अब ExampleScript प्रोग्राम को एब्स्ट्रैक्ट सिंटैक्स ट्री के तौर पर दिखाया जा सकता है. हालांकि, यह बहुत आसान है. अगला चरण, एब्स्ट्रैक्ट इंटरमीडिएट रिप्रज़ेंटेशन बनाना है. पहला चरण, Binaryen में नया मॉड्यूल बनाना है:

const module = new binaryen.Module();

अब्सट्रैक्ट सिंटैक्स ट्री की हर लाइन में एक ट्रिपल होता है, जिसमें firstOperand, operator, और secondOperand शामिल होते हैं. ExampleScript में मौजूद चार ऑपरेटर, यानी +, -, *, और / के लिए, Binaryen के Module#addFunction() तरीके का इस्तेमाल करके, मॉड्यूल में एक नया फ़ंक्शन जोड़ना ज़रूरी है. Module#addFunction() तरीकों के पैरामीटर इस तरह के होते हैं:

  • name: string, फ़ंक्शन का नाम दिखाता है.
  • functionType: Signature, फ़ंक्शन के हस्ताक्षर को दिखाता है.
  • varTypes: Type[], दिए गए क्रम में अन्य लोकल के बारे में बताता है.
  • body: Expression, फ़ंक्शन का कॉन्टेंट.

इस बारे में ज़्यादा जानकारी पाने के लिए, Binaryen दस्तावेज़ पढ़ें. इससे आपको इस बारे में ज़्यादा जानकारी मिलेगी. हालांकि, आखिर में, ExampleScript के + ऑपरेटर के लिए, आपको Module#i32.add() का तरीका मिलेगा. यह कई उपलब्ध इंटिजर ऑपरेशन में से एक है. जोड़ने के लिए दो ऑपरेंड की ज़रूरत होती है, पहला और दूसरा जोड़. फ़ंक्शन को असल में कॉल करने के लिए, उसे Module#addFunctionExport() के साथ एक्सपोर्ट करना होगा.

module.addFunction(
  'add', // name: string
  binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
  binaryen.i32, // results: Type
  [binaryen.i32], // vars: Type[]
  //  body: ExpressionRef
  module.block(null, [
    module.local.set(
      2,
      module.i32.add(
        module.local.get(0, binaryen.i32),
        module.local.get(1, binaryen.i32),
      ),
    ),
    module.return(module.local.get(2, binaryen.i32)),
  ]),
);
module.addFunctionExport('add', 'add');

एब्स्ट्रैक्ट सिंटैक्स ट्री को प्रोसेस करने के बाद, मॉड्यूल में चार तरीके होते हैं. इनमें से तीन तरीके पूर्णांक संख्याओं के साथ काम करते हैं. जैसे, Module#i32.add() पर आधारित add(), Module#i32.sub() पर आधारित subtract(), Module#i32.mul() पर आधारित multiply(), और Module#f64.div() पर आधारित आउटलायर divide(). ऐसा इसलिए है, क्योंकि ExampleScript फ़्लोटिंग पॉइंट के नतीजों के साथ भी काम करता है.

for (const line of parsed) {
      const { firstOperand, operator, secondOperand } = line;

      if (operator === '+') {
        module.addFunction(
          'add', // name: string
          binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
          binaryen.i32, // results: Type
          [binaryen.i32], // vars: Type[]
          //  body: ExpressionRef
          module.block(null, [
            module.local.set(
              2,
              module.i32.add(
                module.local.get(0, binaryen.i32),
                module.local.get(1, binaryen.i32)
              )
            ),
            module.return(module.local.get(2, binaryen.i32)),
          ])
        );
        module.addFunctionExport('add', 'add');
      } else if (operator === '-') {
        module.subtractFunction(
          // Skipped for brevity.
        )
      } else if (operator === '*') {
          // Skipped for brevity.
      }
      // And so on for all other operators, namely `-`, `*`, and `/`.

अगर आपको असल कोड बेस से काम करना है, तो कभी-कभी ऐसा कोड मिल सकता है जिसे कभी इस्तेमाल नहीं किया जाता. ExampleScript को Wasm में कंपाइल करने के उदाहरण में, ग़ैर-एक्सपोर्ट किए गए फ़ंक्शन को जोड़कर, 'काम न करने वाला कोड' (जिसे बाद के चरण में ऑप्टिमाइज़ किया जाएगा और हटा दिया जाएगा) को कृत्रिम तरीके से जोड़ा जा सकता है.

// This function is added, but not exported,
// so it's effectively dead code.
module.addFunction(
  'deadcode', // name: string
  binaryen.createType([binaryen.i32, binaryen.i32]), // params: Type
  binaryen.i32, // results: Type
  [binaryen.i32], // vars: Type[]
  //  body: ExpressionRef
  module.block(null, [
    module.local.set(
      2,
      module.i32.div_u(
        module.local.get(0, binaryen.i32),
        module.local.get(1, binaryen.i32),
      ),
    ),
    module.return(module.local.get(2, binaryen.i32)),
  ]),
);

कंपाइलर अब करीब-करीब तैयार है. यह ज़रूरी नहीं है, लेकिन Module#validate() तरीके का इस्तेमाल करके मॉड्यूल की पुष्टि करना एक अच्छा तरीका है.

if (!module.validate()) {
  throw new Error('Validation error');
}

Wasm कोड पाना

नतीजे के तौर पर मिलने वाला Wasm कोड पाने के लिए, Binaryen में दो तरीके मौजूद हैं. पहला, S-एक्सप्रेशन में .wat फ़ाइल के तौर पर टेक्स्ट के तौर पर दिखाया गया, जो कि मनुष्य के पढ़ने लायक फ़ॉर्मैट में होता है. दूसरा, .wasm फ़ाइल के तौर पर बाइनरी के तौर पर दिखाया गया, जो सीधे ब्राउज़र में चल सकता है. बाइनरी कोड को सीधे ब्राउज़र में चलाया जा सकता है. यह देखने के लिए कि एक्सपोर्ट काम कर रहे हैं या नहीं, एक्सपोर्ट को लॉग करना मददगार हो सकता है.

const textData = module.emitText();
console.log(textData);

const wasmData = module.emitBinary();
const compiled = new WebAssembly.Module(wasmData);
const instance = new WebAssembly.Instance(compiled, {});
console.log('Wasm exports:\n', instance.exports);

नीचे, चारों ऑपरेशन वाले ExampleScript प्रोग्राम का पूरा टेक्स्ट दिखाया गया है. ध्यान दें कि डेड कोड अब भी मौजूद है, लेकिन WebAssembly.Module.exports() के स्क्रीनशॉट के मुताबिक, यह एक्सपोज़ नहीं हुआ है.

(module
 (type $0 (func (param i32 i32) (result i32)))
 (type $1 (func (param f64 f64) (result f64)))
 (export "add" (func $add))
 (export "subtract" (func $subtract))
 (export "multiply" (func $multiply))
 (export "divide" (func $divide))
 (func $add (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (local.set $2
   (i32.add
    (local.get $0)
    (local.get $1)
   )
  )
  (return
   (local.get $2)
  )
 )
 (func $subtract (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (local.set $2
   (i32.sub
    (local.get $0)
    (local.get $1)
   )
  )
  (return
   (local.get $2)
  )
 )
 (func $multiply (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (local.set $2
   (i32.mul
    (local.get $0)
    (local.get $1)
   )
  )
  (return
   (local.get $2)
  )
 )
 (func $divide (param $0 f64) (param $1 f64) (result f64)
  (local $2 f64)
  (local.set $2
   (f64.div
    (local.get $0)
    (local.get $1)
   )
  )
  (return
   (local.get $2)
  )
 )
 (func $deadcode (param $0 i32) (param $1 i32) (result i32)
  (local $2 i32)
  (local.set $2
   (i32.div_u
    (local.get $0)
    (local.get $1)
   )
  )
  (return
   (local.get $2)
  )
 )
)

WebAssembly मॉड्यूल एक्सपोर्ट के DevTools कंसोल का स्क्रीनशॉट, जिसमें चार फ़ंक्शन दिख रहे हैं: जोड़ना, भाग देना, गुणा करना, और घटाना. हालांकि, इसमें एक्सपोज़ नहीं किया गया डेड कोड नहीं दिख रहा है.

WebAssembly को ऑप्टिमाइज़ करना

Binaryen, Wasm कोड को ऑप्टिमाइज़ करने के दो तरीके उपलब्ध कराता है. एक Binaryen.js में और एक कमांड लाइन के लिए. पहला विकल्प, डिफ़ॉल्ट रूप से ऑप्टिमाइज़ेशन के नियमों का स्टैंडर्ड सेट लागू करता है. साथ ही, आपको ऑप्टिमाइज़ और छोटा करने का लेवल सेट करने की सुविधा देता है. वहीं, दूसरा विकल्प डिफ़ॉल्ट रूप से किसी भी नियम का इस्तेमाल नहीं करता. इसके बजाय, इसे पूरी तरह से पसंद के मुताबिक बनाया जा सकता है. इसका मतलब है कि ज़रूरत के मुताबिक प्रयोग करके, अपने कोड के आधार पर ऑप्टिमाइज़ेशन के लिए सेटिंग को बेहतर बनाया जा सकता है.

Binaryen.js का इस्तेमाल करके ऑप्टिमाइज़ करना

Binaryen की मदद से Wasm मॉड्यूल को ऑप्टिमाइज़ करने का सबसे आसान तरीका यह है कि आप सीधे तौर पर Binaryen.js के Module#optimize() तरीके को कॉल करें. इसके अलावा, ऑप्टिमाइज़ और छोटा करने के लेवल को सेट करना भी ज़रूरी नहीं है.

// Assume the `wast` variable contains a Wasm program.
const module = binaryen.parseText(wast);
binaryen.setOptimizeLevel(2);
binaryen.setShrinkLevel(1);
// This corresponds to the `-Os` setting.
module.optimize();

ऐसा करने से, पहले जो डेड कोड कृत्रिम रूप से जोड़ा गया था वह हट जाता है. इसलिए, ExampleScript टॉय के उदाहरण के Wasm वर्शन के टेक्स्ट में अब वह कोड नहीं दिखता. यह भी ध्यान दें कि ऑप्टिमाइज़ेशन के चरणों के ज़रिए local.set/get पेयर कैसे हटाए जाते हैं. जैसे, SimplifyLocals (स्थानीय वैरिएबल से जुड़े अलग-अलग ऑप्टिमाइज़ेशन) और Vacuum (बेवजह इस्तेमाल किए जा रहे कोड को हटाता है). साथ ही, return को RemoveUnusedBrs (जिन जगहों पर ब्रेक की ज़रूरत नहीं है वहां से ब्रेक हटाता है) के ज़रिए हटाया जाता है.

 (module
 (type $0 (func (param i32 i32) (result i32)))
 (type $1 (func (param f64 f64) (result f64)))
 (export "add" (func $add))
 (export "subtract" (func $subtract))
 (export "multiply" (func $multiply))
 (export "divide" (func $divide))
 (func $add (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
  (i32.add
   (local.get $0)
   (local.get $1)
  )
 )
 (func $subtract (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
  (i32.sub
   (local.get $0)
   (local.get $1)
  )
 )
 (func $multiply (; has Stack IR ;) (param $0 i32) (param $1 i32) (result i32)
  (i32.mul
   (local.get $0)
   (local.get $1)
  )
 )
 (func $divide (; has Stack IR ;) (param $0 f64) (param $1 f64) (result f64)
  (f64.div
   (local.get $0)
   (local.get $1)
  )
 )
)

कई ऑप्टिमाइज़ेशन पास होते हैं. साथ ही, Module#optimize() ऑप्टिमाइज़ और छोटा करने के लेवल के डिफ़ॉल्ट सेट का इस्तेमाल करता है. पूरी तरह से कस्टमाइज़ करने के लिए, आपको कमांड लाइन टूल wasm-opt का इस्तेमाल करना होगा.

wasm-opt कमांड लाइन टूल की मदद से ऑप्टिमाइज़ करना

इस्तेमाल किए जाने वाले पास को पूरी तरह से पसंद के मुताबिक बनाने के लिए, Binaryen में wasm-opt कमांड लाइन टूल शामिल होता है. ऑप्टिमाइज़ेशन के संभावित विकल्पों की पूरी सूची पाने के लिए, टूल का सहायता मैसेज देखें. wasm-opt टूल शायद टूल में सबसे लोकप्रिय है. इसका इस्तेमाल, कई कंपाइलर टूलचेन ने Wasm कोड को ऑप्टिमाइज़ करने के लिए किया है. इनमें Emscripten, J2CL, Kotlin/Wasm, dart2wasm, wasm-pack वगैरह शामिल हैं.

wasm-opt --help

पास के बारे में आपको जानकारी देने के लिए, यहां कुछ पास के बारे में बताया गया है. इनमें से कुछ ऐसे पास हैं जिन्हें विशेषज्ञों की जानकारी के बिना भी समझा जा सकता है:

  • CodeFolding: डुप्लीकेट कोड को मर्ज करके उसे हटाता है. उदाहरण के लिए, अगर दो if ग्रुप के आखिर में कुछ शेयर किए गए निर्देश हैं.
  • DeadArgumentElimination: लिंक टाइम ऑप्टिमाइज़ेशन पास, किसी फ़ंक्शन के लिए आर्ग्युमेंट हटाने के लिए है. ऐसा तब किया जाता है, जब फ़ंक्शन को हमेशा एक ही कॉन्स्टेंट के साथ कॉल किया जाता है.
  • MinifyImportsAndExports: इन फ़ंक्शन को "a", "b" तक छोटा कर देता है.
  • DeadCodeElimination: डैड कोड हटाएं.

ऑप्टिमाइज़ेशन कुकबुक में कई सलाह दी गई हैं. इनसे यह पता चलता है कि कौनसे फ़्लैग ज़्यादा अहम हैं और जिन्हें सबसे पहले आज़माना चाहिए. उदाहरण के लिए, कभी-कभी wasm-opt को बार-बार इस्तेमाल करने पर, इनपुट का साइज़ और भी छोटा हो जाता है. ऐसे मामलों में, --converge फ़्लैग के साथ चलाने पर, तब तक दोहराव होता रहता है, जब तक कोई और ऑप्टिमाइज़ेशन नहीं होता और तय किए गए पॉइंट तक नहीं पहुंचा जाता.

डेमो

इस पोस्ट में बताए गए कॉन्सेप्ट को काम करते हुए देखने के लिए, एम्बेड किए गए डिमो को चलाएं. इसके लिए, अपनी पसंद के मुताबिक ExampleScript का कोई भी इनपुट दें. साथ ही, डेमो का सोर्स कोड देखना न भूलें.

मीटिंग में सामने आए नतीजे

Binaryen, भाषाओं को WebAssembly में कंपाइल करने और उससे मिले कोड को ऑप्टिमाइज़ करने के लिए, एक बेहतरीन टूलकिट उपलब्ध कराता है. इसकी JavaScript लाइब्रेरी और कमांड-लाइन टूल, इस्तेमाल में आसान और सुविधाजनक हैं. इस पोस्ट में, Wasm कंपाइलेशन के मुख्य सिद्धांतों के बारे में बताया गया है. साथ ही, Binaryen के असरदार होने और ज़्यादा से ज़्यादा ऑप्टिमाइज़ेशन की संभावना के बारे में बताया गया है. Binaryen के ऑप्टिमाइज़ेशन को पसंद के मुताबिक बनाने के कई विकल्पों के लिए, Wasm के इंटरनल के बारे में अच्छी जानकारी ज़रूरी होती है. हालांकि, आम तौर पर डिफ़ॉल्ट सेटिंग पहले से ही बेहतर तरीके से काम करती हैं. इसके बाद, Binaryen की मदद से कोड को कॉम्पाइल और ऑप्टिमाइज़ करने का आनंद लें!

आभार

इस पोस्ट की समीक्षा अलोन ज़काई, थॉमस लाइवली, और रेचल एंड्रयू ने की है.