Version 2.18.0-91.0.dev Merge commit '4f0ed6a45cb778c02e1351399d63ddc917f61404' into 'dev'
diff --git a/.github/move.yml b/.github/move.yml deleted file mode 100644 index bf0cceb..0000000 --- a/.github/move.yml +++ /dev/null
@@ -1,21 +0,0 @@ -# Configuration for move-issues - https://github.com/dessant/move-issues - -# Delete the command comment when it contains no other content -deleteCommand: true - -# Close the source issue after moving -closeSourceIssue: true - -# Lock the source issue after moving -lockSourceIssue: false - -# Mention issue and comment authors -mentionAuthors: true - -# Preserve mentions in the issue content -keepContentMentions: true - -# Set custom aliases for targets -aliases: - flutter: flutter/flutter - flutter-intellij: flutter/flutter-intellij
diff --git a/.github/no-response.yml b/.github/no-response.yml deleted file mode 100644 index 81cec3e..0000000 --- a/.github/no-response.yml +++ /dev/null
@@ -1,16 +0,0 @@ -# Configuration for probot-no-response - https://github.com/probot/no-response - -# Number of days of inactivity before an issue is closed for lack of response. -daysUntilClose: 21 - -# Label requiring a response. -responseRequiredLabel: "needs-info" - -# Comment to post when closing an Issue for lack of response. -closeComment: >- - Without additional information, we are unfortunately not sure how to - resolve this issue. We are therefore reluctantly going to close this - bug for now. Please don't hesitate to comment on the bug if you have - any more information for us; we will reopen it right away! - - Thanks for your contribution.
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart index 6fd8abf..cf79edf 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/feature_computer.dart
@@ -158,13 +158,13 @@ /// offset is within the given [node], or `null` if the context does not /// impose any type. DartType? computeContextType(AstNode node, int offset) { - var type = node - .accept(_ContextTypeVisitor(typeProvider, offset)) - ?.resolveToBound(typeProvider.objectType); - if (type == null || type.isDynamic) { + final contextType = node.accept( + _ContextTypeVisitor(typeProvider, offset), + ); + if (contextType == null || contextType.isDynamic) { return null; } - return type; + return typeSystem.resolveToBound(contextType); } /// Return the element kind used to compute relevance for the given [element].
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart index b809dbe..ef27adf 100644 --- a/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart +++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -42,7 +42,10 @@ } // Determine the target expression's type. - var type = expression.staticType?.resolveToBound(request.objectType); + final expressionType = expression.staticType; + var type = expressionType != null + ? request.libraryElement.typeSystem.resolveToBound(expressionType) + : null; if (type == null || type.isDynamic) { // If the expression does not provide a good type, then attempt to get a // better type from the element.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart b/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart index a1f240b..c6a9dc9 100644 --- a/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart +++ b/pkg/analysis_server/test/src/services/correction/fix/sort_constructor_first_test.dart
@@ -80,6 +80,77 @@ @override String get lintCode => LintNames.sort_constructors_first; + @FailingTest( + reason: 'The beginToken is the comment, which has no previous token.', + issue: 'https://github.com/dart-lang/sdk/issues/48966', + ) + Future<void> test_hasComment() async { + await resolveTestCode(''' +class A { + void foo() {} + /// comment + A(); +} +'''); + await assertHasFix(''' +class A { + /// comment + A(); + void foo() {} +} +'''); + } + + @FailingTest( + reason: 'The beginToken is the comment, which has no previous token.', + issue: 'https://github.com/dart-lang/sdk/issues/48966', + ) + Future<void> test_hasComment_hasMetadata_afterComment() async { + await resolveTestCode(''' +const a = 0; + +class A { + void foo() {} + /// comment + @a + A(); +} +'''); + await assertHasFix(''' +const a = 0; + +class A { + /// comment + @a + A(); + void foo() {} +} +'''); + } + + Future<void> test_hasComment_hasMetadata_beforeComment() async { + await resolveTestCode(''' +const a = 0; + +class A { + void foo() {} + @a + /// comment + A(); +} +'''); + await assertHasFix(''' +const a = 0; + +class A { + @a + /// comment + A(); + void foo() {} +} +'''); + } + Future<void> test_one_fix() async { await resolveTestCode(''' class A {
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md index 4e91889..4462b02 100644 --- a/pkg/analyzer/CHANGELOG.md +++ b/pkg/analyzer/CHANGELOG.md
@@ -2,6 +2,7 @@ * Deprecated `ParameterElement.isNotOptional`, use `isRequired` instead. * Deprecated `ResourceProviderMixin.newFile2`, use `newFile` instead. * Deprecated `ResourceProviderMixin.newAnalysisOptionsYamlFile2`, use `newAnalysisOptionsYamlFile` instead. +* Deprecated `DartType.resolveToBound`, use `TypeSystem.resolveToBound` instead. ## 4.0.0 * Removed deprecated `UriKind` and `Source.uriKind`.
diff --git a/pkg/analyzer/lib/dart/element/type.dart b/pkg/analyzer/lib/dart/element/type.dart index 2f479bd..806186f 100644 --- a/pkg/analyzer/lib/dart/element/type.dart +++ b/pkg/analyzer/lib/dart/element/type.dart
@@ -176,6 +176,7 @@ /// /// For any other type, returns `this`. Applies recursively -- if the bound is /// itself a type parameter, that is resolved too. + @Deprecated('Use TypeSystem.resolveToBound() instead') DartType resolveToBound(DartType objectType); }
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart index dcef43d..113b883 100644 --- a/pkg/analyzer/lib/src/dart/element/type.dart +++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1063,6 +1063,7 @@ return false; } + @Deprecated('Use TypeSystem.resolveToBound() instead') @override DartType resolveToBound(DartType objectType) => this; @@ -1201,6 +1202,7 @@ return parameters.contains(element); } + @Deprecated('Use TypeSystem.resolveToBound() instead') @override DartType resolveToBound(DartType objectType) { final promotedBound = this.promotedBound;
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart index d420c963..5208c75 100644 --- a/pkg/analyzer/lib/src/dart/element/type_system.dart +++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -1468,26 +1468,26 @@ @override DartType resolveToBound(DartType type) { if (type is TypeParameterTypeImpl) { - var element = type.element; + final promotedBound = type.promotedBound; + if (promotedBound != null) { + return resolveToBound(promotedBound); + } - var bound = element.bound; + final bound = type.element.bound; if (bound == null) { - return typeProvider.objectType; + return isNonNullableByDefault ? objectQuestion : objectStar; } - NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix; - NullabilitySuffix newNullabilitySuffix; - if (nullabilitySuffix == NullabilitySuffix.question || - bound.nullabilitySuffix == NullabilitySuffix.question) { - newNullabilitySuffix = NullabilitySuffix.question; - } else if (nullabilitySuffix == NullabilitySuffix.star || - bound.nullabilitySuffix == NullabilitySuffix.star) { - newNullabilitySuffix = NullabilitySuffix.star; - } else { - newNullabilitySuffix = NullabilitySuffix.none; - } + final resolved = resolveToBound(bound) as TypeImpl; - var resolved = resolveToBound(bound) as TypeImpl; + final newNullabilitySuffix = uniteNullabilities( + uniteNullabilities( + type.nullabilitySuffix, + bound.nullabilitySuffix, + ), + resolved.nullabilitySuffix, + ); + return resolved.withNullability(newNullabilitySuffix); }
diff --git a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart index 6d8741a..0906db3 100644 --- a/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/binary_expression_resolver.dart
@@ -233,13 +233,6 @@ contextType: contextType); } - /// If the given [type] is a type parameter, resolve it to the type that should - /// be used when looking up members. Otherwise, return the original type. - /// - /// TODO(scheglov) this is duplicate - DartType _resolveTypeParameter(DartType type) => - type.resolveToBound(_typeProvider.objectType); - void _resolveUnsupportedOperator(BinaryExpressionImpl node, {required DartType? contextType}) { node.leftOperand.accept(_resolver); @@ -304,7 +297,7 @@ } var leftType = leftOperand.typeOrThrow; - leftType = _resolveTypeParameter(leftType); + leftType = _typeSystem.resolveToBound(leftType); if (identical(leftType, NeverTypeImpl.instance)) { _resolver.errorReporter.reportErrorForNode( @@ -354,7 +347,7 @@ leftType = leftOperand.extendedType!; } else { leftType = leftOperand.typeOrThrow; - leftType = _resolveTypeParameter(leftType); + leftType = _typeSystem.resolveToBound(leftType); } if (identical(leftType, NeverTypeImpl.instance)) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart index f43eecf..5cebadf 100644 --- a/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/comment_reference_resolver.dart
@@ -7,6 +7,7 @@ import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/src/dart/ast/ast.dart'; import 'package:analyzer/src/dart/element/type_provider.dart'; +import 'package:analyzer/src/dart/element/type_system.dart'; import 'package:analyzer/src/dart/resolver/type_property_resolver.dart'; import 'package:analyzer/src/generated/resolver.dart'; @@ -21,6 +22,8 @@ CommentReferenceResolver(this._typeProvider, this._resolver) : _typePropertyResolver = _resolver.typePropertyResolver; + TypeSystemImpl get _typeSystem => _resolver.typeSystem; + /// Resolves [commentReference]. void resolve(CommentReference commentReference) { _resolver.errorReporter.lockLevel++; @@ -150,8 +153,9 @@ if (enclosingExtension == null) { return null; } - var extendedType = enclosingExtension.extendedType - .resolveToBound(_typeProvider.objectType); + var extendedType = _typeSystem.resolveToBound( + enclosingExtension.extendedType, + ); if (extendedType is InterfaceType) { enclosingType = extendedType; } else if (extendedType is FunctionType) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart index dceec2d..4784ae4 100644 --- a/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/for_resolver.dart
@@ -9,6 +9,7 @@ import 'package:analyzer/src/dart/element/element.dart'; import 'package:analyzer/src/dart/element/type.dart'; import 'package:analyzer/src/dart/element/type_schema.dart'; +import 'package:analyzer/src/dart/element/type_system.dart'; import 'package:analyzer/src/dart/resolver/assignment_expression_resolver.dart'; import 'package:analyzer/src/dart/resolver/typed_literal_resolver.dart'; import 'package:analyzer/src/error/codes.dart'; @@ -22,6 +23,8 @@ required ResolverVisitor resolver, }) : _resolver = resolver; + TypeSystemImpl get _typeSystem => _resolver.typeSystem; + void resolveElement(ForElementImpl node, CollectionLiteralContext? context) { var forLoopParts = node.forLoopParts; void visitBody() { @@ -57,8 +60,7 @@ DartType? _computeForEachElementType(Expression iterable, bool isAsync) { var iterableType = iterable.staticType; if (iterableType == null) return null; - iterableType = - iterableType.resolveToBound(_resolver.typeProvider.objectType); + iterableType = _typeSystem.resolveToBound(iterableType); ClassElement iteratedElement = isAsync ? _resolver.typeProvider.streamElement
diff --git a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart index e7d3b26..8fdaa1a 100644 --- a/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/method_invocation_resolver.dart
@@ -868,15 +868,6 @@ } } - /// If the given [type] is a type parameter, replace with its bound. - /// Otherwise, return the original type. - DartType _resolveTypeParameter(DartType type) { - if (type is TypeParameterType) { - return type.resolveToBound(_resolver.typeProvider.objectType); - } - return type; - } - /// We have identified that [node] is not a real [MethodInvocation], /// because it does not invoke a method, but instead invokes the result /// of a getter execution, or implicitly invokes the `call` method of @@ -885,7 +876,7 @@ void _rewriteAsFunctionExpressionInvocation( MethodInvocationImpl node, DartType getterReturnType, {required DartType? contextType}) { - var targetType = _resolveTypeParameter(getterReturnType); + var targetType = _typeSystem.resolveToBound(getterReturnType); _inferenceHelper.recordStaticType(node.methodName, targetType, contextType: contextType);
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart index 8e8bce1..47bfe31 100644 --- a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -68,7 +68,7 @@ } var targetType = target.typeOrThrow; - targetType = _resolveTypeParameter(targetType); + targetType = _typeSystem.resolveToBound(targetType); if (targetType.isVoid) { // TODO(scheglov) Report directly in TypePropertyResolver? @@ -815,15 +815,6 @@ ); } - /// If the given [type] is a type parameter, replace with its bound. - /// Otherwise, return the original type. - DartType _resolveTypeParameter(DartType type) { - if (type is TypeParameterType) { - return type.resolveToBound(_resolver.typeProvider.objectType); - } - return type; - } - PropertyElementResolverResult _toIndexResult(ResolutionResult result) { var readElement = result.getter; var writeElement = result.setter;
diff --git a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart index fc870ea..6e9f0cc 100644 --- a/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart +++ b/pkg/analyzer/lib/src/dart/resolver/type_property_resolver.dart
@@ -282,7 +282,7 @@ bool ifNullSafe = false, }) { if (_typeSystem.isNonNullableByDefault ? ifNullSafe : ifLegacy) { - return type.resolveToBound(_typeProvider.objectType); + return _typeSystem.resolveToBound(type); } else { return type; }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart index d5a1aac..039fbff 100644 --- a/pkg/analyzer/lib/src/generated/error_verifier.dart +++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2393,7 +2393,7 @@ // The object being iterated has to implement Iterable<T> for some T that // is assignable to the variable's type. // TODO(rnystrom): Move this into mostSpecificTypeArgument()? - iterableType = iterableType.resolveToBound(_typeProvider.objectType); + iterableType = typeSystem.resolveToBound(iterableType); var requiredSequenceType = awaitKeyword != null ? _typeProvider.streamDynamicType
diff --git a/pkg/analyzer/lib/src/summary2/macro_application.dart b/pkg/analyzer/lib/src/summary2/macro_application.dart index 6b7dd6c..42ac2f3 100644 --- a/pkg/analyzer/lib/src/summary2/macro_application.dart +++ b/pkg/analyzer/lib/src/summary2/macro_application.dart
@@ -486,7 +486,7 @@ return null; } - return declarationBuilder.fromElement.classDeclaration( + return declarationBuilder.fromElement.classElement( superType.element, ); }
diff --git a/pkg/analyzer/lib/src/summary2/macro_declarations.dart b/pkg/analyzer/lib/src/summary2/macro_declarations.dart index 47bcc2b..21707bc 100644 --- a/pkg/analyzer/lib/src/summary2/macro_declarations.dart +++ b/pkg/analyzer/lib/src/summary2/macro_declarations.dart
@@ -8,6 +8,8 @@ as macro; import 'package:analyzer/dart/ast/ast.dart' as ast; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/nullability_suffix.dart'; +import 'package:analyzer/dart/element/type.dart'; class ClassDeclarationImpl extends macro.ClassDeclarationImpl { late final ClassElement element; @@ -43,7 +45,7 @@ /// corresponding elements. So, we can access them uniformly via interfaces, /// mixins, etc. void transferToElements() { - for (final entry in fromNode._classNodes.entries) { + for (final entry in fromNode._classMap.entries) { final element = entry.key.declaredElement as ClassElement; final declaration = entry.value; declaration.element = element; @@ -54,51 +56,86 @@ class DeclarationBuilderFromElement { final Map<ClassElement, ClassDeclarationImpl> _classMap = Map.identity(); + final Map<TypeParameterElement, macro.TypeParameterDeclarationImpl> + _typeParameterMap = Map.identity(); - macro.ClassDeclarationImpl classDeclaration(ClassElement element) { - return _classMap[element] ??= _classDeclaration(element); + macro.ClassDeclarationImpl classElement(ClassElement element) { + return _classMap[element] ??= _classElement(element); } - ClassDeclarationImpl _classDeclaration(ClassElement element) { + macro.TypeParameterDeclarationImpl typeParameter( + TypeParameterElement element, + ) { + return _typeParameterMap[element] ??= _typeParameter(element); + } + + ClassDeclarationImpl _classElement(ClassElement element) { assert(!_classMap.containsKey(element)); return ClassDeclarationImpl._( id: macro.RemoteInstance.uniqueId, - identifier: _identifierFromName(element.name), - typeParameters: [], // TODO _buildTypeParameters(node.typeParameters), - interfaces: [], // TODO _buildTypeAnnotations(node.implementsClause?.interfaces), - isAbstract: false, // TODO node.abstractKeyword != null, + identifier: _identifier(element.name), + typeParameters: element.typeParameters.map(_typeParameter).toList(), + interfaces: element.interfaces.map(_dartType).toList(), + isAbstract: element.isAbstract, isExternal: false, - mixins: [], // TODO _buildTypeAnnotations(node.withClause?.mixinTypes), - superclass: null, - // TODO(scheglov) implement - // superclass: node.extendsClause?.superclass.mapOrNull( - // _buildTypeAnnotation, - // ), + mixins: element.mixins.map(_dartType).toList(), + superclass: element.supertype.mapOrNull(_dartType), )..element = element; } - macro.IdentifierImpl _identifierFromName(String name) { + macro.TypeAnnotationImpl _dartType(DartType type) { + if (type is InterfaceType) { + return macro.NamedTypeAnnotationImpl( + id: macro.RemoteInstance.uniqueId, + isNullable: type.nullabilitySuffix == NullabilitySuffix.question, + identifier: _identifier(type.element.name), + typeArguments: type.typeArguments.map(_dartType).toList(), + ); + } else if (type is TypeParameterType) { + return macro.NamedTypeAnnotationImpl( + id: macro.RemoteInstance.uniqueId, + isNullable: type.nullabilitySuffix == NullabilitySuffix.question, + identifier: _identifier(type.element.name), + typeArguments: const [], + ); + } else { + // TODO(scheglov) other types + throw UnimplementedError('(${type.runtimeType}) $type'); + } + } + + macro.IdentifierImpl _identifier(String name) { return _IdentifierImpl( id: macro.RemoteInstance.uniqueId, name: name, ); } + + macro.TypeParameterDeclarationImpl _typeParameter( + TypeParameterElement element, + ) { + return macro.TypeParameterDeclarationImpl( + id: macro.RemoteInstance.uniqueId, + identifier: _identifier(element.name), + bound: element.bound.mapOrNull(_dartType), + ); + } } class DeclarationBuilderFromNode { - final Map<ast.ClassDeclaration, ClassDeclarationImpl> _classNodes = + final Map<ast.ClassDeclaration, ClassDeclarationImpl> _classMap = Map.identity(); macro.ClassDeclarationImpl classDeclaration( ast.ClassDeclaration node, ) { - return _classNodes[node] ??= _classDeclaration(node); + return _classMap[node] ??= _classDeclaration(node); } ClassDeclarationImpl _classDeclaration( ast.ClassDeclaration node, ) { - assert(!_classNodes.containsKey(node)); + assert(!_classMap.containsKey(node)); return ClassDeclarationImpl._( id: macro.RemoteInstance.uniqueId, identifier: _identifier(node.name),
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart index d105672..6873d5f 100644 --- a/pkg/analyzer/test/src/dart/element/element_test.dart +++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -789,6 +789,7 @@ expect(types[1], stringNone); } + @deprecated void test_resolveToBound() { var type = functionTypeNone( typeFormals: [], @@ -1235,6 +1236,7 @@ expect(0 == typeA.hashCode, isFalse); } + @deprecated void test_resolveToBound() { var type = interfaceTypeStar(ElementFactory.classElement2('A')); @@ -1414,6 +1416,7 @@ expect(type.element, element); } + @deprecated void test_resolveToBound_bound() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1422,6 +1425,7 @@ expect(type.resolveToBound(objectNone), interfaceTypeStar(classS)); } + @deprecated void test_resolveToBound_bound_nullableInner() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1430,6 +1434,7 @@ expect(type.resolveToBound(objectNone), same(element.bound)); } + @deprecated void test_resolveToBound_bound_nullableInnerOuter() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1439,6 +1444,7 @@ expect(type.resolveToBound(objectNone), same(element.bound)); } + @deprecated void test_resolveToBound_bound_nullableInnerStarOuter() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1449,6 +1455,7 @@ type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS))); } + @deprecated void test_resolveToBound_bound_nullableOuter() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1459,6 +1466,7 @@ type.resolveToBound(objectNone), equals(interfaceTypeQuestion(classS))); } + @deprecated void test_resolveToBound_bound_starInner() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1467,6 +1475,7 @@ expect(type.resolveToBound(objectNone), same(element.bound)); } + @deprecated void test_resolveToBound_bound_starInnerNullableOuter() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1476,6 +1485,7 @@ expect(type.resolveToBound(objectNone), same(element.bound)); } + @deprecated void test_resolveToBound_bound_starOuter() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl element = TypeParameterElementImpl('E', -1); @@ -1485,6 +1495,7 @@ expect(type.resolveToBound(objectNone), interfaceTypeStar(classS)); } + @deprecated void test_resolveToBound_nestedBound() { ClassElementImpl classS = class_(name: 'A'); TypeParameterElementImpl elementE = TypeParameterElementImpl('E', -1); @@ -1496,6 +1507,7 @@ expect(typeF.resolveToBound(objectNone), interfaceTypeStar(classS)); } + @deprecated void test_resolveToBound_promotedBound_interfaceType() { var A = class_(name: 'A'); var A_none = interfaceTypeNone(A); @@ -1505,6 +1517,7 @@ expect(T_A.resolveToBound(objectQuestion), A_none); } + @deprecated void test_resolveToBound_promotedBound_typeParameterType_interfaceType() { var A = class_(name: 'A'); var A_none = interfaceTypeNone(A); @@ -1517,6 +1530,7 @@ expect(U_T.resolveToBound(objectQuestion), A_none); } + @deprecated void test_resolveToBound_unbound() { TypeParameterTypeImpl type = typeParameterTypeStar(TypeParameterElementImpl('E', -1)); @@ -1597,6 +1611,7 @@ expect(_voidType.isVoid, isTrue); } + @deprecated void test_resolveToBound() { // Returns this. expect(_voidType.resolveToBound(objectNone), same(_voidType));
diff --git a/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart new file mode 100644 index 0000000..b733568 --- /dev/null +++ b/pkg/analyzer/test/src/dart/element/resolve_to_bound_test.dart
@@ -0,0 +1,225 @@ +// 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. + +import 'package:analyzer/dart/element/type.dart'; +import 'package:test/test.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; + +import '../../../generated/type_system_test.dart'; + +main() { + defineReflectiveSuite(() { + defineReflectiveTests(ResolveToBoundTest); + defineReflectiveTests(ResolveToBoundWithoutNullSafetyTest); + }); +} + +@reflectiveTest +class ResolveToBoundTest extends AbstractTypeSystemTest { + test_dynamic() { + _check(dynamicType, 'dynamic'); + } + + test_functionType() { + _check( + functionTypeNone(returnType: voidNone), + 'void Function()', + ); + } + + test_interfaceType() { + _check(intNone, 'int'); + _check(intQuestion, 'int?'); + _check(intStar, 'int*'); + } + + test_typeParameter_bound() { + _check( + typeParameterTypeNone( + typeParameter('T', bound: intNone), + ), + 'int', + ); + + _check( + typeParameterTypeNone( + typeParameter('T', bound: intQuestion), + ), + 'int?', + ); + + _check( + typeParameterTypeStar( + typeParameter('T', bound: intStar), + ), + 'int*', + ); + } + + test_typeParameter_bound_functionType() { + _check( + typeParameterTypeNone( + typeParameter( + 'T', + bound: functionTypeNone( + returnType: voidNone, + ), + ), + ), + 'void Function()', + ); + } + + test_typeParameter_bound_nested_noBound() { + final T = typeParameter('T'); + final U = typeParameter( + 'U', + bound: typeParameterTypeNone(T), + ); + _check(typeParameterTypeNone(U), 'Object?'); + } + + test_typeParameter_bound_nested_none() { + final T = typeParameter('T', bound: intNone); + final U = typeParameter( + 'U', + bound: typeParameterTypeNone(T), + ); + _check(typeParameterTypeNone(U), 'int'); + } + + test_typeParameter_bound_nested_none_outerNullable() { + final T = typeParameter('T', bound: intNone); + final U = typeParameter( + 'U', + bound: typeParameterTypeQuestion(T), + ); + _check(typeParameterTypeNone(U), 'int?'); + } + + test_typeParameter_bound_nested_question() { + final T = typeParameter('T', bound: intQuestion); + final U = typeParameter( + 'U', + bound: typeParameterTypeNone(T), + ); + _check(typeParameterTypeNone(U), 'int?'); + } + + test_typeParameter_bound_nullableInner() { + _check( + typeParameterTypeNone( + typeParameter('T', bound: intQuestion), + ), + 'int?', + ); + } + + test_typeParameter_bound_nullableInnerOuter() { + _check( + typeParameterTypeQuestion( + typeParameter('T', bound: intQuestion), + ), + 'int?', + ); + } + + test_typeParameter_bound_nullableOuter() { + _check( + typeParameterTypeQuestion( + typeParameter('T', bound: intNone), + ), + 'int?', + ); + } + + test_typeParameter_noBound() { + _check( + typeParameterTypeNone( + typeParameter('T'), + ), + 'Object?', + ); + } + + test_typeParameter_promotedBound() { + _check( + typeParameterTypeNone( + typeParameter('T', bound: numNone), + promotedBound: intNone, + ), + 'int', + ); + + _check( + typeParameterTypeNone( + typeParameter('T', bound: numQuestion), + promotedBound: intQuestion, + ), + 'int?', + ); + + _check( + typeParameterTypeNone( + typeParameter('T', bound: numStar), + promotedBound: intStar, + ), + 'int*', + ); + } + + test_void() { + _check(voidNone, 'void'); + } + + void _check(DartType type, String expectedStr) { + var result = typeSystem.resolveToBound(type); + var resultStr = _typeString(result); + expect(resultStr, expectedStr); + } + + String _typeString(DartType type) { + return type.getDisplayString(withNullability: true); + } +} + +@reflectiveTest +class ResolveToBoundWithoutNullSafetyTest + extends AbstractTypeSystemWithoutNullSafetyTest { + test_dynamic() { + _check(dynamicType, 'dynamic'); + } + + test_typeParameter_bound() { + _check( + typeParameterTypeStar( + typeParameter('T', bound: intStar), + ), + 'int*', + ); + } + + test_typeParameter_noBound() { + _check( + typeParameterTypeNone( + typeParameter('T'), + ), + 'Object*', + ); + } + + test_void() { + _check(voidNone, 'void'); + } + + void _check(DartType type, String expectedStr) { + var result = typeSystem.resolveToBound(type); + var resultStr = _typeString(result); + expect(resultStr, expectedStr); + } + + String _typeString(DartType type) { + return type.getDisplayString(withNullability: true); + } +}
diff --git a/pkg/analyzer/test/src/dart/element/test_all.dart b/pkg/analyzer/test/src/dart/element/test_all.dart index f3019b9..8d78853 100644 --- a/pkg/analyzer/test/src/dart/element/test_all.dart +++ b/pkg/analyzer/test/src/dart/element/test_all.dart
@@ -21,6 +21,7 @@ import 'nullability_eliminator_test.dart' as nullability_eliminator; import 'nullable_test.dart' as nullable; import 'replace_top_bottom_test.dart' as replace_top_bottom; +import 'resolve_to_bound_test.dart' as resolve_to_bound; import 'runtime_type_equality_test.dart' as runtime_type_equality; import 'subtype_test.dart' as subtype; import 'top_merge_test.dart' as top_merge; @@ -52,6 +53,7 @@ nullability_eliminator.main(); nullable.main(); replace_top_bottom.main(); + resolve_to_bound.main(); runtime_type_equality.main(); subtype.main(); top_merge.main();
diff --git a/pkg/analyzer/test/src/summary/macro/declaration_text.dart b/pkg/analyzer/test/src/summary/macro/declaration_text.dart index f438eec..265f230 100644 --- a/pkg/analyzer/test/src/summary/macro/declaration_text.dart +++ b/pkg/analyzer/test/src/summary/macro/declaration_text.dart
@@ -6,6 +6,8 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; +import 'introspect_shared.dart'; + /*macro*/ class DeclarationTextMacro implements ClassTypesMacro { const DeclarationTextMacro(); @@ -88,15 +90,14 @@ _sink.write('$name: '); if (type != null) { - _writeln(_typeStr(type)); + _writeln(type.asString); } else { _writeln('null'); } } void _writeTypeAnnotationLine(TypeAnnotation type) { - var typeStr = _typeStr(type); - _writelnWithIndent(typeStr); + _writelnWithIndent(type.asString); } void _writeTypeAnnotations(String name, Iterable<TypeAnnotation> elements) { @@ -117,138 +118,4 @@ void _writeTypeParameters(Iterable<TypeParameterDeclaration> elements) { _writeElements('typeParameters', elements, _writeTypeParameter); } - - static String _typeStr(TypeAnnotation type) { - final buffer = StringBuffer(); - _TypeStringBuilder(buffer).write(type); - return buffer.toString(); - } -} - -class _TypeStringBuilder { - final StringSink _sink; - - _TypeStringBuilder(this._sink); - - void write(TypeAnnotation type) { - if (type is FunctionTypeAnnotation) { - _writeFunctionTypeAnnotation(type); - } else if (type is NamedTypeAnnotation) { - _writeNamedTypeAnnotation(type); - } else if (type is OmittedTypeAnnotation) { - _sink.write('OmittedType'); - } else { - throw UnimplementedError('(${type.runtimeType}) $type'); - } - if (type.isNullable) { - _sink.write('?'); - } - } - - void _writeFormalParameter(FunctionTypeParameter node) { - final String closeSeparator; - if (node.isNamed) { - _sink.write('{'); - closeSeparator = '}'; - if (node.isRequired) { - _sink.write('required '); - } - } else if (!node.isRequired) { - _sink.write('['); - closeSeparator = ']'; - } else { - closeSeparator = ''; - } - - write(node.type); - if (node.name != null) { - _sink.write(' '); - _sink.write(node.name); - } - - _sink.write(closeSeparator); - } - - void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) { - write(type.returnType); - _sink.write(' Function'); - - _sink.writeList( - elements: type.typeParameters, - write: _writeTypeParameter, - separator: ', ', - open: '<', - close: '>', - ); - - _sink.write('('); - var hasFormalParameter = false; - for (final formalParameter in type.positionalParameters) { - if (hasFormalParameter) { - _sink.write(', '); - } - _writeFormalParameter(formalParameter); - hasFormalParameter = true; - } - for (final formalParameter in type.namedParameters) { - if (hasFormalParameter) { - _sink.write(', '); - } - _writeFormalParameter(formalParameter); - hasFormalParameter = true; - } - _sink.write(')'); - } - - void _writeNamedTypeAnnotation(NamedTypeAnnotation type) { - _sink.write(type.identifier.name); - _sink.writeList( - elements: type.typeArguments, - write: write, - separator: ', ', - open: '<', - close: '>', - ); - } - - void _writeTypeParameter(TypeParameterDeclaration node) { - _sink.write(node.identifier.name); - - final bound = node.bound; - if (bound != null) { - _sink.write(' extends '); - write(bound); - } - } -} - -extension on StringSink { - void writeList<T>({ - required Iterable<T> elements, - required void Function(T element) write, - required String separator, - String? open, - String? close, - }) { - elements = elements.toList(); - if (elements.isEmpty) { - return; - } - - if (open != null) { - this.write(open); - } - var isFirst = true; - for (var element in elements) { - if (isFirst) { - isFirst = false; - } else { - this.write(separator); - } - write(element); - } - if (close != null) { - this.write(close); - } - } }
diff --git a/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart b/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart index 3a2515a..d5889ae 100644 --- a/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart +++ b/pkg/analyzer/test/src/summary/macro/introspect_declarations_phase.dart
@@ -6,6 +6,8 @@ import 'package:_fe_analyzer_shared/src/macros/api.dart'; +import 'introspect_shared.dart'; + const introspectMacro = IntrospectDeclarationsPhaseMacro(); /*macro*/ class IntrospectDeclarationsPhaseMacro @@ -19,6 +21,7 @@ ) async { final printer = _DeclarationPrinter( classIntrospector: builder, + typeResolver: builder, ); await printer.writeClassDeclaration(declaration); final text = printer._sink.toString(); @@ -34,11 +37,13 @@ class _DeclarationPrinter { final ClassIntrospector classIntrospector; + final TypeResolver typeResolver; final StringBuffer _sink = StringBuffer(); String _indent = ''; _DeclarationPrinter({ required this.classIntrospector, + required this.typeResolver, }); Future<void> writeClassDeclaration(ClassDeclaration e) async { @@ -55,10 +60,9 @@ await _withIndent(() => writeClassDeclaration(superclass)); } - // TODO(scheglov) implement - // _writeTypeParameters(e.typeParameters); - // _writeTypeAnnotations('mixins', e.mixins); - // _writeTypeAnnotations('interfaces', e.interfaces); + await _writeTypeParameters(e.typeParameters); + await _writeTypeAnnotations('mixins', e.mixins); + await _writeTypeAnnotations('interfaces', e.interfaces); }); } @@ -69,6 +73,21 @@ _indent = savedIndent; } + Future<void> _writeElements<T>( + String name, + Iterable<T> elements, + Future<void> Function(T) f, + ) async { + if (elements.isNotEmpty) { + _writelnWithIndent(name); + await _withIndent(() async { + for (var element in elements) { + await f(element); + } + }); + } + } + void _writeIf(bool flag, String str) { if (flag) { _sink.write(str); @@ -83,4 +102,43 @@ _sink.write(_indent); _sink.writeln(line); } + + void _writeTypeAnnotation(String name, TypeAnnotation? type) { + _sink.write(_indent); + _sink.write('$name: '); + + if (type != null) { + _writeln(type.asString); + } else { + _writeln('null'); + } + } + + Future<void> _writeTypeAnnotationLine(TypeAnnotation type) async { + _writelnWithIndent(type.asString); + } + + Future<void> _writeTypeAnnotations( + String name, + Iterable<TypeAnnotation> elements, + ) async { + await _writeElements(name, elements, _writeTypeAnnotationLine); + } + + Future<void> _writeTypeParameter(TypeParameterDeclaration e) async { + _writelnWithIndent(e.identifier.name); + + await _withIndent(() async { + var bound = e.bound; + if (bound != null) { + _writeTypeAnnotation('bound', bound); + } + }); + } + + Future<void> _writeTypeParameters( + Iterable<TypeParameterDeclaration> elements, + ) async { + await _writeElements('typeParameters', elements, _writeTypeParameter); + } }
diff --git a/pkg/analyzer/test/src/summary/macro/introspect_shared.dart b/pkg/analyzer/test/src/summary/macro/introspect_shared.dart new file mode 100644 index 0000000..b1c5b7f --- /dev/null +++ b/pkg/analyzer/test/src/summary/macro/introspect_shared.dart
@@ -0,0 +1,141 @@ +// 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. + +import 'package:_fe_analyzer_shared/src/macros/api.dart'; + +class _TypeAnnotationStringBuilder { + final StringSink _sink; + + _TypeAnnotationStringBuilder(this._sink); + + void write(TypeAnnotation type) { + if (type is FunctionTypeAnnotation) { + _writeFunctionTypeAnnotation(type); + } else if (type is NamedTypeAnnotation) { + _writeNamedTypeAnnotation(type); + } else if (type is OmittedTypeAnnotation) { + _sink.write('OmittedType'); + } else { + throw UnimplementedError('(${type.runtimeType}) $type'); + } + if (type.isNullable) { + _sink.write('?'); + } + } + + void _writeFormalParameter(FunctionTypeParameter node) { + final String closeSeparator; + if (node.isNamed) { + _sink.write('{'); + closeSeparator = '}'; + if (node.isRequired) { + _sink.write('required '); + } + } else if (!node.isRequired) { + _sink.write('['); + closeSeparator = ']'; + } else { + closeSeparator = ''; + } + + write(node.type); + if (node.name != null) { + _sink.write(' '); + _sink.write(node.name); + } + + _sink.write(closeSeparator); + } + + void _writeFunctionTypeAnnotation(FunctionTypeAnnotation type) { + write(type.returnType); + _sink.write(' Function'); + + _sink.writeList( + elements: type.typeParameters, + write: _writeTypeParameter, + separator: ', ', + open: '<', + close: '>', + ); + + _sink.write('('); + var hasFormalParameter = false; + for (final formalParameter in type.positionalParameters) { + if (hasFormalParameter) { + _sink.write(', '); + } + _writeFormalParameter(formalParameter); + hasFormalParameter = true; + } + for (final formalParameter in type.namedParameters) { + if (hasFormalParameter) { + _sink.write(', '); + } + _writeFormalParameter(formalParameter); + hasFormalParameter = true; + } + _sink.write(')'); + } + + void _writeNamedTypeAnnotation(NamedTypeAnnotation type) { + _sink.write(type.identifier.name); + _sink.writeList( + elements: type.typeArguments, + write: write, + separator: ', ', + open: '<', + close: '>', + ); + } + + void _writeTypeParameter(TypeParameterDeclaration node) { + _sink.write(node.identifier.name); + + final bound = node.bound; + if (bound != null) { + _sink.write(' extends '); + write(bound); + } + } +} + +extension on StringSink { + void writeList<T>({ + required Iterable<T> elements, + required void Function(T element) write, + required String separator, + String? open, + String? close, + }) { + elements = elements.toList(); + if (elements.isEmpty) { + return; + } + + if (open != null) { + this.write(open); + } + var isFirst = true; + for (var element in elements) { + if (isFirst) { + isFirst = false; + } else { + this.write(separator); + } + write(element); + } + if (close != null) { + this.write(close); + } + } +} + +extension E on TypeAnnotation { + String get asString { + final buffer = StringBuffer(); + _TypeAnnotationStringBuilder(buffer).write(this); + return buffer.toString(); + } +}
diff --git a/pkg/analyzer/test/src/summary/macro_test.dart b/pkg/analyzer/test/src/summary/macro_test.dart index a775b53..27d3339 100644 --- a/pkg/analyzer/test/src/summary/macro_test.dart +++ b/pkg/analyzer/test/src/summary/macro_test.dart
@@ -65,6 +65,12 @@ return code.replaceAll('/*macro*/', 'macro'); } + String get _introspectSharedCode { + return MacrosEnvironment.instance.packageAnalyzerFolder + .getChildAssumingFile('test/src/summary/macro/introspect_shared.dart') + .readAsStringSync(); + } + Future<void> setUp() async { writeTestPackageConfig( PackageConfigFileBuilder(), @@ -1152,6 +1158,133 @@ '''); } + test_introspect_declarations_ClassDeclaration_imported_interfaces() async { + newFile('$testPackageLibPath/a.dart', r''' +class A {} +class B {} +class C implements A, B {} +'''); + + await _assertIntrospectDeclarationsText(r''' +import 'a.dart'; + +@introspectMacro +class X extends C {} +''', r''' +class X + superclass + class C + superclass + class Object + interfaces + A + B +'''); + } + + test_introspect_declarations_ClassDeclaration_imported_isAbstract() async { + newFile('$testPackageLibPath/a.dart', r''' +abstract class A {} +'''); + + await _assertIntrospectDeclarationsText(r''' +import 'a.dart'; + +@introspectMacro +class X extends A {} +''', r''' +class X + superclass + abstract class A + superclass + class Object +'''); + } + + test_introspect_declarations_ClassDeclaration_imported_mixins() async { + newFile('$testPackageLibPath/a.dart', r''' +mixin M1 {} +mixin M2 {} +class C with M1, M2 {} +'''); + + await _assertIntrospectDeclarationsText(r''' +import 'a.dart'; + +@introspectMacro +class X extends C {} +''', r''' +class X + superclass + class C + superclass + class Object + mixins + M1 + M2 +'''); + } + + test_introspect_declarations_ClassDeclaration_imported_superclass() async { + newFile('$testPackageLibPath/a.dart', r''' +class A {} +class B extends A {} +'''); + + await _assertIntrospectDeclarationsText(r''' +import 'a.dart'; + +@introspectMacro +class X extends B {} +''', r''' +class X + superclass + class B + superclass + class A + superclass + class Object +'''); + } + + test_introspect_declarations_ClassDeclaration_imported_typeParameters() async { + newFile('$testPackageLibPath/a.dart', r''' +class A<T, U extends List<T>> {} +'''); + + await _assertIntrospectDeclarationsText(r''' +import 'a.dart'; + +@introspectMacro +class X extends A {} +''', r''' +class X + superclass + class A + superclass + class Object + typeParameters + T + U + bound: List<T> +'''); + } + + test_introspect_declarations_ClassDeclaration_superclassOf() async { + await _assertIntrospectDeclarationsText(r''' +class A {} + +@introspectMacro +class X extends A {} +''', r''' +class X + superclass + class A + superclass + class Object +'''); + } + test_introspect_declarations_ClassDeclaration_superclassOf_implicit() async { await _assertIntrospectDeclarationsText(r''' @introspectMacro @@ -1163,18 +1296,14 @@ '''); } - test_introspect_declarations_ClassDeclaration_superclassOf_local() async { + test_introspect_declarations_ClassDeclaration_superclassOf_unresolved() async { await _assertIntrospectDeclarationsText(r''' -class A<T> {} - @introspectMacro -class X extends A<int> {} +class X extends A {} ''', r''' class X superclass - class A - superclass - class Object + class Object '''); } @@ -1598,6 +1727,11 @@ /// declaration. Future<String> _getDeclarationText(String declarationCode) async { newFile( + '$testPackageLibPath/introspect_shared.dart', + _introspectSharedCode, + ); + + newFile( '$testPackageLibPath/declaration_text.dart', _declarationTextCode, ); @@ -1608,7 +1742,10 @@ @DeclarationTextMacro() $declarationCode ''', preBuildSequence: [ - {'package:test/declaration_text.dart'} + { + 'package:test/introspect_shared.dart', + 'package:test/declaration_text.dart', + } ]); _assertNoErrorsForClassElement( @@ -1627,16 +1764,23 @@ /// macro annotated declarations. Future<String> _getIntrospectDeclarationsText(String declarationCode) async { newFile( + '$testPackageLibPath/introspect_shared.dart', + _introspectSharedCode, + ); + + newFile( '$testPackageLibPath/introspect_declarations_phase.dart', _introspectDeclarationsPhaseCode, ); var library = await buildLibrary(''' import 'introspect_declarations_phase.dart'; - $declarationCode ''', preBuildSequence: [ - {'package:test/introspect_declarations_phase.dart'} + { + 'package:test/introspect_shared.dart', + 'package:test/introspect_declarations_phase.dart', + } ]); for (final class_ in library.definingCompilationUnit.classes) {
diff --git a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart index 1f5e31b..1a578bb 100644 --- a/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart +++ b/pkg/compiler/lib/src/kernel/transformations/async_lowering.dart
@@ -11,7 +11,9 @@ class _FunctionData { final List<AwaitExpression> awaits = []; final Set<ReturnStatement> returnStatements = {}; - bool hasAsyncLoop = false; + // If we find certain control flow statements in this function, we choose to + // not lower it. + bool shouldLower = true; _FunctionData(); @@ -35,7 +37,9 @@ AsyncLowering(this._coreTypes); bool _shouldTryAsyncLowering(FunctionNode node) => - node.asyncMarker == AsyncMarker.Async && !_functions.last.hasAsyncLoop; + node.asyncMarker == AsyncMarker.Async && + node.futureValueType != null && + _functions.last.shouldLower; void enterFunction(FunctionNode node) { _functions.add(_FunctionData()); @@ -66,6 +70,20 @@ ])))); } + void _wrapReturns(_FunctionData functionData, FunctionNode node) { + final futureValueType = node.futureValueType!; + for (final returnStatement in functionData.returnStatements) { + final expression = returnStatement.expression; + // Ensure the returned future has a runtime type (T) matching the + // function's return type by wrapping with Future.value<T>. + if (expression == null) continue; + final futureValueCall = StaticInvocation(_coreTypes.futureValueFactory, + Arguments([expression], types: [futureValueType])); + returnStatement.expression = futureValueCall; + futureValueCall.parent = returnStatement; + } + } + void _transformDirectReturnAwaits( FunctionNode node, _FunctionData functionData) { // If every await is the direct child of a return statement then we can @@ -117,6 +135,7 @@ isLowered = true; } if (isLowered) { + _wrapReturns(functionData, node); _wrapBodySync(node); } } @@ -138,7 +157,11 @@ void visitForInStatement(ForInStatement statement) { if (statement.isAsync && _functions.isNotEmpty) { - _functions.last.hasAsyncLoop = true; + _functions.last.shouldLower = false; } } + + void visitTry() { + _functions.last.shouldLower = false; + } }
diff --git a/pkg/compiler/lib/src/kernel/transformations/lowering.dart b/pkg/compiler/lib/src/kernel/transformations/lowering.dart index b90f526..9490c32 100644 --- a/pkg/compiler/lib/src/kernel/transformations/lowering.dart +++ b/pkg/compiler/lib/src/kernel/transformations/lowering.dart
@@ -114,4 +114,18 @@ statement.transformChildren(this); return statement; } + + @override + TreeNode visitTryFinally(TryFinally statement) { + _asyncLowering?.visitTry(); + statement.transformChildren(this); + return statement; + } + + @override + TreeNode visitTryCatch(TryCatch statement) { + _asyncLowering?.visitTry(); + statement.transformChildren(this); + return statement; + } }
diff --git a/pkg/compiler/lib/src/serialization/binary_sink.dart b/pkg/compiler/lib/src/serialization/binary_sink.dart index c5c52a7..c408ccc 100644 --- a/pkg/compiler/lib/src/serialization/binary_sink.dart +++ b/pkg/compiler/lib/src/serialization/binary_sink.dart
@@ -2,16 +2,17 @@ // 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 - -part of 'serialization.dart'; +import 'dart:convert'; +import 'package:kernel/binary/ast_to_binary.dart'; +import 'data_sink.dart'; /// [DataSink] that writes data as a sequence of bytes. /// /// This data sink works together with [BinarySourceWriter]. class BinaryDataSink implements DataSink { final Sink<List<int>> sink; - BufferedSink _bufferedSink; + // Nullable and non-final to allow storage to be released. + BufferedSink? _bufferedSink; int _length = 0; BinaryDataSink(this.sink) : _bufferedSink = BufferedSink(sink); @@ -33,7 +34,7 @@ void writeString(String value) { List<int> bytes = utf8.encode(value); writeInt(bytes.length); - _bufferedSink.addBytes(bytes); + _bufferedSink!.addBytes(bytes); _length += bytes.length; } @@ -41,13 +42,13 @@ void writeInt(int value) { assert(value >= 0 && value >> 30 == 0); if (value < 0x80) { - _bufferedSink.addByte(value); + _bufferedSink!.addByte(value); _length += 1; } else if (value < 0x4000) { - _bufferedSink.addByte2((value >> 8) | 0x80, value & 0xFF); + _bufferedSink!.addByte2((value >> 8) | 0x80, value & 0xFF); _length += 2; } else { - _bufferedSink.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF, + _bufferedSink!.addByte4((value >> 24) | 0xC0, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF); _length += 4; } @@ -60,7 +61,7 @@ @override void close() { - _bufferedSink.flushAndDestroy(); + _bufferedSink!.flushAndDestroy(); _bufferedSink = null; sink.close(); }
diff --git a/pkg/compiler/lib/src/serialization/binary_source.dart b/pkg/compiler/lib/src/serialization/binary_source.dart index 00d1291..59f40ff 100644 --- a/pkg/compiler/lib/src/serialization/binary_source.dart +++ b/pkg/compiler/lib/src/serialization/binary_source.dart
@@ -2,9 +2,10 @@ // 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 - -part of 'serialization.dart'; +import 'dart:convert'; +import 'dart:typed_data'; +import 'data_source.dart'; +import 'serialization_interfaces.dart' show StringInterner; /// [DataSource] that reads data from a sequence of bytes. /// @@ -12,10 +13,12 @@ class BinaryDataSource implements DataSource { int _byteOffset = 0; final List<int> _bytes; - final StringInterner _stringInterner; + final StringInterner? _stringInterner; - BinaryDataSource(this._bytes, {StringInterner stringInterner}) - : _stringInterner = stringInterner; + BinaryDataSource(this._bytes, {StringInterner? stringInterner}) + : _stringInterner = stringInterner { + assert((_bytes as dynamic) != null); // TODO(48820): Remove when sound. + } @override void begin(String tag) {} @@ -33,7 +36,7 @@ _byteOffset += bytes.length; String string = utf8.decode(bytes); if (_stringInterner == null) return string; - return _stringInterner.internString(string); + return _stringInterner!.internString(string); } @override
diff --git a/pkg/compiler/lib/src/serialization/data_sink.dart b/pkg/compiler/lib/src/serialization/data_sink.dart new file mode 100644 index 0000000..b87ebcd --- /dev/null +++ b/pkg/compiler/lib/src/serialization/data_sink.dart
@@ -0,0 +1,30 @@ +// Copyright (c) 2018, 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. + +/// Interface handling [DataSinkWriter] low-level data serialization. +/// +/// Each implementation of [DataSink] should have a corresponding +/// [DataSource] that deserializes data serialized by that implementation. +// TODO(48820): Move this interface back to 'sink.dart'. +abstract class DataSink { + int get length; + + /// Serialization of a non-negative integer value. + void writeInt(int value); + + /// Serialization of an enum value. + void writeEnum(dynamic value); + + /// Serialization of a String value. + void writeString(String value); + + /// Serialization of a section begin tag. May be omitted by some writers. + void beginTag(String tag); + + /// Serialization of a section end tag. May be omitted by some writers. + void endTag(String tag); + + /// Closes any underlying data sinks. + void close(); +}
diff --git a/pkg/compiler/lib/src/serialization/data_source.dart b/pkg/compiler/lib/src/serialization/data_source.dart new file mode 100644 index 0000000..ee73699 --- /dev/null +++ b/pkg/compiler/lib/src/serialization/data_source.dart
@@ -0,0 +1,29 @@ +// Copyright (c) 2018, 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. + +/// Interface handling [DataSourceReader] low-level data deserialization. +/// +/// Each implementation of [DataSource] should have a corresponding +/// [DataSink] for which it deserializes data. +abstract class DataSource { + /// Deserialization of a section begin tag. + void begin(String tag); + + /// Deserialization of a section end tag. + void end(String tag); + + /// Deserialization of a string value. + String readString(); + + /// Deserialization of a non-negative integer value. + int readInt(); + + /// Deserialization of an enum value in [values]. + E readEnum<E>(List<E> values); + + /// Returns a string representation of the current state of the data source + /// useful for debugging in consistencies between serialization and + /// deserialization. + String get errorContext; +}
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart index 51e28e1..46791ba 100644 --- a/pkg/compiler/lib/src/serialization/helpers.dart +++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -166,66 +166,3 @@ visitTypes(node.typeArguments, functionTypeVariables); } } - -/// Data sink helper that canonicalizes [E] values using indices. -class IndexedSink<E> { - final DataSink _sink; - Map<E, int> cache; - - IndexedSink(this._sink, {this.cache}) { - // [cache] slot 0 is pre-allocated to `null`. - this.cache ??= {null: 0}; - } - - /// Write a reference to [value] to the data sink. - /// - /// If [value] has not been canonicalized yet, [writeValue] is called to - /// serialize the [value] itself. - void write(E value, void writeValue(E value)) { - const int pending = -1; - int index = cache[value]; - if (index == null) { - index = cache.length; - _sink.writeInt(index); - cache[value] = pending; // Increments length to allocate slot. - writeValue(value); - cache[value] = index; - } else if (index == pending) { - throw ArgumentError("Cyclic dependency on cached value: $value"); - } else { - _sink.writeInt(index); - } - } -} - -/// Data source helper reads canonicalized [E] values through indices. -class IndexedSource<E> { - final DataSource _sourceReader; - List<E> cache; - - IndexedSource(this._sourceReader, {this.cache}) { - // [cache] slot 0 is pre-allocated to `null`. - this.cache ??= [null]; - } - - /// Reads a reference to an [E] value from the data source. - /// - /// If the value hasn't yet been read, [readValue] is called to deserialize - /// the value itself. - E read(E readValue()) { - int index = _sourceReader.readInt(); - if (index >= cache.length) { - assert(index == cache.length); - cache.add(null); // placeholder. - E value = readValue(); - cache[index] = value; - return value; - } else { - E value = cache[index]; - if (value == null && index != 0) { - throw StateError('Unfilled index $index of $E'); - } - return value; - } - } -}
diff --git a/pkg/compiler/lib/src/serialization/indexed_sink_source.dart b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart new file mode 100644 index 0000000..82db5e0 --- /dev/null +++ b/pkg/compiler/lib/src/serialization/indexed_sink_source.dart
@@ -0,0 +1,75 @@ +// Copyright (c) 2018, 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 'data_sink.dart'; +import 'data_source.dart'; + +/// Data sink helper that canonicalizes [E?] values using indices. +class IndexedSink<E extends Object> { + final DataSink _sink; + final Map<E?, int> cache; + + IndexedSink._(this._sink, this.cache); + + factory IndexedSink(DataSink sink, {Map<E?, int>? cache}) { + // [cache] slot 0 is pre-allocated to `null`. + cache ??= {null: 0}; + return IndexedSink._(sink, cache); + } + + /// Write a reference to [value] to the data sink. + /// + /// If [value] has not been canonicalized yet, [writeValue] is called to + /// serialize the [value] itself. + void write(E? value, void writeValue(E value)) { + const int pending = -1; + int? index = cache[value]; + if (index == null) { + index = cache.length; + _sink.writeInt(index); + cache[value] = pending; // Increments length to allocate slot. + writeValue(value!); // `null` would have been found in slot 0. + cache[value] = index; + } else if (index == pending) { + throw ArgumentError("Cyclic dependency on cached value: $value"); + } else { + _sink.writeInt(index); + } + } +} + +/// Data source helper reads canonicalized [E?] values through indices. +class IndexedSource<E extends Object> { + final DataSource _source; + final List<E?> cache; + + IndexedSource._(this._source, this.cache); + + factory IndexedSource(DataSource source, {List<E?>? cache}) { + // [cache] slot 0 is pre-allocated to `null`. + cache ??= [null]; + return IndexedSource._(source, cache); + } + + /// Reads a reference to an [E] value from the data source. + /// + /// If the value hasn't yet been read, [readValue] is called to deserialize + /// the value itself. + E? read(E readValue()) { + int index = _source.readInt(); + if (index >= cache.length) { + assert(index == cache.length); + cache.add(null); // placeholder. + E value = readValue(); + cache[index] = value; + return value; + } else { + E? value = cache[index]; + if (value == null && index != 0) { + throw StateError('Unfilled index $index of $E'); + } + return value; + } + } +}
diff --git a/pkg/compiler/lib/src/serialization/object_sink.dart b/pkg/compiler/lib/src/serialization/object_sink.dart index d5b54b4..3bbbd3b 100644 --- a/pkg/compiler/lib/src/serialization/object_sink.dart +++ b/pkg/compiler/lib/src/serialization/object_sink.dart
@@ -2,45 +2,45 @@ // 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 - -part of 'serialization.dart'; +import 'data_sink.dart'; +import 'tags.dart' show Tag; /// [DataSinkWriter] that writes to a list of objects, useful for debugging /// inconsistencies between serialization and deserialization. /// /// This data sink writer works together with [ObjectDataSource]. class ObjectDataSink implements DataSink { - List<dynamic> _data; + // [_data] is nullable and non-final to allow storage to be released. + List<dynamic>? _data; ObjectDataSink(this._data); @override void beginTag(String tag) { - _data.add(Tag('begin:$tag')); + _data!.add(Tag('begin:$tag')); } @override void endTag(String tag) { - _data.add(Tag('end:$tag')); + _data!.add(Tag('end:$tag')); } @override void writeEnum(dynamic value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override void writeInt(int value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override void writeString(String value) { - assert(value != null); - _data.add(value); + assert((value as dynamic) != null); // TODO(48820): Remove when sound. + _data!.add(value); } @override @@ -50,5 +50,5 @@ /// Returns the number of objects written to this data sink. @override - int get length => _data.length; + int get length => _data!.length; }
diff --git a/pkg/compiler/lib/src/serialization/object_source.dart b/pkg/compiler/lib/src/serialization/object_source.dart index bc34994..f8279a2 100644 --- a/pkg/compiler/lib/src/serialization/object_source.dart +++ b/pkg/compiler/lib/src/serialization/object_source.dart
@@ -2,9 +2,8 @@ // 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 - -part of 'serialization.dart'; +import 'data_source.dart'; +import 'tags.dart' show Tag; /// [DataSource] that read from a list of objects, useful for debugging /// inconsistencies between serialization and deserialization. @@ -17,9 +16,9 @@ ObjectDataSource(this._data); T _read<T>() { - dynamic value = _data[_index++]; - assert(value is T, "Expected $T value, found $value.$errorContext"); - return value; + Object? value = _data[_index++]; + if (value is T) return value; + throw StateError('Expected $T value, found $value.$errorContext'); } @override
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart index a863d05..d0aa69e 100644 --- a/pkg/compiler/lib/src/serialization/serialization.dart +++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -5,10 +5,8 @@ // @dart = 2.10 import 'dart:collection'; -import 'dart:convert'; import 'dart:typed_data'; import 'package:kernel/ast.dart' as ir; -import 'package:kernel/binary/ast_to_binary.dart'; import '../closure.dart'; import '../constants/constant_system.dart' as constant_system; import '../constants/values.dart'; @@ -25,24 +23,24 @@ import '../js_model/locals.dart'; import '../js_model/type_recipe.dart' show TypeRecipe; +import 'data_sink.dart'; +import 'data_source.dart'; import 'member_data.dart'; -export 'member_data.dart' show ComponentLookup, computeMemberName; import 'serialization_interfaces.dart' as migrated show DataSourceReader, DataSinkWriter; +import 'indexed_sink_source.dart'; import 'tags.dart'; + +export 'binary_sink.dart'; +export 'binary_source.dart'; +export 'member_data.dart' show ComponentLookup, computeMemberName; +export 'object_sink.dart'; +export 'object_source.dart'; export 'tags.dart'; part 'sink.dart'; part 'source.dart'; -part 'binary_sink.dart'; -part 'binary_source.dart'; part 'helpers.dart'; -part 'object_sink.dart'; -part 'object_source.dart'; - -abstract class StringInterner { - String internString(String string); -} class ValueInterner { final Map<DartType, DartType> _dartTypeMap = HashMap();
diff --git a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart index a2ee9dd..efa9bb1 100644 --- a/pkg/compiler/lib/src/serialization/serialization_interfaces.dart +++ b/pkg/compiler/lib/src/serialization/serialization_interfaces.dart
@@ -9,6 +9,10 @@ export 'tags.dart'; +abstract class StringInterner { + String internString(String string); +} + /// NNBD-migrated interface for methods of DataSinkWriter. /// /// This is a pure interface or facade for DataSinkWriter. @@ -73,6 +77,7 @@ {bool allowNull = false}); void writeCached<E extends Object>(E value, void f(E value)); + void writeList<E extends Object>(Iterable<E> values, void f(E value), {bool allowNull = false}); } @@ -112,6 +117,7 @@ Map<K, V>? readTreeNodeMapInContextOrNull<K extends ir.TreeNode, V>(V f()); E readCached<E extends Object>(E f()); + List<E> readList<E extends Object>(E f()); List<E>? readListOrNull<E extends Object>(E f()); }
diff --git a/pkg/compiler/lib/src/serialization/sink.dart b/pkg/compiler/lib/src/serialization/sink.dart index 67ec6b5..214b6e9 100644 --- a/pkg/compiler/lib/src/serialization/sink.dart +++ b/pkg/compiler/lib/src/serialization/sink.dart
@@ -6,32 +6,6 @@ part of 'serialization.dart'; -/// Interface handling [DataSinkWriter] low-level data serialization. -/// -/// Each implementation of [DataSink] should have a corresponding -/// [DataSource] that deserializes data serialized by that implementation. -abstract class DataSink { - int get length; - - /// Serialization of a non-negative integer value. - void writeInt(int value); - - /// Serialization of an enum value. - void writeEnum(dynamic value); - - /// Serialization of a String value. - void writeString(String value); - - /// Serialization of a section begin tag. May be omitted by some writers. - void beginTag(String tag); - - /// Serialization of a section end tag. May be omitted by some writers. - void endTag(String tag); - - /// Closes any underlying data sinks. - void close(); -} - /// Serialization writer /// /// To be used with [DataSourceReader] to read and write serialized data.
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart index 806731c..2d0855c 100644 --- a/pkg/compiler/lib/src/serialization/source.dart +++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -6,32 +6,6 @@ part of 'serialization.dart'; -/// Interface handling [DataSourceReader] low-level data deserialization. -/// -/// Each implementation of [DataSource] should have a corresponding -/// [DataSink] for which it deserializes data. -abstract class DataSource { - /// Deserialization of a section begin tag. - void begin(String tag); - - /// Deserialization of a section end tag. - void end(String tag); - - /// Deserialization of a string value. - String readString(); - - /// Deserialization of a non-negative integer value. - int readInt(); - - /// Deserialization of an enum value in [values]. - E readEnum<E>(List<E> values); - - /// Returns a string representation of the current state of the data source - /// useful for debugging in consistencies between serialization and - /// deserialization. - String get errorContext; -} - /// Deserialization reader /// /// To be used with [DataSinkWriter] to read and write serialized data.
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart index 6f9d2c4..b4e8b0b 100644 --- a/pkg/compiler/lib/src/serialization/task.dart +++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -29,6 +29,7 @@ import '../util/sink_adapter.dart'; import '../world.dart'; import 'serialization.dart'; +import 'serialization_interfaces.dart' show StringInterner; /// A data class holding a [JsClosedWorld] and the associated /// [DataSourceIndices].
diff --git a/pkg/dev_compiler/lib/src/compiler/module_containers.dart b/pkg/dev_compiler/lib/src/compiler/module_containers.dart index 8e954be..8150de59 100644 --- a/pkg/dev_compiler/lib/src/compiler/module_containers.dart +++ b/pkg/dev_compiler/lib/src/compiler/module_containers.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.9 - import '../compiler/js_names.dart' as js_ast; import '../js_ast/js_ast.dart' as js_ast; import '../js_ast/js_ast.dart' show js; @@ -78,7 +76,7 @@ /// Creates an automatically sharding container backed by JS Objects. factory ModuleItemContainer.asObject(String name, - {String Function(K) keyToString}) { + {required String Function(K) keyToString}) { return ModuleItemObjectContainer<K>(name, keyToString); } @@ -95,7 +93,7 @@ bool get isEmpty => moduleItems.isEmpty; - js_ast.Expression operator [](K key) => moduleItems[key]?.jsValue; + js_ast.Expression? operator [](K key) => moduleItems[key]?.jsValue; void operator []=(K key, js_ast.Expression value); @@ -125,7 +123,7 @@ /// necessary. /// /// Uses [emitValue] to emit the values in the table. - List<js_ast.Statement> emit({EmitValue<K> emitValue}); + List<js_ast.Statement> emit({EmitValue<K>? emitValue}); } /// Associates a [K] with a container-unique JS key and arbitrary JS value. @@ -157,7 +155,7 @@ @override void operator []=(K key, js_ast.Expression value) { if (contains(key)) { - moduleItems[key].jsValue = value; + moduleItems[key]!.jsValue = value; return; } // Create a unique name for K when emitted as a JS field. @@ -179,12 +177,12 @@ @override js_ast.Expression access(K key) { - var id = moduleItems[key].id; - return js.call('#.#', [id, moduleItems[key].jsKey]); + var id = moduleItems[key]!.id; + return js.call('#.#', [id, moduleItems[key]!.jsKey]); } @override - List<js_ast.Statement> emit({EmitValue<K> emitValue}) { + List<js_ast.Statement> emit({EmitValue<K>? emitValue}) { var containersToProperties = <js_ast.Identifier, List<js_ast.Property>>{}; moduleItems.forEach((k, v) { if (!incrementalMode && _noEmit.contains(k)) return; @@ -193,7 +191,7 @@ if (!containersToProperties.containsKey(v.id)) { containersToProperties[v.id] = <js_ast.Property>[]; } - containersToProperties[v.id].add(js_ast.Property( + containersToProperties[v.id]!.add(js_ast.Property( v.jsKey, emitValue == null ? v.jsValue : emitValue(k, v))); }); @@ -226,7 +224,7 @@ @override void operator []=(K key, js_ast.Expression value) { if (moduleItems.containsKey(key)) { - moduleItems[key].jsValue = value; + moduleItems[key]!.jsValue = value; return; } moduleItems[key] = @@ -236,12 +234,13 @@ @override js_ast.Expression access(K key) { var id = containerId; - return js.call('#[#]', [id, moduleItems[key].jsKey]); + return js.call('#[#]', [id, moduleItems[key]!.jsKey]); } @override - List<js_ast.Statement> emit({EmitValue<K> emitValue}) { - var properties = List<js_ast.Expression>.filled(length, null); + List<js_ast.Statement> emit({EmitValue<K>? emitValue}) { + var dummyExpression = js_ast.TemporaryId('dummyExpression'); + var properties = List<js_ast.Expression>.filled(length, dummyExpression); // If the entire array holds just one value, generate a short initializer. var valueSet = <js_ast.Expression>{};
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect index 0e794df..7c9bb06 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.strong.transformed.expect
@@ -8,19 +8,19 @@ } static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { - return self::bar(); + return asy::Future::value<core::int>(self::bar()); }); static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return asy::Future::value<core::int>(345); - return self::bar(); + return asy::Future::value<core::int>(asy::Future::value<core::int>(345)); + return asy::Future::value<core::int>(self::bar()); }); static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return 234; - return asy::Future::value<core::int>(123); + return asy::Future::value<core::int>(234); + return asy::Future::value<core::int>(asy::Future::value<core::int>(123)); }); static method main() → void { self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect index 0e794df..7c9bb06 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/collapse_return_await.dart.weak.transformed.expect
@@ -8,19 +8,19 @@ } static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { - return self::bar(); + return asy::Future::value<core::int>(self::bar()); }); static method foo2(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return asy::Future::value<core::int>(345); - return self::bar(); + return asy::Future::value<core::int>(asy::Future::value<core::int>(345)); + return asy::Future::value<core::int>(self::bar()); }); static method foo3(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return 234; - return asy::Future::value<core::int>(123); + return asy::Future::value<core::int>(234); + return asy::Future::value<core::int>(asy::Future::value<core::int>(123)); }); static method main() → void { self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect index 63a5d71..d926489 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.strong.transformed.expect
@@ -6,7 +6,7 @@ static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { final core::int c = 3; - return c; + return asy::Future::value<core::int>(c); }); static method foo2() → asy::Future<void> /* futureValueType= void */ /* originally async */ return asy::Future::sync<void>(() → FutureOr<void>? { @@ -14,21 +14,21 @@ }); static method foo3() → dynamic /* futureValueType= dynamic */ /* originally async */ return asy::Future::sync<dynamic>(() → FutureOr<dynamic>? { - return 234; + return asy::Future::value<dynamic>(234); }); static method bar(() → asy::Future<core::int> func) → void { func(){() → asy::Future<core::int>}; } static method foo4() → asy::Future<core::bool> async /* futureValueType= core::bool */ { await asy::Future::value<core::int>(2); - self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => 3)); + self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => asy::Future::value<core::int>(3))); return true; } static method foo5(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return 123; - return 234; + return asy::Future::value<core::int>(123); + return asy::Future::value<core::int>(234); }); static method main() → void { self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect index 63a5d71..d926489 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_await.dart.weak.transformed.expect
@@ -6,7 +6,7 @@ static method foo1() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { final core::int c = 3; - return c; + return asy::Future::value<core::int>(c); }); static method foo2() → asy::Future<void> /* futureValueType= void */ /* originally async */ return asy::Future::sync<void>(() → FutureOr<void>? { @@ -14,21 +14,21 @@ }); static method foo3() → dynamic /* futureValueType= dynamic */ /* originally async */ return asy::Future::sync<dynamic>(() → FutureOr<dynamic>? { - return 234; + return asy::Future::value<dynamic>(234); }); static method bar(() → asy::Future<core::int> func) → void { func(){() → asy::Future<core::int>}; } static method foo4() → asy::Future<core::bool> async /* futureValueType= core::bool */ { await asy::Future::value<core::int>(2); - self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => 3)); + self::bar(() → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ => asy::Future::sync<core::int>(() → FutureOr<core::int> => asy::Future::value<core::int>(3))); return true; } static method foo5(core::bool x) → asy::Future<core::int> /* futureValueType= core::int */ /* originally async */ return asy::Future::sync<core::int>(() → FutureOr<core::int> { if(x) - return 123; - return 234; + return asy::Future::value<core::int>(123); + return asy::Future::value<core::int>(234); }); static method main() → void { self::foo1();
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart index e19523f..3e885ac 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart
@@ -8,14 +8,35 @@ return (await 6) + 3; } +// Function contains an async for-in loop. Future<void> foo3() async { await for (final x in Stream.empty()) { break; } } +// Function contains a try-finally statement. +Future<int> foo4() async { + try { + return 3; + } finally { + return 2; + } +} + +// Function contains a try-catch statement. +Future<int> foo5() async { + try { + return 3; + } catch (e) { + return 2; + } +} + void main() { foo1(); foo2(); foo3(); + foo4(); + foo5(); }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect index f3422b1..f6a9d58 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.expect
@@ -15,8 +15,26 @@ break #L1; } } +static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + finally { + return 2; + } +} +static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + on core::Object catch(final core::Object e) { + return 2; + } +} static method main() → void { self::foo1(); self::foo2(); self::foo3(); + self::foo4(); + self::foo5(); }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect index f3422b1..f6a9d58 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.strong.transformed.expect
@@ -15,8 +15,26 @@ break #L1; } } +static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + finally { + return 2; + } +} +static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + on core::Object catch(final core::Object e) { + return 2; + } +} static method main() → void { self::foo1(); self::foo2(); self::foo3(); + self::foo4(); + self::foo5(); }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect index c9ebdd9..85cdbd2 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline.expect
@@ -1,4 +1,6 @@ Future<void> foo1() async {} Future<int> foo2() async {} Future<void> foo3() async {} +Future<int> foo4() async {} +Future<int> foo5() async {} void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect index 4ab2b8a..51fc18a 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.textual_outline_modelled.expect
@@ -1,4 +1,6 @@ Future<int> foo2() async {} +Future<int> foo4() async {} +Future<int> foo5() async {} Future<void> foo1() async {} Future<void> foo3() async {} void main() {}
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect index f3422b1..f6a9d58 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.expect
@@ -15,8 +15,26 @@ break #L1; } } +static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + finally { + return 2; + } +} +static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + on core::Object catch(final core::Object e) { + return 2; + } +} static method main() → void { self::foo1(); self::foo2(); self::foo3(); + self::foo4(); + self::foo5(); }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect index f3422b1..f6a9d58 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.modular.expect
@@ -15,8 +15,26 @@ break #L1; } } +static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + finally { + return 2; + } +} +static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + on core::Object catch(final core::Object e) { + return 2; + } +} static method main() → void { self::foo1(); self::foo2(); self::foo3(); + self::foo4(); + self::foo5(); }
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect index 0c508d4..389e9c1 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.outline.expect
@@ -9,5 +9,9 @@ ; static method foo3() → asy::Future<void> async ; +static method foo4() → asy::Future<core::int> async + ; +static method foo5() → asy::Future<core::int> async + ; static method main() → void ;
diff --git a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect index f3422b1..f6a9d58 100644 --- a/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect +++ b/pkg/front_end/testcases/dart2js/async_lowering/no_transform.dart.weak.transformed.expect
@@ -15,8 +15,26 @@ break #L1; } } +static method foo4() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + finally { + return 2; + } +} +static method foo5() → asy::Future<core::int> async /* futureValueType= core::int */ { + try { + return 3; + } + on core::Object catch(final core::Object e) { + return 2; + } +} static method main() → void { self::foo1(); self::foo2(); self::foo3(); + self::foo4(); + self::foo5(); }
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart index 4b5adb2..70edb2c 100644 --- a/pkg/kernel/lib/core_types.dart +++ b/pkg/kernel/lib/core_types.dart
@@ -181,6 +181,9 @@ late final Procedure futureSyncFactory = index.getMember('dart:async', 'Future', 'sync') as Procedure; + late final Procedure futureValueFactory = + index.getMember('dart:async', 'Future', 'value') as Procedure; + // TODO(cstefantsova): Remove it when FutureOrType is fully supported. late final Class deprecatedFutureOrClass = index.getClass('dart:async', 'FutureOr');
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart index 013e482..d6bfd32 100644 --- a/pkg/nnbd_migration/lib/src/edge_builder.dart +++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -7,6 +7,7 @@ import 'package:analyzer/dart/ast/token.dart'; import 'package:analyzer/dart/ast/visitor.dart'; import 'package:analyzer/dart/element/element.dart'; +import 'package:analyzer/dart/element/nullability_suffix.dart'; import 'package:analyzer/dart/element/type.dart'; import 'package:analyzer/dart/element/type_provider.dart'; import 'package:analyzer/dart/element/type_system.dart'; @@ -280,8 +281,7 @@ if (targetType != null) { var enclosingElement = baseElement!.enclosingElement; if (enclosingElement is ClassElement) { - if (targetType.type!.resolveToBound(typeProvider.dynamicType) - is InterfaceType && + if (targetType.type.explicitBound is InterfaceType && enclosingElement.typeParameters.isNotEmpty) { substitution = _decoratedClassHierarchy! .asInstanceOf(targetType, enclosingElement) @@ -3971,3 +3971,14 @@ trueDemonstratesNonNullIntent: falseDemonstratesNonNullIntent, falseDemonstratesNonNullIntent: trueDemonstratesNonNullIntent); } + +extension on DartType? { + DartType? get explicitBound { + final self = this; + if (self is TypeParameterType && + self.nullabilitySuffix == NullabilitySuffix.star) { + return self.element.bound.explicitBound; + } + return self; + } +}
diff --git a/pkg/test_runner/lib/src/browser_controller.dart b/pkg/test_runner/lib/src/browser_controller.dart index d785338..a6c8b8a 100644 --- a/pkg/test_runner/lib/src/browser_controller.dart +++ b/pkg/test_runner/lib/src/browser_controller.dart
@@ -12,6 +12,7 @@ import 'android.dart'; import 'configuration.dart'; import 'path.dart'; +import 'service/web_driver_service.dart'; import 'utils.dart'; typedef BrowserDoneCallback = void Function(BrowserTestOutput output); @@ -75,7 +76,8 @@ browser = Chrome(configuration.browserLocation); break; case Runtime.safari: - browser = Safari(); + var service = WebDriverService.fromRuntime(Runtime.safari); + browser = Safari(service.port); break; case Runtime.ie9: case Runtime.ie10: @@ -262,20 +264,15 @@ abstract class WebDriverBrowser extends Browser { WebDriver _driver; + final int _port; + final Map<String, dynamic> _desiredCapabilities; - String get driverExecutable; - List<String> get driverArguments; - Map<String, dynamic> get desiredCapabilities; + WebDriverBrowser(this._port, this._desiredCapabilities); @override Future<bool> start(String url) async { _logEvent('Starting $this browser on: $url'); - var port = await _findUnusedPort(); - if (!await startBrowserProcess( - driverExecutable, ['--port', '$port', ...driverArguments])) { - return false; - } - await _createDriver(port); + await _createDriver(); await _driver.get(url); try { _logEvent('Got version: ${await version}'); @@ -286,14 +283,14 @@ return true; } - Future<void> _createDriver(int port) async { + Future<void> _createDriver() async { for (var i = 5; i >= 0; i--) { // Give the driver process some time to be ready to accept connections. await Future.delayed(const Duration(seconds: 1)); try { _driver = await createDriver( - uri: Uri.parse('http://localhost:$port/'), - desired: desiredCapabilities); + uri: Uri.parse('http://localhost:$_port/'), + desired: _desiredCapabilities); } catch (error) { if (i > 0) { _logEvent( @@ -308,33 +305,10 @@ } } - /// Returns a port that is probably, but not definitely, not in use. - /// - /// This has a built-in race condition: another process may bind this port at - /// any time after this call has returned. - static Future<int> _findUnusedPort() async { - int port; - ServerSocket socket; - try { - socket = await ServerSocket.bind(InternetAddress.loopbackIPv6, 0, - v6Only: true); - } on SocketException { - socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0); - } - port = socket.port; - await socket.close(); - return port; - } - @override Future<bool> close() async { - try { - await _driver?.quit(); - // Give the driver process some time to be quit the browser. - await Future.delayed(const Duration(seconds: 1)); - } finally { - process?.kill(); - } + await _driver?.quit(); + // Give the driver process some time to be quit the browser. return true; } } @@ -343,14 +317,11 @@ /// We get the safari version by parsing a version file static const versionFile = '/Applications/Safari.app/Contents/version.plist'; - @override - final driverExecutable = '/usr/bin/safaridriver'; - @override - final driverArguments = <String>[]; - @override - final desiredCapabilities = <String, dynamic>{ - 'browserName': 'safari', - }; + Safari(int port) + : super(port, { + 'browserName': 'safari', + }); + @override Future<String> get version async { // Example of the file:
diff --git a/pkg/test_runner/lib/src/service/service.dart b/pkg/test_runner/lib/src/service/service.dart new file mode 100644 index 0000000..25ac0b7 --- /dev/null +++ b/pkg/test_runner/lib/src/service/service.dart
@@ -0,0 +1,11 @@ +// 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. + +enum ServiceState { + created, + starting, + running, + failed, + stopped, +}
diff --git a/pkg/test_runner/lib/src/service/web_driver_service.dart b/pkg/test_runner/lib/src/service/web_driver_service.dart new file mode 100644 index 0000000..9719116 --- /dev/null +++ b/pkg/test_runner/lib/src/service/web_driver_service.dart
@@ -0,0 +1,73 @@ +// 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. + +import 'dart:async'; +import 'dart:io'; + +import 'package:smith/smith.dart'; + +import '../test_progress.dart'; +import 'service.dart'; + +const safariDriverPort = 7055; + +class WebDriverService extends EventListener { + static final _instances = <Runtime, WebDriverService>{}; + static final supportedRuntimes = <Runtime>{ + Runtime.safari, + }; + + final String _driverExecutable; + final List<String> _driverArguments; + Future<void> _started; + Process _process; + + ServiceState state = ServiceState.created; + final int port; + + WebDriverService(this._driverExecutable, this._driverArguments, this.port); + + Future<void> start() { + if (_started != null) { + return _started; + } + return _started = () async { + state = ServiceState.starting; + try { + _process = await Process.start( + _driverExecutable, ['--port', '$port', ..._driverArguments]); + _process.exitCode.then((exitCode) { + if (state != ServiceState.stopped) { + state = ServiceState.failed; + print('$runtimeType stopped unexpectedly: $exitCode'); + } + }); + state = ServiceState.running; + print('Started $runtimeType on port $port'); + } catch (error) { + state = ServiceState.failed; + print('Failed to start $runtimeType: $error'); + rethrow; + } + }(); + } + + @override + void allDone() { + state = ServiceState.stopped; + _process?.kill(); + } + + factory WebDriverService.fromRuntime(Runtime runtime) { + return _instances.putIfAbsent(runtime, () { + switch (runtime) { + case Runtime.safari: + return WebDriverService( + '/usr/bin/safaridriver', [], safariDriverPort); + default: + throw ArgumentError.value(runtime, 'runtime', 'Unsupported runtime'); + } + }); + } +}
diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart index 6d7f1f8..e5157fe 100644 --- a/pkg/test_runner/lib/src/test_configurations.dart +++ b/pkg/test_runner/lib/src/test_configurations.dart
@@ -13,6 +13,7 @@ import 'fuchsia.dart'; import 'path.dart'; import 'process_queue.dart'; +import 'service/web_driver_service.dart'; import 'terminal.dart'; import 'test_progress.dart'; import 'test_suite.dart'; @@ -89,8 +90,9 @@ var runningBrowserTests = configurations.any((config) => config.runtime.isBrowser); - var serverFutures = <Future>[]; + var eventListeners = <EventListener>[]; var testSuites = <TestSuite>[]; + var serverFutures = <Future>[]; var maxBrowserProcesses = maxProcesses; if (configurations.length > 1 && (configurations[0].testServerPort != 0 || @@ -101,9 +103,13 @@ exit(1); } + var services = <WebDriverService>{}; for (var configuration in configurations) { if (!listTests && !listStatusFiles && runningBrowserTests) { serverFutures.add(configuration.startServers()); + if (WebDriverService.supportedRuntimes.contains(configuration.runtime)) { + services.add(WebDriverService.fromRuntime(configuration.runtime)); + } } if (configuration.runtime.isIE) { @@ -170,6 +176,11 @@ } } + for (var service in services) { + serverFutures.add(service.start()); + eventListeners.add(service); + } + // If we only need to print out status files for test suites // we return from running here and just print. if (firstConf.listStatusFiles) { @@ -194,8 +205,6 @@ } } - var eventListener = <EventListener>[]; - // We don't print progress if we list tests. if (progress != Progress.silent && !listTests) { var formatter = Formatter.normal; @@ -204,53 +213,53 @@ formatter = Formatter.color; } - eventListener.add(SummaryPrinter()); + eventListeners.add(SummaryPrinter()); if (!firstConf.silentFailures) { - eventListener.add(TestFailurePrinter(formatter)); + eventListeners.add(TestFailurePrinter(formatter)); } if (firstConf.printPassingStdout) { - eventListener.add(PassingStdoutPrinter(formatter)); + eventListeners.add(PassingStdoutPrinter(formatter)); } var indicator = ProgressIndicator.fromProgress(progress, startTime, formatter); - if (indicator != null) eventListener.add(indicator); + if (indicator != null) eventListeners.add(indicator); if (printTiming) { - eventListener.add(TimingPrinter(startTime)); + eventListeners.add(TimingPrinter(startTime)); } - eventListener.add(SkippedCompilationsPrinter()); + eventListeners.add(SkippedCompilationsPrinter()); if (progress == Progress.status) { - eventListener.add(TimedProgressPrinter()); + eventListeners.add(TimedProgressPrinter()); } if (firstConf.reportFailures) { - eventListener.add(FailedTestsPrinter()); + eventListeners.add(FailedTestsPrinter()); } - eventListener.add(ResultCountPrinter(formatter)); + eventListeners.add(ResultCountPrinter(formatter)); } if (firstConf.writeResults) { - eventListener.add(ResultWriter(firstConf.outputDirectory)); + eventListeners.add(ResultWriter(firstConf.outputDirectory)); } if (firstConf.copyCoreDumps) { - eventListener.add(UnexpectedCrashLogger()); + eventListeners.add(UnexpectedCrashLogger()); } // The only progress indicator when listing tests should be the // the summary printer. if (listTests) { - eventListener.add(SummaryPrinter(jsonOnly: reportInJson)); + eventListeners.add(SummaryPrinter(jsonOnly: reportInJson)); } else { if (!firstConf.cleanExit) { - eventListener.add(ExitCodeSetter()); + eventListeners.add(ExitCodeSetter()); } - eventListener.add(IgnoredTestMonitor()); + eventListeners.add(IgnoredTestMonitor()); } // If any of the configurations need to access android devices we'll first @@ -270,5 +279,5 @@ // [firstConf] is needed here, because the ProcessQueue uses some settings. ProcessQueue(firstConf, maxProcesses, maxBrowserProcesses, testSuites, - eventListener, allTestsFinished, verbose, adbDevicePool); + eventListeners, allTestsFinished, verbose, adbDevicePool); }
diff --git a/pkg/test_runner/test/browser_controller_test.dart b/pkg/test_runner/test/browser_controller_test.dart index c801de2..b9738e0 100644 --- a/pkg/test_runner/test/browser_controller_test.dart +++ b/pkg/test_runner/test/browser_controller_test.dart
@@ -5,8 +5,9 @@ import 'dart:io'; import 'package:expect/expect.dart'; - +import 'package:smith/smith.dart'; import 'package:test_runner/src/browser_controller.dart'; +import 'package:test_runner/src/service/web_driver_service.dart'; void main() async { if (Platform.environment.containsKey('CHROME_PATH')) { @@ -31,8 +32,11 @@ return testBrowser(Firefox(Platform.environment['FIREFOX_PATH'])); } -Future<void> testSafari() { - return testBrowser(Safari()); +Future<void> testSafari() async { + var service = WebDriverService.fromRuntime(Runtime.safari); + await service.start(); + await testBrowser(Safari(service.port)); + service.allDone(); } Future<void> testBrowser(Browser browser) async {
diff --git a/runtime/vm/app_snapshot.cc b/runtime/vm/app_snapshot.cc index c8f2ca5..178aedf 100644 --- a/runtime/vm/app_snapshot.cc +++ b/runtime/vm/app_snapshot.cc
@@ -1030,9 +1030,9 @@ s->WriteTokenPosition(func->untag()->token_pos_); s->WriteTokenPosition(func->untag()->end_token_pos_); s->Write<uint32_t>(func->untag()->kernel_offset_); + s->Write<uint32_t>(func->untag()->packed_fields_); } - s->Write<uint32_t>(func->untag()->packed_fields_); s->Write<uint32_t>(func->untag()->kind_tag_); } } @@ -1192,8 +1192,8 @@ func->untag()->end_token_pos_ = d.ReadTokenPosition(); func->untag()->kernel_offset_ = d.Read<uint32_t>(); func->untag()->unboxed_parameters_info_.Reset(); -#endif func->untag()->packed_fields_ = d.Read<uint32_t>(); +#endif func->untag()->kind_tag_ = d.Read<uint32_t>(); #if !defined(DART_PRECOMPILED_RUNTIME) func->untag()->usage_counter_ = 0;
diff --git a/runtime/vm/canonical_tables.cc b/runtime/vm/canonical_tables.cc index bfdc140..d2fd487 100644 --- a/runtime/vm/canonical_tables.cc +++ b/runtime/vm/canonical_tables.cc
@@ -69,4 +69,46 @@ UNREACHABLE(); } +CanonicalInstanceKey::CanonicalInstanceKey(const Instance& key) : key_(key) { + ASSERT(!(key.IsString() || key.IsAbstractType())); +} + +bool CanonicalInstanceKey::Matches(const Instance& obj) const { + ASSERT(!(obj.IsString() || obj.IsAbstractType())); + if (key_.CanonicalizeEquals(obj)) { + ASSERT(obj.IsCanonical()); + return true; + } + return false; +} + +uword CanonicalInstanceKey::Hash() const { + return key_.CanonicalizeHash(); +} + +bool CanonicalInstanceTraits::IsMatch(const Object& a, const Object& b) { + ASSERT(!(a.IsString() || a.IsAbstractType())); + ASSERT(!(b.IsString() || b.IsAbstractType())); + return a.ptr() == b.ptr(); +} + +bool CanonicalInstanceTraits::IsMatch(const CanonicalInstanceKey& a, + const Object& b) { + return a.Matches(Instance::Cast(b)); +} + +uword CanonicalInstanceTraits::Hash(const Object& key) { + ASSERT(!(key.IsString() || key.IsAbstractType())); + ASSERT(key.IsInstance()); + return Instance::Cast(key).CanonicalizeHash(); +} + +uword CanonicalInstanceTraits::Hash(const CanonicalInstanceKey& key) { + return key.Hash(); +} + +ObjectPtr CanonicalInstanceTraits::NewKey(const CanonicalInstanceKey& obj) { + return obj.key_.ptr(); +} + } // namespace dart
diff --git a/runtime/vm/canonical_tables.h b/runtime/vm/canonical_tables.h index ba9297e..f4f758f 100644 --- a/runtime/vm/canonical_tables.h +++ b/runtime/vm/canonical_tables.h
@@ -303,6 +303,31 @@ }; typedef UnorderedHashMap<MetadataMapTraits> MetadataMap; +class CanonicalInstanceKey { + public: + explicit CanonicalInstanceKey(const Instance& key); + bool Matches(const Instance& obj) const; + uword Hash() const; + const Instance& key_; + + private: + DISALLOW_ALLOCATION(); +}; + +// Traits for looking up Canonical Instances based on a hash of the fields. +class CanonicalInstanceTraits { + public: + static const char* Name() { return "CanonicalInstanceTraits"; } + static bool ReportStats() { return false; } + + // Called when growing the table. + static bool IsMatch(const Object& a, const Object& b); + static bool IsMatch(const CanonicalInstanceKey& a, const Object& b); + static uword Hash(const Object& key); + static uword Hash(const CanonicalInstanceKey& key); + static ObjectPtr NewKey(const CanonicalInstanceKey& obj); +}; + } // namespace dart #endif // RUNTIME_VM_CANONICAL_TABLES_H_
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc index b58ff26..4e9be6f 100644 --- a/runtime/vm/compiler/aot/precompiler.cc +++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -4,6 +4,8 @@ #include "vm/compiler/aot/precompiler.h" +#include <memory> + #include "platform/unicode.h" #include "platform/utils.h" #include "vm/canonical_tables.h" @@ -400,6 +402,7 @@ dropped_functiontype_count_(0), dropped_typeparam_count_(0), dropped_library_count_(0), + dropped_constants_arrays_entries_count_(0), libraries_(GrowableObjectArray::Handle( isolate_->group()->object_store()->libraries())), pending_functions_( @@ -607,6 +610,7 @@ DropFunctions(); DropFields(); + DropTransitiveUserDefinedConstants(); TraceTypesFromRetainedClasses(); // Clear these before dropping classes as they may hold onto otherwise @@ -688,7 +692,9 @@ THR_Print(" %" Pd " type parameters,", dropped_typeparam_count_); THR_Print(" %" Pd " type arguments,", dropped_typearg_count_); THR_Print(" %" Pd " classes,", dropped_class_count_); - THR_Print(" %" Pd " libraries.\n", dropped_library_count_); + THR_Print(" %" Pd " libraries,", dropped_library_count_); + THR_Print(" %" Pd " constants arrays entries.\n", + dropped_constants_arrays_entries_count_); } } @@ -2420,6 +2426,190 @@ StubCode::TopTypeTypeTest().EntryPoint()); } +enum ConstantVisitedValue { kNotVisited = 0, kRetain, kDrop }; + +static bool IsUserDefinedClass(Zone* zone, + ClassPtr cls, + ObjectStore* object_store) { + intptr_t cid = cls.untag()->id(); + if (cid < kNumPredefinedCids) { + return false; + } + + const UntaggedClass* untagged_cls = cls.untag(); + return ((untagged_cls->library() != object_store->core_library()) && + (untagged_cls->library() != object_store->collection_library()) && + (untagged_cls->library() != object_store->typed_data_library())); +} + +/// Updates |visited| weak table with information about whether object +/// (transitevly) references constants of user-defined classes: |kDrop| +/// indicates it does, |kRetain| - does not. +class ConstantInstanceVisitor { + public: + ConstantInstanceVisitor(Zone* zone, + WeakTable* visited, + ObjectStore* object_store) + : zone_(zone), + visited_(visited), + object_store_(object_store), + object_(Object::Handle(zone)), + array_(Array::Handle(zone)) {} + + void Visit(ObjectPtr object_ptr) { + if (!object_ptr->IsHeapObject()) { + return; + } + ConstantVisitedValue value = static_cast<ConstantVisitedValue>( + visited_->GetValueExclusive(object_ptr)); + if (value != kNotVisited) { + return; + } + object_ = object_ptr; + if (IsUserDefinedClass(zone_, object_.clazz(), object_store_)) { + visited_->SetValueExclusive(object_ptr, kDrop); + return; + } + + // Conservatively assume an object will be retained. + visited_->SetValueExclusive(object_ptr, kRetain); + switch (object_ptr.untag()->GetClassId()) { + case kImmutableArrayCid: { + array_ ^= object_ptr; + for (intptr_t i = 0; i < array_.Length(); i++) { + ObjectPtr element = array_.At(i); + Visit(element); + if (static_cast<ConstantVisitedValue>( + visited_->GetValueExclusive(element)) == kDrop) { + visited_->SetValueExclusive(object_ptr, kDrop); + break; + } + } + break; + } + case kImmutableLinkedHashMapCid: { + const LinkedHashMap& map = + LinkedHashMap::Handle(LinkedHashMap::RawCast(object_ptr)); + LinkedHashMap::Iterator iterator(map); + while (iterator.MoveNext()) { + ObjectPtr element = iterator.CurrentKey(); + Visit(element); + if (static_cast<ConstantVisitedValue>( + visited_->GetValueExclusive(element)) == kDrop) { + visited_->SetValueExclusive(object_ptr, kDrop); + break; + } + element = iterator.CurrentValue(); + Visit(element); + if (static_cast<ConstantVisitedValue>( + visited_->GetValueExclusive(element)) == kDrop) { + visited_->SetValueExclusive(object_ptr, kDrop); + break; + } + } + break; + } + case kImmutableLinkedHashSetCid: { + const LinkedHashSet& set = + LinkedHashSet::Handle(LinkedHashSet::RawCast(object_ptr)); + LinkedHashSet::Iterator iterator(set); + while (iterator.MoveNext()) { + ObjectPtr element = iterator.CurrentKey(); + Visit(element); + if (static_cast<ConstantVisitedValue>( + visited_->GetValueExclusive(element)) == kDrop) { + visited_->SetValueExclusive(object_ptr, kDrop); + break; + } + } + break; + } + } + } + + private: + Zone* zone_; + WeakTable* visited_; + ObjectStore* object_store_; + Object& object_; + Array& array_; +}; + +// To reduce snapshot size, we remove from constant tables all constants that +// cannot be sent in messages between isolate groups. Such constants will not +// be canonicalized at runtime. +void Precompiler::DropTransitiveUserDefinedConstants() { + HANDLESCOPE(T); + auto& constants = Array::Handle(Z); + auto& obj = Object::Handle(Z); + auto& lib = Library::Handle(Z); + auto& cls = Class::Handle(Z); + auto& instance = Instance::Handle(Z); + + { + NoSafepointScope no_safepoint(T); + std::unique_ptr<WeakTable> visited(new WeakTable()); + ObjectStore* object_store = IG->object_store(); + ConstantInstanceVisitor visitor(Z, visited.get(), object_store); + + for (intptr_t i = 0; i < libraries_.Length(); i++) { + lib ^= libraries_.At(i); + HANDLESCOPE(T); + ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); + while (it.HasNext()) { + cls = it.GetNextClass(); + if (cls.constants() == Array::null()) { + continue; + } + typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet; + + CanonicalInstancesSet constants_set(cls.constants()); + CanonicalInstancesSet::Iterator iterator(&constants_set); + + if (IsUserDefinedClass(Z, cls.ptr(), object_store)) { + // All constants for user-defined classes can be dropped. + constants = cls.constants(); + dropped_constants_arrays_entries_count_ += constants.Length(); + if (FLAG_trace_precompiler) { + THR_Print("Dropping %" Pd " entries from constants for class %s\n", + constants.Length(), cls.ToCString()); + } + while (iterator.MoveNext()) { + obj = constants_set.GetKey(iterator.Current()); + instance = Instance::RawCast(obj.ptr()); + consts_to_retain_.Remove(&instance); + visited->SetValueExclusive(obj.ptr(), kDrop); + } + } else { + // Core classes might have constants that refer to user-defined + // classes. Those should be dropped too. + while (iterator.MoveNext()) { + obj = constants_set.GetKey(iterator.Current()); + ConstantVisitedValue value = static_cast<ConstantVisitedValue>( + visited->GetValueExclusive(obj.ptr())); + if (value == kNotVisited) { + visitor.Visit(obj.ptr()); + value = static_cast<ConstantVisitedValue>( + visited->GetValueExclusive(obj.ptr())); + } + ASSERT(value == kDrop || value == kRetain); + if (value == kDrop) { + dropped_constants_arrays_entries_count_++; + if (FLAG_trace_precompiler) { + THR_Print("Dropping constant entry for class %s instance:%s\n", + cls.ToCString(), obj.ToCString()); + } + instance = Instance::RawCast(obj.ptr()); + consts_to_retain_.Remove(&instance); + } + } + } + constants_set.Release(); + } + } + } +} + void Precompiler::TraceTypesFromRetainedClasses() { HANDLESCOPE(T); auto& lib = Library::Handle(Z);
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h index ba2aee7..4e0d211 100644 --- a/runtime/vm/compiler/aot/precompiler.h +++ b/runtime/vm/compiler/aot/precompiler.h
@@ -333,6 +333,10 @@ void ReplaceFunctionStaticCallEntries(); void DropFunctions(); void DropFields(); + void VisitConstantInstance(ObjectPtr instance, + WeakTable* visited, + ObjectStore* object_store); + void DropTransitiveUserDefinedConstants(); void TraceTypesFromRetainedClasses(); void DropMetadata(); void DropLibraryEntries(); @@ -370,6 +374,7 @@ intptr_t dropped_functiontype_count_; intptr_t dropped_typeparam_count_; intptr_t dropped_library_count_; + intptr_t dropped_constants_arrays_entries_count_; compiler::ObjectPoolBuilder global_object_pool_builder_; GrowableObjectArray& libraries_;
diff --git a/runtime/vm/compiler/assembler/assembler_arm.cc b/runtime/vm/compiler/assembler/assembler_arm.cc index 771887e..dac6e38 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.cc +++ b/runtime/vm/compiler/assembler/assembler_arm.cc
@@ -2455,6 +2455,16 @@ ldm(IA_W, SP, regs, cond); } +void Assembler::PushQuad(FpuRegister reg, Condition cond) { + DRegister dreg = EvenDRegisterOf(reg); + vstmd(DB_W, SP, dreg, 2, cond); // 2 D registers per Q register. +} + +void Assembler::PopQuad(FpuRegister reg, Condition cond) { + DRegister dreg = EvenDRegisterOf(reg); + vldmd(IA_W, SP, dreg, 2, cond); // 2 D registers per Q register. +} + void Assembler::PushRegisters(const RegisterSet& regs) { const intptr_t fpu_regs_count = regs.FpuRegisterCount(); if (fpu_regs_count > 0) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm.h b/runtime/vm/compiler/assembler/assembler_arm.h index 821426e..ff2af91 100644 --- a/runtime/vm/compiler/assembler/assembler_arm.h +++ b/runtime/vm/compiler/assembler/assembler_arm.h
@@ -1134,6 +1134,9 @@ void PushList(RegList regs, Condition cond = AL); void PopList(RegList regs, Condition cond = AL); + void PushQuad(FpuRegister rd, Condition cond = AL); + void PopQuad(FpuRegister rd, Condition cond = AL); + void PushRegisters(const RegisterSet& regs); void PopRegisters(const RegisterSet& regs);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc index 8d90c0f..ade3a3e 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.cc +++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -854,91 +854,62 @@ } } +Address Assembler::PrepareLargeOffset(Register base, + int32_t offset, + OperandSize sz) { + if (Address::CanHoldOffset(offset, Address::Offset, sz)) { + return Address(base, offset, Address::Offset, sz); + } + ASSERT(base != TMP2); + Operand op; + const uint32_t upper20 = offset & 0xfffff000; + const uint32_t lower12 = offset & 0x00000fff; + if ((base != CSP) && + (Operand::CanHold(upper20, kXRegSizeInBits, &op) == Operand::Immediate) && + Address::CanHoldOffset(lower12, Address::Offset, sz)) { + add(TMP2, base, op); + return Address(TMP2, lower12, Address::Offset, sz); + } + LoadImmediate(TMP2, offset); + return Address(base, TMP2); +} + void Assembler::LoadFromOffset(Register dest, Register base, int32_t offset, OperandSize sz) { - if (Address::CanHoldOffset(offset, Address::Offset, sz)) { - LoadFromOffset(dest, Address(base, offset, Address::Offset, sz), sz); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - LoadFromOffset(dest, Address(TMP2), sz); - } + LoadFromOffset(dest, PrepareLargeOffset(base, offset, sz), sz); } void Assembler::LoadSFromOffset(VRegister dest, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) { - fldrs(dest, Address(base, offset, Address::Offset, kSWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fldrs(dest, Address(TMP2)); - } + fldrs(dest, PrepareLargeOffset(base, offset, kSWord)); } void Assembler::LoadDFromOffset(VRegister dest, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { - fldrd(dest, Address(base, offset, Address::Offset, kDWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fldrd(dest, Address(TMP2)); - } + fldrd(dest, PrepareLargeOffset(base, offset, kDWord)); } void Assembler::LoadQFromOffset(VRegister dest, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { - fldrq(dest, Address(base, offset, Address::Offset, kQWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fldrq(dest, Address(TMP2)); - } + fldrq(dest, PrepareLargeOffset(base, offset, kQWord)); } void Assembler::StoreToOffset(Register src, Register base, int32_t offset, OperandSize sz) { - ASSERT(base != TMP2); - if (Address::CanHoldOffset(offset, Address::Offset, sz)) { - StoreToOffset(src, Address(base, offset, Address::Offset, sz), sz); - } else { - ASSERT(src != TMP2); - AddImmediate(TMP2, base, offset); - StoreToOffset(src, Address(TMP2), sz); - } + StoreToOffset(src, PrepareLargeOffset(base, offset, sz), sz); } void Assembler::StoreSToOffset(VRegister src, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kSWord)) { - fstrs(src, Address(base, offset, Address::Offset, kSWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fstrs(src, Address(TMP2)); - } + fstrs(src, PrepareLargeOffset(base, offset, kSWord)); } void Assembler::StoreDToOffset(VRegister src, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kDWord)) { - fstrd(src, Address(base, offset, Address::Offset, kDWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fstrd(src, Address(TMP2)); - } + fstrd(src, PrepareLargeOffset(base, offset, kDWord)); } void Assembler::StoreQToOffset(VRegister src, Register base, int32_t offset) { - if (Address::CanHoldOffset(offset, Address::Offset, kQWord)) { - fstrq(src, Address(base, offset, Address::Offset, kQWord)); - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - fstrq(src, Address(TMP2)); - } + fstrq(src, PrepareLargeOffset(base, offset, kQWord)); } void Assembler::VRecps(VRegister vd, VRegister vn) { @@ -984,17 +955,9 @@ Register base, int32_t offset) { #if !defined(DART_COMPRESSED_POINTERS) - LoadFromOffset(dest, base, offset); + LoadFromOffset(dest, base, offset, kObjectBytes); #else - if (Address::CanHoldOffset(offset, Address::Offset, kObjectBytes)) { - ldr(dest, Address(base, offset, Address::Offset, kObjectBytes), - kUnsignedFourBytes); // Zero-extension. - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - ldr(dest, Address(TMP2, 0, Address::Offset, kObjectBytes), - kUnsignedFourBytes); // Zero-extension. - } + LoadFromOffset(dest, base, offset, kUnsignedFourBytes); // Zero-extension. add(dest, dest, Operand(HEAP_BITS, LSL, 32)); #endif } @@ -1019,15 +982,7 @@ #if !defined(DART_COMPRESSED_POINTERS) LoadFromOffset(dest, base, offset); #else - if (Address::CanHoldOffset(offset, Address::Offset, kObjectBytes)) { - ldr(dest, Address(base, offset, Address::Offset, kObjectBytes), - kUnsignedFourBytes); // Zero-extension. - } else { - ASSERT(base != TMP2); - AddImmediate(TMP2, base, offset); - ldr(dest, Address(TMP2, 0, Address::Offset, kObjectBytes), - kUnsignedFourBytes); // Zero-extension. - } + LoadFromOffset(dest, base, offset, kUnsignedFourBytes); // Zero-extension. #endif #if defined(DEBUG) Label done; @@ -1081,11 +1036,8 @@ MemoryOrder memory_order) { if (memory_order == kRelease) { StoreRelease(value, object, offset); - } else if (FieldAddress::CanHoldOffset(offset)) { - str(value, FieldAddress(object, offset)); } else { - AddImmediate(TMP, object, offset - kHeapObjectTag); - str(value, Address(TMP)); + StoreToOffset(value, object, offset - kHeapObjectTag); } StoreBarrier(object, value, value_can_be_smi); } @@ -1097,11 +1049,8 @@ MemoryOrder memory_order) { if (memory_order == kRelease) { StoreReleaseCompressed(value, object, offset); - } else if (FieldAddress::CanHoldOffset(offset)) { - str(value, FieldAddress(object, offset), kObjectBytes); } else { - AddImmediate(TMP, object, offset - kHeapObjectTag); - str(value, Address(TMP), kObjectBytes); + StoreToOffset(value, object, offset - kHeapObjectTag, kObjectBytes); } StoreBarrier(object, value, value_can_be_smi); }
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h index 116083a..0429fc0 100644 --- a/runtime/vm/compiler/assembler/assembler_arm64.h +++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1840,6 +1840,7 @@ void TestImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes); void CompareImmediate(Register rn, int64_t imm, OperandSize sz = kEightBytes); + Address PrepareLargeOffset(Register base, int32_t offset, OperandSize sz); void LoadFromOffset(Register dest, const Address& address, OperandSize sz = kEightBytes) override {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc index 6bdd476..e737994 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1271,15 +1271,11 @@ } void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { - DRegister dreg = EvenDRegisterOf(reg); - __ vstrd(dreg, - compiler::Address(SP, -kDoubleSize, compiler::Address::PreIndex)); + __ PushQuad(reg); } void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { - DRegister dreg = EvenDRegisterOf(reg); - __ vldrd(dreg, - compiler::Address(SP, kDoubleSize, compiler::Address::PostIndex)); + __ PopQuad(reg); } #undef __
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc index b4f95bd..d7a6ff6 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm64.cc
@@ -1234,11 +1234,11 @@ } void ParallelMoveResolver::SpillFpuScratch(FpuRegister reg) { - __ PushDouble(reg); + __ PushQuad(reg); } void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { - __ PopDouble(reg); + __ PopQuad(reg); } #undef __
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc index c129e1b..6e0172d 100644 --- a/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc +++ b/runtime/vm/compiler/backend/flow_graph_compiler_riscv.cc
@@ -819,7 +819,7 @@ } else if (destination.IsFpuRegister()) { const intptr_t src_offset = source.ToStackSlotOffset(); FRegister dst = destination.fpu_reg(); - __ fld(dst, compiler::Address(source.base_reg(), src_offset)); + __ LoadDFromOffset(dst, source.base_reg(), src_offset); } else { ASSERT(destination.IsStackSlot()); const intptr_t source_offset = source.ToStackSlotOffset(); @@ -837,7 +837,7 @@ destination.IsDoubleStackSlot()) { const intptr_t dest_offset = destination.ToStackSlotOffset(); FRegister src = source.fpu_reg(); - __ fsd(src, compiler::Address(destination.base_reg(), dest_offset)); + __ StoreDToOffset(src, destination.base_reg(), dest_offset); } else { ASSERT(destination.IsQuadStackSlot()); UNIMPLEMENTED(); @@ -847,14 +847,14 @@ if (destination.IsFpuRegister()) { const intptr_t source_offset = source.ToStackSlotOffset(); const FRegister dst = destination.fpu_reg(); - __ fld(dst, compiler::Address(source.base_reg(), source_offset)); + __ LoadDFromOffset(dst, source.base_reg(), source_offset); } else { ASSERT(destination.IsDoubleStackSlot() || destination.IsStackSlot() /*32-bit float*/); const intptr_t source_offset = source.ToStackSlotOffset(); const intptr_t dest_offset = destination.ToStackSlotOffset(); - __ fld(FTMP, compiler::Address(source.base_reg(), source_offset)); - __ fsd(FTMP, compiler::Address(destination.base_reg(), dest_offset)); + __ LoadDFromOffset(FTMP, source.base_reg(), source_offset); + __ StoreDToOffset(FTMP, destination.base_reg(), dest_offset); } } else if (source.IsQuadStackSlot()) { UNIMPLEMENTED();
diff --git a/runtime/vm/compiler/backend/flow_graph_test.cc b/runtime/vm/compiler/backend/flow_graph_test.cc index 8f82bb1..d97244f 100644 --- a/runtime/vm/compiler/backend/flow_graph_test.cc +++ b/runtime/vm/compiler/backend/flow_graph_test.cc
@@ -6,6 +6,7 @@ #include <vector> +#include "platform/text_buffer.h" #include "platform/utils.h" #include "vm/compiler/backend/block_builder.h" #include "vm/compiler/backend/il_printer.h" @@ -146,4 +147,101 @@ EXPECT_PROPERTY(late_var, it.representation() == kTagged); } +void TestLargeFrame(const char* type, + const char* zero, + const char* one, + const char* main) { + SetFlagScope<int> sfs(&FLAG_optimization_counter_threshold, 1000); + TextBuffer printer(256 * KB); + + intptr_t num_locals = 2000; + printer.Printf("import 'dart:typed_data';\n"); + printer.Printf("@pragma('vm:never-inline')\n"); + printer.Printf("%s one() { return %s; }\n", type, one); + printer.Printf("@pragma('vm:never-inline')\n"); + printer.Printf("%s largeFrame(int n) {\n", type); + for (intptr_t i = 0; i < num_locals; i++) { + printer.Printf(" %s local%" Pd " = %s;\n", type, i, zero); + } + printer.Printf(" for (int i = 0; i < n; i++) {\n"); + for (intptr_t i = 0; i < num_locals; i++) { + printer.Printf(" local%" Pd " += one();\n", i); + } + printer.Printf(" }\n"); + printer.Printf(" %s sum = %s;\n", type, zero); + for (intptr_t i = 0; i < num_locals; i++) { + printer.Printf(" sum += local%" Pd ";\n", i); + } + printer.Printf(" return sum;\n"); + printer.Printf("}\n"); + + printer.AddString(main); + + const auto& root_library = Library::Handle(LoadTestScript(printer.buffer())); + Invoke(root_library, "main"); +} + +ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int) { + TestLargeFrame("int", "0", "1", + "main() {\n" + " for (var i = 0; i < 100; i++) {\n" + " var r = largeFrame(1);\n" + " if (r != 2000) throw r;\n" + " }\n" + " return 'Okay';\n" + "}\n"); +} + +ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Double) { + TestLargeFrame("double", "0.0", "1.0", + "main() {\n" + " for (var i = 0; i < 100; i++) {\n" + " var r = largeFrame(1);\n" + " if (r != 2000.0) throw r;\n" + " }\n" + " return 'Okay';\n" + "}\n"); +} + +ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Int32x4) { + TestLargeFrame("Int32x4", "Int32x4(0, 0, 0, 0)", "Int32x4(1, 2, 3, 4)", + "main() {\n" + " for (var i = 0; i < 100; i++) {\n" + " var r = largeFrame(1);\n" + " if (r.x != 2000) throw r;\n" + " if (r.y != 4000) throw r;\n" + " if (r.z != 6000) throw r;\n" + " if (r.w != 8000) throw r;\n" + " }\n" + " return 'Okay';\n" + "}\n"); +} + +ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float32x4) { + TestLargeFrame("Float32x4", "Float32x4(0.0, 0.0, 0.0, 0.0)", + "Float32x4(1.0, 2.0, 3.0, 4.0)", + "main() {\n" + " for (var i = 0; i < 100; i++) {\n" + " var r = largeFrame(1);\n" + " if (r.x != 2000.0) throw r;\n" + " if (r.y != 4000.0) throw r;\n" + " if (r.z != 6000.0) throw r;\n" + " if (r.w != 8000.0) throw r;\n" + " }\n" + " return 'Okay';\n" + "}\n"); +} + +ISOLATE_UNIT_TEST_CASE(FlowGraph_LargeFrame_Float64x2) { + TestLargeFrame("Float64x2", "Float64x2(0.0, 0.0)", "Float64x2(1.0, 2.0)", + "main() {\n" + " for (var i = 0; i < 100; i++) {\n" + " var r = largeFrame(1);\n" + " if (r.x != 2000.0) throw r;\n" + " if (r.y != 4000.0) throw r;\n" + " }\n" + " return 'Okay';\n" + "}\n"); +} + } // namespace dart
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h index e4efe29..eb87355 100644 --- a/runtime/vm/compiler/backend/slot.h +++ b/runtime/vm/compiler/backend/slot.h
@@ -177,7 +177,6 @@ V(FinalizerEntry, UntaggedFinalizerEntry, external_size, IntPtr, VAR) \ V(Function, UntaggedFunction, entry_point, Uword, FINAL) \ V(Function, UntaggedFunction, kind_tag, Uint32, FINAL) \ - V(Function, UntaggedFunction, packed_fields, Uint32, FINAL) \ V(FunctionType, UntaggedFunctionType, packed_parameter_counts, Uint32, \ FINAL) \ V(FunctionType, UntaggedFunctionType, packed_type_parameter_counts, Uint16, \
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index 31c7822..22befb9 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h
@@ -508,7 +508,6 @@ static word data_offset(); static word entry_point_offset(CodeEntryKind kind = CodeEntryKind::kNormal); static word kind_tag_offset(); - static word packed_fields_offset(); static word signature_offset(); static word usage_counter_offset(); static word InstanceSize();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h index 2fc188c..1a4718e 100644 --- a/runtime/vm/compiler/runtime_offsets_extracted.h +++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -161,8 +161,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -782,8 +780,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -1408,8 +1404,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -2026,8 +2020,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -2653,8 +2645,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 91; static constexpr dart::compiler::target::word Function_signature_offset = 32; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -3279,8 +3269,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 91; static constexpr dart::compiler::target::word Function_signature_offset = 32; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -3906,8 +3894,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -4529,8 +4515,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -5153,8 +5137,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -5768,8 +5750,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -6388,8 +6368,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -7000,8 +6978,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -7621,8 +7597,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 91; static constexpr dart::compiler::target::word Function_signature_offset = 32; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -8241,8 +8215,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 91; static constexpr dart::compiler::target::word Function_signature_offset = 32; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -8862,8 +8834,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 4, 8}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 64; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 83; static constexpr dart::compiler::target::word Function_signature_offset = 20; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 4; @@ -9479,8 +9449,6 @@ static constexpr dart::compiler::target::word Function_entry_point_offset[] = { 8, 16}; static constexpr dart::compiler::target::word Function_kind_tag_offset = 104; -static constexpr dart::compiler::target::word Function_packed_fields_offset = - 123; static constexpr dart::compiler::target::word Function_signature_offset = 40; static constexpr dart::compiler::target::word FutureOr_type_arguments_offset = 8; @@ -10119,8 +10087,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {4, 8}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 40; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 20; static constexpr dart::compiler::target::word @@ -10581,7 +10547,7 @@ 24; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; +static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8; @@ -10816,8 +10782,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word @@ -11519,8 +11483,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word @@ -12219,8 +12181,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 52; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 32; static constexpr dart::compiler::target::word @@ -12918,8 +12878,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 52; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 32; static constexpr dart::compiler::target::word @@ -13618,8 +13576,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {4, 8}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 40; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 20; static constexpr dart::compiler::target::word @@ -14082,7 +14038,7 @@ 24; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; +static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8; @@ -14317,8 +14273,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word @@ -15014,8 +14968,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {4, 8}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 40; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 20; static constexpr dart::compiler::target::word @@ -15474,7 +15426,7 @@ 24; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; +static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8; @@ -15704,8 +15656,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word @@ -16400,8 +16350,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word @@ -17093,8 +17041,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 52; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 32; static constexpr dart::compiler::target::word @@ -17785,8 +17731,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 52; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 32; static constexpr dart::compiler::target::word @@ -18478,8 +18422,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {4, 8}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 40; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 20; static constexpr dart::compiler::target::word @@ -18940,7 +18882,7 @@ 24; static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24; static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24; -static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44; +static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize = 40; static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8; @@ -19170,8 +19112,6 @@ static constexpr dart::compiler::target::word AOT_Function_entry_point_offset[] = {8, 16}; static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72; -static constexpr dart::compiler::target::word - AOT_Function_packed_fields_offset = 76; static constexpr dart::compiler::target::word AOT_Function_signature_offset = 40; static constexpr dart::compiler::target::word
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h index 04aa47b..2e7c90f 100644 --- a/runtime/vm/compiler/runtime_offsets_list.h +++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -133,7 +133,6 @@ RANGE(Function, entry_point_offset, CodeEntryKind, CodeEntryKind::kNormal, \ CodeEntryKind::kUnchecked, [](CodeEntryKind value) { return true; }) \ FIELD(Function, kind_tag_offset) \ - FIELD(Function, packed_fields_offset) \ FIELD(Function, signature_offset) \ FIELD(FutureOr, type_arguments_offset) \ FIELD(GrowableObjectArray, data_offset) \
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index c38de03..4f03fb7a 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc
@@ -2844,13 +2844,15 @@ DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* len) { Thread* thread = Thread::Current(); DARTSCOPE(thread); - ReusableObjectHandleScope reused_obj_handle(thread); - const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str); - if (str_obj.IsNull()) { - RETURN_TYPE_ERROR(thread->zone(), str, String); + { + ReusableObjectHandleScope reused_obj_handle(thread); + const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str); + if (!str_obj.IsNull()) { + *len = str_obj.Length(); + return Api::Success(); + } } - *len = str_obj.Length(); - return Api::Success(); + RETURN_TYPE_ERROR(thread->zone(), str, String); } DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str) { @@ -3044,16 +3046,18 @@ Thread* thread = Thread::Current(); CHECK_ISOLATE(thread->isolate()); TransitionNativeToVM transition(thread); - ReusableObjectHandleScope reused_obj_handle(thread); - const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str); - if (str_obj.IsNull()) { - RETURN_TYPE_ERROR(thread->zone(), str, String); - } if (size == NULL) { RETURN_NULL_ERROR(size); } - *size = (str_obj.Length() * str_obj.CharSize()); - return Api::Success(); + { + ReusableObjectHandleScope reused_obj_handle(thread); + const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str); + if (!str_obj.IsNull()) { + *size = (str_obj.Length() * str_obj.CharSize()); + return Api::Success(); + } + } + RETURN_TYPE_ERROR(thread->zone(), str, String); } DART_EXPORT Dart_Handle Dart_StringGetProperties(Dart_Handle object, @@ -3063,21 +3067,23 @@ Thread* thread = Thread::Current(); CHECK_ISOLATE(thread->isolate()); TransitionNativeToVM transition(thread); - ReusableObjectHandleScope reused_obj_handle(thread); - const String& str = Api::UnwrapStringHandle(reused_obj_handle, object); - if (str.IsNull()) { - RETURN_TYPE_ERROR(thread->zone(), object, String); + { + ReusableObjectHandleScope reused_obj_handle(thread); + const String& str = Api::UnwrapStringHandle(reused_obj_handle, object); + if (!str.IsNull()) { + if (str.IsExternal()) { + *peer = str.GetPeer(); + ASSERT(*peer != NULL); + } else { + NoSafepointScope no_safepoint_scope; + *peer = thread->heap()->GetPeer(str.ptr()); + } + *char_size = str.CharSize(); + *str_len = str.Length(); + return Api::Success(); + } } - if (str.IsExternal()) { - *peer = str.GetPeer(); - ASSERT(*peer != NULL); - } else { - NoSafepointScope no_safepoint_scope; - *peer = thread->heap()->GetPeer(str.ptr()); - } - *char_size = str.CharSize(); - *str_len = str.Length(); - return Api::Success(); + RETURN_TYPE_ERROR(thread->zone(), object, String); } // --- Lists --- @@ -4927,13 +4933,16 @@ Thread* thread = Thread::Current(); CHECK_ISOLATE(thread->isolate()); TransitionNativeToVM transition(thread); - ReusableObjectHandleScope reused_obj_handle(thread); - const Instance& instance = Api::UnwrapInstanceHandle(reused_obj_handle, obj); - if (instance.IsNull()) { - RETURN_TYPE_ERROR(thread->zone(), obj, Instance); + { + ReusableObjectHandleScope reused_obj_handle(thread); + const Instance& instance = + Api::UnwrapInstanceHandle(reused_obj_handle, obj); + if (!instance.IsNull()) { + *count = instance.NumNativeFields(); + return Api::Success(); + } } - *count = instance.NumNativeFields(); - return Api::Success(); + RETURN_TYPE_ERROR(thread->zone(), obj, Instance); } DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, @@ -4942,18 +4951,26 @@ Thread* thread = Thread::Current(); CHECK_ISOLATE(thread->isolate()); TransitionNativeToVM transition(thread); - ReusableObjectHandleScope reused_obj_handle(thread); - const Instance& instance = Api::UnwrapInstanceHandle(reused_obj_handle, obj); - if (instance.IsNull()) { + bool is_null = false; + { + ReusableObjectHandleScope reused_obj_handle(thread); + const Instance& instance = + Api::UnwrapInstanceHandle(reused_obj_handle, obj); + if (!instance.IsNull()) { + if (instance.IsValidNativeIndex(index)) { + *value = instance.GetNativeField(index); + return Api::Success(); + } + } else { + is_null = true; + } + } + if (is_null) { RETURN_TYPE_ERROR(thread->zone(), obj, Instance); } - if (!instance.IsValidNativeIndex(index)) { - return Api::NewError( - "%s: invalid index %d passed in to access native instance field", - CURRENT_FUNC, index); - } - *value = instance.GetNativeField(index); - return Api::Success(); + return Api::NewError( + "%s: invalid index %d passed in to access native instance field", + CURRENT_FUNC, index); } DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index da4f734..c454796 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc
@@ -5949,51 +5949,6 @@ return static_cast<uint32_t>(v); } -class CanonicalInstanceKey { - public: - explicit CanonicalInstanceKey(const Instance& key) : key_(key) { - ASSERT(!(key.IsString() || key.IsAbstractType())); - } - bool Matches(const Instance& obj) const { - ASSERT(!(obj.IsString() || obj.IsAbstractType())); - if (key_.CanonicalizeEquals(obj)) { - ASSERT(obj.IsCanonical()); - return true; - } - return false; - } - uword Hash() const { return key_.CanonicalizeHash(); } - const Instance& key_; - - private: - DISALLOW_ALLOCATION(); -}; - -// Traits for looking up Canonical Instances based on a hash of the fields. -class CanonicalInstanceTraits { - public: - static const char* Name() { return "CanonicalInstanceTraits"; } - static bool ReportStats() { return false; } - - // Called when growing the table. - static bool IsMatch(const Object& a, const Object& b) { - ASSERT(!(a.IsString() || a.IsAbstractType())); - ASSERT(!(b.IsString() || b.IsAbstractType())); - return a.ptr() == b.ptr(); - } - static bool IsMatch(const CanonicalInstanceKey& a, const Object& b) { - return a.Matches(Instance::Cast(b)); - } - static uword Hash(const Object& key) { - ASSERT(!(key.IsString() || key.IsAbstractType())); - ASSERT(key.IsInstance()); - return Instance::Cast(key).CanonicalizeHash(); - } - static uword Hash(const CanonicalInstanceKey& key) { return key.Hash(); } - static ObjectPtr NewKey(const CanonicalInstanceKey& obj) { - return obj.key_.ptr(); - } -}; typedef UnorderedHashSet<CanonicalInstanceTraits> CanonicalInstancesSet; InstancePtr Class::LookupCanonicalInstance(Zone* zone, @@ -8109,7 +8064,11 @@ } void Function::set_packed_fields(uint32_t packed_fields) const { +#if defined(DART_PRECOMPILED_RUNTIME) + UNREACHABLE(); +#else StoreNonPointer(&untag()->packed_fields_, packed_fields); +#endif } bool Function::IsOptimizable() const {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h index b5eaa99..19f2fd3 100644 --- a/runtime/vm/object.h +++ b/runtime/vm/object.h
@@ -3141,11 +3141,14 @@ // Returns the size of the source for this function. intptr_t SourceSize() const; - uint32_t packed_fields() const { return untag()->packed_fields_; } - void set_packed_fields(uint32_t packed_fields) const; - static intptr_t packed_fields_offset() { - return OFFSET_OF(UntaggedFunction, packed_fields_); + uint32_t packed_fields() const { +#if defined(DART_PRECOMPILED_RUNTIME) + UNREACHABLE(); +#else + return untag()->packed_fields_; +#endif } + void set_packed_fields(uint32_t packed_fields) const; // Returns the number of required positional parameters. intptr_t num_fixed_parameters() const; @@ -3881,11 +3884,19 @@ // some functions known to be execute infrequently and functions // which have been de-optimized too many times. bool is_optimizable() const { +#if defined(DART_PRECOMPILED_RUNTIME) + UNREACHABLE(); +#else return untag()->packed_fields_.Read<UntaggedFunction::PackedOptimizable>(); +#endif } void set_is_optimizable(bool value) const { +#if defined(DART_PRECOMPILED_RUNTIME) + UNREACHABLE(); +#else untag()->packed_fields_.UpdateBool<UntaggedFunction::PackedOptimizable>( value); +#endif } enum KindTagBits {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h index 6b5dab8..f490865 100644 --- a/runtime/vm/raw_object.h +++ b/runtime/vm/raw_object.h
@@ -1346,14 +1346,13 @@ JIT_FUNCTION_COUNTERS(DECLARE) #undef DECLARE -#endif // !defined(DART_PRECOMPILED_RUNTIME) - AtomicBitFieldContainer<uint8_t> packed_fields_; static constexpr intptr_t kMaxOptimizableBits = 1; using PackedOptimizable = BitField<decltype(packed_fields_), bool, 0, kMaxOptimizableBits>; +#endif // !defined(DART_PRECOMPILED_RUNTIME) }; class UntaggedClosureData : public UntaggedObject {
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc index 33b2332..d0d878c 100644 --- a/runtime/vm/zone.cc +++ b/runtime/vm/zone.cc
@@ -320,19 +320,25 @@ } StackZone::StackZone(ThreadState* thread) +#if defined(DART_USE_ABSL) + // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading. : StackResource(thread), zone_(new Zone()) { +#else + : StackResource(thread), zone_() { +#endif // defined(DART_USE_ABSL) if (FLAG_trace_zones) { OS::PrintErr("*** Starting a new Stack zone 0x%" Px "(0x%" Px ")\n", reinterpret_cast<intptr_t>(this), - reinterpret_cast<intptr_t>(zone_)); + reinterpret_cast<intptr_t>(GetZone())); } // This thread must be preventing safepoints or the GC could be visiting the // chain of handle blocks we're about the mutate. ASSERT(Thread::Current()->MayAllocateHandles()); - zone_->Link(thread->zone()); - thread->set_zone(zone_); + Zone* lzone = GetZone(); + lzone->Link(thread->zone()); + thread->set_zone(lzone); } StackZone::~StackZone() { @@ -340,15 +346,19 @@ // chain of handle blocks we're about the mutate. ASSERT(Thread::Current()->MayAllocateHandles()); - ASSERT(thread()->zone() == zone_); - thread()->set_zone(zone_->previous_); + Zone* lzone = GetZone(); + ASSERT(thread()->zone() == lzone); + thread()->set_zone(lzone->previous_); if (FLAG_trace_zones) { OS::PrintErr("*** Deleting Stack zone 0x%" Px "(0x%" Px ")\n", reinterpret_cast<intptr_t>(this), - reinterpret_cast<intptr_t>(zone_)); + reinterpret_cast<intptr_t>(lzone)); } +#if defined(DART_USE_ABSL) + // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading. delete zone_; +#endif // defined(DART_USE_ABSL) } } // namespace dart
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h index a22f953..d5abb3b 100644 --- a/runtime/vm/zone.h +++ b/runtime/vm/zone.h
@@ -192,6 +192,8 @@ // Delete all memory associated with the zone. virtual ~StackZone(); + // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading, +#if defined(DART_USE_ABSL) // Compute the total size of this zone. This includes wasted space that is // due to internal fragmentation in the segments. uintptr_t SizeInBytes() const { return zone_->SizeInBytes(); } @@ -200,9 +202,34 @@ intptr_t CapacityInBytes() const { return zone_->CapacityInBytes(); } Zone* GetZone() { return zone_; } +#else + // Compute the total size of this zone. This includes wasted space that is + // due to internal fragmentation in the segments. + uintptr_t SizeInBytes() const { + return zone_.SizeInBytes(); + } + + // Computes the used space in the zone. + intptr_t CapacityInBytes() const { + return zone_.CapacityInBytes(); + } + + Zone* GetZone() { + return &zone_; + } +#endif // defined(DART_USE_ABSL) private: +#if defined(DART_USE_ABSL) + // When fibers are used we have to make do with a smaller stack size and hence + // the first zone is allocated instead of being a stack resource. Zone* zone_; +#else + // For regular configurations that have larger stack sizes it is ok to + // have the first zone be a stack resource, avoids the overhead of a malloc + // call for every stack zone creation. + Zone zone_; +#endif // defined(DART_USE_ABSL) template <typename T> friend class GrowableArray;
diff --git a/tools/VERSION b/tools/VERSION index 24622c4..33d92f0 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 2 MINOR 18 PATCH 0 -PRERELEASE 90 +PRERELEASE 91 PRERELEASE_PATCH 0 \ No newline at end of file