بهینه سازی تماس WasmGC و Wasm tail اکنون به تازگی در دسترس است

تاریخ انتشار: 29 ژانویه 2025

WebAssembly Garbage Collection (WasmGC)

دو نوع زبان برنامه نویسی وجود دارد: زبان های برنامه نویسی جمع آوری شده زباله و زبان های برنامه نویسی که نیاز به مدیریت دستی حافظه دارند. نمونه های قبلی، در میان بسیاری دیگر، کاتلین، پی اچ پی یا جاوا هستند. نمونه هایی از دومی C، C++ یا Rust هستند. به عنوان یک قاعده کلی، زبان های برنامه نویسی سطح بالاتر به احتمال زیاد دارای جمع آوری زباله به عنوان یک ویژگی استاندارد هستند.

به عبارت ساده‌تر، جمع‌آوری زباله تلاشی برای بازیابی حافظه است که توسط برنامه تخصیص داده شده است، اما دیگر به آن اشاره نمی‌شود. به چنین خاطره ای زباله می گویند. راهکارهای زیادی برای اجرای جمع آوری زباله وجود دارد. یکی از ساده‌ترین روش‌ها، شمارش ارجاع است که در آن هدف، شمارش تعداد ارجاعات به اشیاء در حافظه است.

ممکن است شبیه به آغاز کار باشد، اما زبان های برنامه نویسی در زبان های برنامه نویسی دیگر پیاده سازی می شوند. به عنوان مثال، زمان اجرا PHP اساساً در C پیاده‌سازی می‌شود. اگر توسعه‌دهندگان می‌خواهند زبانی مانند PHP را در Wasm کامپایل کنند، معمولاً باید همه بخش‌ها را کامپایل کنند، مانند تجزیه‌کننده زبان، پشتیبانی کتابخانه، جمع‌آوری زباله و سایر اجزای حیاتی.

Wasm در مرورگر در زمینه جاوا اسکریپت زبان میزبان اجرا می شود. در کروم، جاوا اسکریپت و Wasm در V8، موتور منبع باز جاوا اسکریپت گوگل اجرا می شوند. و V8 در حال حاضر یک زباله جمع کن دارد. این بدان معناست که توسعه‌دهندگانی که از مثلاً PHP کامپایل شده در Wasm استفاده می‌کنند، یک پیاده‌سازی جمع‌آوری زباله از زبان انتقال‌یافته (PHP) را به مرورگری ارسال می‌کنند که قبلاً جمع‌آوری زباله دارد، که به همان اندازه که به نظر می‌رسد ضایع‌کننده است. اینجاست که WasmGC وارد می شود.

برای کسب اطلاعات بیشتر در مورد WasmGC، WebAssembly Garbage Collection (WasmGC) را که اکنون به طور پیش فرض در Chrome فعال شده است بخوانید و اگر می خواهید عمیق تر باشید، پست وبلاگ V8 را بررسی کنید روشی جدید برای آوردن کارآمد زبان های برنامه نویسی جمع آوری زباله به WebAssembly

بهینه سازی تماس Wasm tail

اگر آخرین دستوری باشد که قبل از بازگشت از تابع فعلی اجرا شده است، به یک فراخوانی در موقعیت دم گفته می شود. کامپایلرها می توانند چنین تماس هایی را با دور انداختن فریم تماس گیرنده و جایگزینی تماس با یک پرش بهینه کنند. این به ویژه برای توابع بازگشتی مفید است. به عنوان مثال، این تابع 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 اجازه چنین بهینه سازی تماس های دنباله ای را نمی داد، اما با پیشنهاد Tail Call Extension تغییر کرد. برای عمیق تر شدن، مقاله فراخوانی های دنباله WebAssembly را در وبلاگ V8 بخوانید.

نتیجه گیری

اکنون با در دسترس بودن WasmGC و بهینه‌سازی تماس دنباله‌ای که به تازگی در دسترس است، برنامه‌های بیشتری می‌توانند از این ویژگی‌ها برای عملکرد بهتر استفاده کنند، برای مثال، Google Sheets با انتقال کاربر محاسبه Google Sheets به WasmGC انجام داد.