Both backends interface with a WebAssembly heap that is not managed by the Dart garbage collector (GC), which necessitates an explicit memory management system to prevent leaks.
Current State
Both the CanvasKit and Skwasm backends have implemented separate, parallel memory management systems. Critically, both systems are built on the exact same underlying browser feature: the JavaScript FinalizationRegistry, which is accessed via Dart's JS interop (DomFinalizationRegistry).
- The CanvasKit backend has a well-defined system in
lib/src/engine/canvaskit/native_memory.dart.
- The Skwasm backend has its own implementation with nearly identical logic in
lib/src/engine/skwasm/skwasm_impl/memory.dart.
This has resulted in two parallel implementations of the same logic: registering a native object with a finalizer and providing a mechanism for explicit disposal. This is a classic case of code duplication that increases maintenance overhead and can lead to subtle behavioral differences.
Proposed Unification
Since both backends already use the same underlying finalization mechanism, their Dart wrapper implementations can be unified.
The first step is to merge the logic from native_memory.dart and skwasm_impl/memory.dart into a single, generic NativeResourceManager class. This class would encapsulate the entire finalization and object-tracking logic, configured with a backend-specific "deleter" function upon creation (e.g., (handle) => handle.delete() for CanvasKit, (ptr) => free(ptr) for Skwasm).
As a second, follow-up step, this unified NativeResourceManager can be migrated from the JavaScript FinalizationRegistry to the modern, Dart-idiomatic dart:ffi's Finalizer. This would remove the JS interop dependency and align the web engine with standard Dart practices for managing native resources.
Both backends interface with a WebAssembly heap that is not managed by the Dart garbage collector (GC), which necessitates an explicit memory management system to prevent leaks.
Current State
Both the CanvasKit and Skwasm backends have implemented separate, parallel memory management systems. Critically, both systems are built on the exact same underlying browser feature: the JavaScript
FinalizationRegistry, which is accessed via Dart's JS interop (DomFinalizationRegistry).lib/src/engine/canvaskit/native_memory.dart.lib/src/engine/skwasm/skwasm_impl/memory.dart.This has resulted in two parallel implementations of the same logic: registering a native object with a finalizer and providing a mechanism for explicit disposal. This is a classic case of code duplication that increases maintenance overhead and can lead to subtle behavioral differences.
Proposed Unification
Since both backends already use the same underlying finalization mechanism, their Dart wrapper implementations can be unified.
The first step is to merge the logic from
native_memory.dartandskwasm_impl/memory.dartinto a single, genericNativeResourceManagerclass. This class would encapsulate the entire finalization and object-tracking logic, configured with a backend-specific "deleter" function upon creation (e.g.,(handle) => handle.delete()for CanvasKit,(ptr) => free(ptr)for Skwasm).As a second, follow-up step, this unified
NativeResourceManagercan be migrated from the JavaScriptFinalizationRegistryto the modern, Dart-idiomaticdart:ffi'sFinalizer. This would remove the JS interop dependency and align the web engine with standard Dart practices for managing native resources.