Version 2.10.0-68.0.dev
Merge commit '771fcaf63288f7f346aad8fb48604f0971b1c88c' into 'dev'
diff --git a/DEPS b/DEPS
index 98aeca7..6a63c4a 100644
--- a/DEPS
+++ b/DEPS
@@ -44,7 +44,7 @@
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
# has.
- "co19_rev": "741384c83190cdaa648bf77aefcf4b6c0ec75988",
+ "co19_rev": "826fba7da0ec78f93989b5104e91e46a3ecc52d0",
"co19_2_rev": "e48b3090826cf40b8037648f19d211e8eab1b4b6",
# The internal benchmarks to use. See go/dart-benchmarks-internal
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
index 12d346c..386dd91 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/forwarding_listener.dart
@@ -13,11 +13,6 @@
ForwardingListener([this.listener]);
@override
- set suppressParseErrors(bool value) {
- listener?.suppressParseErrors = value;
- }
-
- @override
Uri get uri => listener?.uri;
@override
@@ -463,11 +458,6 @@
}
@override
- void discardTypeReplacedWithCommentTypeAssign() {
- listener?.discardTypeReplacedWithCommentTypeAssign();
- }
-
- @override
void endArguments(int count, Token beginToken, Token endToken) {
listener?.endArguments(count, beginToken, endToken);
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
index 735b41c..0d57f76 100644
--- a/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/parser/listener.dart
@@ -44,8 +44,6 @@
void logEvent(String name) {}
- set suppressParseErrors(bool value) {}
-
void beginArguments(Token token) {}
void endArguments(int count, Token beginToken, Token endToken) {
@@ -1630,11 +1628,6 @@
logEvent("Script");
}
- /// A type has been just parsed, and the parser noticed that the next token
- /// has a type substitution comment /*=T*. So, the type that has been just
- /// parsed should be discarded, and a new type should be parsed instead.
- void discardTypeReplacedWithCommentTypeAssign() {}
-
/// A single comment reference has been found
/// where [referenceSource] is the text between the `[` and `]`
/// and [referenceOffset] is the character offset in the token stream.
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e0ed8b3..4fd12b4 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -487,11 +487,6 @@
// printEvent('AstBuilder: $name');
}
- @override
- void discardTypeReplacedWithCommentTypeAssign() {
- pop();
- }
-
void doDotExpression(Token dot) {
Expression identifierOrInvoke = pop();
Expression receiver = pop();
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index cfccc6a..d9e3e7e 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -58,10 +58,6 @@
doPrint('logEvent(' '$name)');
}
- set suppressParseErrors(bool value) {
- doPrint('suppressParseErrors(' '$value)');
- }
-
void beginArguments(Token token) {
seen(token);
doPrint('beginArguments(' '$token)');
@@ -2150,10 +2146,6 @@
doPrint('handleScript(' '$token)');
}
- void discardTypeReplacedWithCommentTypeAssign() {
- doPrint('discardTypeReplacedWithCommentTypeAssign()');
- }
-
void handleCommentReferenceText(String referenceSource, int referenceOffset) {
doPrint(
'handleCommentReferenceText(' '$referenceSource, ' '$referenceOffset)');
diff --git a/pkg/native_stack_traces/bin/decode.dart b/pkg/native_stack_traces/bin/decode.dart
index 22a5e7e..2458e16 100644
--- a/pkg/native_stack_traces/bin/decode.dart
+++ b/pkg/native_stack_traces/bin/decode.dart
@@ -57,7 +57,7 @@
help: 'Print usage information for this or a particular subcommand');
final String _mainUsage = '''
-Usage: convert_stack_traces <command> [options] ...
+Usage: decode <command> [options] ...
Commands:
${_argParser.commands.keys.join("\n")}
@@ -66,15 +66,15 @@
${_argParser.usage}''';
final String _helpUsage = '''
-Usage: convert_stack_traces help [<command>]
+Usage: decode help [<command>]
-Returns usage for the convert_stack_traces utility or a particular command.
+Returns usage for the decode utility or a particular command.
Commands:
${_argParser.commands.keys.join("\n")}''';
final String _translateUsage = '''
-Usage: convert_stack_traces translate [options]
+Usage: decode translate [options]
The translate command takes text that includes non-symbolic stack traces
generated by the VM when executing a snapshot compiled with the
@@ -89,7 +89,7 @@
${_translateParser.usage}''';
final String _findUsage = '''
-Usage: convert_stack_traces find [options] <PC> ...
+Usage: decode find [options] <PC> ...
The find command looks up program counter (PC) addresses, either given as
arguments on the command line or via the -l/--location option. For each
diff --git a/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart b/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart
index bf1f858..2c69ae0 100644
--- a/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart
+++ b/pkg/vm/lib/transformations/type_flow/table_selector_assigner.dart
@@ -146,4 +146,7 @@
methodSelector.tornOff = true;
}
}
+
+ /// A (conservative) number which is bigger than all selector IDs.
+ int get selectorIdRange => metadata.selectors.length;
}
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 798233b..71e556b 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -96,9 +96,8 @@
final tableSelectorAssigner = new TableSelectorAssigner(component);
- final unboxingInfo = new UnboxingInfoManager(typeFlowAnalysis);
-
- _makePartition(component, typeFlowAnalysis, unboxingInfo);
+ final unboxingInfo = new UnboxingInfoManager(typeFlowAnalysis)
+ ..analyzeComponent(component, typeFlowAnalysis, tableSelectorAssigner);
new AnnotateKernel(component, typeFlowAnalysis, treeShaker.fieldMorpher,
tableSelectorAssigner, unboxingInfo)
@@ -499,86 +498,6 @@
}
}
-// Partition the methods in order to idenfity parameters and return values
-// that are unboxing candidates
-void _makePartition(Component component, TypeFlowAnalysis typeFlowAnalysis,
- UnboxingInfoManager unboxingInfo) {
- // Traverses all the members and creates the partition graph.
- // Currently unboxed parameters and return value are not supported for
- // closures, therefore they do not exist in this graph
- for (bool registering in const [true, false]) {
- for (Library library in component.libraries) {
- for (Class cls in library.classes) {
- for (Member member in cls.members) {
- if (registering) {
- unboxingInfo.registerMember(member);
- } else {
- unboxingInfo.linkWithSuperClasses(member);
- }
- }
- }
- if (registering) {
- for (Member member in library.members) {
- unboxingInfo.registerMember(member);
- }
- }
- }
- }
- unboxingInfo.finishGraph();
-
- for (Library library in component.libraries) {
- for (Class cls in library.classes) {
- for (Member member in cls.members) {
- _updateUnboxingInfoOfMember(member, typeFlowAnalysis, unboxingInfo);
- }
- }
- for (Member member in library.members) {
- _updateUnboxingInfoOfMember(member, typeFlowAnalysis, unboxingInfo);
- }
- }
-}
-
-void _updateUnboxingInfoOfMember(Member member,
- TypeFlowAnalysis typeFlowAnalysis, UnboxingInfoManager unboxingInfo) {
- if (typeFlowAnalysis.isMemberUsed(member)) {
- if (member is Procedure || member is Constructor) {
- final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member);
- assertx(argTypes != null);
-
- final int firstParamIndex =
- numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
-
- final positionalParams = member.function.positionalParameters;
- assertx(argTypes.positionalCount ==
- firstParamIndex + positionalParams.length);
-
- for (int i = 0; i < positionalParams.length; i++) {
- final inferredType = argTypes.values[firstParamIndex + i];
- unboxingInfo.applyToArg(member, i, inferredType);
- }
-
- final names = argTypes.names;
- for (int i = 0; i < names.length; i++) {
- final inferredType =
- argTypes.values[firstParamIndex + positionalParams.length + i];
- unboxingInfo.applyToArg(
- member, positionalParams.length + i, inferredType);
- }
-
- final Type resultType = typeFlowAnalysis.getSummary(member).resultType;
- unboxingInfo.applyToReturn(member, resultType);
- } else if (member is Field) {
- final fieldValue = typeFlowAnalysis.getFieldValue(member).value;
- if (member.hasSetter) {
- unboxingInfo.applyToArg(member, 0, fieldValue);
- }
- unboxingInfo.applyToReturn(member, fieldValue);
- } else {
- assertx(false);
- }
- }
-}
-
/// Tree shaking based on results of type flow analysis (TFA).
///
/// TFA provides information about allocated classes and reachable member
diff --git a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
index 33e1899..0e9dad1 100644
--- a/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
+++ b/pkg/vm/lib/transformations/type_flow/unboxing_info.dart
@@ -5,96 +5,167 @@
import 'package:kernel/ast.dart';
import 'package:kernel/core_types.dart';
import 'package:kernel/external_name.dart' show getExternalName;
+import 'package:vm/metadata/procedure_attributes.dart';
import 'package:vm/transformations/type_flow/analysis.dart';
+import 'package:vm/transformations/type_flow/calls.dart';
import 'package:vm/transformations/type_flow/native_code.dart';
+import 'package:vm/transformations/type_flow/table_selector_assigner.dart';
import 'package:vm/transformations/type_flow/types.dart';
import '../../metadata/unboxing_info.dart';
import 'utils.dart';
class UnboxingInfoManager {
- final List<UnboxingInfoMetadata> _allUnboxingInfo = [];
- final Map<Member, int> _memberIds = {};
- final List<int> _partitionIds = [];
- final List<int> _partitionRank = [];
- final Set<Member> _mustBox = {};
+ final Map<Member, UnboxingInfoMetadata> _memberInfo = {};
final TypeHierarchy _typeHierarchy;
final CoreTypes _coreTypes;
final NativeCodeOracle _nativeCodeOracle;
- bool _finishedGraph;
UnboxingInfoManager(TypeFlowAnalysis typeFlowAnalysis)
: _typeHierarchy = typeFlowAnalysis.hierarchyCache,
_coreTypes = typeFlowAnalysis.environment.coreTypes,
- _nativeCodeOracle = typeFlowAnalysis.nativeCodeOracle,
- _finishedGraph = false;
-
- void registerMember(Member member) {
- member = _validMemberOrNull(member);
- if (member == null) return;
- _addMember(member);
- }
+ _nativeCodeOracle = typeFlowAnalysis.nativeCodeOracle;
UnboxingInfoMetadata getUnboxingInfoOfMember(Member member) {
- assertx(_finishedGraph);
- member = _validMemberOrNull(member);
- if ((member == null || (!_memberIds.containsKey(member)))) {
- return null;
+ final UnboxingInfoMetadata info = _memberInfo[member];
+ if (member is Procedure && member.isGetter) {
+ // Remove placeholder parameter info slot for setters that the getter is
+ // grouped with.
+ return UnboxingInfoMetadata(0)..returnInfo = info.returnInfo;
}
- final partitionId = _memberIds[member];
- return _allUnboxingInfo[partitionId];
+ return info;
}
- void linkWithSuperClasses(Member member) {
- member = _validMemberOrNull(member);
- if (member == null) return;
- _linkRecursive(member, member.enclosingClass);
- }
+ void analyzeComponent(Component component, TypeFlowAnalysis typeFlowAnalysis,
+ TableSelectorAssigner tableSelectorAssigner) {
+ const kInvalidSelectorId = ProcedureAttributesMetadata.kInvalidSelectorId;
- void finishGraph() {
- assertx(!_finishedGraph);
- final oldToNewId = {};
- final newUnboxingInfo = <UnboxingInfoMetadata>[];
- for (int i = 0; i < _allUnboxingInfo.length; i++) {
- if (_find(i) == i) {
- final newId = oldToNewId.length;
- oldToNewId[i] = newId;
- newUnboxingInfo.add(_allUnboxingInfo[i]);
+ // Unboxing info for instance members is grouped by selector ID, such that
+ // the unboxing decisions match up for all members that can be called from
+ // the same call site.
+
+ // Unify the selector IDs for the getter and setter of every (writable)
+ // field, such that it can be grouped with both getters and setters.
+ // In the unified unboxing info, the return info represents the getters, and
+ // the parameter info represents the setters.
+ final selectorUnionFind = UnionFind(tableSelectorAssigner.selectorIdRange);
+ for (Library library in component.libraries) {
+ for (Class cls in library.classes) {
+ for (Field field in cls.fields) {
+ if (field.isInstanceMember && field.hasSetter) {
+ final getterId = tableSelectorAssigner.getterSelectorId(field);
+ final setterId =
+ tableSelectorAssigner.methodOrSetterSelectorId(field);
+ assertx(getterId != kInvalidSelectorId);
+ assertx(setterId != kInvalidSelectorId);
+ selectorUnionFind.union(getterId, setterId);
+ }
+ }
}
}
- for (final key in _memberIds.keys) {
- final newId = oldToNewId[_partitionIds[_memberIds[key]]];
- assertx(newId != null);
- _memberIds[key] = newId;
- }
- _allUnboxingInfo.clear();
- _allUnboxingInfo.insertAll(0, newUnboxingInfo);
- _memberIds.forEach((member, id) {
- if (_mustBox.contains(member)) {
- _allUnboxingInfo[id].returnInfo = UnboxingInfoMetadata.kBoxed;
- _allUnboxingInfo[id].unboxedArgsInfo.clear();
+
+ // Map members to unboxing info.
+ final Map<int, UnboxingInfoMetadata> selectorIdToInfo = {};
+
+ void addMember(Member member) {
+ if (!(member is Procedure || member is Constructor || member is Field)) {
+ return;
}
- });
- _partitionIds.clear();
- _partitionRank.clear();
- _finishedGraph = true;
+ // Give getters one parameter info slot to hold the unboxing info for the
+ // setters that the getter is grouped with.
+ final int paramCount = member is Field
+ ? (member.hasSetter ? 1 : 0)
+ : member is Procedure && member.isGetter
+ ? 1
+ : member.function.requiredParameterCount;
+ UnboxingInfoMetadata info;
+ if (member.isInstanceMember) {
+ int selectorId =
+ member is Field || member is Procedure && member.isGetter
+ ? tableSelectorAssigner.getterSelectorId(member)
+ : tableSelectorAssigner.methodOrSetterSelectorId(member);
+ assertx(selectorId != kInvalidSelectorId);
+ selectorId = selectorUnionFind.find(selectorId);
+ info = selectorIdToInfo[selectorId];
+ if (info == null) {
+ info = UnboxingInfoMetadata(paramCount);
+ selectorIdToInfo[selectorId] = info;
+ } else {
+ if (paramCount < info.unboxedArgsInfo.length) {
+ info.unboxedArgsInfo.length = paramCount;
+ }
+ }
+ } else {
+ info = UnboxingInfoMetadata(paramCount);
+ }
+ _memberInfo[member] = info;
+ _updateUnboxingInfoOfMember(member, typeFlowAnalysis);
+ }
+
+ for (Library library in component.libraries) {
+ for (Class cls in library.classes) {
+ for (Member member in cls.members) {
+ addMember(member);
+ }
+ }
+ for (Member member in library.members) {
+ addMember(member);
+ }
+ }
}
- void applyToArg(Member member, int argPos, Type type) {
- assertx(_finishedGraph);
- member = _validMemberOrNull(member);
- if (member == null) return;
- assertx(_memberIds.containsKey(member));
- final partitionId = _memberIds[member];
+ void _updateUnboxingInfoOfMember(
+ Member member, TypeFlowAnalysis typeFlowAnalysis) {
+ if (typeFlowAnalysis.isMemberUsed(member)) {
+ final UnboxingInfoMetadata unboxingInfo = _memberInfo[member];
+ if (_cannotUnbox(member)) {
+ unboxingInfo.unboxedArgsInfo.length = 0;
+ unboxingInfo.returnInfo = UnboxingInfoMetadata.kBoxed;
+ return;
+ }
+ if (member is Procedure || member is Constructor) {
+ final Args<Type> argTypes = typeFlowAnalysis.argumentTypes(member);
+ assertx(argTypes != null);
- if (argPos < 0 ||
- _allUnboxingInfo[partitionId].unboxedArgsInfo.length <= argPos) {
+ final int firstParamIndex =
+ numTypeParams(member) + (hasReceiverArg(member) ? 1 : 0);
+
+ final positionalParams = member.function.positionalParameters;
+ assertx(argTypes.positionalCount ==
+ firstParamIndex + positionalParams.length);
+
+ for (int i = 0; i < positionalParams.length; i++) {
+ final inferredType = argTypes.values[firstParamIndex + i];
+ _applyToArg(unboxingInfo, i, inferredType);
+ }
+
+ final names = argTypes.names;
+ for (int i = 0; i < names.length; i++) {
+ final inferredType =
+ argTypes.values[firstParamIndex + positionalParams.length + i];
+ _applyToArg(unboxingInfo, positionalParams.length + i, inferredType);
+ }
+
+ final Type resultType = typeFlowAnalysis.getSummary(member).resultType;
+ _applyToReturn(unboxingInfo, resultType);
+ } else if (member is Field) {
+ final fieldValue = typeFlowAnalysis.getFieldValue(member).value;
+ if (member.hasSetter) {
+ _applyToArg(unboxingInfo, 0, fieldValue);
+ }
+ _applyToReturn(unboxingInfo, fieldValue);
+ } else {
+ assertx(false);
+ }
+ }
+ }
+
+ void _applyToArg(UnboxingInfoMetadata unboxingInfo, int argPos, Type type) {
+ if (argPos < 0 || unboxingInfo.unboxedArgsInfo.length <= argPos) {
return;
}
- final unboxingInfo = _allUnboxingInfo[partitionId];
-
if (type is NullableType ||
(!type.isSubtypeOf(_typeHierarchy, _coreTypes.intClass) &&
!type.isSubtypeOf(_typeHierarchy, _coreTypes.doubleClass))) {
@@ -107,14 +178,7 @@
}
}
- void applyToReturn(Member member, Type type) {
- assertx(_finishedGraph);
- member = _validMemberOrNull(member);
- if (member == null) return;
- assertx(_memberIds.containsKey(member));
- final partitionId = _memberIds[member];
- final unboxingInfo = _allUnboxingInfo[partitionId];
-
+ void _applyToReturn(UnboxingInfoMetadata unboxingInfo, Type type) {
if (type is NullableType ||
(!type.isSubtypeOf(_typeHierarchy, _coreTypes.intClass) &&
!type.isSubtypeOf(_typeHierarchy, _coreTypes.doubleClass))) {
@@ -127,82 +191,18 @@
}
}
- void _linkRecursive(Member member, Class cls) {
- for (final superType in cls.supers) {
- final superClass = superType.classNode;
- bool linked = false;
- superClass.members.forEach((Member superMember) {
- if (member.isInstanceMember) {
- if (member.name == superMember.name) {
- _linkMembers(member, superMember);
- linked = true;
- }
- }
- });
- if (!linked) {
- _linkRecursive(member, superClass);
- }
- }
- }
-
- void _linkMembers(Member member1, Member member2) {
- member1 = _validMemberOrNull(member1);
- member2 = _validMemberOrNull(member2);
- if (member1 == null ||
- member2 == null ||
- _isConstructorOrStatic(member1) ||
- _isConstructorOrStatic(member2)) {
- return;
- }
- _union(_getMemberId(member1), _getMemberId(member2));
- }
-
- Member _validMemberOrNull(Member member) {
- if (member == null ||
- (member is! Procedure && member is! Constructor && member is! Field)) {
- return null;
- }
- return member;
- }
-
- bool _isConstructorOrStatic(Member member) {
- return ((member is Constructor) ||
- ((member is Procedure) && member.isStatic));
- }
-
- void _addMember(Member member) {
- assertx(!_finishedGraph);
-
- if (_cannotUnbox(member)) {
- _mustBox.add(member);
- }
-
- final int memberId = _allUnboxingInfo.length;
- assertx(memberId == _partitionIds.length);
- assertx(_partitionIds.length == _partitionRank.length);
- final int argsLen = member is Field
- ? (member.hasSetter ? 1 : 0)
- : member.function.requiredParameterCount;
- _memberIds[member] = memberId;
- _allUnboxingInfo.add(UnboxingInfoMetadata(argsLen));
- _partitionIds.add(memberId);
- _partitionRank.add(1);
- }
-
bool _cannotUnbox(Member member) {
// Methods that do not need dynamic invocation forwarders can not have
// unboxed parameters and return because dynamic calls always use boxed
// values.
// Similarly C->Dart calls (entrypoints) and Dart->C calls (natives) need to
// have boxed parameters and return values.
- return (_isNative(member) ||
+ return _isNative(member) ||
_nativeCodeOracle.isMemberReferencedFromNativeCode(member) ||
- _isEnclosingClassSubtypeOfNum(member));
+ _isEnclosingClassSubtypeOfNum(member);
}
- bool _isNative(Member member) {
- return (getExternalName(member) != null);
- }
+ bool _isNative(Member member) => getExternalName(member) != null;
// TODO(dartbug.com/33549): Calls to these methods could be replaced by
// CheckedSmiOpInstr, so in order to allow the parameters and return
@@ -213,48 +213,4 @@
ConeType(_typeHierarchy.getTFClass(member.enclosingClass))
.isSubtypeOf(_typeHierarchy, _coreTypes.numClass));
}
-
- int _getMemberId(Member member) {
- return _memberIds[member];
- }
-
- int _find(int memberId) {
- assertx(!_finishedGraph);
- if (memberId == _partitionIds[memberId]) {
- return memberId;
- }
- final partitionId = _find(_partitionIds[memberId]);
- _allUnboxingInfo[memberId] = null;
- _partitionIds[memberId] = partitionId;
- return partitionId;
- }
-
- void _union(int memberId1, int memberId2) {
- assertx(!_finishedGraph);
- final partitionId1 = _find(memberId1);
- final partitionId2 = _find(memberId2);
-
- if (partitionId1 == partitionId2) {
- return;
- }
-
- int from, to;
- if (_partitionRank[partitionId1] < _partitionRank[partitionId2]) {
- from = partitionId1;
- to = partitionId2;
- } else {
- from = partitionId2;
- to = partitionId1;
- }
- final fromArgsInfo = _allUnboxingInfo[from].unboxedArgsInfo;
- final toArgsInfo = _allUnboxingInfo[to].unboxedArgsInfo;
- if (fromArgsInfo.length < toArgsInfo.length) {
- toArgsInfo.length = fromArgsInfo.length;
- }
- _allUnboxingInfo[from] = null;
- _partitionIds[from] = to;
- if (_partitionRank[from] == _partitionRank[to]) {
- _partitionRank[to]++;
- }
- }
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart
new file mode 100644
index 0000000..65d7485
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void foo(/* boxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void foo(/* unboxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().foo(r.nextInt(10));
+ B().foo(r.nextInt(10));
+ A().foo(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.foo(13);
+ }
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart.expect
new file mode 100644
index 0000000..5df0c21
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_1_test.dart.expect
@@ -0,0 +1,49 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+import "dart:math" as math;
+
+import "dart:math";
+import "package:expect/expect.dart";
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] @#C3
+ method foo([@vm.inferred-type.metadata=int?] core::int* x) → void
+ return [@vm.inferred-type.metadata=dart.core::Null? (value: null)] exp::Expect::isTrue([@vm.direct-call.metadata=dart.core::_IntegerImplementation.isOdd??] [@vm.inferred-type.metadata=dart.core::bool] x.{core::int::isOdd});
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B*
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] @#C3
+ method foo([@vm.inferred-type.metadata=int] core::int* x) → void
+ return [@vm.inferred-type.metadata=dart.core::Null? (value: null)] exp::Expect::isTrue([@vm.direct-call.metadata=dart.core::_IntegerImplementation.isOdd] [@vm.inferred-type.metadata=dart.core::bool] x.{core::int::isOdd});
+}
+class C extends self::A implements self::B {
+ synthetic constructor •() → self::C*
+ : super self::A::•()
+ ;
+}
+[@vm.inferred-type.metadata=dart.core::bool?]static final field core::bool* alwaysFalse = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.inferred-type.metadata=int] core::int::parse("1").{core::num::==}(2);
+static method main() → dynamic {
+ final math::Random* r = [@vm.inferred-type.metadata=dart.math::_Random] math::Random::•();
+ if([@vm.inferred-type.metadata=dart.core::bool?] self::alwaysFalse) {
+ [@vm.direct-call.metadata=#lib::A.foo] [@vm.inferred-type.metadata=!? (skip check)] new self::A::•().{self::A::foo}([@vm.direct-call.metadata=dart.math::_Random.nextInt] [@vm.inferred-type.metadata=int (skip check)] r.{math::Random::nextInt}(10));
+ [@vm.direct-call.metadata=#lib::B.foo] [@vm.inferred-type.metadata=!? (skip check)] new self::B::•().{self::B::foo}([@vm.direct-call.metadata=dart.math::_Random.nextInt] [@vm.inferred-type.metadata=int (skip check)] r.{math::Random::nextInt}(10));
+ [@vm.direct-call.metadata=#lib::A.foo] [@vm.inferred-type.metadata=!? (skip check)] new self::A::•().{self::A::foo}(null);
+ }
+ final core::List<self::B*>* l = <self::B*>[new self::B::•(), new self::C::•()];
+ {
+ core::Iterator<self::B*>* :sync-for-iterator = [@vm.direct-call.metadata=dart.core::_GrowableList.iterator] [@vm.inferred-type.metadata=dart._internal::ListIterator<#lib::B*>] l.{core::Iterable::iterator};
+ for (; [@vm.direct-call.metadata=dart._internal::ListIterator.moveNext] [@vm.inferred-type.metadata=dart.core::bool (skip check)] :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ self::B* b = [@vm.direct-call.metadata=dart._internal::ListIterator.current] :sync-for-iterator.{core::Iterator::current};
+ {
+ b.{self::B::foo}(13);
+ }
+ }
+ }
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart
new file mode 100644
index 0000000..824ac78
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void bar(/* unboxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void bar(/* boxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().bar(r.nextInt(10));
+ B().bar(r.nextInt(10));
+ B().bar(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.bar(13);
+ }
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart.expect
new file mode 100644
index 0000000..11a9912
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_42418_2_test.dart.expect
@@ -0,0 +1,49 @@
+library #lib;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+import "dart:math" as math;
+
+import "dart:math";
+import "package:expect/expect.dart";
+
+class A extends core::Object {
+ synthetic constructor •() → self::A*
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] @#C3
+ method bar([@vm.inferred-type.metadata=int] core::int* x) → void
+ return [@vm.inferred-type.metadata=dart.core::Null? (value: null)] exp::Expect::isTrue([@vm.direct-call.metadata=dart.core::_IntegerImplementation.isOdd] [@vm.inferred-type.metadata=dart.core::bool] x.{core::int::isOdd});
+}
+class B extends core::Object {
+ synthetic constructor •() → self::B*
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] @#C3
+ method bar([@vm.inferred-type.metadata=int?] core::int* x) → void
+ return [@vm.inferred-type.metadata=dart.core::Null? (value: null)] exp::Expect::isTrue([@vm.direct-call.metadata=dart.core::_IntegerImplementation.isOdd??] [@vm.inferred-type.metadata=dart.core::bool] x.{core::int::isOdd});
+}
+class C extends self::A implements self::B {
+ synthetic constructor •() → self::C*
+ : super self::A::•()
+ ;
+}
+[@vm.inferred-type.metadata=dart.core::bool?]static final field core::bool* alwaysFalse = [@vm.direct-call.metadata=dart.core::_IntegerImplementation.==] [@vm.inferred-type.metadata=dart.core::bool (skip check)] [@vm.inferred-type.metadata=int] core::int::parse("1").{core::num::==}(2);
+static method main() → dynamic {
+ final math::Random* r = [@vm.inferred-type.metadata=dart.math::_Random] math::Random::•();
+ if([@vm.inferred-type.metadata=dart.core::bool?] self::alwaysFalse) {
+ [@vm.direct-call.metadata=#lib::A.bar] [@vm.inferred-type.metadata=!? (skip check)] new self::A::•().{self::A::bar}([@vm.direct-call.metadata=dart.math::_Random.nextInt] [@vm.inferred-type.metadata=int (skip check)] r.{math::Random::nextInt}(10));
+ [@vm.direct-call.metadata=#lib::B.bar] [@vm.inferred-type.metadata=!? (skip check)] new self::B::•().{self::B::bar}([@vm.direct-call.metadata=dart.math::_Random.nextInt] [@vm.inferred-type.metadata=int (skip check)] r.{math::Random::nextInt}(10));
+ [@vm.direct-call.metadata=#lib::B.bar] [@vm.inferred-type.metadata=!? (skip check)] new self::B::•().{self::B::bar}(null);
+ }
+ final core::List<self::B*>* l = <self::B*>[new self::B::•(), new self::C::•()];
+ {
+ core::Iterator<self::B*>* :sync-for-iterator = [@vm.direct-call.metadata=dart.core::_GrowableList.iterator] [@vm.inferred-type.metadata=dart._internal::ListIterator<#lib::B*>] l.{core::Iterable::iterator};
+ for (; [@vm.direct-call.metadata=dart._internal::ListIterator.moveNext] [@vm.inferred-type.metadata=dart.core::bool (skip check)] :sync-for-iterator.{core::Iterator::moveNext}(); ) {
+ self::B* b = [@vm.direct-call.metadata=dart._internal::ListIterator.current] :sync-for-iterator.{core::Iterator::current};
+ {
+ b.{self::B::bar}(13);
+ }
+ }
+ }
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_getters.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_getters.dart.expect
index 408a9b7..be40648 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_getters.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/unboxed_getters.dart.expect
@@ -56,7 +56,7 @@
[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:5] [@vm.unboxing-info.metadata=()->i] abstract get value() → core::int*;
}
class UBIA extends core::Object implements self::UBI {
-[@vm.inferred-type.metadata=int] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:5] [@vm.unboxing-info.metadata=()->i] field core::int* value;
+[@vm.inferred-type.metadata=int] [@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:6,getterSelectorId:5] [@vm.unboxing-info.metadata=(i)->i] field core::int* value;
[@vm.unboxing-info.metadata=(i)->b] constructor •([@vm.inferred-type.metadata=int] core::int* value) → self::UBIA*
: self::UBIA::value = value, super core::Object::•()
;
diff --git a/runtime/docs/dwarf_stack_traces.md b/runtime/docs/dwarf_stack_traces.md
index 0c80515..afddbc7 100644
--- a/runtime/docs/dwarf_stack_traces.md
+++ b/runtime/docs/dwarf_stack_traces.md
@@ -136,8 +136,8 @@
### Using the stack trace converter tool
-A simple way to translate DWARF stack traces is to use the tool
-`pkg/vm/bin/convert_stack_traces.dart`. The tool has one required
+A simple way to translate DWARF stack traces is to use the tool `decode`
+from the package [native_stack_traces](https://pub.dev/packages/native_stack_traces). The tool has one required
argument `-e`, which takes the name of the file containing DWARF
debugging information as an input. This can either be an
unstripped ELF snapshot or a file generated by `--save-debugging-info=<...>`.
@@ -147,7 +147,7 @@
```bash
# Using the unstripped ELF snapshot and piping all output to the tool's stdin.
-$ out/ReleaseX64/dart_precompiled_runtime dwarf_snapshot.so |& out/ReleaseX64/dart pkg/vm/bin/convert_stack_traces.dart -e dwarf_snapshot.so
+$ out/ReleaseX64/dart_precompiled_runtime dwarf_snapshot.so |& out/ReleaseX64/dart pkg/native_stack_traces/bin/decode.dart -e dwarf_snapshot.so
Unhandled exception:
Throw of null.
Warning: This VM has been configured to produce stack traces that violate the Dart standard.
@@ -161,7 +161,7 @@
#4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174)
# Using the separately saved debugging information and piping all output to the tool's stdin.
-$ out/ReleaseX64/dart_precompiled_runtime dwarf_snapshot.so |& out/ReleaseX64/dart pkg/vm/bin/convert_stack_traces.dart -e debug.data
+$ out/ReleaseX64/dart_precompiled_runtime dwarf_snapshot.so |& out/ReleaseX64/dart pkg/native_stack_traces/bin/decode.dart -e debug.data
Unhandled exception:
Throw of null.
Warning: This VM has been configured to produce stack traces that violate the Dart standard.
@@ -178,7 +178,7 @@
$ out/ReleaseX64/dart_precompiled_runtime dwarf_snapshot.so >output.txt 2>&1
# Reading the input to convert from the file "output.txt" instead of stdin.
-$ out/ReleaseX64/dart pkg/vm/bin/convert_stack_traces.dart -e debug.data -i output.txt
+$ out/ReleaseX64/dart pkg/native_stack_traces/bin/decode.dart -e debug.data -i output.txt
Unhandled exception:
Throw of null.
Warning: This VM has been configured to produce stack traces that violate the Dart standard.
@@ -192,7 +192,7 @@
#4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174)
# Output the converted input to the file "converted.txt" instead of stdout.
-$ out/ReleaseX64/dart pkg/vm/bin/convert_stack_traces.dart -e debug.data -i output.txt -o converted.txt
+$ out/ReleaseX64/dart pkg/native_stack_traces/bin/decode.dart -e debug.data -i output.txt -o converted.txt
$ cat converted.txt
Unhandled exception:
@@ -248,7 +248,7 @@
To convert a stream of lines that may include DWARF stack traces, use
the stack transformer `DwarfStackTraceDecoder`. Its constructor takes a `Dwarf`
-object, and the transformer, like `convert_stack_traces.dart`, only changes
+object, and the transformer, like `decode.dart` from the package [native_stack_traces](https://pub.dev/packages/native_stack_traces), only changes
lines that correspond to stack trace frames.
> **Note**: The stack transformer assumes that lines are not combined or broken
diff --git a/runtime/tests/vm/dart/regress_42418_1_test.dart b/runtime/tests/vm/dart/regress_42418_1_test.dart
new file mode 100644
index 0000000..add07b4
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_42418_1_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void foo(/* boxed */ int? x) => Expect.isTrue(x!.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void foo(/* unboxed */ int? x) => Expect.isTrue(x!.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().foo(r.nextInt(10));
+ B().foo(r.nextInt(10));
+ A().foo(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.foo(13);
+ }
+}
diff --git a/runtime/tests/vm/dart/regress_42418_2_test.dart b/runtime/tests/vm/dart/regress_42418_2_test.dart
new file mode 100644
index 0000000..01bede8
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_42418_2_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void bar(/* unboxed */ int? x) => Expect.isTrue(x!.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void bar(/* boxed */ int? x) => Expect.isTrue(x!.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().bar(r.nextInt(10));
+ B().bar(r.nextInt(10));
+ B().bar(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.bar(13);
+ }
+}
diff --git a/runtime/tests/vm/dart_2/regress_42418_1_test.dart b/runtime/tests/vm/dart_2/regress_42418_1_test.dart
new file mode 100644
index 0000000..65d7485
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_42418_1_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void foo(/* boxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void foo(/* unboxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().foo(r.nextInt(10));
+ B().foo(r.nextInt(10));
+ A().foo(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.foo(13);
+ }
+}
diff --git a/runtime/tests/vm/dart_2/regress_42418_2_test.dart b/runtime/tests/vm/dart_2/regress_42418_2_test.dart
new file mode 100644
index 0000000..824ac78
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_42418_2_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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';
+
+import 'package:expect/expect.dart';
+
+final bool alwaysFalse = int.parse('1') == 2;
+
+class A {
+ @pragma("vm:never-inline")
+ void bar(/* unboxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class B {
+ @pragma("vm:never-inline")
+ void bar(/* boxed */ int x) => Expect.isTrue(x.isOdd);
+}
+
+class C extends A implements B {}
+
+main() {
+ final Random r = Random();
+ if (alwaysFalse) {
+ A().bar(r.nextInt(10));
+ B().bar(r.nextInt(10));
+ B().bar(null);
+ }
+ final List<B> l = [B(), C()];
+ for (B b in l) {
+ b.bar(13);
+ }
+}
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index a992ff3..fd3f576 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -2277,7 +2277,7 @@
setter.set_accessor_field(field);
setter.set_is_extension_member(field.is_extension_member());
H.SetupFieldAccessorFunction(klass, setter, field_type);
- T.SetupUnboxingInfoMetadataForFieldAccessors(getter,
+ T.SetupUnboxingInfoMetadataForFieldAccessors(setter,
library_kernel_offset_);
}
}
diff --git a/tools/VERSION b/tools/VERSION
index da8eb4b..29d04b0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 67
+PRERELEASE 68
PRERELEASE_PATCH 0
\ No newline at end of file