[record_use] Support double constants

Quirks:
- JS backend compiles some values to ints instead of doubles.

Closes: https://github.com/dart-lang/native/issues/3221

TEST=pkg/compiler/test/record_use/record_use_test.dart
TEST=pkg/dart2wasm/test/record_use_test.dart
TEST=pkg/vm/test/transformations/record_use_test.dart

Change-Id: Ic8c95094343d6d1fed3a37b0772269a8232bc205
Cq-Include-Trybots: luci.dart.try:dart2wasm-asserts-linux-chrome-try,dart2wasm-asserts-minified-linux-d8-try,dart2wasm-linux-chrome-try,dart2wasm-linux-d8-try,dart2wasm-linux-firefox-try,dart2wasm-linux-jscm-chrome-try,dart2wasm-linux-optimized-jsc-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-canary-linux-try,dart2js-hostasserts-linux-d8-try,dart2js-linux-chrome-try,dart2js-linux-firefox-try,dart2js-mac-chrome-try,dart2js-mac-safari-try,dart2js-minified-csp-linux-chrome-try,dart2js-minified-linux-d8-try,dart2js-unit-linux-x64-release-try,dart2js-win-chrome-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/487860
Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
Daco Harkes
2026-03-17 01:46:44 -07:00
committed by Commit Queue
parent aa08628c36
commit 786e90791d
12 changed files with 475 additions and 10 deletions
+1 -1
View File
@@ -143,7 +143,7 @@ vars = {
"i18n_rev": "de7e11b7cc231d8daf6e49dc12690d7339241691",
"leak_tracker_rev": "f5620600a5ce1c44f65ddaa02001e200b096e14c", # rolled manually
"material_color_utilities_rev": "799b6ba2f3f1c28c67cc7e0b4f18e0c7d7f3c03e",
"native_rev": "c478dfede2b37000ea52ac57da7a48ab9e99f5af", # rolled manually while record_use is experimental
"native_rev": "ac1144e65a4621b9f94324f307bc3437b5b74f66", # rolled manually while record_use is experimental
"protobuf_rev": "d5639f45b8468fba684b076b9403ccd5f2290056",
"pub_rev": "74408212b5348003381bc63f3b59274aaa23cfa3", # rolled manually
"shelf_rev": "900731b313dabf48927a82f2124e5a996c4a3d05",
@@ -456,9 +456,7 @@ class RecordUseValueConverter {
MapConstantValue() => _findMapValue(constant),
ListConstantValue() => _findListValue(constant),
ConstructedConstantValue() => findInstanceValue(constant),
DoubleConstantValue() => record_use.UnsupportedConstant(
'Double literals are not supported for recording.',
),
DoubleConstantValue() => record_use.DoubleConstant(constant.doubleValue),
SetConstantValue() => record_use.UnsupportedConstant(
'Set literals are not supported for recording.',
),
@@ -0,0 +1,31 @@
// 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.
// ignore: experimental_member_use
import 'package:meta/meta.dart' show RecordUse;
const zero = 0.0;
const maxFinite = 1.7976931348623157e+308;
const minusMaxFinite = -maxFinite;
void main() {
// In dart2js, 0.0 is canonicalized to IntConstant(0).
print(SomeClass.someStaticMethod(zero));
// In dart2js, maxFinite is canonicalized to IntConstant.
// When running the compiler on the VM, BigInt.toInt() clamps it to
// 9223372036854775807 (Int64.MAX).
print(SomeClass.someStaticMethod(maxFinite));
// In dart2js, -maxFinite is canonicalized to IntConstant.
// When running the compiler on the VM, BigInt.toInt() clamps it to
// -9223372036854775808 (Int64.MIN).
print(SomeClass.someStaticMethod(minusMaxFinite));
}
class SomeClass {
// ignore: experimental_member_use
@RecordUse()
static String someStaticMethod(double d) => d.toString();
}
@@ -0,0 +1,73 @@
{
"constants": [
{
"type": "int",
"value": -9223372036854775808
},
{
"type": "int",
"value": 0
},
{
"type": "int",
"value": 9223372036854775807
}
],
"definitions": [
{
"path": [
{
"kind": "class",
"name": "SomeClass"
},
{
"disambiguators": [
"static"
],
"kind": "method",
"name": "someStaticMethod"
}
],
"uri": "package:record_use_js_test/double_constants_js.dart"
}
],
"loading_units": [
{
"name": "out"
}
],
"metadata": {
"comment": "Recorded usages of objects tagged with a `RecordUse` annotation.",
"version": "0.4.0"
},
"uses": {
"static_calls": [
{
"definition_index": 0,
"uses": [
{
"loading_unit_index": 0,
"positional": [
0
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
1
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
2
],
"type": "with_arguments"
}
]
}
]
}
}
@@ -252,6 +252,10 @@ const Set<String> dart2jsNotSupported = {
// a compile-time error for these literals when targeting the web.
'large_integers.dart',
// The JS backend represents doubles that are an int value as that int value
// and clamps large double values.
'double_constants_js_divergent.dart',
// There is an extra loading unit out_2 which contains the shared stuff
// between out_1 and out_3. Either of those loads out_2. We need a more robust
// semanticEquality solution than mapping loading unit names. We might only be
@@ -236,9 +236,7 @@ Constant evaluateConstant(ast.Constant constant) => switch (constant) {
ast.NullConstant() => NullConstant(),
ast.BoolConstant() => BoolConstant(constant.value),
ast.IntConstant() => IntConstant(constant.value),
ast.DoubleConstant() => UnsupportedConstant(
'Double literals are not supported for recording.',
),
ast.DoubleConstant() => DoubleConstant(constant.value),
ast.StringConstant() => StringConstant(constant.value),
ast.SymbolConstant() => SymbolConstant(
constant.name,
@@ -289,9 +287,7 @@ Constant evaluateLiteral(ast.BasicLiteral expression) => switch (expression) {
ast.IntLiteral() => IntConstant(expression.value),
ast.BoolLiteral() => BoolConstant(expression.value),
ast.StringLiteral() => StringConstant(expression.value),
ast.DoubleLiteral() => UnsupportedConstant(
'Double literals are not supported for recording.',
),
ast.DoubleLiteral() => DoubleConstant(expression.value),
ast.BasicLiteral() => _unsupported(expression.runtimeType.toString()),
};
@@ -0,0 +1,30 @@
// 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:math' as math;
import 'package:meta/meta.dart' show RecordUse;
const negativeZero = -0.0;
const minPositive = 5e-324;
const minusMinPositive = -minPositive;
const highPrecision = 0.12345678901234567;
void main() {
print(SomeClass.someStaticMethod(1.234));
print(SomeClass.someStaticMethod(double.infinity));
print(SomeClass.someStaticMethod(double.negativeInfinity));
print(SomeClass.someStaticMethod(double.nan));
print(SomeClass.someStaticMethod(negativeZero));
print(SomeClass.someStaticMethod(minPositive));
print(SomeClass.someStaticMethod(minusMinPositive));
print(SomeClass.someStaticMethod(highPrecision));
print(SomeClass.someStaticMethod(math.pi));
}
class SomeClass {
@RecordUse()
static String someStaticMethod(double d) => d.toString();
}
@@ -0,0 +1,40 @@
library #lib;
import self as self;
import "dart:core" as core;
import "package:meta/meta.dart" as meta;
import "dart:math" as math;
import "package:meta/meta.dart" show RecordUse;
class SomeClass extends core::Object {
[@vm.inferred-return-type.metadata=!]
[@vm.unboxing-info.metadata=[!regcc]]
@#C1
static method someStaticMethod([@vm.inferred-arg-type.metadata=dart.core::_Double] core::double d) → core::String
return [@vm.direct-call.metadata=dart.core::_Double.toString] [@vm.inferred-type.metadata=! (skip check)] d.{core::double::toString}(){() → core::String};
}
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
static method main() → void {
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(1.234));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C2));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C3));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C4));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C5));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C6));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C7));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C8));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C9));
}
constants {
#C1 = meta::RecordUse {}
#C2 = Infinity
#C3 = -Infinity
#C4 = NaN
#C5 = -0.0
#C6 = 5e-324
#C7 = -5e-324
#C8 = 0.12345678901234566
#C9 = 3.141592653589793
}
@@ -0,0 +1,163 @@
{
"constants": [
{
"type": "double",
"value": {
"type": "negative_infinity"
}
},
{
"type": "double",
"value": {
"type": "number",
"value": -5e-324
}
},
{
"type": "double",
"value": {
"type": "number",
"value": -0.0
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 5e-324
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 0.12345678901234566
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 1.234
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 3.141592653589793
}
},
{
"type": "double",
"value": {
"type": "positive_infinity"
}
},
{
"type": "double",
"value": {
"type": "not_a_number"
}
}
],
"definitions": [
{
"path": [
{
"kind": "class",
"name": "SomeClass"
},
{
"disambiguators": [
"static"
],
"kind": "method",
"name": "someStaticMethod"
}
],
"uri": "package:record_use_test/double_constants.dart"
}
],
"loading_units": [
{
"name": "1"
}
],
"metadata": {
"comment": "Recorded usages of objects tagged with a `RecordUse` annotation.",
"version": "0.4.0"
},
"uses": {
"static_calls": [
{
"definition_index": 0,
"uses": [
{
"loading_unit_index": 0,
"positional": [
0
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
1
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
2
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
3
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
4
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
5
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
6
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
7
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
8
],
"type": "with_arguments"
}
]
}
]
}
}
@@ -0,0 +1,20 @@
// 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 'package:meta/meta.dart' show RecordUse;
const zero = 0.0;
const maxFinite = 1.7976931348623157e+308;
const minusMaxFinite = -maxFinite;
void main() {
print(SomeClass.someStaticMethod(zero));
print(SomeClass.someStaticMethod(maxFinite));
print(SomeClass.someStaticMethod(minusMaxFinite));
}
class SomeClass {
@RecordUse()
static String someStaticMethod(double d) => d.toString();
}
@@ -0,0 +1,28 @@
library #lib;
import self as self;
import "dart:core" as core;
import "package:meta/meta.dart" as meta;
import "package:meta/meta.dart" show RecordUse;
class SomeClass extends core::Object {
[@vm.inferred-return-type.metadata=!]
[@vm.unboxing-info.metadata=[!regcc]]
@#C1
static method someStaticMethod([@vm.inferred-arg-type.metadata=dart.core::_Double] core::double d) → core::String
return [@vm.direct-call.metadata=dart.core::_Double.toString] [@vm.inferred-type.metadata=! (skip check)] d.{core::double::toString}(){() → core::String};
}
[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)]
static method main() → void {
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C2));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C3));
core::print([@vm.inferred-type.metadata=!] self::SomeClass::someStaticMethod(#C4));
}
constants {
#C1 = meta::RecordUse {}
#C2 = 0.0
#C3 = 1.7976931348623157e+308
#C4 = -1.7976931348623157e+308
}
@@ -0,0 +1,82 @@
{
"constants": [
{
"type": "double",
"value": {
"type": "number",
"value": -1.7976931348623157e+308
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 0.0
}
},
{
"type": "double",
"value": {
"type": "number",
"value": 1.7976931348623157e+308
}
}
],
"definitions": [
{
"path": [
{
"kind": "class",
"name": "SomeClass"
},
{
"disambiguators": [
"static"
],
"kind": "method",
"name": "someStaticMethod"
}
],
"uri": "package:record_use_test/double_constants_js_divergent.dart"
}
],
"loading_units": [
{
"name": "1"
}
],
"metadata": {
"comment": "Recorded usages of objects tagged with a `RecordUse` annotation.",
"version": "0.4.0"
},
"uses": {
"static_calls": [
{
"definition_index": 0,
"uses": [
{
"loading_unit_index": 0,
"positional": [
0
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
1
],
"type": "with_arguments"
},
{
"loading_unit_index": 0,
"positional": [
2
],
"type": "with_arguments"
}
]
}
]
}
}