Files
sdk/pkg/vm/lib/bytecode/generics.dart
T
Alexander Markov 61f0f5bc43 [vm/bytecode] Declare members in bytecode
This change replaces kernel AST declarations of fields and functions
with bytecode declarations.

Size of dilp files is reduced by 11-12%.

Startup latency:
Time to the first full frame: 1.945s -> 1.687s
FinalizeClass: 554ms -> 277ms
FinishClassLoading: 296ms -> 156ms

There are following regressions in bytecode mode, which will be fixed
in future:

* dart:mirrors are not supported yet (implementation of mirrors relies
  on reading kernel AST in certain cases).

  As the result, lib_2/mirrors/* tests fail.

* native extensions are not supported yet (annotations on libraries
  and classes in AST are cleaned up as they could reference members
  which are now removed from AST).

  As the result, standalone_2/entrypoints_verification_test test fails.

* language_2/spread_collections/const_error_test/* tests fail
  due to https://github.com/dart-lang/sdk/issues/36286.

Change-Id: I5130f401fd7b84038b136136e7ccc1a6e51b6cea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97561
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2019-03-26 21:40:10 +00:00

239 lines
6.5 KiB
Dart

// Copyright (c) 2019, 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.
library vm.bytecode.generics;
import 'dart:math' show min;
import 'package:kernel/ast.dart' hide MapEntry;
import 'package:kernel/type_algebra.dart' show Substitution;
bool hasInstantiatorTypeArguments(Class c) {
for (; c != null; c = c.superclass) {
if (c.typeParameters.isNotEmpty) {
return true;
}
}
return false;
}
bool _canReuseSuperclassTypeArguments(List<DartType> superTypeArgs,
List<TypeParameter> typeParameters, int overlap) {
for (int i = 0; i < overlap; ++i) {
final superTypeArg = superTypeArgs[superTypeArgs.length - overlap + i];
if (!(superTypeArg is TypeParameterType &&
superTypeArg.parameter == typeParameters[i])) {
return false;
}
}
return true;
}
List<DartType> flattenInstantiatorTypeArguments(
Class instantiatedClass, List<DartType> typeArgs) {
final typeParameters = instantiatedClass.typeParameters;
assert(typeArgs.length == typeParameters.length);
final supertype = instantiatedClass.supertype;
if (supertype == null) {
return typeArgs;
}
final superTypeArgs = flattenInstantiatorTypeArguments(
supertype.classNode, supertype.typeArguments);
// Shrink type arguments by reusing portion of superclass type arguments
// if there is an overlapping. This optimization should be consistent with
// VM in order to correctly reuse instantiator type arguments.
int overlap = min(superTypeArgs.length, typeArgs.length);
for (; overlap > 0; --overlap) {
if (_canReuseSuperclassTypeArguments(
superTypeArgs, typeParameters, overlap)) {
break;
}
}
final substitution = Substitution.fromPairs(typeParameters, typeArgs);
List<DartType> flatTypeArgs = <DartType>[];
flatTypeArgs.addAll(superTypeArgs.map((t) => substitution.substituteType(t)));
flatTypeArgs.addAll(typeArgs.getRange(overlap, typeArgs.length));
return flatTypeArgs;
}
List<DartType> getInstantiatorTypeArguments(
Class instantiatedClass, List<DartType> typeArgs) {
final flatTypeArgs =
flattenInstantiatorTypeArguments(instantiatedClass, typeArgs);
if (_isAllDynamic(flatTypeArgs)) {
return null;
}
return flatTypeArgs;
}
List<DartType> getDefaultFunctionTypeArguments(FunctionNode function) {
List<DartType> defaultTypes = function.typeParameters
.map((p) => p.defaultType ?? const DynamicType())
.toList();
if (_isAllDynamic(defaultTypes)) {
return null;
}
return defaultTypes;
}
bool _isAllDynamic(List<DartType> typeArgs) {
for (var t in typeArgs) {
if (t != const DynamicType()) {
return false;
}
}
return true;
}
bool hasFreeTypeParameters(List<DartType> typeArgs) {
final findTypeParams = new FindFreeTypeParametersVisitor();
return typeArgs.any((t) => t.accept(findTypeParams));
}
class FindFreeTypeParametersVisitor extends DartTypeVisitor<bool> {
Set<TypeParameter> _declaredTypeParameters;
bool visit(DartType type) => type.accept(this);
@override
bool defaultDartType(DartType node) =>
throw 'Unexpected type ${node.runtimeType} $node';
@override
bool visitInvalidType(InvalidType node) => false;
@override
bool visitDynamicType(DynamicType node) => false;
@override
bool visitVoidType(VoidType node) => false;
@override
bool visitBottomType(BottomType node) => false;
@override
bool visitTypeParameterType(TypeParameterType node) =>
_declaredTypeParameters == null ||
!_declaredTypeParameters.contains(node.parameter);
@override
bool visitInterfaceType(InterfaceType node) =>
node.typeArguments.any((t) => t.accept(this));
@override
bool visitTypedefType(TypedefType node) =>
node.typeArguments.any((t) => t.accept(this));
@override
bool visitFunctionType(FunctionType node) {
if (node.typeParameters.isNotEmpty) {
_declaredTypeParameters ??= new Set<TypeParameter>();
_declaredTypeParameters.addAll(node.typeParameters);
}
final bool result = node.positionalParameters.any((t) => t.accept(this)) ||
node.namedParameters.any((p) => p.type.accept(this)) ||
node.returnType.accept(this);
if (node.typeParameters.isNotEmpty) {
_declaredTypeParameters.removeAll(node.typeParameters);
}
return result;
}
}
/// Returns true if the given type is recursive after its type arguments
/// are flattened.
bool isRecursiveAfterFlattening(InterfaceType type) {
final visitor = new IsRecursiveAfterFlatteningVisitor();
visitor.visit(type);
return visitor.isRecursive(type);
}
class IsRecursiveAfterFlatteningVisitor extends DartTypeVisitor<void> {
Set<DartType> _visited = new Set<DartType>();
List<DartType> _stack = <DartType>[];
Set<DartType> _recursive;
bool isRecursive(DartType type) =>
_recursive != null && _recursive.contains(type);
void visit(DartType type) {
if (!_visited.add(type)) {
_recordRecursiveType(type);
return;
}
_stack.add(type);
type.accept(this);
_stack.removeLast();
_visited.remove(type);
}
void _recordRecursiveType(DartType type) {
final int start = _stack.lastIndexOf(type);
final recursive = (_recursive ??= new Set<DartType>());
for (int i = start; i < _stack.length; ++i) {
recursive.add(_stack[i]);
}
}
@override
void defaultDartType(DartType node) =>
throw 'Unexpected type ${node.runtimeType} $node';
@override
void visitInvalidType(InvalidType node) {}
@override
void visitDynamicType(DynamicType node) {}
@override
void visitVoidType(VoidType node) {}
@override
void visitBottomType(BottomType node) {}
@override
void visitTypeParameterType(TypeParameterType node) {}
@override
void visitInterfaceType(InterfaceType node) {
for (var typeArg in node.typeArguments) {
visit(typeArg);
}
if (isRecursive(node)) {
return;
}
final flatTypeArgs =
flattenInstantiatorTypeArguments(node.classNode, node.typeArguments);
for (var typeArg in flatTypeArgs.getRange(
0, flatTypeArgs.length - node.typeArguments.length)) {
visit(typeArg);
}
}
@override
void visitTypedefType(TypedefType node) => visit(node.unalias);
@override
void visitFunctionType(FunctionType node) {
for (var p in node.positionalParameters) {
visit(p);
}
for (var p in node.namedParameters) {
visit(p.type);
}
visit(node.returnType);
}
}