| // Copyright (c) 2016, 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 '../common.dart'; | |
| import '../common/elements.dart'; | |
| import '../common/names.dart'; | |
| import '../constants/values.dart'; | |
| import '../elements/entities.dart'; | |
| import '../elements/types.dart'; | |
| import '../ir/constants.dart'; | |
| import '../ir/impact.dart'; | |
| import '../ir/impact_data.dart'; | |
| import '../ir/runtime_type_analysis.dart'; | |
| import '../ir/visitors.dart'; | |
| import '../js_backend/annotations.dart'; | |
| import '../js_backend/backend_impact.dart'; | |
| import '../js_backend/backend_usage.dart'; | |
| import '../js_backend/custom_elements_analysis.dart'; | |
| import '../js_backend/native_data.dart'; | |
| import '../js_backend/runtime_types_resolution.dart'; | |
| import '../js_model/elements.dart'; | |
| import '../native/behavior.dart'; | |
| import '../native/enqueue.dart'; | |
| import '../universe/call_structure.dart'; | |
| import '../universe/feature.dart'; | |
| import '../universe/selector.dart'; | |
| import '../universe/use.dart'; | |
| import '../universe/world_builder.dart'; | |
| import '../universe/world_impact.dart'; | |
| import 'element_map.dart'; | |
| /// [ImpactRegistry] that converts kernel based impact data to world impact | |
| /// object based on the K model. | |
| class KernelImpactConverter implements ImpactRegistry { | |
| final KernelToElementMap elementMap; | |
| final DiagnosticReporter reporter; | |
| final MemberEntity currentMember; | |
| final ConstantValuefier _constantValuefier; | |
| final ir.StaticTypeContext staticTypeContext; | |
| final BackendImpacts _impacts; | |
| final NativeResolutionEnqueuer _nativeResolutionEnqueuer; | |
| final BackendUsageBuilder _backendUsageBuilder; | |
| final CustomElementsResolutionAnalysis _customElementsResolutionAnalysis; | |
| final RuntimeTypesNeedBuilder _rtiNeedBuilder; | |
| final AnnotationsData _annotationsData; | |
| WorldImpactBuilder? _impactBuilder; | |
| WorldImpactBuilder get impactBuilder => _impactBuilder!; | |
| KernelImpactConverter( | |
| this.elementMap, | |
| this.currentMember, | |
| this.reporter, | |
| this._constantValuefier, | |
| this.staticTypeContext, | |
| this._impacts, | |
| this._nativeResolutionEnqueuer, | |
| this._backendUsageBuilder, | |
| this._customElementsResolutionAnalysis, | |
| this._rtiNeedBuilder, | |
| this._annotationsData, | |
| ); | |
| ir.TypeEnvironment get typeEnvironment => elementMap.typeEnvironment; | |
| CommonElements get commonElements => elementMap.commonElements; | |
| NativeBasicData get _nativeBasicData => elementMap.nativeBasicData; | |
| ElementEnvironment get elementEnvironment => elementMap.elementEnvironment; | |
| DartTypes get dartTypes => commonElements.dartTypes; | |
| String typeToString(DartType type) => type.toStructuredText(dartTypes); | |
| Object? _computeReceiverConstraint(ir.DartType receiverType) { | |
| if (receiverType is ir.InterfaceType) { | |
| return defaultReceiverClass( | |
| commonElements, | |
| _nativeBasicData, | |
| elementMap.getClass(receiverType.classNode), | |
| ); | |
| } else if (receiverType is ir.NullType) { | |
| return elementMap.getClass(typeEnvironment.coreTypes.deprecatedNullClass); | |
| } | |
| return null; | |
| } | |
| void registerBackendImpact(BackendImpact impact) { | |
| impact.registerImpact(impactBuilder, elementEnvironment); | |
| _backendUsageBuilder.processBackendImpact(impact); | |
| } | |
| void registerNativeImpact(NativeBehavior behavior) { | |
| _nativeResolutionEnqueuer.registerNativeBehavior( | |
| impactBuilder, | |
| behavior, | |
| impactBuilder, | |
| ); | |
| } | |
| // TODO(johnniwinther): Maybe split this into [onAssertType] and [onTestType]. | |
| void onIsCheck(DartType type) { | |
| registerBackendImpact(_impacts.typeCheck); | |
| var typeWithoutNullability = type.withoutNullability; | |
| if (!dartTypes.treatAsRawType(typeWithoutNullability) || | |
| typeWithoutNullability.containsTypeVariables || | |
| typeWithoutNullability is FunctionType) { | |
| registerBackendImpact(_impacts.genericTypeCheck); | |
| if (typeWithoutNullability is TypeVariableType) { | |
| registerBackendImpact(_impacts.typeVariableTypeCheck); | |
| } | |
| } | |
| if (typeWithoutNullability is FunctionType) { | |
| registerBackendImpact(_impacts.functionTypeCheck); | |
| } | |
| if (typeWithoutNullability is InterfaceType && | |
| _nativeBasicData.isNativeClass(typeWithoutNullability.element)) { | |
| registerBackendImpact(_impacts.nativeTypeCheck); | |
| } | |
| if (typeWithoutNullability is FutureOrType) { | |
| registerBackendImpact(_impacts.futureOrTypeCheck); | |
| } | |
| } | |
| @override | |
| void registerParameterCheck(ir.DartType irType) { | |
| DartType type = elementMap.getDartType(irType); | |
| if (type is! DynamicType) { | |
| impactBuilder.registerTypeUse(TypeUse.parameterCheck(type)); | |
| if (_annotationsData.getParameterCheckPolicy(currentMember).isEmitted) { | |
| onIsCheck(type); | |
| } | |
| } | |
| } | |
| List<DartType>? _getTypeArguments(List<ir.DartType> types) { | |
| if (types.isEmpty) return null; | |
| return types.map(elementMap.getDartType).toList(); | |
| } | |
| @override | |
| void registerLazyField() { | |
| registerBackendImpact(_impacts.lazyField); | |
| } | |
| @override | |
| void registerFieldNode(ir.Field field) { | |
| if (field.isInstanceMember && | |
| _nativeBasicData.isNativeClass( | |
| elementMap.getClass(field.enclosingClass!), | |
| )) { | |
| MemberEntity member = elementMap.getMember(field); | |
| // TODO(johnniwinther): NativeDataBuilder already has the native behavior | |
| // at this point. Use that instead. | |
| bool isJsInterop = _nativeBasicData.isJsInteropMember(member); | |
| Iterable<ConstantValue> metadata = elementMap.elementEnvironment | |
| .getMemberMetadata(member as JMember); | |
| Iterable<String> createsAnnotations = getCreatesAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| Iterable<String> returnsAnnotations = getReturnsAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| registerNativeImpact( | |
| elementMap.getNativeBehaviorForFieldLoad( | |
| field, | |
| createsAnnotations, | |
| returnsAnnotations, | |
| isJsInterop: isJsInterop, | |
| ), | |
| ); | |
| registerNativeImpact(elementMap.getNativeBehaviorForFieldStore(field)); | |
| } | |
| } | |
| @override | |
| void registerExternalConstructorNode(ir.Constructor constructor) { | |
| MemberEntity member = elementMap.getMember(constructor); | |
| if (constructor.isExternal && !commonElements.isForeignHelper(member)) { | |
| // TODO(johnniwinther): NativeDataBuilder already has the native behavior | |
| // at this point. Use that instead. | |
| bool isJsInterop = _nativeBasicData.isJsInteropMember(member); | |
| Iterable<ConstantValue> metadata = elementMap.elementEnvironment | |
| .getMemberMetadata(member as JMember); | |
| Iterable<String> createsAnnotations = getCreatesAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| Iterable<String> returnsAnnotations = getReturnsAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| registerNativeImpact( | |
| elementMap.getNativeBehaviorForMethod( | |
| constructor, | |
| createsAnnotations, | |
| returnsAnnotations, | |
| isJsInterop: isJsInterop, | |
| ), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerSyncStar(ir.DartType elementType) { | |
| registerBackendImpact(_impacts.syncStarBody); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke( | |
| commonElements.syncStarIterableFactory, | |
| CallStructure.unnamed(1, 1), | |
| <DartType>[elementMap.getDartType(elementType)], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerAsync(ir.DartType elementType) { | |
| registerBackendImpact(_impacts.asyncBody); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke( | |
| commonElements.asyncAwaitCompleterFactory, | |
| CallStructure.unnamed(0, 1), | |
| <DartType>[elementMap.getDartType(elementType)], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerAsyncStar(ir.DartType elementType) { | |
| registerBackendImpact(_impacts.asyncStarBody); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke( | |
| commonElements.asyncStarStreamControllerFactory, | |
| CallStructure.unnamed(1, 1), | |
| <DartType>[elementMap.getDartType(elementType)], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerExternalProcedureNode(ir.Procedure procedure) { | |
| MemberEntity member = elementMap.getMember(procedure); | |
| if (procedure.isExternal && !commonElements.isForeignHelper(member)) { | |
| // TODO(johnniwinther): NativeDataBuilder already has the native behavior | |
| // at this point. Use that instead. | |
| bool isJsInterop = _nativeBasicData.isJsInteropMember(member); | |
| Iterable<ConstantValue> metadata = elementMap.elementEnvironment | |
| .getMemberMetadata(member as JMember); | |
| Iterable<String> createsAnnotations = getCreatesAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| Iterable<String> returnsAnnotations = getReturnsAnnotations( | |
| dartTypes, | |
| reporter, | |
| commonElements, | |
| metadata, | |
| ); | |
| registerNativeImpact( | |
| elementMap.getNativeBehaviorForMethod( | |
| procedure, | |
| createsAnnotations, | |
| returnsAnnotations, | |
| isJsInterop: isJsInterop, | |
| ), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerIntLiteral() { | |
| registerBackendImpact(_impacts.intLiteral); | |
| } | |
| @override | |
| void registerDoubleLiteral() { | |
| registerBackendImpact(_impacts.doubleLiteral); | |
| } | |
| @override | |
| void registerBoolLiteral() { | |
| registerBackendImpact(_impacts.boolLiteral); | |
| } | |
| @override | |
| void registerStringLiteral() { | |
| registerBackendImpact(_impacts.stringLiteral); | |
| } | |
| @override | |
| void registerSymbolLiteral() { | |
| registerBackendImpact(_impacts.constSymbol); | |
| } | |
| @override | |
| void registerNullLiteral() { | |
| registerBackendImpact(_impacts.nullLiteral); | |
| } | |
| @override | |
| void registerListLiteral( | |
| ir.DartType elementType, { | |
| required bool isConst, | |
| required bool isEmpty, | |
| }) { | |
| // TODO(johnniwinther): Use the [isConstant] and [isEmpty] property when | |
| // factory constructors are registered directly. | |
| impactBuilder.registerTypeUse( | |
| TypeUse.instantiation( | |
| commonElements.listType(elementMap.getDartType(elementType)), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerSetLiteral( | |
| ir.DartType elementType, { | |
| required bool isConst, | |
| required bool isEmpty, | |
| }) { | |
| // TODO(johnniwinther): Use the [isEmpty] property when factory | |
| // constructors are registered directly. | |
| if (isConst) { | |
| registerBackendImpact(_impacts.constantSetLiteral); | |
| } else { | |
| impactBuilder.registerTypeUse( | |
| TypeUse.instantiation( | |
| commonElements.setType(elementMap.getDartType(elementType)), | |
| ), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerMapLiteral( | |
| ir.DartType keyType, | |
| ir.DartType valueType, { | |
| required bool isConst, | |
| required bool isEmpty, | |
| }) { | |
| // TODO(johnniwinther): Use the [isEmpty] property when factory | |
| // constructors are registered directly. | |
| if (isConst) { | |
| registerBackendImpact(_impacts.constantMapLiteral); | |
| } else { | |
| impactBuilder.registerTypeUse( | |
| TypeUse.instantiation( | |
| commonElements.mapType( | |
| elementMap.getDartType(keyType), | |
| elementMap.getDartType(valueType), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerRecordLiteral( | |
| ir.RecordType recordType, { | |
| required bool isConst, | |
| }) { | |
| registerBackendImpact(_impacts.recordInstantiation); | |
| final type = elementMap.getDartType(recordType) as RecordType; | |
| impactBuilder.registerTypeUse(TypeUse.recordInstantiation(type)); | |
| } | |
| @override | |
| void registerNew( | |
| ir.Member target, | |
| ir.InterfaceType type, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ir.LibraryDependency? import, { | |
| required bool isConst, | |
| }) { | |
| ConstructorEntity constructor = elementMap.getConstructor(target); | |
| CallStructure callStructure = CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ); | |
| ImportEntity? deferredImport = elementMap.getImport(import); | |
| impactBuilder.registerStaticUse( | |
| isConst | |
| ? StaticUse.constConstructorInvoke( | |
| constructor, | |
| callStructure, | |
| elementMap.getInterfaceType(type), | |
| deferredImport, | |
| ) | |
| : StaticUse.typedConstructorInvoke( | |
| constructor, | |
| callStructure, | |
| elementMap.getInterfaceType(type), | |
| deferredImport, | |
| ), | |
| ); | |
| if (type.typeArguments.any((ir.DartType type) => type is! ir.DynamicType)) { | |
| registerBackendImpact(_impacts.typeVariableBoundCheck); | |
| } | |
| if (target.isExternal && | |
| constructor.isFromEnvironmentConstructor && | |
| !isConst) { | |
| registerBackendImpact(_impacts.throwUnsupportedError); | |
| // We need to register the external constructor as live below, so don't | |
| // return here. | |
| } | |
| } | |
| @override | |
| void registerConstInstantiation( | |
| ir.Class cls, | |
| List<ir.DartType> typeArguments, | |
| ir.LibraryDependency? import, | |
| ) { | |
| ImportEntity? deferredImport = elementMap.getImport(import); | |
| InterfaceType type = elementMap.createInterfaceType(cls, typeArguments); | |
| impactBuilder.registerTypeUse( | |
| TypeUse.constInstantiation(type, deferredImport), | |
| ); | |
| } | |
| @override | |
| void registerConstSymbolConstructorInvocationNode() { | |
| registerBackendImpact(_impacts.constSymbol); | |
| } | |
| @override | |
| void registerSuperInitializer( | |
| ir.Constructor source, | |
| ir.Constructor target, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| // TODO(johnniwinther): Maybe rewrite `node.target` to point to a | |
| // synthesized unnamed mixin constructor when needed. This would require us | |
| // to consider impact building a required pre-step for inference and | |
| // ssa-building. | |
| ConstructorEntity constructor = elementMap.getSuperConstructor( | |
| source, | |
| target, | |
| ); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.superConstructorInvoke( | |
| constructor, | |
| CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerStaticInvocation( | |
| ir.Procedure procedure, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ir.LibraryDependency? import, | |
| ) { | |
| FunctionEntity target = elementMap.getMethod(procedure); | |
| CallStructure callStructure = CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ); | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| if (commonElements.isExtractTypeArguments(target)) { | |
| _handleExtractTypeArguments(target, dartTypeArguments!, callStructure); | |
| return; | |
| } else { | |
| ImportEntity? deferredImport = elementMap.getImport(import); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke( | |
| target, | |
| callStructure, | |
| dartTypeArguments, | |
| deferredImport, | |
| ), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerForeignStaticInvocationNode(ir.StaticInvocation node) { | |
| switch (elementMap.getForeignKind(node)) { | |
| case ForeignKind.js: | |
| registerNativeImpact(elementMap.getNativeBehaviorForJsCall(node)); | |
| break; | |
| case ForeignKind.jsBuiltin: | |
| registerNativeImpact( | |
| elementMap.getNativeBehaviorForJsBuiltinCall(node), | |
| ); | |
| break; | |
| case ForeignKind.jsEmbeddedGlobal: | |
| registerNativeImpact( | |
| elementMap.getNativeBehaviorForJsEmbeddedGlobalCall(node), | |
| ); | |
| break; | |
| case ForeignKind.jsInterceptorConstant: | |
| InterfaceType? type = elementMap.getInterfaceTypeForJsInterceptorCall( | |
| node, | |
| ); | |
| if (type != null) { | |
| impactBuilder.registerTypeUse(TypeUse.instantiation(type)); | |
| } | |
| break; | |
| case ForeignKind.none: | |
| break; | |
| } | |
| } | |
| void _handleExtractTypeArguments( | |
| FunctionEntity target, | |
| List<DartType> typeArguments, | |
| CallStructure callStructure, | |
| ) { | |
| // extractTypeArguments<Map>(obj, fn) has additional impacts: | |
| // | |
| // 1. All classes implementing Map need to carry type arguments (similar | |
| // to checking `o is Map<K, V>`). | |
| // | |
| // 2. There is an invocation of fn with some number of type arguments. | |
| // | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke(target, callStructure, typeArguments), | |
| ); | |
| if (typeArguments.length != 1) return; | |
| DartType matchedType = typeArguments.single; | |
| if (matchedType is! InterfaceType) return; | |
| InterfaceType interfaceType = matchedType; | |
| ClassEntity cls = interfaceType.element; | |
| InterfaceType thisType = elementMap.elementEnvironment.getThisType(cls); | |
| _registerIsCheckInternal(thisType); | |
| Selector selector = Selector.callClosure( | |
| 0, | |
| const <String>[], | |
| thisType.typeArguments.length, | |
| ); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(selector, null, thisType.typeArguments), | |
| ); | |
| } | |
| @override | |
| void registerStaticTearOff( | |
| ir.Procedure procedure, | |
| ir.LibraryDependency? import, | |
| ) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticTearOff( | |
| elementMap.getMethod(procedure), | |
| elementMap.getImport(import), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerWeakStaticTearOff( | |
| ir.Procedure procedure, | |
| ir.LibraryDependency? import, | |
| ) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.weakStaticTearOff( | |
| elementMap.getMethod(procedure), | |
| elementMap.getImport(import), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerStaticGet(ir.Member member, ir.LibraryDependency? import) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticGet( | |
| elementMap.getMember(member), | |
| elementMap.getImport(import), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerStaticSet(ir.Member member, ir.LibraryDependency? import) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticSet( | |
| elementMap.getMember(member), | |
| elementMap.getImport(import), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerSuperInvocation( | |
| ir.Member target, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| FunctionEntity method = elementMap.getMember(target) as FunctionEntity; | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.superInvoke( | |
| method, | |
| CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ), | |
| dartTypeArguments, | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerSuperGet(ir.Member target) { | |
| MemberEntity member = elementMap.getMember(target); | |
| if (member.isFunction) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.superTearOff(member as FunctionEntity), | |
| ); | |
| } else { | |
| impactBuilder.registerStaticUse(StaticUse.superGet(member)); | |
| } | |
| } | |
| @override | |
| void registerSuperSet(ir.Member target) { | |
| MemberEntity member = elementMap.getMember(target); | |
| if (member is FieldEntity) { | |
| impactBuilder.registerStaticUse(StaticUse.superFieldSet(member)); | |
| } else { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.superSetterSet(member as FunctionEntity), | |
| ); | |
| } | |
| } | |
| @override | |
| void registerLocalFunctionInvocation( | |
| ir.FunctionDeclaration localFunction, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| CallStructure callStructure = CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ); | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| // Invocation of a local function. No need for dynamic use, but | |
| // we need to track the type arguments. | |
| impactBuilder.registerStaticUse( | |
| StaticUse.closureCall( | |
| elementMap.getLocalFunction(localFunction), | |
| callStructure, | |
| dartTypeArguments, | |
| ), | |
| ); | |
| // TODO(johnniwinther): Yet, alas, we need the dynamic use for now. Remove | |
| // this when kernel adds an `isFunctionCall` flag to | |
| // [ir.MethodInvocation]. | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(callStructure.callSelector, null, dartTypeArguments), | |
| ); | |
| } | |
| @override | |
| void registerDynamicInvocation( | |
| ir.DartType receiverType, | |
| ir.Name name, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| Selector selector = elementMap.getInvocationSelector( | |
| name, | |
| positionalArguments, | |
| namedArguments, | |
| typeArguments.length, | |
| ); | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| selector, | |
| _computeReceiverConstraint(receiverType), | |
| dartTypeArguments, | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerFunctionInvocation( | |
| ir.DartType receiverType, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| CallStructure callStructure = CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ); | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| callStructure.callSelector, | |
| _computeReceiverConstraint(receiverType), | |
| dartTypeArguments, | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerInstanceInvocation( | |
| ir.DartType receiverType, | |
| ir.Member target, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| List<DartType>? dartTypeArguments = _getTypeArguments(typeArguments); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| elementMap.getInvocationSelector( | |
| target.name, | |
| positionalArguments, | |
| namedArguments, | |
| typeArguments.length, | |
| ), | |
| _computeReceiverConstraint(receiverType), | |
| dartTypeArguments, | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerDynamicGet(ir.DartType receiverType, ir.Name name) { | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| Selector.getter(elementMap.getName(name)), | |
| _computeReceiverConstraint(receiverType), | |
| const <DartType>[], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerInstanceGet(ir.DartType receiverType, ir.Member target) { | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| Selector.getter(elementMap.getName(target.name)), | |
| _computeReceiverConstraint(receiverType), | |
| const <DartType>[], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerDynamicSet(ir.DartType receiverType, ir.Name name) { | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| Selector.setter(elementMap.getName(name)), | |
| _computeReceiverConstraint(receiverType), | |
| const <DartType>[], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerInstanceSet(ir.DartType receiverType, ir.Member target) { | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse( | |
| Selector.setter(elementMap.getName(target.name)), | |
| _computeReceiverConstraint(receiverType), | |
| const <DartType>[], | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerRuntimeTypeUse( | |
| RuntimeTypeUseKind kind, | |
| ir.DartType receiverType, | |
| ir.DartType? argumentType, | |
| ) { | |
| DartType receiverDartType = elementMap.getDartType(receiverType); | |
| DartType? argumentDartType = argumentType == null | |
| ? null | |
| : elementMap.getDartType(argumentType); | |
| // Enable runtime type support if we discover a getter called | |
| // runtimeType. We have to enable runtime type before hitting the | |
| // codegen, so that constructors know whether they need to generate code | |
| // for runtime type. | |
| _backendUsageBuilder.registerRuntimeTypeUse( | |
| RuntimeTypeUse(kind, receiverDartType, argumentDartType), | |
| ); | |
| } | |
| @override | |
| void registerAssert({required bool withMessage}) { | |
| registerBackendImpact( | |
| withMessage ? _impacts.assertWithMessage : _impacts.assertWithoutMessage, | |
| ); | |
| } | |
| @override | |
| void registerGenericInstantiation( | |
| ir.FunctionType expressionType, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| // TODO(johnniwinther): Track which arities are used in instantiation. | |
| final instantiation = GenericInstantiation( | |
| elementMap.getDartType(expressionType).withoutNullability as FunctionType, | |
| typeArguments.map(elementMap.getDartType).toList(), | |
| ); | |
| registerBackendImpact( | |
| _impacts.getGenericInstantiation(instantiation.typeArguments.length), | |
| ); | |
| _rtiNeedBuilder.registerGenericInstantiation(instantiation); | |
| } | |
| @override | |
| void registerStringConcatenation() { | |
| registerBackendImpact(_impacts.stringInterpolation); | |
| registerBackendImpact(_impacts.stringJuxtaposition); | |
| } | |
| @override | |
| void registerLocalFunction(covariant ir.LocalFunction node) { | |
| Local function = elementMap.getLocalFunction(node); | |
| impactBuilder.registerStaticUse(StaticUse.closure(function)); | |
| registerBackendImpact(_impacts.closure); | |
| registerBackendImpact(_impacts.computeSignature); | |
| } | |
| @override | |
| void registerLocalWithoutInitializer() { | |
| impactBuilder.registerTypeUse( | |
| TypeUse.instantiation(commonElements.nullType), | |
| ); | |
| registerBackendImpact(_impacts.nullLiteral); | |
| } | |
| void _registerIsCheckInternal(DartType type) { | |
| impactBuilder.registerTypeUse(TypeUse.isCheck(type)); | |
| onIsCheck(type); | |
| } | |
| @override | |
| void registerIsCheck(ir.DartType irType) { | |
| _registerIsCheckInternal(elementMap.getDartType(irType)); | |
| } | |
| @override | |
| void registerImplicitCast(ir.DartType irType) { | |
| DartType type = elementMap.getDartType(irType); | |
| impactBuilder.registerTypeUse(TypeUse.implicitCast(type)); | |
| if (_annotationsData | |
| .getImplicitDowncastCheckPolicy(currentMember) | |
| .isEmitted) { | |
| onIsCheck(type); | |
| } | |
| } | |
| @override | |
| void registerAsCast(ir.DartType irType) { | |
| DartType type = elementMap.getDartType(irType); | |
| impactBuilder.registerTypeUse(TypeUse.asCast(type)); | |
| if (_annotationsData.getExplicitCastCheckPolicy(currentMember).isEmitted) { | |
| onIsCheck(type); | |
| registerBackendImpact(_impacts.asCheck); | |
| } | |
| } | |
| @override | |
| void registerThrow() { | |
| registerBackendImpact(_impacts.throwExpression); | |
| } | |
| @override | |
| void registerSyncForIn(ir.DartType iterableType, ir.DartType iteratorType) { | |
| Object? receiverConstraint = _computeReceiverConstraint(iteratorType); | |
| registerBackendImpact(_impacts.syncForIn); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.iterator, receiverConstraint, const []), | |
| ); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.current, receiverConstraint, const []), | |
| ); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.moveNext, receiverConstraint, const []), | |
| ); | |
| } | |
| @override | |
| void registerAsyncForIn(ir.DartType iterableType, ir.DartType iteratorType) { | |
| Object? receiverConstraint = _computeReceiverConstraint(iteratorType); | |
| registerBackendImpact(_impacts.asyncForIn); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.cancel, receiverConstraint, const []), | |
| ); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.current, receiverConstraint, const []), | |
| ); | |
| impactBuilder.registerDynamicUse( | |
| DynamicUse(Selectors.moveNext, receiverConstraint, const []), | |
| ); | |
| } | |
| @override | |
| void registerCatch() { | |
| registerBackendImpact(_impacts.catchStatement); | |
| } | |
| @override | |
| void registerStackTrace() { | |
| registerBackendImpact(_impacts.stackTraceInCatch); | |
| } | |
| @override | |
| void registerCatchType(ir.DartType irType) { | |
| DartType type = elementMap.getDartType(irType); | |
| impactBuilder.registerTypeUse(TypeUse.catchType(type)); | |
| onIsCheck(type); | |
| } | |
| @override | |
| void registerTypeLiteral(ir.DartType irType, ir.LibraryDependency? import) { | |
| ImportEntity? deferredImport = elementMap.getImport(import); | |
| DartType type = elementMap.getDartType(irType); | |
| impactBuilder.registerTypeUse(TypeUse.typeLiteral(type, deferredImport)); | |
| _customElementsResolutionAnalysis.registerTypeLiteral(type); | |
| type.forEachTypeVariable((TypeVariableType variable) { | |
| _rtiNeedBuilder.registerTypeVariableLiteral(variable); | |
| registerBackendImpact(_impacts.typeVariableExpression); | |
| }); | |
| impactBuilder.registerTypeUse( | |
| TypeUse.instantiation(commonElements.typeType), | |
| ); | |
| registerBackendImpact(_impacts.typeLiteral); | |
| } | |
| @override | |
| void registerFieldInitialization(ir.Field node) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.fieldInit(elementMap.getField(node)), | |
| ); | |
| } | |
| @override | |
| void registerFieldConstantInitialization( | |
| ir.Field node, | |
| ConstantReference constant, | |
| ) { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.fieldConstantInit( | |
| elementMap.getField(node), | |
| _constantValuefier.visitConstant(constant.constant), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerRedirectingInitializer( | |
| ir.Constructor constructor, | |
| int positionalArguments, | |
| List<String> namedArguments, | |
| List<ir.DartType> typeArguments, | |
| ) { | |
| ConstructorEntity target = elementMap.getConstructor(constructor); | |
| impactBuilder.registerStaticUse( | |
| StaticUse.superConstructorInvoke( | |
| target, | |
| CallStructure( | |
| positionalArguments + namedArguments.length, | |
| namedArguments, | |
| typeArguments.length, | |
| ), | |
| ), | |
| ); | |
| } | |
| @override | |
| void registerLoadLibrary() { | |
| impactBuilder.registerStaticUse( | |
| StaticUse.staticInvoke( | |
| commonElements.loadDeferredLibrary, | |
| CallStructure.oneArg, | |
| ), | |
| ); | |
| registerBackendImpact(_impacts.loadLibrary); | |
| } | |
| /// Converts a [ImpactData] object based on kernel to the corresponding | |
| /// [WorldImpact] based on the K model. | |
| WorldImpact convert(ImpactData impactData) { | |
| final oldBuilder = _impactBuilder; | |
| final newBuilder = _impactBuilder = WorldImpactBuilderImpl(currentMember); | |
| impactData.apply(this); | |
| _impactBuilder = oldBuilder; | |
| return newBuilder; | |
| } | |
| @override | |
| void registerConditionalImpact(ConditionalImpactData impact) { | |
| final conditionalUse = ConditionalUse.withReplacement( | |
| impact: convert(impact.impactData), | |
| replacementImpact: convert(impact.replacementImpactData), | |
| originalConditions: impact.originalConditions | |
| .map(elementMap.getMember) | |
| .toList(), | |
| original: impact.original, | |
| replacement: impact.replacement, | |
| ); | |
| impactBuilder.registerConditionalUse(conditionalUse); | |
| } | |
| } |