diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 477bd20564f91..a6644dfc5fc9b 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -40598,6 +40598,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart + ../../../flutte ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/codecs.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/dart_js_conversion.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/image.dart + ../../../flutter/LICENSE @@ -40634,6 +40635,7 @@ ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.da ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/dart_js_conversion.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart + ../../../flutter/LICENSE ORIGIN: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart + ../../../flutter/LICENSE @@ -43471,6 +43473,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/shadow.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/canvas.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/codecs.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/dart_js_conversion.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/filters.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/font_collection.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/image.dart @@ -43507,6 +43510,7 @@ FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/shaders.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/surface.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/vertices.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart +FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/dart_js_conversion.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/renderer.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/svg.dart FILE: ../../../flutter/lib/web_ui/lib/src/engine/test_embedding.dart diff --git a/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart b/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart index 4b5c85dff526d..0ef83b4b9810e 100644 --- a/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart +++ b/lib/web_ui/lib/src/engine/canvaskit/native_memory.dart @@ -20,9 +20,9 @@ import 'package:ui/src/engine.dart'; /// 4. GC decides to perform a GC cycle and collects CkPaint. /// 5. The finalizer function is called with the SkPaint as the sole argument. /// 6. We call `delete` on SkPaint. -DomFinalizationRegistry _finalizationRegistry = createDomFinalizationRegistry( +DomFinalizationRegistry _finalizationRegistry = DomFinalizationRegistry( (JSBoxedDartObject boxedUniq) { - final UniqueRef uniq = boxedUniq.toDart as UniqueRef; + final UniqueRef uniq = boxedUniq.fromJSWrapper as UniqueRef; uniq.collect(); }.toJS ); @@ -34,7 +34,7 @@ NativeMemoryFinalizationRegistry nativeMemoryFinalizationRegistry = NativeMemory class NativeMemoryFinalizationRegistry { void register(Object owner, UniqueRef ref) { if (browserSupportsFinalizationRegistry) { - _finalizationRegistry.register(owner, ref.toJSBox); + _finalizationRegistry.register(owner.toJSWrapper, ref.toJSWrapper); } } } diff --git a/lib/web_ui/lib/src/engine/dom.dart b/lib/web_ui/lib/src/engine/dom.dart index 386666d6797ae..8dfa57b2a9420 100644 --- a/lib/web_ui/lib/src/engine/dom.dart +++ b/lib/web_ui/lib/src/engine/dom.dart @@ -9,6 +9,7 @@ import 'dart:typed_data'; import 'package:js/js_util.dart' as js_util; import 'package:meta/meta.dart'; +import 'package:ui/src/engine/skwasm/skwasm_stub.dart' if (dart.library.ffi) 'package:ui/src/engine/skwasm/skwasm_impl.dart'; import 'browser_detection.dart'; @@ -37,6 +38,15 @@ import 'browser_detection.dart'; /// used carefully and only on types that are known to not contains `JSNull` and /// `JSUndefined`. extension ObjectToJSAnyExtension on Object { + // Once `Object.toJSBox` is faster (see + // https://github.com/dart-lang/sdk/issues/55183) we can remove this + // backend-specific workaround. + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') + JSAny get toJSWrapper => dartToJsWrapper(this); + + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') JSAny get toJSAnyShallow { if (isWasm) { return toJSAnyDeep; @@ -45,10 +55,18 @@ extension ObjectToJSAnyExtension on Object { } } + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') JSAny get toJSAnyDeep => js_util.jsify(this) as JSAny; } extension JSAnyToObjectExtension on JSAny { + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') + Object get fromJSWrapper => jsWrapperToDart(this); + + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') Object get toObjectShallow { if (isWasm) { return toObjectDeep; @@ -57,6 +75,8 @@ extension JSAnyToObjectExtension on JSAny { } } + @pragma('wasm:prefer-inline') + @pragma('dart2js:tryInline') Object get toObjectDeep => js_util.dartify(this)!; } @@ -3648,38 +3668,24 @@ extension DomTextDecoderExtension on DomTextDecoder { @JS('window.FinalizationRegistry') @staticInterop -class DomFinalizationRegistry {} - -@JS('window.FinalizationRegistry') -external JSAny? get _finalizationRegistryConstructor; - -// Note: We don't use a factory constructor here because there is an issue in -// dart2js that causes a crash in the Google3 build if we do use a factory -// constructor. See b/284478971 -DomFinalizationRegistry createDomFinalizationRegistry(JSFunction cleanup) => - js_util.callConstructor( - _finalizationRegistryConstructor!.toObjectShallow, [cleanup]); +class DomFinalizationRegistry { + external factory DomFinalizationRegistry(JSFunction cleanup); +} extension DomFinalizationRegistryExtension on DomFinalizationRegistry { @JS('register') - external JSVoid _register1(JSAny target, JSAny value); + external JSVoid register(JSAny target, JSAny value); @JS('register') - external JSVoid _register2(JSAny target, JSAny value, JSAny token); - void register(Object target, Object value, [Object? token]) { - if (token != null) { - _register2( - target.toJSAnyShallow, value.toJSAnyShallow, token.toJSAnyShallow); - } else { - _register1(target.toJSAnyShallow, value.toJSAnyShallow); - } - } + external JSVoid registerWithToken(JSAny target, JSAny value, JSAny token); @JS('unregister') - external JSVoid _unregister(JSAny token); - void unregister(Object token) => _unregister(token.toJSAnyShallow); + external JSVoid unregister(JSAny token); } +@JS('window.FinalizationRegistry') +external JSAny? get _finalizationRegistryConstructor; + /// Whether the current browser supports `FinalizationRegistry`. bool browserSupportsFinalizationRegistry = _finalizationRegistryConstructor != null; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart index fd370c7a0fb18..e36e4359c67bc 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl.dart @@ -11,6 +11,7 @@ import 'dart:ffi'; export 'skwasm_impl/canvas.dart'; export 'skwasm_impl/codecs.dart'; +export 'skwasm_impl/dart_js_conversion.dart'; export 'skwasm_impl/filters.dart'; export 'skwasm_impl/font_collection.dart'; export 'skwasm_impl/image.dart'; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/dart_js_conversion.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/dart_js_conversion.dart new file mode 100644 index 0000000000000..dbde1bee5cd5d --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/dart_js_conversion.dart @@ -0,0 +1,16 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:_wasm'; +import 'dart:js_interop'; + +@pragma('wasm:prefer-inline') +@pragma('dart2js:tryInline') +JSAny dartToJsWrapper(Object object) => + WasmAnyRef.fromObject(object).externalize().toJS; + +@pragma('wasm:prefer-inline') +@pragma('dart2js:tryInline') +Object jsWrapperToDart(JSAny jsWrapper) => + externRefForJSAny(jsWrapper).internalize()!.toObject(); diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/memory.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/memory.dart index 030122c83f5e3..c0f9a8470b3ba 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/memory.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_impl/memory.dart @@ -28,7 +28,7 @@ typedef DisposeFunction = void Function(Pointer); class SkwasmFinalizationRegistry { SkwasmFinalizationRegistry(this.dispose) - : registry = createDomFinalizationRegistry(((JSNumber address) => + : registry = DomFinalizationRegistry(((JSNumber address) => dispose(Pointer.fromAddress(address.toDartDouble.toInt())) ).toJS); @@ -36,11 +36,14 @@ class SkwasmFinalizationRegistry { final DisposeFunction dispose; void register(SkwasmObjectWrapper wrapper) { - registry.register(wrapper, wrapper.handle.address, wrapper); + final JSAny jsWrapper = wrapper.toJSWrapper; + registry.registerWithToken( + jsWrapper, wrapper.handle.address.toJS, jsWrapper); } void evict(SkwasmObjectWrapper wrapper) { - registry.unregister(wrapper); + final JSAny jsWrapper = wrapper.toJSWrapper; + registry.unregister(jsWrapper); dispose(wrapper.handle); } } diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart index 382d34840e9f6..50c1791aecc2e 100644 --- a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub.dart @@ -6,4 +6,5 @@ // ignore: unnecessary_library_directive library skwasm_stub; +export 'skwasm_stub/dart_js_conversion.dart'; export 'skwasm_stub/renderer.dart'; diff --git a/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/dart_js_conversion.dart b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/dart_js_conversion.dart new file mode 100644 index 0000000000000..b05af5dcff599 --- /dev/null +++ b/lib/web_ui/lib/src/engine/skwasm/skwasm_stub/dart_js_conversion.dart @@ -0,0 +1,13 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:js_interop'; + +@pragma('wasm:prefer-inline') +@pragma('dart2js:tryInline') +JSAny dartToJsWrapper(Object object) => object as JSAny; + +@pragma('wasm:prefer-inline') +@pragma('dart2js:tryInline') +Object jsWrapperToDart(JSAny jsWrapper) => jsWrapper; diff --git a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart index 6a1fea063ef34..69d9f6bf85967 100644 --- a/lib/web_ui/test/canvaskit/canvaskit_api_test.dart +++ b/lib/web_ui/test/canvaskit/canvaskit_api_test.dart @@ -1928,8 +1928,8 @@ void _paragraphTests() { // FinalizationRegistry because it depends on GC, which cannot be controlled, // So the test simply tests that a FinalizationRegistry can be constructed // and its `register` method can be called. - final DomFinalizationRegistry registry = createDomFinalizationRegistry((String arg) {}.toJS); - registry.register(Object(), Object()); + final DomFinalizationRegistry registry = DomFinalizationRegistry((String arg) {}.toJS); + registry.register(Object().toJSWrapper, Object().toJSWrapper); }); }