أصبحت تحسينات WasmGC وWasm tail call متوفّرة الآن في الإصدار الأساسي

تاريخ النشر: 29 كانون الثاني (يناير) 2025

WebAssembly Garbage Collection (WasmGC)

هناك نوعان من لغات البرمجة: لغات البرمجة التي تجمع المهملات ولغات البرمجة التي تتطلّب إدارة الذاكرة يدويًا. ومن الأمثلة على هذه الفئة، من بين غيرها الكثير، Kotlin أو PHP أو Java. ومن الأمثلة على هذه الفئة C أو C++ أو Rust. كقاعدة عامة، من المرجّح أن تتضمّن لغات البرمجة ذات المستوى الأعلى ميزة جمع المهملات كميزة قياسية.

بعبارة مبسطة، جمع المهملات هو محاولة استرداد الذاكرة التي خصصها البرنامج، ولكن لم يعُد يتمّ الرجوع إليها. وتُعرف هذه الذاكرة باسم "الذاكرة المهملة". هناك العديد من الاستراتيجيات لتنفيذ عملية جمع المهملات. ومن أسهل الطرق لفهم ذلك هو احتساب عدد الإشارات حيث يكون الهدف هو احتساب عدد الإشارات إلى العناصر في الذاكرة.

قد يبدو الأمر غريبًا، ولكن يتم تنفيذ لغات البرمجة بلغات برمجة أخرى. على سبيل المثال، يتم تنفيذ وقت تشغيل PHP بشكل أساسي بلغة C. إذا أراد المطوّرون تحويل لغة مثل PHP إلى لغة برمجة تطبيقات صغيرة (Wasm)، عليهم عادةً تجميع جميع الأجزاء، مثل محلل اللغة ودعم المكتبة وجمع المهملات وغيرها من المكوّنات المهمة.

يتم تشغيل Wasm في المتصفّح في سياق لغة المضيف JavaScript. في Chrome، يتم تشغيل JavaScript وWasm في V8، وهو محرك JavaScript مفتوح المصدر من Google. يحتوي V8 على أداة جمع المهملات. وهذا يعني أنّ المطوّرين الذين يستخدِمون، على سبيل المثال، لغة PHP المجمّعة إلى Wasm، ينتهي بهم الأمر بشحن رمز لغة مجمّعة (PHP) لجمع المهملات إلى المتصفّح الذي يتضمّن أداة جمع المهملات، ما يتسبب في إهدار الموارد. وهنا يأتي دور WasmGC.

للاطّلاع على مزيد من المعلومات عن WasmGC، يمكنك قراءة المقالة WebAssembly Garbage Collection (WasmGC) now enabled by default in Chrome، وإذا أردت التعمّق أكثر، يمكنك الاطّلاع على مقالة مدوّنة V8 A new way to bring garbage collected programming languages efficiently to WebAssembly.

تحسينات على طلبات الاستدعاء النهائية في لغة Wasm

يُقال إنّ طلبًا معيّنًا في موضع المتابعة إذا كان آخر تعليمات تم تنفيذها قبل الرجوع من الدالة الحالية. يمكن للمُجمِّعين تحسين هذه المكالمات عن طريق تجاهل إطار المُتصل واستبدال المكالمة بقفزة. وهذا مفيد بشكل خاص للدوالّ المتكرّرة. على سبيل المثال، خذ دالة C هذه التي تضيف عناصر قائمة مرتبطة:

int sum(List* list, int acc) {
  if (list == nullptr) return acc;
  return sum(list->next, acc + list->val);
}

في حال إجراء مكالمة عادية، يستهلك ذلك مساحة تسلسل استدعاءات O(n): يضيف كل عنصر من القائمة إطارًا جديدًا في تسلسل استدعاءات الدوال البرمجية. مع قائمة طويلة بما يكفي، يمكن أن يؤدي ذلك إلى تجاوز الحزمة بسرعة كبيرة. من خلال استبدال الطلب بقفزة، يحوّل تحسين المكالمات النهائية هذه الدالة المتكررة بفعالية إلى حلقة تستخدِم مساحة الحزمة O(1):

int sum(List* list, int acc) {
  while (list != nullptr) {
    acc = acc + list->val;
    list = list->next;
  }
  return acc;
}

وهذا التحسين مهم بشكل خاص للغات الوظيفية. وتعتمد هذه اللغات بشكل كبير على الدوال المتكرّرة، ولا توفّر حتى اللغات الخالصة مثل Haskell هياكل التحكّم في الحلقات. يستخدم أي نوع من التكرار المخصّص عادةً الاستدعاء الذاتي بطريقة أو بأخرى. بدون تحسين المكالمات النهائية، سيؤدي ذلك بسرعة إلى حدوث تدفّق زائد في الذاكرة المؤقتة لأي برنامج غير بسيط، ما سيؤدي إلى نفاد مساحة الذاكرة المؤقتة بسرعة.

في البداية، لم يكن WebAssembly يسمح بتحسينات "طلبات الاستدعاء النهائية" هذه، ولكن تغيّر ذلك مع اقتراح إضافة طلبات الاستدعاء النهائية. للاطّلاع على مزيد من المعلومات، يمكنك قراءة مقالة WebAssembly tail calls على مدوّنة V8.

الاستنتاجات

والآن، مع توفّر تحسينات WasmGC وtail call في الإصدار الأساسي، يمكن للمزيد من التطبيقات استخدام هذه الميزات لتحقيق أداء أفضل، مثل "جداول بيانات Google" من خلال نقل وحدة عمل العمليات الحسابية في "جداول بيانات Google" إلى WasmGC.