From ad62f6033bfa80f27757bb62bab3a3acbc662a4c Mon Sep 17 00:00:00 2001 From: Srujan Gaddam Date: Tue, 15 Aug 2023 20:57:17 +0000 Subject: [PATCH] [dart:js_interop] Relabel globalJSObject as globalContext and point to object used in static interop lowerings This is likely more useful than returning globalThis always. It allows users to workaround issues with lowerings without having to worry about browser compatibility differences. CoreLibraryReviewExempt: Backend-specific library. Change-Id: I01479211fe6b573c845de5b134d36338c40fc10d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319301 Reviewed-by: Sigmund Cherem Commit-Queue: Srujan Gaddam --- CHANGELOG.md | 4 +- .../src/transformations/export_creator.dart | 8 +- .../js_shared/lib/js_interop_patch.dart | 3 +- .../_internal/wasm/lib/js_interop_patch.dart | 5 +- sdk/lib/js_interop/js_interop.dart | 5 +- tests/lib/js_interop_unsafe/basic_test.dart | 78 +++++++++---------- 6 files changed, 53 insertions(+), 50 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c82b350a8d..f82dede9d65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,7 +57,9 @@ case in Dart2JS and DDC. We used either `self` or DDC's `global` in non-static interop APIs with `package:js`. So, static interop APIs will now use one of those global contexts. Functionally, this should matter in only a very small - number of cases, like when using older browser versions. + number of cases, like when using older browser versions. `dart:js_interop`'s + `globalJSObject` is also renamed to `globalContext` and returns the global + context used in the lowerings. ## 3.1.0 diff --git a/pkg/_js_interop_checks/lib/src/transformations/export_creator.dart b/pkg/_js_interop_checks/lib/src/transformations/export_creator.dart index f6f7545a96a..6ebba4e0d99 100644 --- a/pkg/_js_interop_checks/lib/src/transformations/export_creator.dart +++ b/pkg/_js_interop_checks/lib/src/transformations/export_creator.dart @@ -27,7 +27,7 @@ class ExportCreator extends Transformer { final ExportChecker _exportChecker; final Procedure _functionToJS; final Procedure _getProperty; - final Procedure _globalJSObject; + final Procedure _globalContext; final Class _jsAny; final Class _jsObject; final Procedure _setProperty; @@ -48,8 +48,8 @@ class ExportCreator extends Transformer { 'dart:js_interop', 'FunctionToJSExportedDartFunction|get#toJS'), _getProperty = _typeEnvironment.coreTypes.index.getTopLevelProcedure( 'dart:js_interop_unsafe', 'JSObjectUtilExtension|[]'), - _globalJSObject = _typeEnvironment.coreTypes.index - .getTopLevelProcedure('dart:js_interop', 'get:globalJSObject'), + _globalContext = _typeEnvironment.coreTypes.index + .getTopLevelProcedure('dart:js_interop', 'get:globalContext'), _jsAny = _typeEnvironment.coreTypes.index .getClass('dart:_js_types', 'JSAny'), _jsObject = _typeEnvironment.coreTypes.index @@ -201,7 +201,7 @@ class ExportCreator extends Transformer { // Get the global 'Object' property. Expression getObjectProperty() => asJSObject(StaticInvocation(_getProperty, - Arguments([StaticGet(_globalJSObject), toJSString('Object')]))) + Arguments([StaticGet(_globalContext), toJSString('Object')]))) ..fileOffset = node.fileOffset; // Get a fresh object literal, using the proto to create it if one was diff --git a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart index 0d489d29831..a2afcadd61d 100644 --- a/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart +++ b/sdk/lib/_internal/js_shared/lib/js_interop_patch.dart @@ -5,13 +5,14 @@ import 'dart:_foreign_helper' as foreign_helper; import 'dart:_interceptors' show JavaScriptObject; import 'dart:_internal' show patch; +import 'dart:_js_helper' show staticInteropGlobalContext; import 'dart:_js_types'; import 'dart:js_util' as js_util; import 'dart:typed_data'; @patch @pragma('dart2js:prefer-inline') -JSObject get globalJSObject => js_util.globalThis as JSObject; +JSObject get globalContext => staticInteropGlobalContext as JSObject; /// Helper for working with the [JSAny?] top type in a backend agnostic way. /// TODO(joshualitt): Remove conflation of null and undefined after migration. diff --git a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart index b89e983b08f..044ee379a2f 100644 --- a/sdk/lib/_internal/wasm/lib/js_interop_patch.dart +++ b/sdk/lib/_internal/wasm/lib/js_interop_patch.dart @@ -17,10 +17,9 @@ import 'dart:typed_data'; /// TODO(joshualitt): Find a way to get rid of the explicit casts. T _box(WasmExternRef? ref) => JSValue(ref) as T; -// TODO(joshualitt): Eventually delete `dart:js_util` on Dart2Wasm and migrate -// any used logic to this file. +// This should match the global context we use in our static interop lowerings. @patch -JSObject get globalJSObject => js_util.globalThis as JSObject; +JSObject get globalContext => js_util.globalThis as JSObject; /// Helper for working with the [JSAny?] top type in a backend agnostic way. @patch diff --git a/sdk/lib/js_interop/js_interop.dart b/sdk/lib/js_interop/js_interop.dart index 15d9a0eefdd..36e4d5f844f 100644 --- a/sdk/lib/js_interop/js_interop.dart +++ b/sdk/lib/js_interop/js_interop.dart @@ -136,8 +136,9 @@ typedef JSBoolean = js_types.JSBoolean; /// The type of JS strings, [JSString] <: [JSAny]. typedef JSString = js_types.JSString; -/// A getter to retrieve the Global [JSObject]. -external JSObject get globalJSObject; +/// A getter to retrieve the global context that is used in static interop +/// lowering. +external JSObject get globalContext; /// `JSUndefined` and `JSNull` are actual reified types on some backends, but /// not others. Instead, users should use nullable types for any type that could diff --git a/tests/lib/js_interop_unsafe/basic_test.dart b/tests/lib/js_interop_unsafe/basic_test.dart index 820761f0fec..f5becd4c2a0 100644 --- a/tests/lib/js_interop_unsafe/basic_test.dart +++ b/tests/lib/js_interop_unsafe/basic_test.dart @@ -44,11 +44,11 @@ void equalTest() { globalThis.funcData = function JSClass() {} globalThis.JSClass = new globalThis.funcData(); '''); - JSObject gt = globalJSObject; + JSObject gc = globalContext; void test(String propertyName, bool testCanonicalization) { - Expect.equals(gt[propertyName.toJS], gt[propertyName.toJS]); + Expect.equals(gc[propertyName.toJS], gc[propertyName.toJS]); if (testCanonicalization) { - Expect.equals(gt[propertyName.toJS], gt[(propertyName + "2").toJS]); + Expect.equals(gc[propertyName.toJS], gc[(propertyName + "2").toJS]); } } @@ -83,11 +83,11 @@ void typeofTest() { }; void test(String property, String expectedType) { Expect.isTrue( - globalJSObject[property.toJS]?.typeofEquals(expectedType.toJS).toDart); + globalContext[property.toJS]?.typeofEquals(expectedType.toJS).toDart); for (final type in types) { if (type != expectedType) { Expect.isFalse( - globalJSObject[property.toJS]?.typeofEquals(type.toJS).toDart); + globalContext[property.toJS]?.typeofEquals(type.toJS).toDart); } } } @@ -109,10 +109,10 @@ void instanceOfTest() { globalThis.obj = new JSClass1(); '''); - JSObject gt = globalJSObject; - JSObject obj = gt['obj'.toJS] as JSObject; - JSFunction jsClass1Constructor = gt['JSClass1'.toJS] as JSFunction; - JSFunction jsClass2Constructor = gt['JSClass2'.toJS] as JSFunction; + JSObject gc = globalContext; + JSObject obj = gc['obj'.toJS] as JSObject; + JSFunction jsClass1Constructor = gc['JSClass1'.toJS] as JSFunction; + JSFunction jsClass2Constructor = gc['JSClass2'.toJS] as JSFunction; Expect.isTrue(obj.instanceof(jsClass1Constructor).toDart); Expect.isFalse(obj.instanceof(jsClass2Constructor).toDart); } @@ -151,8 +151,8 @@ void evalAndConstructTest() { } globalThis.JSClass = JSClass; '''); - JSObject gt = globalJSObject; - JSFunction constructor = gt['JSClass'.toJS] as JSFunction; + JSObject gc = globalContext; + JSFunction constructor = gc['JSClass'.toJS] as JSFunction; // Var args JSObject jsObj1 = @@ -267,17 +267,17 @@ void deepConversionsTest() { globalThis.keyObject1 = keyObject; globalThis.keyObject2 = keyObject; '''); - JSObject gt = globalJSObject; - Expect.isNull(gt['a'.toJS]); - Expect.equals('foo', gt.getProperty('b'.toJS).toDart); + JSObject gc = globalContext; + Expect.isNull(gc['a'.toJS]); + Expect.equals('foo', gc.getProperty('b'.toJS).toDart); _expectRecEquals( ['a', 'b', 'c'], - gt + gc .getProperty('c'.toJS) .toDart .map((JSAny? o) => (o as JSString).toDart)); - Expect.equals(2.5, gt.getProperty('d'.toJS).toDartDouble); - Expect.equals(true, gt.getProperty('e'.toJS).toDart); + Expect.equals(2.5, gc.getProperty('d'.toJS).toDartDouble); + Expect.equals(true, gc.getProperty('e'.toJS).toDart); _expectRecEquals({ 'null': 'foo', 'foo': null, @@ -289,40 +289,40 @@ void deepConversionsTest() { 'f': 2, 'g': [2, 4, 6] }, - }, gt.getProperty('g'.toJS).dartify()); + }, gc.getProperty('g'.toJS).dartify()); _expectRecEquals({ 'a': {}, - }, gt.getProperty('rec'.toJS).dartify()); + }, gc.getProperty('rec'.toJS).dartify()); _expectIterableEquals(Int8List.fromList([-128, 0, 127]), - gt.getProperty('int8Array'.toJS).toDart); + gc.getProperty('int8Array'.toJS).toDart); _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]), - gt.getProperty('uint8Array'.toJS).toDart); + gc.getProperty('uint8Array'.toJS).toDart); _expectIterableEquals(Uint8ClampedList.fromList([-1, 0, 255, 256]), - gt.getProperty('uint8ClampedArray'.toJS).toDart); + gc.getProperty('uint8ClampedArray'.toJS).toDart); _expectIterableEquals(Int16List.fromList([-32769, -32768, 0, 32767, 32768]), - gt.getProperty('int16Array'.toJS).toDart); + gc.getProperty('int16Array'.toJS).toDart); _expectIterableEquals(Uint16List.fromList([-1, 0, 65535, 65536]), - gt.getProperty('uint16Array'.toJS).toDart); + gc.getProperty('uint16Array'.toJS).toDart); _expectIterableEquals(Int32List.fromList([-2147483648, 0, 2147483647]), - gt.getProperty('int32Array'.toJS).toDart); + gc.getProperty('int32Array'.toJS).toDart); _expectIterableEquals(Uint32List.fromList([-1, 0, 4294967295, 4294967296]), - gt.getProperty('uint32Array'.toJS).toDart); + gc.getProperty('uint32Array'.toJS).toDart); _expectIterableEquals( Float32List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]), - gt.getProperty('float32Array'.toJS).toDart); + gc.getProperty('float32Array'.toJS).toDart); _expectIterableEquals( Float64List.fromList([-1000.488, -0.00001, 0.0001, 10004.888]), - gt.getProperty('float64Array'.toJS).toDart); + gc.getProperty('float64Array'.toJS).toDart); _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]), - gt.getProperty('arrayBuffer'.toJS).toDart.asUint8List()); + gc.getProperty('arrayBuffer'.toJS).toDart.asUint8List()); _expectIterableEquals(Uint8List.fromList([-1, 0, 255, 256]), - gt.getProperty('dataView'.toJS).toDart.buffer.asUint8List()); + gc.getProperty('dataView'.toJS).toDart.buffer.asUint8List()); // Confirm a function that takes a roundtrip remains a function. - JSFunction foo = gt['f'.toJS].dartify() as JSFunction; + JSFunction foo = gc['f'.toJS].dartify() as JSFunction; Expect.equals( - 'hello world', gt.callMethod('invoke'.toJS, foo).toDart); + 'hello world', gc.callMethod('invoke'.toJS, foo).toDart); // Confirm arrays, which need to be converted implicitly, are still // recursively converted by dartify() when desired. @@ -334,12 +334,12 @@ void deepConversionsTest() { 3, {'baz': 'boo'} ], - ], gt['implicitExplicit'.toJS].dartify() as Iterable); + ], gc['implicitExplicit'.toJS].dartify() as Iterable); // Test that JS objects behave as expected in Map / Set. Set set = {}; - JSAny? key1 = gt['keyObject1'.toJS]; - JSAny? key2 = gt['keyObject2'.toJS]; + JSAny? key1 = gc['keyObject1'.toJS]; + JSAny? key2 = gc['keyObject2'.toJS]; Expect.isTrue(set.add(key1)); Expect.isTrue(set.contains(key1)); Expect.isFalse(set.add(key2)); @@ -384,17 +384,17 @@ void symbolTest() { } globalThis.symbol2 = symbol2; '''); - JSObject gt = globalJSObject; + JSObject gc = globalContext; Expect.equals( _JSSymbol.keyFor(_JSSymbol._for('symbol'.toJS)).toDart, 'symbol'); Expect.equals( - gt.getProperty(gt.getProperty('symbol'.toJS)).toDart, + gc.getProperty(gc.getProperty('symbol'.toJS)).toDart, 'boo'); Expect.equals(methodWithSymbol(symbol).toDart, 'symbol'); Expect.equals(_JSSymbol.keyFor(symbol).toDart, 'symbol'); Expect.equals( - _JSSymbol.keyFor(gt.getProperty('symbol'.toJS)).toDart, 'symbol'); - Expect.equals(gt.callMethod(symbol2).toDart, 'hello world'); + _JSSymbol.keyFor(gc.getProperty('symbol'.toJS)).toDart, 'symbol'); + Expect.equals(gc.callMethod(symbol2).toDart, 'hello world'); } void main() {