blob: e1e7473201a4df3f68ec597ceb79e6c2b1821016 [file] [log] [blame]
// 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 'package:kernel/ast.dart' as ir;
import 'package:kernel/type_environment.dart' as ir;
import '../serialization/serialization.dart';
import 'class_relation.dart';
import 'constants.dart';
import 'impact_data.dart' show ImpactData;
import 'runtime_type_analysis.dart';
import 'static_type.dart';
import 'static_type_cache.dart';
/// Interface for collecting world impact data.
///
/// This is used both for direct world impact computation through the
/// [KernelImpactBuilder] and for serialization through the [ImpactBuilder]
/// and [ImpactLoader].
abstract class ImpactRegistry {
void registerIntLiteral(int value);
void registerDoubleLiteral(double value);
void registerBoolLiteral(bool value);
void registerStringLiteral(String value);
void registerSymbolLiteral(String value);
void registerNullLiteral();
void registerListLiteral(ir.DartType elementType,
{required bool isConst, required bool isEmpty});
void registerSetLiteral(ir.DartType elementType,
{required bool isConst, required bool isEmpty});
void registerMapLiteral(ir.DartType keyType, ir.DartType valueType,
{required bool isConst, required bool isEmpty});
void registerStaticTearOff(
ir.Procedure procedure, ir.LibraryDependency? import);
void registerStaticGet(ir.Member member, ir.LibraryDependency? import);
void registerStaticSet(ir.Member member, ir.LibraryDependency? import);
void registerAssert({required bool withMessage});
void registerGenericInstantiation(
ir.FunctionType expressionType, List<ir.DartType> typeArguments);
void registerSyncStar(ir.DartType elementType);
void registerAsync(ir.DartType elementType);
void registerAsyncStar(ir.DartType elementType);
void registerStringConcatenation();
void registerLocalFunction(ir.TreeNode node);
void registerLocalWithoutInitializer();
void registerIsCheck(ir.DartType type);
void registerImplicitCast(ir.DartType type);
void registerAsCast(ir.DartType type);
void registerThrow();
void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
ClassRelation iteratorClassRelation);
void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType,
ClassRelation iteratorClassRelation);
void registerCatch();
void registerStackTrace();
void registerCatchType(ir.DartType type);
void registerTypeLiteral(ir.DartType type, ir.LibraryDependency? import);
void registerFieldInitialization(ir.Field node);
void registerFieldConstantInitialization(
ir.Field node, ConstantReference constant);
void registerLoadLibrary();
void registerRedirectingInitializer(
ir.Constructor constructor,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerParameterCheck(ir.DartType type);
void registerLazyField();
void registerNew(
ir.Member constructor,
ir.InterfaceType type,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import,
{required bool isConst});
void registerConstInstantiation(ir.Class cls, List<ir.DartType> typeArguments,
ir.LibraryDependency? import);
void registerStaticInvocation(
ir.Procedure target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments,
ir.LibraryDependency? import);
void registerLocalFunctionInvocation(
ir.FunctionDeclaration localFunction,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerDynamicInvocation(
ir.DartType receiverType,
ClassRelation relation,
ir.Name name,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerInstanceInvocation(
ir.DartType receiverType,
ClassRelation relation,
ir.Member target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerFunctionInvocation(
ir.DartType receiverType,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerDynamicGet(
ir.DartType receiverType, ClassRelation relation, ir.Name name);
void registerInstanceGet(
ir.DartType receiverType, ClassRelation relation, ir.Member target);
void registerDynamicSet(
ir.DartType receiverType, ClassRelation relation, ir.Name name);
void registerInstanceSet(
ir.DartType receiverType, ClassRelation relation, ir.Member target);
void registerSuperInvocation(ir.Member target, int positionalArguments,
List<String> namedArguments, List<ir.DartType> typeArguments);
void registerSuperGet(ir.Member target);
void registerSuperSet(ir.Member target);
void registerSuperInitializer(
ir.Constructor source,
ir.Constructor target,
int positionalArguments,
List<String> namedArguments,
List<ir.DartType> typeArguments);
void registerRuntimeTypeUse(RuntimeTypeUseKind kind, ir.DartType receiverType,
ir.DartType? argumentType);
void registerConstructorNode(ir.Constructor node);
void registerFieldNode(ir.Field node);
void registerProcedureNode(ir.Procedure node);
void registerStaticInvocationNode(ir.StaticInvocation node);
void registerSwitchStatementNode(ir.SwitchStatement node);
void registerConstSymbolConstructorInvocationNode();
}
class ImpactBuilderData {
static const String tag = 'ImpactBuilderData';
final ir.Member node;
final ImpactData impactData;
final Map<ir.Expression, TypeMap>? typeMapsForTesting;
final StaticTypeCache cachedStaticTypes;
ImpactBuilderData(this.node, this.impactData, this.typeMapsForTesting,
this.cachedStaticTypes);
factory ImpactBuilderData.fromDataSource(DataSourceReader source) {
source.begin(tag);
var node = source.readMemberNode();
var data = ImpactData.fromDataSource(source);
var cache = StaticTypeCache.readFromDataSource(source, node);
source.end(tag);
return ImpactBuilderData(node, data, const {}, cache);
}
void toDataSink(DataSinkWriter sink) {
sink.begin(tag);
sink.writeMemberNode(node);
impactData.toDataSink(sink);
cachedStaticTypes.writeToDataSink(sink, node);
sink.end(tag);
}
}
class ConstantImpactVisitor extends ir.VisitOnceConstantVisitor {
final ImpactRegistry registry;
final ir.LibraryDependency? import;
final ir.ConstantExpression expression;
final ir.StaticTypeContext staticTypeContext;
ConstantImpactVisitor(
this.registry, this.import, this.expression, this.staticTypeContext);
@override
void defaultConstant(ir.Constant node) {
throw UnsupportedError(
"Unexpected constant ${node} (${node.runtimeType}).");
}
@override
void visitUnevaluatedConstant(ir.UnevaluatedConstant node) {
// Do nothing. This occurs when the constant couldn't be evaluated because
// of a compile-time error.
}
@override
void visitTypeLiteralConstant(ir.TypeLiteralConstant node) {
registry.registerTypeLiteral(node.type, import);
}
@override
void visitStaticTearOffConstant(ir.StaticTearOffConstant node) {
registry.registerStaticTearOff(node.target, import);
}
@override
void visitInstantiationConstant(ir.InstantiationConstant node) {
registry.registerGenericInstantiation(
node.tearOffConstant.getType(staticTypeContext) as ir.FunctionType,
node.types);
visitConstant(node.tearOffConstant);
}
@override
void visitTypedefTearOffConstant(ir.TypedefTearOffConstant node) {
defaultConstant(node);
}
@override
void visitInstanceConstant(ir.InstanceConstant node) {
registry.registerConstInstantiation(
node.classNode, node.typeArguments, import);
node.fieldValues.forEach((ir.Reference reference, ir.Constant value) {
ir.Field field = reference.asField;
registry.registerFieldConstantInitialization(
field, ConstantReference(expression, value));
visitConstant(value);
});
}
@override
void visitSetConstant(ir.SetConstant node) {
registry.registerSetLiteral(node.typeArgument,
isConst: true, isEmpty: node.entries.isEmpty);
for (ir.Constant element in node.entries) {
visitConstant(element);
}
}
@override
void visitListConstant(ir.ListConstant node) {
registry.registerListLiteral(node.typeArgument,
isConst: true, isEmpty: node.entries.isEmpty);
for (ir.Constant element in node.entries) {
visitConstant(element);
}
}
@override
void visitMapConstant(ir.MapConstant node) {
registry.registerMapLiteral(node.keyType, node.valueType,
isConst: true, isEmpty: node.entries.isEmpty);
for (ir.ConstantMapEntry entry in node.entries) {
visitConstant(entry.key);
visitConstant(entry.value);
}
}
@override
void visitSymbolConstant(ir.SymbolConstant node) {
// TODO(johnniwinther): Handle the library reference.
registry.registerSymbolLiteral(node.name);
}
@override
void visitStringConstant(ir.StringConstant node) {
registry.registerStringLiteral(node.value);
}
@override
void visitDoubleConstant(ir.DoubleConstant node) {
registry.registerDoubleLiteral(node.value);
}
@override
void visitIntConstant(ir.IntConstant node) {
registry.registerIntLiteral(node.value);
}
@override
void visitBoolConstant(ir.BoolConstant node) {
registry.registerBoolLiteral(node.value);
}
@override
void visitNullConstant(ir.NullConstant node) {
registry.registerNullLiteral();
}
@override
void visitConstructorTearOffConstant(ir.ConstructorTearOffConstant node) {
// The CFE encoding of redirecting factories, which dart2js doesn't use,
// uses ConstructorTearOff(Constant) to point to its effective target.
// However, these should be safe to ignore.
}
}