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