| // 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 'constants.dart'; |
| import 'impact_data.dart' show ConditionalImpactData, ImpactData; |
| import 'runtime_type_analysis.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(); |
| |
| void registerDoubleLiteral(); |
| |
| void registerBoolLiteral(); |
| |
| void registerStringLiteral(); |
| |
| void registerSymbolLiteral(); |
| |
| 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 registerRecordLiteral(ir.RecordType type, {required bool isConst}); |
| |
| void registerStaticTearOff( |
| ir.Procedure procedure, |
| ir.LibraryDependency? import, |
| ); |
| |
| void registerWeakStaticTearOff( |
| 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); |
| |
| void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType); |
| |
| 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, |
| ir.Name name, |
| int positionalArguments, |
| List<String> namedArguments, |
| List<ir.DartType> typeArguments, |
| ); |
| |
| void registerInstanceInvocation( |
| ir.DartType receiverType, |
| 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, ir.Name name); |
| |
| void registerInstanceGet(ir.DartType receiverType, ir.Member target); |
| |
| void registerDynamicSet(ir.DartType receiverType, ir.Name name); |
| |
| void registerInstanceSet(ir.DartType receiverType, 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 registerExternalConstructorNode(ir.Constructor node); |
| void registerFieldNode(ir.Field node); |
| void registerExternalProcedureNode(ir.Procedure node); |
| void registerForeignStaticInvocationNode(ir.StaticInvocation node); |
| void registerConstSymbolConstructorInvocationNode(); |
| void registerConditionalImpact(ConditionalImpactData impact); |
| } |
| |
| class ImpactBuilderData { |
| static const String tag = 'ImpactBuilderData'; |
| |
| final ir.Member node; |
| final ImpactData impactData; |
| |
| ImpactBuilderData(this.node, this.impactData); |
| } |
| |
| 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, |
| ); |
| |
| static Never _unexpectedConstant(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 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 visitRecordConstant(ir.RecordConstant node) { |
| registry.registerRecordLiteral(node.recordType, isConst: true); |
| for (ir.Constant element in node.positional) { |
| visitConstant(element); |
| } |
| for (ir.Constant element in node.named.values) { |
| visitConstant(element); |
| } |
| } |
| |
| @override |
| void visitSymbolConstant(ir.SymbolConstant node) { |
| // TODO(johnniwinther): Handle the library reference. |
| registry.registerSymbolLiteral(); |
| } |
| |
| @override |
| void visitStringConstant(ir.StringConstant node) { |
| registry.registerStringLiteral(); |
| } |
| |
| @override |
| void visitDoubleConstant(ir.DoubleConstant node) { |
| registry.registerDoubleLiteral(); |
| } |
| |
| @override |
| void visitIntConstant(ir.IntConstant node) { |
| registry.registerIntLiteral(); |
| } |
| |
| @override |
| void visitBoolConstant(ir.BoolConstant node) { |
| registry.registerBoolLiteral(); |
| } |
| |
| @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. |
| } |
| |
| @override |
| Never visitRedirectingFactoryTearOffConstant( |
| ir.RedirectingFactoryTearOffConstant node, |
| ) => _unexpectedConstant(node); |
| |
| @override |
| Never visitTypedefTearOffConstant(ir.TypedefTearOffConstant node) => |
| _unexpectedConstant(node); |
| |
| @override |
| Never visitAuxiliaryConstant(ir.AuxiliaryConstant node) => |
| _unexpectedConstant(node); |
| } |