Skip to content

Commit 20e8977

Browse files
rakudramaCommit Queue
authored andcommitted
[rti/js_interop] Redo: Accelerate is JSObject
Change-Id: I9a252319a1c7b426a54d52660c9d8adc5e72cd2b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/425334 Reviewed-by: Srujan Gaddam <[email protected]> Commit-Queue: Stephen Adams <[email protected]>
1 parent 6be3fa5 commit 20e8977

File tree

3 files changed

+88
-2
lines changed

3 files changed

+88
-2
lines changed

sdk/lib/_internal/js_shared/lib/rti.dart

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import 'dart:_foreign_helper'
1818
RAW_DART_FUNCTION_REF,
1919
TYPE_REF;
2020
import 'dart:_interceptors'
21-
show JavaScriptFunction, JSArray, JSNull, JSUnmodifiableArray;
21+
show JavaScriptFunction, JSArray, JSNull, JSUnmodifiableArray, JSObject;
2222
import 'dart:_js_helper'
2323
as records
2424
show createRecordTypePredicate, getRtiForRecord;
@@ -1267,6 +1267,9 @@ bool _installSpecializedIsTest(Object? object) {
12671267
RAW_DART_FUNCTION_REF(_isListTestViaProperty),
12681268
);
12691269
}
1270+
if (_Utils.isIdentical(testRti, TYPE_REF<JSObject>())) {
1271+
return _finishIsFn(testRti, object, RAW_DART_FUNCTION_REF(_isJSObject));
1272+
}
12701273
return _finishIsFn(
12711274
testRti,
12721275
object,
@@ -1432,6 +1435,40 @@ bool _isListTestViaProperty(Object? object) {
14321435
return JS('bool', '!!#[#]', interceptor, tag);
14331436
}
14341437

1438+
/// Specialized test for JSObject that avoids the uncached interceptor for plain
1439+
/// JavaScript objects.
1440+
///
1441+
/// Based on [_isTestViaProperty] to handle mocks and fakes defined in Dart.
1442+
bool _isJSObject(Object? object) {
1443+
// This static method is installed on an Rti object as a JavaScript instance
1444+
// method. The Rti object is 'this'.
1445+
Rti testRti = _Utils.asRti(JS('', 'this'));
1446+
if (object == null) return false;
1447+
if (JS('bool', 'typeof # == "object"', object)) {
1448+
if (_isDartObject(object)) {
1449+
// This path includes dart2js functions which are objects that extend
1450+
// `Closure`.
1451+
//
1452+
// Some Dart objects implement a subtype of JSObject, e.g. a Mock that
1453+
// implements Window from `dart:html`. This test would be unnecessary of
1454+
// the only form of js_interop was `dart:js_interop`.
1455+
var tag = Rti._getSpecializedTestResource(testRti);
1456+
return JS('bool', '!!#[#]', object, tag);
1457+
}
1458+
return true;
1459+
}
1460+
if (JS('bool', 'typeof # == "function"', object)) {
1461+
if (JS_GET_FLAG('DEV_COMPILER')) {
1462+
// DDC functions are JavaScript functions, but have a signature attached.
1463+
var signatureName = JS_GET_NAME(JsGetName.SIGNATURE_NAME);
1464+
var signature = JS('', '#[#]', object, signatureName);
1465+
return signature == null;
1466+
}
1467+
return true;
1468+
}
1469+
return false;
1470+
}
1471+
14351472
/// General unspecialized 'as' check that works for any type.
14361473
/// Called from generated code.
14371474
@pragma('dart2js:stack-starts-at-throw')
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Tests that Dart mocks for `dart:html` classes are recognized as
6+
// `dart:js_interop` JSObjects.
7+
//
8+
// This is expected to work for DDC and dart2js but not dart2wasm.
9+
10+
import 'package:expect/expect.dart';
11+
12+
import 'dart:js_interop' as dartJsInterop;
13+
import 'dart:html' show window, Window, Document, HtmlDocument;
14+
15+
class MockWindow implements Window {
16+
Document get document => MockDocument();
17+
18+
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
19+
}
20+
21+
class MockDocument implements HtmlDocument {
22+
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
23+
}
24+
25+
void main() {
26+
test(MockWindow(), true);
27+
test(window, false);
28+
}
29+
30+
void test(Window w, bool isMock) {
31+
Expect.type<Window>(w);
32+
Expect.type<dartJsInterop.JSObject>(w);
33+
34+
final doc = w.document;
35+
36+
Expect.type<HtmlDocument>(doc);
37+
Expect.type<dartJsInterop.JSObject>(doc);
38+
39+
if (isMock) {
40+
Expect.type<MockWindow>(w);
41+
Expect.type<MockDocument>(doc);
42+
Expect.isTrue(w is MockWindow);
43+
Expect.isTrue(doc is MockDocument);
44+
} else {
45+
Expect.isFalse(w is MockWindow);
46+
Expect.isFalse(doc is MockDocument);
47+
}
48+
}

tests/web/web.status

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ constant_javascript_semantics2_test: Slow, Pass # Issue 25940
3434
deferred_split_test: Slow, Pass # Issue 25940
3535

3636
[ $compiler == dart2js && $runtime == d8 ]
37+
internal/html_mocks_with_static_interop_test: SkipByDesign # Browser test
3738
internal/object_members_test: SkipByDesign # Browser test
3839

3940
[ $compiler == dart2js && $runtime == ff && $system == windows ]
@@ -61,7 +62,7 @@ wasm/source_map_simple_optimized_test: SkipByDesign # Reads source map file usin
6162
wasm/source_map_simple_test: SkipByDesign # Reads source map file using d8's readbuffer
6263
wasm/uri_base_test: SkipByDesign # Converts Uri.base to file path
6364

64-
[ $compiler == dart2wasm && ( $runtime == d8 || $runtime == jsc || $runtime == jsshell ) ]
65+
[ $compiler == dart2wasm && ($runtime == d8 || $runtime == jsc || $runtime == jsshell) ]
6566
wasm/multi_module_stress_test: SkipByDesign # DataView fails to load necessary input file.
6667

6768
[ $compiler == dartk && $runtime == vm ]

0 commit comments

Comments
 (0)