From 9e4bb73f8e0fade5bc4491bdae2f730c723ca6fe Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Fri, 16 Jan 2026 00:27:49 -0800 Subject: [PATCH] [dart2js] `external` functions `record_use` Closes: https://github.com/dart-lang/native/issues/2960 Change-Id: I3d62cb9bee6d06f799ee41bc283dce0dacb893cd Cq-Include-Trybots: luci.dart.try:pkg-linux-debug-try,pkg-linux-release-arm64-try,pkg-linux-release-try,pkg-mac-release-arm64-try,pkg-mac-release-try,pkg-win-release-arm64-try,pkg-win-release-try,dart2js-linux-chrome-try,dart2js-unit-linux-x64-release-try,dart2wasm-linux-jscm-chrome-try,dart2wasm-linux-optimized-jsc-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/473480 Commit-Queue: Daco Harkes Reviewed-by: Nate Biggs --- pkg/compiler/lib/src/ssa/codegen.dart | 15 +++++++++++++++ pkg/compiler/test/record_use/data/js_interop.dart | 15 +++++++++++++++ .../record_use/data/js_interop.dart.json.expect | 15 +++++++++++++++ pkg/compiler/test/record_use/record_use_test.dart | 8 +++++--- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 pkg/compiler/test/record_use/data/js_interop.dart create mode 100644 pkg/compiler/test/record_use/data/js_interop.dart.json.expect diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart index c42efafb911..1b8e2531183 100644 --- a/pkg/compiler/lib/src/ssa/codegen.dart +++ b/pkg/compiler/lib/src/ssa/codegen.dart @@ -2677,6 +2677,15 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { ? _nativeData.getFixedBackendName(target) : target.name; + Object? recordedMethodUses; + if (_closedWorld.annotationsData.shouldRecordMethodUses(target)) { + recordedMethodUses = _recordMethodUses( + target, + inputs, + node.sourceInformation!, + ); + } + void invokeWithJavaScriptReceiver(js.Expression receiverExpression) { // JS-interop target names can be paths ("a.b"), so we parse them to // re-associate the property accesses ("#.a.b" is `dot(dot(#,'a'),'b')`). @@ -2706,6 +2715,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { js.Expression expression = js.js .uncachedExpressionTemplate(template) .instantiateExpression(templateInputs); + if (recordedMethodUses != null) { + expression = expression.withAnnotation(recordedMethodUses); + } push(expression.withSourceInformation(node.sourceInformation)); _registry.registerNativeMethod(target); } @@ -2743,6 +2755,9 @@ class SsaCodeGenerator implements HVisitor, HBlockInformationVisitor { assert(target.isFunction); expression = js.js('#(#)', [targetExpression, arguments]); } + if (recordedMethodUses != null) { + expression = expression.withAnnotation(recordedMethodUses); + } push(expression.withSourceInformation(node.sourceInformation)); _registry.registerNativeMethod(target); return; diff --git a/pkg/compiler/test/record_use/data/js_interop.dart b/pkg/compiler/test/record_use/data/js_interop.dart new file mode 100644 index 00000000000..0fd0ad6a3b2 --- /dev/null +++ b/pkg/compiler/test/record_use/data/js_interop.dart @@ -0,0 +1,15 @@ +// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file +// for details. 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'; + +import 'package:meta/meta.dart' show RecordUse; + +void main() { + print(someExternalFunction(6)); +} + +@JS() +@RecordUse() +external int someExternalFunction(int k); diff --git a/pkg/compiler/test/record_use/data/js_interop.dart.json.expect b/pkg/compiler/test/record_use/data/js_interop.dart.json.expect new file mode 100644 index 00000000000..1108c1c4e38 --- /dev/null +++ b/pkg/compiler/test/record_use/data/js_interop.dart.json.expect @@ -0,0 +1,15 @@ +{ + "metadata": { + "comment": "Resources referenced by annotated resource identifiers", + "AppTag": "TBD", + "environment": { + "dart.web.assertions_enabled": "false", + "dart.tool.dart2js": "true", + "dart.tool.dart2js.minify": "false", + "dart.tool.dart2js.disable_rti_optimization": "false", + "dart.tool.dart2js.primitives:trust": "false", + "dart.tool.dart2js.types:trust": "false" + }, + "version": "0.4.0" + } +} \ No newline at end of file diff --git a/pkg/compiler/test/record_use/record_use_test.dart b/pkg/compiler/test/record_use/record_use_test.dart index 7a986d05bd3..a12786827b7 100644 --- a/pkg/compiler/test/record_use/record_use_test.dart +++ b/pkg/compiler/test/record_use/record_use_test.dart @@ -3,7 +3,7 @@ // BSD-style license that can be found in the LICENSE file. import 'dart:convert'; -import 'dart:io' show File, Directory; +import 'dart:io' show Directory, File, Platform; import 'package:compiler/compiler_api.dart' as api show OutputType; import 'package:compiler/compiler_api.dart'; @@ -20,10 +20,12 @@ const List compilerOptions = [Flags.writeRecordedUses, Flags.testMode]; /// Run `dart --define=updateExpectations=true pkg/compiler/test/record_use/record_use_test.dart` /// to update. +/// Run `dart -DupdateExpectations=true pkg/vm/test/transformations/record_use_test.dart` +/// to update the shared expectations to the VM output. Future main() async { final vmTestCases = Directory('pkg/vm/testcases/transformations/record_use'); - final testFiles = vmTestCases - .listSync() + final jsTestCases = Directory.fromUri(Platform.script.resolve('data')); + final testFiles = [...jsTestCases.listSync(), ...vmTestCases.listSync()] .whereType() .where((file) => file.path.endsWith('.dart')) .map(