Version 2.18.0-73.0.dev
Merge commit 'a0b35de326441b462f6fe0fb3a2b18bb10a40390' into 'dev'
diff --git a/pkg/compiler/lib/src/io/source_file.dart b/pkg/compiler/lib/src/io/source_file.dart
index 489f6c6..5fe6a18 100644
--- a/pkg/compiler/lib/src/io/source_file.dart
+++ b/pkg/compiler/lib/src/io/source_file.dart
@@ -2,8 +2,6 @@
// 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.
-// @dart = 2.10
-
library dart2js.io.source_file;
import 'dart:convert' show utf8;
@@ -25,12 +23,12 @@
@override
api.InputKind get inputKind => api.InputKind.UTF8;
- kernel.Source cachedKernelSource;
+ kernel.Source? _cachedKernelSource;
kernel.Source get kernelSource {
// TODO(johnniwinther): Instead of creating a new Source object,
// we should use the one provided by the front-end.
- return cachedKernelSource ??= kernel.Source(
+ return _cachedKernelSource ??= kernel.Source(
lineStarts,
slowUtf8ZeroTerminatedBytes(),
uri /* TODO(jensj): What is the import URI? */,
@@ -62,12 +60,10 @@
/// A map from line numbers to offsets in the string text representation of
/// this source file.
List<int> get lineStarts {
- if (lineStartsCache == null) {
- // When reporting errors during scanning, the line numbers are not yet
- // available and need to be computed using this slow path.
- lineStartsCache = lineStartsFromString(slowText());
- }
- return lineStartsCache;
+ // When reporting errors during scanning, the line numbers are not yet
+ // available and need to be computed using this slow path.
+ // TODO(sra): Scanning is now done entirely by the CFE.
+ return _lineStartsCache ??= _lineStartsFromString(slowText());
}
/// Sets the line numbers map for this source file. This map is computed and
@@ -76,11 +72,11 @@
/// The map contains one additional entry at the end of the file, as if the
/// source file had one more empty line at the end. This simplifies the binary
/// search in [getLocation].
- set lineStarts(List<int> v) => lineStartsCache = v;
+ set lineStarts(List<int> v) => _lineStartsCache = v;
- List<int> lineStartsCache;
+ List<int>? _lineStartsCache;
- List<int> lineStartsFromString(String text) {
+ static List<int> _lineStartsFromString(String text) {
var starts = [0];
var index = 0;
while (index < text.length) {
@@ -94,7 +90,7 @@
@override
kernel.Location getLocation(int offset) {
- return kernelSource.getLocation(null, offset);
+ return kernelSource.getLocation(uri, offset);
}
String slowSubstring(int start, int end);
@@ -109,13 +105,13 @@
/// Use [colorize] to wrap source code text and marker characters in color
/// escape codes.
String getLocationMessage(String message, int start, int end,
- {bool includeSourceLine = true, String colorize(String text)}) {
+ {bool includeSourceLine = true, String colorize(String text)?}) {
if (colorize == null) {
colorize = (text) => text;
}
- kernel.Location startLocation = kernelSource.getLocation(null, start);
- kernel.Location endLocation = kernelSource.getLocation(null, end);
+ kernel.Location startLocation = kernelSource.getLocation(uri, start);
+ kernel.Location endLocation = kernelSource.getLocation(uri, end);
int lineStart = startLocation.line - 1;
int columnStart = startLocation.column - 1;
int lineEnd = endLocation.line - 1;
@@ -130,7 +126,7 @@
if (start != end && includeSourceLine) {
if (lineStart == lineEnd) {
- String textLine = kernelSource.getTextLine(startLocation.line);
+ String textLine = kernelSource.getTextLine(startLocation.line)!;
int toColumn = min(columnStart + (end - start), textLine.length);
buf.write(textLine.substring(0, columnStart));
@@ -147,7 +143,7 @@
}
} else {
for (int line = lineStart; line <= lineEnd; line++) {
- String textLine = kernelSource.getTextLine(line + 1);
+ String textLine = kernelSource.getTextLine(line + 1)!;
if (line == lineStart) {
if (columnStart > textLine.length) {
columnStart = textLine.length;
@@ -233,7 +229,7 @@
}
class CachingUtf8BytesSourceFile extends Utf8BytesSourceFile {
- String cachedText;
+ String? _cachedText;
@override
final String filename;
@@ -242,15 +238,12 @@
@override
String slowText() {
- if (cachedText == null) {
- cachedText = super.slowText();
- }
- return cachedText;
+ return _cachedText ??= super.slowText();
}
@override
void release() {
- cachedText = null;
+ _cachedText = null;
super.release();
}
}
@@ -297,13 +290,13 @@
class Binary implements api.Input<List<int>> {
@override
final Uri uri;
- List<int> /*?*/ _data;
+ List<int>? _data;
Binary(this.uri, List<int> data) : _data = data;
@override
List<int> get data {
- if (_data != null) return _data;
+ if (_data != null) return _data!;
throw StateError("'get data' after 'release()'");
}
diff --git a/pkg/compiler/lib/src/js/js_source_mapping.dart b/pkg/compiler/lib/src/js/js_source_mapping.dart
index d5b4383..fc932c3 100644
--- a/pkg/compiler/lib/src/js/js_source_mapping.dart
+++ b/pkg/compiler/lib/src/js/js_source_mapping.dart
@@ -10,7 +10,7 @@
show BufferedCodeOutput, SourceLocations, SourceLocationsProvider;
import '../io/source_information.dart'
show SourceLocation, SourceInformation, SourceInformationStrategy;
-import 'js.dart';
+import 'js.dart' show Node;
/// [SourceInformationStrategy] that can associate source information with
/// JavaScript output.
diff --git a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
index fe6ef0c..6098493 100644
--- a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
@@ -6,6 +6,7 @@
library dart2js.js_emitter.main_call_stub_generator;
+import 'package:compiler/src/options.dart';
import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
import '../common/elements.dart';
@@ -16,8 +17,12 @@
import 'code_emitter_task.dart' show Emitter;
class MainCallStubGenerator {
- static jsAst.Statement generateInvokeMain(CommonElements commonElements,
- Emitter emitter, FunctionEntity main, bool requiresStartupMetrics) {
+ static jsAst.Statement generateInvokeMain(
+ CommonElements commonElements,
+ Emitter emitter,
+ FunctionEntity main,
+ bool requiresStartupMetrics,
+ CompilerOptions options) {
jsAst.Expression mainAccess = emitter.staticFunctionAccess(main);
jsAst.Expression currentScriptAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.CURRENT_SCRIPT);
@@ -96,6 +101,10 @@
if (#startupMetrics) {
init.#startupMetricsEmbeddedGlobal.add('callMainMs');
}
+ if (#isCollectingRuntimeMetrics) {
+ self.#runtimeMetricsContainer = self.#runtimeMetricsContainer || Object.create(null);
+ self.#runtimeMetricsContainer[currentScript.src] = init.#runtimeMetricsEmbeddedGlobal;
+ }
var callMain = #mainCallClosure;
if (typeof dartMainRunner === "function") {
dartMainRunner(callMain, []);
@@ -105,6 +114,9 @@
})''', {
'currentScript': currentScriptAccess,
'mainCallClosure': mainCallClosure,
+ 'isCollectingRuntimeMetrics': options.experimentalTrackAllocations,
+ 'runtimeMetricsContainer': embeddedNames.RUNTIME_METRICS_CONTAINER,
+ 'runtimeMetricsEmbeddedGlobal': embeddedNames.RUNTIME_METRICS,
'startupMetrics': requiresStartupMetrics,
'startupMetricsEmbeddedGlobal': embeddedNames.STARTUP_METRICS,
});
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 5068dda..b9f1535 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -296,8 +296,12 @@
}
js.Statement _buildInvokeMain() {
- return MainCallStubGenerator.generateInvokeMain(_commonElements,
- _task.emitter, _mainFunction, _backendUsage.requiresStartupMetrics);
+ return MainCallStubGenerator.generateInvokeMain(
+ _commonElements,
+ _task.emitter,
+ _mainFunction,
+ _backendUsage.requiresStartupMetrics,
+ _options);
}
DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) {
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 66db107..fc83adb 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -46,6 +46,11 @@
.add("dartProgramMs");
}
+if (#isCollectingRuntimeMetrics) {
+ dartProgram.$RUNTIME_METRICS = Object.create(null);
+ var allocations = dartProgram.$RUNTIME_METRICS['allocations'] = Object.create(null);
+}
+
// Copies the own properties from [from] to [to].
function copyProperties(from, to) {
var keys = Object.keys(from);
@@ -420,10 +425,6 @@
hunk(hunkHelpers, #embeddedGlobalsObject, holders, #staticState);
}
-if (#isTrackingAllocations) {
- var allocations = #deferredGlobal['allocations'] = {};
-}
-
// Creates the holders.
#holders;
@@ -523,7 +524,9 @@
/// This template is used for Dart 2.
const String _deferredBoilerplate = '''
function(hunkHelpers, #embeddedGlobalsObject, holdersList, #staticState) {
-
+if (#isCollectingRuntimeMetrics) {
+ var allocations = #embeddedGlobalsObject.#runtimeMetrics['allocations'];
+}
// Builds the holders. They only contain the data for new holders.
// If names are not set on functions, we do it now. Finally, updates the
// holders of the main-fragment. Uses the provided holdersList to access the
@@ -751,8 +754,7 @@
//'stubName': js.string(_namer.stubNameField),
//'argumentCount': js.string(_namer.fixedNames.requiredParameterField),
//'defaultArgumentValues': js.string(_namer.fixedNames.defaultValuesField),
- 'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
- 'isTrackingAllocations': _options.experimentalTrackAllocations,
+ 'isCollectingRuntimeMetrics': _options.experimentalTrackAllocations,
'prototypes': emitPrototypes(fragment),
'inheritance': emitInheritance(fragment),
'aliases': emitInstanceMethodAliases(fragment),
@@ -808,7 +810,9 @@
js.Expression code = js.js(_deferredBoilerplate, {
// TODO(floitsch): don't just reference 'init'.
'embeddedGlobalsObject': js.Parameter('init'),
+ 'isCollectingRuntimeMetrics': _options.experimentalTrackAllocations,
'staticState': DeferredHolderParameter(),
+ 'runtimeMetrics': RUNTIME_METRICS,
'updateHolders': updateHolders,
'prototypes': fragment.classPrototypes,
'closures': fragment.closurePrototypes,
@@ -1875,6 +1879,12 @@
js.string(STARTUP_METRICS), js.js('dartProgram.$STARTUP_METRICS')));
}
+ if (_options.experimentalTrackAllocations) {
+ // Copy the metrics object that was stored on the main unit IIFE.
+ globals.add(js.Property(
+ js.string(RUNTIME_METRICS), js.js('dartProgram.$RUNTIME_METRICS')));
+ }
+
js.ObjectInitializer globalsObject =
js.ObjectInitializer(globals, isOneLiner: false);
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 242dc31..b5bf78d 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -27,6 +27,7 @@
NATIVE_SUPERCLASS_TAG_NAME,
RTI_UNIVERSE,
RtiUniverseFieldNames,
+ RUNTIME_METRICS,
STARTUP_METRICS,
TearOffParametersPropertyNames,
TYPE_TO_INTERCEPTOR_MAP,
@@ -368,19 +369,11 @@
return js.Comment(generatedBy(_options, flavor: '$flavor'));
}
- List<js.Statement> buildDeferredInitializerGlobal() {
- return [
- js.js.statement(
- 'self.#deferredInitializers = '
- 'self.#deferredInitializers || Object.create(null);',
- {'deferredInitializers': deferredInitializersGlobal}),
- if (_options.experimentalTrackAllocations)
- js.js.statement(
- 'self.#deferredInitializers["allocations"] = '
- 'self.#deferredInitializers["allocations"] '
- '|| Object.create(null)',
- {'deferredInitializers': deferredInitializersGlobal})
- ];
+ js.Statement buildDeferredInitializerGlobal() {
+ return js.js.statement(
+ 'self.#deferredInitializers = '
+ 'self.#deferredInitializers || Object.create(null);',
+ {'deferredInitializers': deferredInitializersGlobal});
}
js.Statement buildStartupMetrics() {
@@ -431,7 +424,7 @@
js.Program program = js.Program([
buildGeneratedBy(),
js.Comment(HOOKS_API_USAGE),
- if (isSplit) ...buildDeferredInitializerGlobal(),
+ if (isSplit) buildDeferredInitializerGlobal(),
if (_closedWorld.backendUsage.requiresStartupMetrics)
buildStartupMetrics(),
code
@@ -566,10 +559,7 @@
js.Program program = js.Program([
if (isFirst) buildGeneratedBy(),
- if (isFirst) ...buildDeferredInitializerGlobal(),
- if (_options.experimentalTrackAllocations)
- js.js.statement("var allocations = #deferredGlobal['allocations']",
- {'deferredGlobal': deferredInitializersGlobal}),
+ if (isFirst) buildDeferredInitializerGlobal(),
js.js.statement('$deferredInitializersGlobal.current = #', code)
]);
diff --git a/pkg/dart2js_runtime_metrics/CHANGELOG.md b/pkg/dart2js_runtime_metrics/CHANGELOG.md
index a0712a7..b7d9e52 100644
--- a/pkg/dart2js_runtime_metrics/CHANGELOG.md
+++ b/pkg/dart2js_runtime_metrics/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.0
+
+- Adding `runtimeMetrics`.
+
## 0.1.0
- Initial version.
diff --git a/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dart2js.dart b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dart2js.dart
new file mode 100644
index 0000000..3aa7cbb
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dart2js.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2022, 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.
+
+export 'dart:_dart2js_runtime_metrics' show runtimeMetrics;
diff --git a/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dartdevc.dart b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dartdevc.dart
new file mode 100644
index 0000000..43382b8
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_dartdevc.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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.
+
+/// A collection of metrics collected during the runtime of a Dart app.
+///
+/// The contents of the map depend on the platform. The map values are simple
+/// objects (strings, numbers, Booleans). There is always an entry for the key
+/// `'runtime'` with a [String] value.
+Map<String, Object> get runtimeMetrics {
+ return {'runtime': 'dartdevc'};
+}
diff --git a/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_unknown.dart b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_unknown.dart
new file mode 100644
index 0000000..41659d2
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_unknown.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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.
+
+/// A collection of metrics collected during the runtime of a Dart app.
+///
+/// The contents of the map depend on the platform. The map values are simple
+/// objects (strings, numbers, Booleans). There is always an entry for the key
+/// `'runtime'` with a [String] value.
+Map<String, Object> get runtimeMetrics {
+ return {'runtime': 'unknown'};
+}
diff --git a/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_vm.dart b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_vm.dart
new file mode 100644
index 0000000..8c4a779
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/lib/_runtime_metrics_vm.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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.
+
+/// A collection of metrics collected during the runtime of a Dart app.
+///
+/// The contents of the map depend on the platform. The map values are simple
+/// objects (strings, numbers, Booleans). There is always an entry for the key
+/// `'runtime'` with a [String] value.
+Map<String, Object> get runtimeMetrics {
+ return {'runtime': 'vm'};
+}
diff --git a/pkg/dart2js_runtime_metrics/lib/runtime_metrics.dart b/pkg/dart2js_runtime_metrics/lib/runtime_metrics.dart
new file mode 100644
index 0000000..1ae29fd
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/lib/runtime_metrics.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2022, 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.
+
+export '_runtime_metrics_unknown.dart'
+ if (dart.library._dart2js_runtime_metrics) '_runtime_metrics_dart2js.dart'
+ if (dart.library.ffi) '_runtime_metrics_vm.dart'
+ if (dart.library.js) '_runtime_metrics_dartdevc.dart';
diff --git a/pkg/dart2js_runtime_metrics/pubspec.yaml b/pkg/dart2js_runtime_metrics/pubspec.yaml
index 7b9b439..31c227f5 100644
--- a/pkg/dart2js_runtime_metrics/pubspec.yaml
+++ b/pkg/dart2js_runtime_metrics/pubspec.yaml
@@ -1,7 +1,7 @@
name: dart2js_runtime_metrics
# This package is not intended for consumption on pub.dev. DO NOT publish.
publish_to: none
-version: 0.1.0
+version: 0.2.0
description: >-
`dart2js` can generate extra code to measure certain activities.
This library provides access to the measurements at runtime.
diff --git a/pkg/dart2js_runtime_metrics/test/runtime_metrics_test.dart b/pkg/dart2js_runtime_metrics/test/runtime_metrics_test.dart
new file mode 100644
index 0000000..8b0d0b5
--- /dev/null
+++ b/pkg/dart2js_runtime_metrics/test/runtime_metrics_test.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2022, 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.
+
+// dart2jsOptions=--experimental-track-allocations
+
+import 'package:dart2js_runtime_metrics/runtime_metrics.dart';
+import 'package:expect/expect.dart';
+
+void main() {
+ Map<String, Object> metrics = runtimeMetrics;
+
+ print('metrics: $metrics');
+
+ String expectedRuntime;
+ if (1.0 is! int) {
+ expectedRuntime = 'vm';
+ } else if (ClassWithLongName().toString().contains('minified:')) {
+ // dart2js minified: "Instance of 'minified:xy'".
+ expectedRuntime = 'dart2js';
+ } else if ('$main' == "Closure 'main'") {
+ // dart2js non-minified.
+ expectedRuntime = 'dart2js';
+ } else if ('$main'.startsWith('Closure: () => void from: function main()')) {
+ expectedRuntime = 'dartdevc';
+ } else {
+ throw 'Cannot feature-test current runtime:'
+ '\nmetrics = $metrics\n main = $main';
+ }
+
+ Expect.isTrue(metrics.containsKey('runtime'), "Has 'runtime' key: $metrics");
+ Expect.equals(expectedRuntime, metrics['runtime'],
+ "Expected 'runtime: $expectedRuntime': $metrics");
+
+ if (expectedRuntime == 'dart2js') {
+ Expect.isTrue(metrics.containsKey('allocations'));
+ return;
+ }
+
+ if (expectedRuntime == 'dartdevc') {
+ return;
+ }
+
+ if (expectedRuntime == 'vm') {
+ return;
+ }
+
+ throw 'Should not get here.';
+}
+
+class ClassWithLongName {}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 415fe83..7da2ade 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -2462,8 +2462,12 @@
"invocation.");
continue;
}
+ Expression unparenthesizedExpression = argumentExpression;
+ while (unparenthesizedExpression is ParenthesizedExpression) {
+ unparenthesizedExpression = unparenthesizedExpression.expression;
+ }
if (isInferenceUpdate1Enabled &&
- argumentExpression is FunctionExpression) {
+ unparenthesizedExpression is FunctionExpression) {
(deferredFunctionLiterals ??= []).add(new _DeferredParamInfo(
formalType: formalType,
argumentExpression: argumentExpression,
@@ -5942,8 +5946,9 @@
/// argument.
final DartType formalType;
- /// The function literal expression.
- final FunctionExpression argumentExpression;
+ /// The argument expression (possibly wrapped in an arbitrary number of
+ /// ParenthesizedExpressions).
+ final Expression argumentExpression;
/// Indicates whether this is a named argument.
final bool isNamed;
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 103c5d1..a7fc5e8 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -1430,6 +1430,7 @@
unneeded
unordered
unpaired
+unparenthesized
unparsed
unpleasant
unqualified
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart
index 454d46f..d3cb021 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart
@@ -17,6 +17,24 @@
}
}
+withUnnamedArgumentsParenthesized(int? i, void Function(void Function(), Object?) f) {
+ if (i != null) {
+ f((() {
+ i = null;
+ }), i);
+ i;
+ }
+}
+
+withUnnamedArgumentsParenthesizedTwice(int? i, void Function(void Function(), Object?) f) {
+ if (i != null) {
+ f(((() {
+ i = null;
+ })), i);
+ i;
+ }
+}
+
withNamedArguments(
int? i, void Function({required void Function() g, Object? x}) f) {
if (i != null) {
@@ -29,6 +47,30 @@
}
}
+withNamedArgumentsParenthesized(
+ int? i, void Function({required void Function() g, Object? x}) f) {
+ if (i != null) {
+ f(
+ g: (() {
+ i = null;
+ }),
+ x: i);
+ i;
+ }
+}
+
+withNamedArgumentsParenthesizedTwice(
+ int? i, void Function({required void Function() g, Object? x}) f) {
+ if (i != null) {
+ f(
+ g: ((() {
+ i = null;
+ })),
+ x: i);
+ i;
+ }
+}
+
withIdentical_lhs(int? i) {
if (i != null) {
i;
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline.expect
index b846752..b9ed055 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline.expect
@@ -1,6 +1,14 @@
withUnnamedArguments(int? i, void Function(void Function(), Object?) f) {}
+withUnnamedArgumentsParenthesized(
+ int? i, void Function(void Function(), Object?) f) {}
+withUnnamedArgumentsParenthesizedTwice(
+ int? i, void Function(void Function(), Object?) f) {}
withNamedArguments(
int? i, void Function({required void Function() g, Object? x}) f) {}
+withNamedArgumentsParenthesized(
+ int? i, void Function({required void Function() g, Object? x}) f) {}
+withNamedArgumentsParenthesizedTwice(
+ int? i, void Function({required void Function() g, Object? x}) f) {}
withIdentical_lhs(int? i) {}
withIdentical_rhs(int? i) {}
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline_modelled.expect
index f4cf2ee..1d74f38 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.textual_outline_modelled.expect
@@ -18,4 +18,12 @@
withIdentical_rhs(int? i) {}
withNamedArguments(
int? i, void Function({required void Function() g, Object? x}) f) {}
+withNamedArgumentsParenthesized(
+ int? i, void Function({required void Function() g, Object? x}) f) {}
+withNamedArgumentsParenthesizedTwice(
+ int? i, void Function({required void Function() g, Object? x}) f) {}
withUnnamedArguments(int? i, void Function(void Function(), Object?) f) {}
+withUnnamedArgumentsParenthesized(
+ int? i, void Function(void Function(), Object?) f) {}
+withUnnamedArgumentsParenthesizedTwice(
+ int? i, void Function(void Function(), Object?) f) {}
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.expect
index 7e1a0ea..e0d8d30 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.expect
@@ -27,6 +27,22 @@
i;
}
}
+static method withUnnamedArgumentsParenthesized(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
+static method withUnnamedArgumentsParenthesizedTwice(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
static method withNamedArguments(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
if(!(i == null)) {
f(g: () → void {
@@ -35,6 +51,22 @@
i;
}
}
+static method withNamedArgumentsParenthesized(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
+static method withNamedArgumentsParenthesizedTwice(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
static method withIdentical_lhs(core::int? i) → dynamic {
if(!(i == null)) {
i{core::int};
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.modular.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.modular.expect
index 7e1a0ea..e0d8d30 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.modular.expect
@@ -27,6 +27,22 @@
i;
}
}
+static method withUnnamedArgumentsParenthesized(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
+static method withUnnamedArgumentsParenthesizedTwice(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
static method withNamedArguments(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
if(!(i == null)) {
f(g: () → void {
@@ -35,6 +51,22 @@
i;
}
}
+static method withNamedArgumentsParenthesized(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
+static method withNamedArgumentsParenthesizedTwice(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
static method withIdentical_lhs(core::int? i) → dynamic {
if(!(i == null)) {
i{core::int};
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.outline.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.outline.expect
index f98b778..734591f 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.outline.expect
@@ -14,8 +14,16 @@
}
static method withUnnamedArguments(core::int? i, (() → void, core::Object?) → void f) → dynamic
;
+static method withUnnamedArgumentsParenthesized(core::int? i, (() → void, core::Object?) → void f) → dynamic
+ ;
+static method withUnnamedArgumentsParenthesizedTwice(core::int? i, (() → void, core::Object?) → void f) → dynamic
+ ;
static method withNamedArguments(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic
;
+static method withNamedArgumentsParenthesized(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic
+ ;
+static method withNamedArgumentsParenthesizedTwice(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic
+ ;
static method withIdentical_lhs(core::int? i) → dynamic
;
static method withIdentical_rhs(core::int? i) → dynamic
diff --git a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.transformed.expect b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.transformed.expect
index 7e1a0ea..e0d8d30 100644
--- a/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference_update_1/write_capture_deferral.dart.weak.transformed.expect
@@ -27,6 +27,22 @@
i;
}
}
+static method withUnnamedArgumentsParenthesized(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
+static method withUnnamedArgumentsParenthesizedTwice(core::int? i, (() → void, core::Object?) → void f) → dynamic {
+ if(!(i == null)) {
+ f(() → void {
+ i = null;
+ }, i{core::int}){(() → void, core::Object?) → void};
+ i;
+ }
+}
static method withNamedArguments(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
if(!(i == null)) {
f(g: () → void {
@@ -35,6 +51,22 @@
i;
}
}
+static method withNamedArgumentsParenthesized(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
+static method withNamedArgumentsParenthesizedTwice(core::int? i, ({required g: () → void, x: core::Object?}) → void f) → dynamic {
+ if(!(i == null)) {
+ f(g: () → void {
+ i = null;
+ }, x: i{core::int}){({required g: () → void, x: core::Object?}) → void};
+ i;
+ }
+}
static method withIdentical_lhs(core::int? i) → dynamic {
if(!(i == null)) {
i{core::int};
diff --git a/pkg/js_runtime/lib/shared/embedded_names.dart b/pkg/js_runtime/lib/shared/embedded_names.dart
index 0334810..9d48e1a 100644
--- a/pkg/js_runtime/lib/shared/embedded_names.dart
+++ b/pkg/js_runtime/lib/shared/embedded_names.dart
@@ -179,6 +179,12 @@
/// This embedded global is used for --experiment-new-rti.
const RTI_UNIVERSE = 'typeUniverse';
+/// An embedded global used to collect and access runtime metrics.
+const RUNTIME_METRICS = 'rm';
+
+/// Global name that holds runtime metrics Dart2JS apps.
+const RUNTIME_METRICS_CONTAINER = 'runtimeMetrics';
+
/// An embedded global used to collect and access startup metrics.
const STARTUP_METRICS = 'sm';
diff --git a/sdk/lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart b/sdk/lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart
index 637d2c7..7077d0a 100644
--- a/sdk/lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart
+++ b/sdk/lib/_internal/js_runtime/lib/dart2js_runtime_metrics.dart
@@ -4,7 +4,12 @@
library dart2js_runtime_metrics;
-import 'dart:_js_helper' show fillLiteralMap, rawStartupMetrics;
+import 'dart:_js_helper'
+ show
+ copyAndStringifyProperties,
+ fillLiteralMap,
+ rawRuntimeMetrics,
+ rawStartupMetrics;
/// A collection of metrics for events that happen before `main()` is entered.
///
@@ -35,3 +40,23 @@
fillLiteralMap(raw, result);
return result;
}
+
+/// A collection of metrics collected during the runtime of a Dart app.
+///
+/// The contents of the map depend on the platform. The map values are simple
+/// objects (strings, numbers, Booleans). There is always an entry for the key
+/// `'runtime'` with a [String] value.
+///
+/// This implementation for dart2js has the content (subject to change):
+///
+/// - `runtime`: `'dart2js'`
+///
+/// - `allocations`: A string representation of a Json Map<String, Object>,
+/// which holds every class or closure created at runtime. The key contains
+/// a resolved path of the class or closure. The value is currently unused.
+Map<String, Object> get runtimeMetrics {
+ final Map<String, Object> result = {'runtime': 'dart2js'};
+ final raw = rawRuntimeMetrics();
+ copyAndStringifyProperties(raw, result);
+ return result;
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index ae676e0..50f9c4f 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -21,6 +21,7 @@
JsGetName,
LEAF_TAGS,
NATIVE_SUPERCLASS_TAG_NAME,
+ RUNTIME_METRICS,
STARTUP_METRICS,
STATIC_FUNCTION_NAME_PROPERTY_NAME,
TearOffParametersPropertyNames;
@@ -1801,6 +1802,21 @@
return result;
}
+/// Called by generated code to move and stringify properties from an object
+/// to a map literal.
+copyAndStringifyProperties(from, Map to) {
+ if (JS('bool', '!#', from)) return to;
+ List keys = JS('JSArray', r'Object.keys(#)', from);
+ int index = 0;
+ int length = getLength(keys);
+ while (index < length) {
+ var key = getIndex(keys, index++);
+ var value = JS('String', r'JSON.stringify(#[#])', from, key);
+ to[key] = value;
+ }
+ return to;
+}
+
/// Returns the property [index] of the JavaScript array [array].
getIndex(var array, int index) {
return JS('var', r'#[#]', array, index);
@@ -3064,6 +3080,10 @@
return JS('JSArray', '#.a', JS_EMBEDDED_GLOBAL('', STARTUP_METRICS));
}
+Object? rawRuntimeMetrics() {
+ return JS('', '#', JS_EMBEDDED_GLOBAL('', RUNTIME_METRICS));
+}
+
/// Wraps the given [callback] within the current Zone.
void Function(T)? wrapZoneUnaryCallback<T>(void Function(T)? callback) {
// For performance reasons avoid wrapping if we are in the root zone.
diff --git a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
index 0334810..9d48e1a 100644
--- a/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
+++ b/sdk/lib/_internal/js_runtime/lib/shared/embedded_names.dart
@@ -179,6 +179,12 @@
/// This embedded global is used for --experiment-new-rti.
const RTI_UNIVERSE = 'typeUniverse';
+/// An embedded global used to collect and access runtime metrics.
+const RUNTIME_METRICS = 'rm';
+
+/// Global name that holds runtime metrics Dart2JS apps.
+const RUNTIME_METRICS_CONTAINER = 'runtimeMetrics';
+
/// An embedded global used to collect and access startup metrics.
const STARTUP_METRICS = 'sm';
diff --git a/tests/language/inference_update_1/write_capture_deferral_enabled_test.dart b/tests/language/inference_update_1/write_capture_deferral_enabled_test.dart
index 1a9a79f6..36a8824 100644
--- a/tests/language/inference_update_1/write_capture_deferral_enabled_test.dart
+++ b/tests/language/inference_update_1/write_capture_deferral_enabled_test.dart
@@ -21,6 +21,26 @@
}
}
+withUnnamedArgumentsParenthesized(
+ int? i, void Function(void Function(), Object?) f) {
+ if (i != null) {
+ f((() {
+ i = null;
+ }), i..expectStaticType<Exactly<int>>());
+ i..expectStaticType<Exactly<int?>>();
+ }
+}
+
+withUnnamedArgumentsParenthesizedTwice(
+ int? i, void Function(void Function(), Object?) f) {
+ if (i != null) {
+ f(((() {
+ i = null;
+ })), i..expectStaticType<Exactly<int>>());
+ i..expectStaticType<Exactly<int?>>();
+ }
+}
+
withNamedArguments(
int? i, void Function({required void Function() g, Object? x}) f) {
if (i != null) {
@@ -33,6 +53,30 @@
}
}
+withNamedArgumentsParenthesized(
+ int? i, void Function({required void Function() g, Object? x}) f) {
+ if (i != null) {
+ f(
+ g: (() {
+ i = null;
+ }),
+ x: i..expectStaticType<Exactly<int>>());
+ i..expectStaticType<Exactly<int?>>();
+ }
+}
+
+withNamedArgumentsParenthesizedTwice(
+ int? i, void Function({required void Function() g, Object? x}) f) {
+ if (i != null) {
+ f(
+ g: ((() {
+ i = null;
+ })),
+ x: i..expectStaticType<Exactly<int>>());
+ i..expectStaticType<Exactly<int?>>();
+ }
+}
+
withIdentical_lhs(int? i) {
if (i != null) {
i..expectStaticType<Exactly<int>>();
diff --git a/tools/VERSION b/tools/VERSION
index 7dda1ca..9d184e4 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 72
+PRERELEASE 73
PRERELEASE_PATCH 0
\ No newline at end of file