| // Copyright (c) 2017, 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 dart2js.js_model.strategy; |
| |
| import 'package:kernel/ast.dart' as ir; |
| |
| import '../backend_strategy.dart'; |
| import '../closure.dart'; |
| import '../common.dart'; |
| import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| import '../common/tasks.dart'; |
| import '../common_elements.dart'; |
| import '../compiler.dart'; |
| import '../constants/constant_system.dart'; |
| import '../constants/values.dart'; |
| import '../deferred_load.dart'; |
| import '../diagnostics/diagnostic_listener.dart'; |
| import '../elements/entities.dart'; |
| import '../elements/names.dart'; |
| import '../elements/types.dart'; |
| import '../elements/entity_utils.dart' as utils; |
| import '../environment.dart'; |
| import '../enqueue.dart'; |
| import '../io/kernel_source_information.dart' |
| show KernelSourceInformationStrategy; |
| import '../io/source_information.dart'; |
| import '../inferrer/type_graph_inferrer.dart'; |
| import '../js_emitter/sorter.dart'; |
| import '../js/js_source_mapping.dart'; |
| import '../js_backend/annotations.dart'; |
| import '../js_backend/allocator_analysis.dart'; |
| import '../js_backend/backend.dart'; |
| import '../js_backend/backend_usage.dart'; |
| import '../js_backend/constant_system_javascript.dart'; |
| import '../js_backend/inferred_data.dart'; |
| import '../js_backend/interceptor_data.dart'; |
| import '../js_backend/native_data.dart'; |
| import '../js_backend/no_such_method_registry.dart'; |
| import '../js_backend/runtime_types.dart'; |
| import '../kernel/kernel_strategy.dart'; |
| import '../kernel/kelements.dart'; |
| import '../native/behavior.dart'; |
| import '../ordered_typeset.dart'; |
| import '../options.dart'; |
| import '../serialization/serialization.dart'; |
| import '../ssa/builder_kernel.dart'; |
| import '../ssa/nodes.dart'; |
| import '../ssa/ssa.dart'; |
| import '../ssa/types.dart'; |
| import '../types/abstract_value_domain.dart'; |
| import '../types/types.dart'; |
| import '../universe/class_hierarchy.dart'; |
| import '../universe/class_set.dart'; |
| import '../universe/feature.dart'; |
| import '../universe/selector.dart'; |
| import '../universe/world_builder.dart'; |
| import '../universe/world_impact.dart'; |
| import '../world.dart'; |
| import 'closure.dart'; |
| import 'elements.dart'; |
| import 'element_map.dart'; |
| import 'element_map_impl.dart'; |
| import 'locals.dart'; |
| |
| class JsBackendStrategy implements BackendStrategy { |
| final Compiler _compiler; |
| JsKernelToElementMap _elementMap; |
| |
| JsBackendStrategy(this._compiler); |
| |
| @deprecated |
| JsToElementMap get elementMap { |
| assert(_elementMap != null, |
| "JsBackendStrategy.elementMap has not been created yet."); |
| return _elementMap; |
| } |
| |
| ElementEnvironment get _elementEnvironment => _elementMap.elementEnvironment; |
| CommonElements get _commonElements => _elementMap.commonElements; |
| |
| @override |
| JClosedWorld createJClosedWorld( |
| KClosedWorld closedWorld, OutputUnitData outputUnitData) { |
| KernelFrontEndStrategy strategy = _compiler.frontendStrategy; |
| _elementMap = new JsKernelToElementMap( |
| _compiler.reporter, |
| _compiler.environment, |
| strategy.elementMap, |
| closedWorld.processedMembers); |
| GlobalLocalsMap _globalLocalsMap = new GlobalLocalsMap(); |
| ClosureDataBuilder closureDataBuilder = new ClosureDataBuilder( |
| _elementMap, _globalLocalsMap, _compiler.options); |
| JsClosedWorldBuilder closedWorldBuilder = new JsClosedWorldBuilder( |
| _elementMap, |
| _globalLocalsMap, |
| closureDataBuilder, |
| _compiler.options, |
| _compiler.abstractValueStrategy); |
| return closedWorldBuilder._convertClosedWorld( |
| closedWorld, strategy.closureModels, outputUnitData); |
| } |
| |
| @override |
| void registerJClosedWorld(covariant JsClosedWorld closedWorld) { |
| _elementMap = closedWorld.elementMap; |
| } |
| |
| @override |
| SourceInformationStrategy get sourceInformationStrategy { |
| if (!_compiler.options.generateSourceMap) { |
| return const JavaScriptSourceInformationStrategy(); |
| } |
| return new KernelSourceInformationStrategy(this); |
| } |
| |
| @override |
| SsaBuilder createSsaBuilder(CompilerTask task, JavaScriptBackend backend, |
| SourceInformationStrategy sourceInformationStrategy) { |
| return new KernelSsaBuilder(task, backend.compiler, elementMap); |
| } |
| |
| @override |
| WorkItemBuilder createCodegenWorkItemBuilder(JClosedWorld closedWorld, |
| GlobalTypeInferenceResults globalInferenceResults) { |
| return new KernelCodegenWorkItemBuilder( |
| _compiler.backend, closedWorld, globalInferenceResults); |
| } |
| |
| @override |
| CodegenWorldBuilder createCodegenWorldBuilder( |
| NativeBasicData nativeBasicData, |
| covariant JsClosedWorld closedWorld, |
| SelectorConstraintsStrategy selectorConstraintsStrategy) { |
| return new CodegenWorldBuilderImpl( |
| closedWorld.elementMap, closedWorld, selectorConstraintsStrategy); |
| } |
| |
| @override |
| SourceSpan spanFromSpannable(Spannable spannable, Entity currentElement) { |
| return _elementMap.getSourceSpan(spannable, currentElement); |
| } |
| |
| @override |
| TypesInferrer createTypesInferrer( |
| JClosedWorld closedWorld, InferredDataBuilder inferredDataBuilder) { |
| return new TypeGraphInferrer(_compiler, closedWorld, inferredDataBuilder); |
| } |
| } |
| |
| class JsClosedWorldBuilder { |
| final JsKernelToElementMap _elementMap; |
| final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes = |
| new ClassHierarchyNodesMap(); |
| final Map<ClassEntity, ClassSet> _classSets = <ClassEntity, ClassSet>{}; |
| final GlobalLocalsMap _globalLocalsMap; |
| final ClosureDataBuilder _closureDataBuilder; |
| final CompilerOptions _options; |
| final AbstractValueStrategy _abstractValueStrategy; |
| |
| JsClosedWorldBuilder(this._elementMap, this._globalLocalsMap, |
| this._closureDataBuilder, this._options, this._abstractValueStrategy); |
| |
| ElementEnvironment get _elementEnvironment => _elementMap.elementEnvironment; |
| CommonElements get _commonElements => _elementMap.commonElements; |
| |
| JsClosedWorld _convertClosedWorld( |
| KClosedWorld closedWorld, |
| Map<MemberEntity, ScopeModel> closureModels, |
| OutputUnitData kOutputUnitData) { |
| JsToFrontendMap map = new JsToFrontendMapImpl(_elementMap); |
| |
| BackendUsage backendUsage = |
| _convertBackendUsage(map, closedWorld.backendUsage); |
| NativeData nativeData = _convertNativeData(map, closedWorld.nativeData); |
| _elementMap.nativeBasicData = nativeData; |
| InterceptorData interceptorData = |
| _convertInterceptorData(map, nativeData, closedWorld.interceptorData); |
| |
| Set<ClassEntity> implementedClasses = new Set<ClassEntity>(); |
| |
| /// Converts [node] from the frontend world to the corresponding |
| /// [ClassHierarchyNode] for the backend world. |
| ClassHierarchyNode convertClassHierarchyNode(ClassHierarchyNode node) { |
| ClassEntity cls = map.toBackendClass(node.cls); |
| if (closedWorld.isImplemented(node.cls)) { |
| implementedClasses.add(cls); |
| } |
| ClassHierarchyNode newNode = _classHierarchyNodes.putIfAbsent(cls, () { |
| ClassHierarchyNode parentNode; |
| if (node.parentNode != null) { |
| parentNode = convertClassHierarchyNode(node.parentNode); |
| } |
| return new ClassHierarchyNode(parentNode, cls, node.hierarchyDepth); |
| }); |
| newNode.isAbstractlyInstantiated = node.isAbstractlyInstantiated; |
| newNode.isDirectlyInstantiated = node.isDirectlyInstantiated; |
| return newNode; |
| } |
| |
| /// Converts [classSet] from the frontend world to the corresponding |
| /// [ClassSet] for the backend world. |
| ClassSet convertClassSet(ClassSet classSet) { |
| ClassEntity cls = map.toBackendClass(classSet.cls); |
| return _classSets.putIfAbsent(cls, () { |
| ClassHierarchyNode newNode = convertClassHierarchyNode(classSet.node); |
| ClassSet newClassSet = new ClassSet(newNode); |
| for (ClassHierarchyNode subtype in classSet.subtypeNodes) { |
| ClassHierarchyNode newSubtype = convertClassHierarchyNode(subtype); |
| newClassSet.addSubtype(newSubtype); |
| } |
| return newClassSet; |
| }); |
| } |
| |
| closedWorld.classHierarchy |
| .getClassHierarchyNode(closedWorld.commonElements.objectClass) |
| .forEachSubclass((ClassEntity cls) { |
| convertClassSet(closedWorld.classHierarchy.getClassSet(cls)); |
| }, ClassHierarchyNode.ALL); |
| |
| Set<MemberEntity> liveInstanceMembers = |
| map.toBackendMemberSet(closedWorld.liveInstanceMembers); |
| |
| Map<ClassEntity, Set<ClassEntity>> mixinUses = |
| map.toBackendClassMap(closedWorld.mixinUses, map.toBackendClassSet); |
| |
| Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses = |
| map.toBackendClassMap( |
| closedWorld.typesImplementedBySubclasses, map.toBackendClassSet); |
| |
| Iterable<MemberEntity> assignedInstanceMembers = |
| map.toBackendMemberSet(closedWorld.assignedInstanceMembers); |
| |
| Iterable<ClassEntity> liveNativeClasses = |
| map.toBackendClassSet(closedWorld.liveNativeClasses); |
| |
| Iterable<MemberEntity> processedMembers = |
| map.toBackendMemberSet(closedWorld.processedMembers); |
| |
| RuntimeTypesNeed rtiNeed; |
| |
| List<FunctionEntity> callMethods = <FunctionEntity>[]; |
| ClosureData closureData; |
| if (_options.disableRtiOptimization) { |
| rtiNeed = new TrivialRuntimeTypesNeed(); |
| closureData = _closureDataBuilder.createClosureEntities( |
| this, |
| map.toBackendMemberMap(closureModels, identity), |
| const TrivialClosureRtiNeed(), |
| callMethods); |
| } else { |
| RuntimeTypesNeedImpl kernelRtiNeed = closedWorld.rtiNeed; |
| Set<ir.Node> localFunctionsNodesNeedingSignature = new Set<ir.Node>(); |
| for (KLocalFunction localFunction |
| in kernelRtiNeed.localFunctionsNeedingSignature) { |
| ir.Node node = localFunction.node; |
| assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression, |
| "Unexpected local function node: $node"); |
| localFunctionsNodesNeedingSignature.add(node); |
| } |
| Set<ir.Node> localFunctionsNodesNeedingTypeArguments = new Set<ir.Node>(); |
| for (KLocalFunction localFunction |
| in kernelRtiNeed.localFunctionsNeedingTypeArguments) { |
| ir.Node node = localFunction.node; |
| assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression, |
| "Unexpected local function node: $node"); |
| localFunctionsNodesNeedingTypeArguments.add(node); |
| } |
| |
| RuntimeTypesNeedImpl jRtiNeed = |
| _convertRuntimeTypesNeed(map, backendUsage, kernelRtiNeed); |
| closureData = _closureDataBuilder.createClosureEntities( |
| this, |
| map.toBackendMemberMap(closureModels, identity), |
| new JsClosureRtiNeed( |
| jRtiNeed, |
| localFunctionsNodesNeedingTypeArguments, |
| localFunctionsNodesNeedingSignature), |
| callMethods); |
| |
| List<FunctionEntity> callMethodsNeedingSignature = <FunctionEntity>[]; |
| for (ir.Node node in localFunctionsNodesNeedingSignature) { |
| callMethodsNeedingSignature |
| .add(closureData.getClosureInfo(node).callMethod); |
| } |
| List<FunctionEntity> callMethodsNeedingTypeArguments = <FunctionEntity>[]; |
| for (ir.Node node in localFunctionsNodesNeedingTypeArguments) { |
| callMethodsNeedingTypeArguments |
| .add(closureData.getClosureInfo(node).callMethod); |
| } |
| jRtiNeed.methodsNeedingSignature.addAll(callMethodsNeedingSignature); |
| jRtiNeed.methodsNeedingTypeArguments |
| .addAll(callMethodsNeedingTypeArguments); |
| |
| rtiNeed = jRtiNeed; |
| } |
| |
| NoSuchMethodDataImpl oldNoSuchMethodData = closedWorld.noSuchMethodData; |
| NoSuchMethodData noSuchMethodData = new NoSuchMethodDataImpl( |
| map.toBackendFunctionSet(oldNoSuchMethodData.throwingImpls), |
| map.toBackendFunctionSet(oldNoSuchMethodData.otherImpls), |
| map.toBackendFunctionSet(oldNoSuchMethodData.forwardingSyntaxImpls)); |
| |
| JAllocatorAnalysis allocatorAnalysis = |
| JAllocatorAnalysis.from(closedWorld.allocatorAnalysis, map, _options); |
| |
| AnnotationsData annotationsData = new AnnotationsDataImpl( |
| map.toBackendFunctionSet( |
| closedWorld.annotationsData.nonInlinableFunctions), |
| map.toBackendFunctionSet( |
| closedWorld.annotationsData.tryInlineFunctions), |
| map.toBackendFunctionSet( |
| closedWorld.annotationsData.cannotThrowFunctions), |
| map.toBackendFunctionSet( |
| closedWorld.annotationsData.sideEffectFreeFunctions), |
| map.toBackendMemberSet( |
| closedWorld.annotationsData.trustTypeAnnotationsMembers), |
| map.toBackendMemberSet( |
| closedWorld.annotationsData.assumeDynamicMembers)); |
| |
| OutputUnitData outputUnitData = |
| _convertOutputUnitData(map, kOutputUnitData, closureData); |
| |
| return new JsClosedWorld(_elementMap, |
| backendUsage: backendUsage, |
| noSuchMethodData: noSuchMethodData, |
| nativeData: nativeData, |
| interceptorData: interceptorData, |
| rtiNeed: rtiNeed, |
| classHierarchy: new ClassHierarchyImpl( |
| _elementMap.commonElements, _classHierarchyNodes, _classSets), |
| implementedClasses: implementedClasses, |
| liveNativeClasses: liveNativeClasses, |
| // TODO(johnniwinther): Include the call method when we can also |
| // represent the synthesized call methods for static and instance method |
| // closurizations. |
| liveInstanceMembers: liveInstanceMembers /*..addAll(callMethods)*/, |
| assignedInstanceMembers: assignedInstanceMembers, |
| processedMembers: processedMembers, |
| mixinUses: mixinUses, |
| typesImplementedBySubclasses: typesImplementedBySubclasses, |
| abstractValueStrategy: _abstractValueStrategy, |
| allocatorAnalysis: allocatorAnalysis, |
| annotationsData: annotationsData, |
| globalLocalsMap: _globalLocalsMap, |
| closureDataLookup: closureData, |
| outputUnitData: outputUnitData); |
| } |
| |
| BackendUsage _convertBackendUsage( |
| JsToFrontendMap map, BackendUsageImpl backendUsage) { |
| Set<FunctionEntity> globalFunctionDependencies = |
| map.toBackendFunctionSet(backendUsage.globalFunctionDependencies); |
| Set<ClassEntity> globalClassDependencies = |
| map.toBackendClassSet(backendUsage.globalClassDependencies); |
| Set<FunctionEntity> helperFunctionsUsed = |
| map.toBackendFunctionSet(backendUsage.helperFunctionsUsed); |
| Set<ClassEntity> helperClassesUsed = |
| map.toBackendClassSet(backendUsage.helperClassesUsed); |
| Set<RuntimeTypeUse> runtimeTypeUses = |
| backendUsage.runtimeTypeUses.map((RuntimeTypeUse runtimeTypeUse) { |
| return new RuntimeTypeUse( |
| runtimeTypeUse.kind, |
| map.toBackendType(runtimeTypeUse.receiverType), |
| map.toBackendType(runtimeTypeUse.argumentType)); |
| }).toSet(); |
| |
| return new BackendUsageImpl( |
| globalFunctionDependencies: globalFunctionDependencies, |
| globalClassDependencies: globalClassDependencies, |
| helperFunctionsUsed: helperFunctionsUsed, |
| helperClassesUsed: helperClassesUsed, |
| needToInitializeIsolateAffinityTag: |
| backendUsage.needToInitializeIsolateAffinityTag, |
| needToInitializeDispatchProperty: |
| backendUsage.needToInitializeDispatchProperty, |
| requiresPreamble: backendUsage.requiresPreamble, |
| runtimeTypeUses: runtimeTypeUses, |
| isFunctionApplyUsed: backendUsage.isFunctionApplyUsed, |
| isMirrorsUsed: backendUsage.isMirrorsUsed, |
| isNoSuchMethodUsed: backendUsage.isNoSuchMethodUsed); |
| } |
| |
| NativeBasicData _convertNativeBasicData( |
| JsToFrontendMap map, NativeBasicDataImpl nativeBasicData) { |
| Map<ClassEntity, NativeClassTag> nativeClassTagInfo = |
| <ClassEntity, NativeClassTag>{}; |
| nativeBasicData.nativeClassTagInfo |
| .forEach((ClassEntity cls, NativeClassTag tag) { |
| nativeClassTagInfo[map.toBackendClass(cls)] = tag; |
| }); |
| Map<LibraryEntity, String> jsInteropLibraries = |
| map.toBackendLibraryMap(nativeBasicData.jsInteropLibraries, identity); |
| Map<ClassEntity, String> jsInteropClasses = |
| map.toBackendClassMap(nativeBasicData.jsInteropClasses, identity); |
| Set<ClassEntity> anonymousJsInteropClasses = |
| map.toBackendClassSet(nativeBasicData.anonymousJsInteropClasses); |
| Map<MemberEntity, String> jsInteropMembers = |
| map.toBackendMemberMap(nativeBasicData.jsInteropMembers, identity); |
| return new NativeBasicDataImpl( |
| _elementEnvironment, |
| nativeClassTagInfo, |
| jsInteropLibraries, |
| jsInteropClasses, |
| anonymousJsInteropClasses, |
| jsInteropMembers); |
| } |
| |
| NativeData _convertNativeData( |
| JsToFrontendMap map, NativeDataImpl nativeData) { |
| convertNativeBehaviorType(type) { |
| if (type is DartType) return map.toBackendType(type); |
| assert(type is SpecialType); |
| return type; |
| } |
| |
| NativeBehavior convertNativeBehavior(NativeBehavior behavior) { |
| NativeBehavior newBehavior = new NativeBehavior(); |
| |
| for (dynamic type in behavior.typesReturned) { |
| newBehavior.typesReturned.add(convertNativeBehaviorType(type)); |
| } |
| for (dynamic type in behavior.typesInstantiated) { |
| newBehavior.typesInstantiated.add(convertNativeBehaviorType(type)); |
| } |
| |
| newBehavior.codeTemplateText = behavior.codeTemplateText; |
| newBehavior.codeTemplate = behavior.codeTemplate; |
| newBehavior.throwBehavior = behavior.throwBehavior; |
| newBehavior.isAllocation = behavior.isAllocation; |
| newBehavior.useGvn = behavior.useGvn; |
| return newBehavior; |
| } |
| |
| NativeBasicData nativeBasicData = _convertNativeBasicData(map, nativeData); |
| |
| Map<MemberEntity, String> nativeMemberName = |
| map.toBackendMemberMap(nativeData.nativeMemberName, identity); |
| Map<FunctionEntity, NativeBehavior> nativeMethodBehavior = |
| <FunctionEntity, NativeBehavior>{}; |
| nativeData.nativeMethodBehavior |
| .forEach((FunctionEntity method, NativeBehavior behavior) { |
| FunctionEntity backendMethod = map.toBackendMember(method); |
| if (backendMethod != null) { |
| // If [method] isn't used it doesn't have a corresponding backend |
| // method. |
| nativeMethodBehavior[backendMethod] = convertNativeBehavior(behavior); |
| } |
| }); |
| Map<MemberEntity, NativeBehavior> nativeFieldLoadBehavior = |
| map.toBackendMemberMap( |
| nativeData.nativeFieldLoadBehavior, convertNativeBehavior); |
| Map<MemberEntity, NativeBehavior> nativeFieldStoreBehavior = |
| map.toBackendMemberMap( |
| nativeData.nativeFieldStoreBehavior, convertNativeBehavior); |
| Map<LibraryEntity, String> jsInteropLibraryNames = |
| map.toBackendLibraryMap(nativeData.jsInteropLibraries, identity); |
| Set<ClassEntity> anonymousJsInteropClasses = |
| map.toBackendClassSet(nativeData.anonymousJsInteropClasses); |
| Map<ClassEntity, String> jsInteropClassNames = |
| map.toBackendClassMap(nativeData.jsInteropClasses, identity); |
| Map<MemberEntity, String> jsInteropMemberNames = |
| map.toBackendMemberMap(nativeData.jsInteropMembers, identity); |
| |
| return new NativeDataImpl( |
| nativeBasicData, |
| nativeMemberName, |
| nativeMethodBehavior, |
| nativeFieldLoadBehavior, |
| nativeFieldStoreBehavior, |
| jsInteropLibraryNames, |
| anonymousJsInteropClasses, |
| jsInteropClassNames, |
| jsInteropMemberNames); |
| } |
| |
| InterceptorData _convertInterceptorData(JsToFrontendMap map, |
| NativeData nativeData, InterceptorDataImpl interceptorData) { |
| Map<String, Set<MemberEntity>> interceptedMembers = |
| <String, Set<MemberEntity>>{}; |
| interceptorData.interceptedMembers |
| .forEach((String name, Set<MemberEntity> members) { |
| interceptedMembers[name] = map.toBackendMemberSet(members); |
| }); |
| return new InterceptorDataImpl( |
| nativeData, |
| _commonElements, |
| interceptedMembers, |
| map.toBackendClassSet(interceptorData.interceptedClasses), |
| map.toBackendClassSet( |
| interceptorData.classesMixedIntoInterceptedClasses)); |
| } |
| |
| RuntimeTypesNeed _convertRuntimeTypesNeed(JsToFrontendMap map, |
| BackendUsage backendUsage, RuntimeTypesNeedImpl rtiNeed) { |
| Set<ClassEntity> classesNeedingTypeArguments = |
| map.toBackendClassSet(rtiNeed.classesNeedingTypeArguments); |
| Set<FunctionEntity> methodsNeedingTypeArguments = |
| map.toBackendFunctionSet(rtiNeed.methodsNeedingTypeArguments); |
| Set<FunctionEntity> methodsNeedingSignature = |
| map.toBackendFunctionSet(rtiNeed.methodsNeedingSignature); |
| Set<Selector> selectorsNeedingTypeArguments = |
| rtiNeed.selectorsNeedingTypeArguments.map((Selector selector) { |
| if (selector.memberName.isPrivate) { |
| return new Selector( |
| selector.kind, |
| new PrivateName(selector.memberName.text, |
| map.toBackendLibrary(selector.memberName.library), |
| isSetter: selector.memberName.isSetter), |
| selector.callStructure); |
| } |
| return selector; |
| }).toSet(); |
| return new RuntimeTypesNeedImpl( |
| _elementEnvironment, |
| classesNeedingTypeArguments, |
| methodsNeedingSignature, |
| methodsNeedingTypeArguments, |
| null, |
| null, |
| selectorsNeedingTypeArguments, |
| rtiNeed.instantiationsNeedingTypeArguments); |
| } |
| |
| /// Construct a closure class and set up the necessary class inference |
| /// hierarchy. |
| KernelClosureClassInfo buildClosureClass( |
| MemberEntity member, |
| ir.FunctionNode originalClosureFunctionNode, |
| JLibrary enclosingLibrary, |
| Map<Local, JRecordField> boxedVariables, |
| KernelScopeInfo info, |
| KernelToLocalsMap localsMap, |
| {bool createSignatureMethod}) { |
| ClassEntity superclass = _commonElements.closureClass; |
| |
| KernelClosureClassInfo closureClassInfo = _elementMap.constructClosureClass( |
| member, |
| originalClosureFunctionNode, |
| enclosingLibrary, |
| boxedVariables, |
| info, |
| localsMap, |
| new InterfaceType(superclass, const []), |
| createSignatureMethod: createSignatureMethod); |
| |
| // Tell the hierarchy that this is the super class. then we can use |
| // .getSupertypes(class) |
| ClassHierarchyNode parentNode = _classHierarchyNodes[superclass]; |
| ClassHierarchyNode node = new ClassHierarchyNode(parentNode, |
| closureClassInfo.closureClassEntity, parentNode.hierarchyDepth + 1); |
| _classHierarchyNodes[closureClassInfo.closureClassEntity] = node; |
| _classSets[closureClassInfo.closureClassEntity] = new ClassSet(node); |
| node.isDirectlyInstantiated = true; |
| |
| return closureClassInfo; |
| } |
| |
| OutputUnitData _convertOutputUnitData(JsToFrontendMapImpl map, |
| OutputUnitData data, ClosureData closureDataLookup) { |
| Entity toBackendEntity(Entity entity) { |
| if (entity is ClassEntity) return map.toBackendClass(entity); |
| if (entity is MemberEntity) return map.toBackendMember(entity); |
| if (entity is TypedefEntity) return map.toBackendTypedef(entity); |
| if (entity is TypeVariableEntity) { |
| return map.toBackendTypeVariable(entity); |
| } |
| assert( |
| entity is LibraryEntity, 'unexpected entity ${entity.runtimeType}'); |
| return map.toBackendLibrary(entity); |
| } |
| |
| // Convert front-end maps containing K-class and K-local function keys to a |
| // backend map using J-classes as keys. |
| Map<ClassEntity, OutputUnit> convertClassMap( |
| Map<ClassEntity, OutputUnit> classMap, |
| Map<Local, OutputUnit> localFunctionMap) { |
| var result = <ClassEntity, OutputUnit>{}; |
| classMap.forEach((ClassEntity entity, OutputUnit unit) { |
| ClassEntity backendEntity = toBackendEntity(entity); |
| if (backendEntity != null) { |
| // If [entity] isn't used it doesn't have a corresponding backend |
| // entity. |
| result[backendEntity] = unit; |
| } |
| }); |
| localFunctionMap.forEach((Local entity, OutputUnit unit) { |
| // Ensure closure classes are included in the output unit corresponding |
| // to the local function. |
| if (entity is KLocalFunction) { |
| var closureInfo = closureDataLookup.getClosureInfo(entity.node); |
| result[closureInfo.closureClassEntity] = unit; |
| } |
| }); |
| return result; |
| } |
| |
| // Convert front-end maps containing K-member and K-local function keys to |
| // a backend map using J-members as keys. |
| Map<MemberEntity, OutputUnit> convertMemberMap( |
| Map<MemberEntity, OutputUnit> memberMap, |
| Map<Local, OutputUnit> localFunctionMap) { |
| var result = <MemberEntity, OutputUnit>{}; |
| memberMap.forEach((MemberEntity entity, OutputUnit unit) { |
| MemberEntity backendEntity = toBackendEntity(entity); |
| if (backendEntity != null) { |
| // If [entity] isn't used it doesn't have a corresponding backend |
| // entity. |
| result[backendEntity] = unit; |
| } |
| }); |
| localFunctionMap.forEach((Local entity, OutputUnit unit) { |
| // Ensure closure call-methods are included in the output unit |
| // corresponding to the local function. |
| if (entity is KLocalFunction) { |
| var closureInfo = closureDataLookup.getClosureInfo(entity.node); |
| result[closureInfo.callMethod] = unit; |
| } |
| }); |
| return result; |
| } |
| |
| ConstantValue toBackendConstant(ConstantValue constant) { |
| return constant.accept(new ConstantConverter(toBackendEntity), null); |
| } |
| |
| return new OutputUnitData.from( |
| data, |
| convertClassMap, |
| convertMemberMap, |
| (m) => convertMap<ConstantValue, OutputUnit>( |
| m, toBackendConstant, (v) => v)); |
| } |
| } |
| |
| class JsClosedWorld extends ClosedWorldBase { |
| static const String tag = 'closed-world'; |
| |
| final JsKernelToElementMap elementMap; |
| final RuntimeTypesNeed rtiNeed; |
| AbstractValueDomain _abstractValueDomain; |
| final JAllocatorAnalysis allocatorAnalysis; |
| final AnnotationsData annotationsData; |
| final GlobalLocalsMap globalLocalsMap; |
| final ClosureData closureDataLookup; |
| final OutputUnitData outputUnitData; |
| Sorter _sorter; |
| |
| JsClosedWorld(this.elementMap, |
| {ConstantSystem constantSystem, |
| NativeData nativeData, |
| InterceptorData interceptorData, |
| BackendUsage backendUsage, |
| this.rtiNeed, |
| this.allocatorAnalysis, |
| NoSuchMethodData noSuchMethodData, |
| Iterable<ClassEntity> implementedClasses, |
| Iterable<ClassEntity> liveNativeClasses, |
| Iterable<MemberEntity> liveInstanceMembers, |
| Iterable<MemberEntity> assignedInstanceMembers, |
| Iterable<MemberEntity> processedMembers, |
| Map<ClassEntity, Set<ClassEntity>> mixinUses, |
| Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses, |
| ClassHierarchy classHierarchy, |
| AbstractValueStrategy abstractValueStrategy, |
| this.annotationsData, |
| this.globalLocalsMap, |
| this.closureDataLookup, |
| this.outputUnitData}) |
| : super( |
| elementMap.elementEnvironment, |
| elementMap.types, |
| elementMap.commonElements, |
| JavaScriptConstantSystem.only, |
| nativeData, |
| interceptorData, |
| backendUsage, |
| noSuchMethodData, |
| implementedClasses, |
| liveNativeClasses, |
| liveInstanceMembers, |
| assignedInstanceMembers, |
| processedMembers, |
| mixinUses, |
| typesImplementedBySubclasses, |
| classHierarchy) { |
| _abstractValueDomain = abstractValueStrategy.createDomain(this); |
| } |
| |
| /// Deserializes a [JsClosedWorld] object from [source]. |
| factory JsClosedWorld.readFromDataSource( |
| CompilerOptions options, |
| DiagnosticReporter reporter, |
| Environment environment, |
| AbstractValueStrategy abstractValueStrategy, |
| ir.Component component, |
| DataSource source) { |
| source.begin(tag); |
| |
| JsKernelToElementMap elementMap = |
| new JsKernelToElementMap.readFromDataSource( |
| options, reporter, environment, component, source); |
| GlobalLocalsMap globalLocalsMap = |
| new GlobalLocalsMap.readFromDataSource(source); |
| source.registerLocalLookup(new LocalLookupImpl(globalLocalsMap)); |
| ClassHierarchy classHierarchy = new ClassHierarchy.readFromDataSource( |
| source, elementMap.commonElements); |
| NativeData nativeData = new NativeData.readFromDataSource( |
| source, elementMap.elementEnvironment); |
| elementMap.nativeBasicData = nativeData; |
| InterceptorData interceptorData = new InterceptorData.readFromDataSource( |
| source, nativeData, elementMap.commonElements); |
| BackendUsage backendUsage = new BackendUsage.readFromDataSource(source); |
| RuntimeTypesNeed rtiNeed = new RuntimeTypesNeed.readFromDataSource( |
| source, elementMap.elementEnvironment); |
| JAllocatorAnalysis allocatorAnalysis = |
| new JAllocatorAnalysis.readFromDataSource(source, options); |
| NoSuchMethodData noSuchMethodData = |
| new NoSuchMethodData.readFromDataSource(source); |
| |
| Set<ClassEntity> implementedClasses = source.readClasses().toSet(); |
| Iterable<ClassEntity> liveNativeClasses = source.readClasses(); |
| Iterable<MemberEntity> liveInstanceMembers = source.readMembers(); |
| Iterable<MemberEntity> assignedInstanceMembers = source.readMembers(); |
| Iterable<MemberEntity> processedMembers = source.readMembers(); |
| Map<ClassEntity, Set<ClassEntity>> mixinUses = |
| source.readClassMap(() => source.readClasses().toSet()); |
| Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses = |
| source.readClassMap(() => source.readClasses().toSet()); |
| |
| AnnotationsData annotationsData = |
| new AnnotationsData.readFromDataSource(source); |
| |
| ClosureData closureData = |
| new ClosureData.readFromDataSource(elementMap, source); |
| |
| OutputUnitData outputUnitData = |
| new OutputUnitData.readFromDataSource(source); |
| |
| source.end(tag); |
| |
| return new JsClosedWorld(elementMap, |
| nativeData: nativeData, |
| interceptorData: interceptorData, |
| backendUsage: backendUsage, |
| rtiNeed: rtiNeed, |
| allocatorAnalysis: allocatorAnalysis, |
| noSuchMethodData: noSuchMethodData, |
| implementedClasses: implementedClasses, |
| liveNativeClasses: liveNativeClasses, |
| liveInstanceMembers: liveInstanceMembers, |
| assignedInstanceMembers: assignedInstanceMembers, |
| processedMembers: processedMembers, |
| mixinUses: mixinUses, |
| typesImplementedBySubclasses: typesImplementedBySubclasses, |
| classHierarchy: classHierarchy, |
| abstractValueStrategy: abstractValueStrategy, |
| annotationsData: annotationsData, |
| globalLocalsMap: globalLocalsMap, |
| closureDataLookup: closureData, |
| outputUnitData: outputUnitData); |
| } |
| |
| /// Serializes this [JsClosedWorld] to [sink]. |
| void writeToDataSink(DataSink sink) { |
| sink.begin(tag); |
| elementMap.writeToDataSink(sink); |
| globalLocalsMap.writeToDataSink(sink); |
| |
| classHierarchy.writeToDataSink(sink); |
| nativeData.writeToDataSink(sink); |
| interceptorData.writeToDataSink(sink); |
| backendUsage.writeToDataSink(sink); |
| rtiNeed.writeToDataSink(sink); |
| allocatorAnalysis.writeToDataSink(sink); |
| noSuchMethodData.writeToDataSink(sink); |
| sink.writeClasses(implementedClasses); |
| sink.writeClasses(liveNativeClasses); |
| sink.writeMembers(liveInstanceMembers); |
| sink.writeMembers(assignedInstanceMembers); |
| sink.writeMembers(processedMembers); |
| sink.writeClassMap( |
| mixinUses, (Set<ClassEntity> set) => sink.writeClasses(set)); |
| sink.writeClassMap(typesImplementedBySubclasses, |
| (Set<ClassEntity> set) => sink.writeClasses(set)); |
| annotationsData.writeToDataSink(sink); |
| closureDataLookup.writeToDataSink(sink); |
| outputUnitData.writeToDataSink(sink); |
| sink.end(tag); |
| } |
| |
| @override |
| Sorter get sorter { |
| return _sorter ??= new KernelSorter(elementMap); |
| } |
| |
| @override |
| AbstractValueDomain get abstractValueDomain { |
| return _abstractValueDomain; |
| } |
| |
| @override |
| bool hasElementIn(ClassEntity cls, Selector selector, Entity element) { |
| while (cls != null) { |
| MemberEntity member = elementEnvironment.lookupLocalClassMember( |
| cls, selector.name, |
| setter: selector.isSetter); |
| if (member != null && |
| !member.isAbstract && |
| (!selector.memberName.isPrivate || |
| member.library == selector.library)) { |
| return member == element; |
| } |
| cls = elementEnvironment.getSuperClass(cls); |
| } |
| return false; |
| } |
| |
| @override |
| bool hasConcreteMatch(ClassEntity cls, Selector selector, |
| {ClassEntity stopAtSuperclass}) { |
| assert(classHierarchy.isInstantiated(cls), |
| failedAt(cls, '$cls has not been instantiated.')); |
| MemberEntity element = elementEnvironment |
| .lookupClassMember(cls, selector.name, setter: selector.isSetter); |
| if (element == null) return false; |
| |
| if (element.isAbstract) { |
| ClassEntity enclosingClass = element.enclosingClass; |
| return hasConcreteMatch( |
| elementEnvironment.getSuperClass(enclosingClass), selector); |
| } |
| return selector.appliesUntyped(element); |
| } |
| |
| @override |
| bool isNamedMixinApplication(ClassEntity cls) { |
| return elementMap.elementEnvironment.isMixinApplication(cls) && |
| !elementMap.elementEnvironment.isUnnamedMixinApplication(cls); |
| } |
| |
| @override |
| ClassEntity getAppliedMixin(ClassEntity cls) { |
| return elementMap.getAppliedMixin(cls); |
| } |
| |
| @override |
| Iterable<ClassEntity> getInterfaces(ClassEntity cls) { |
| return elementMap.getInterfaces(cls).map((t) => t.element); |
| } |
| |
| @override |
| ClassEntity getSuperClass(ClassEntity cls) { |
| return elementMap.getSuperType(cls)?.element; |
| } |
| |
| @override |
| int getHierarchyDepth(ClassEntity cls) { |
| return elementMap.getHierarchyDepth(cls); |
| } |
| |
| @override |
| OrderedTypeSet getOrderedTypeSet(ClassEntity cls) { |
| return elementMap.getOrderedTypeSet(cls); |
| } |
| } |
| |
| class ConstantConverter implements ConstantValueVisitor<ConstantValue, Null> { |
| final Entity Function(Entity) toBackendEntity; |
| final TypeConverter typeConverter; |
| |
| ConstantConverter(this.toBackendEntity) |
| : typeConverter = new TypeConverter(toBackendEntity); |
| |
| ConstantValue visitNull(NullConstantValue constant, _) => constant; |
| ConstantValue visitInt(IntConstantValue constant, _) => constant; |
| ConstantValue visitDouble(DoubleConstantValue constant, _) => constant; |
| ConstantValue visitBool(BoolConstantValue constant, _) => constant; |
| ConstantValue visitString(StringConstantValue constant, _) => constant; |
| ConstantValue visitSynthetic(SyntheticConstantValue constant, _) => constant; |
| ConstantValue visitNonConstant(NonConstantValue constant, _) => constant; |
| |
| ConstantValue visitFunction(FunctionConstantValue constant, _) { |
| return new FunctionConstantValue(toBackendEntity(constant.element), |
| typeConverter.convert(constant.type)); |
| } |
| |
| ConstantValue visitList(ListConstantValue constant, _) { |
| var type = typeConverter.convert(constant.type); |
| List<ConstantValue> entries = _handleValues(constant.entries); |
| if (identical(entries, constant.entries) && type == constant.type) { |
| return constant; |
| } |
| return new ListConstantValue(type, entries); |
| } |
| |
| ConstantValue visitMap(MapConstantValue constant, _) { |
| var type = typeConverter.convert(constant.type); |
| List<ConstantValue> keys = _handleValues(constant.keys); |
| List<ConstantValue> values = _handleValues(constant.values); |
| if (identical(keys, constant.keys) && |
| identical(values, constant.values) && |
| type == constant.type) { |
| return constant; |
| } |
| return new MapConstantValue(type, keys, values); |
| } |
| |
| ConstantValue visitConstructed(ConstructedConstantValue constant, _) { |
| var type = typeConverter.convert(constant.type); |
| if (type == constant.type && constant.fields.isEmpty) { |
| return constant; |
| } |
| var fields = <FieldEntity, ConstantValue>{}; |
| constant.fields.forEach((f, v) { |
| fields[toBackendEntity(f)] = v.accept(this, null); |
| }); |
| return new ConstructedConstantValue(type, fields); |
| } |
| |
| ConstantValue visitType(TypeConstantValue constant, _) { |
| var type = typeConverter.convert(constant.type); |
| var representedType = typeConverter.convert(constant.representedType); |
| if (type == constant.type && representedType == constant.representedType) { |
| return constant; |
| } |
| return new TypeConstantValue(representedType, type); |
| } |
| |
| ConstantValue visitInterceptor(InterceptorConstantValue constant, _) { |
| return new InterceptorConstantValue(toBackendEntity(constant.cls)); |
| } |
| |
| ConstantValue visitDeferred(DeferredConstantValue constant, _) { |
| throw new UnsupportedError("DeferredConstantValue with --use-kernel"); |
| } |
| |
| ConstantValue visitDeferredGlobal(DeferredGlobalConstantValue constant, _) { |
| var referenced = constant.referenced.accept(this, null); |
| if (referenced == constant.referenced) return constant; |
| return new DeferredGlobalConstantValue(referenced, constant.unit); |
| } |
| |
| ConstantValue visitInstantiation(InstantiationConstantValue constant, _) { |
| ConstantValue function = constant.function.accept(this, null); |
| List<DartType> typeArguments = |
| typeConverter.convertTypes(constant.typeArguments); |
| return new InstantiationConstantValue(typeArguments, function); |
| } |
| |
| List<ConstantValue> _handleValues(List<ConstantValue> values) { |
| List<ConstantValue> result; |
| for (int i = 0; i < values.length; i++) { |
| var value = values[i]; |
| var newValue = value.accept(this, null); |
| if (newValue != value && result == null) { |
| result = values.sublist(0, i).toList(); |
| } |
| result?.add(newValue); |
| } |
| return result ?? values; |
| } |
| } |
| |
| class TypeConverter extends DartTypeVisitor<DartType, Null> { |
| final Entity Function(Entity) toBackendEntity; |
| TypeConverter(this.toBackendEntity); |
| |
| Map<FunctionTypeVariable, FunctionTypeVariable> _functionTypeVariables = |
| <FunctionTypeVariable, FunctionTypeVariable>{}; |
| |
| DartType convert(DartType type) => type.accept(this, null); |
| |
| List<DartType> convertTypes(List<DartType> types) => _visitList(types); |
| |
| DartType visitVoidType(VoidType type, _) => type; |
| DartType visitDynamicType(DynamicType type, _) => type; |
| |
| DartType visitTypeVariableType(TypeVariableType type, _) { |
| return new TypeVariableType(toBackendEntity(type.element)); |
| } |
| |
| DartType visitFunctionTypeVariable(FunctionTypeVariable type, _) { |
| return _functionTypeVariables[type]; |
| } |
| |
| DartType visitFunctionType(FunctionType type, _) { |
| var returnType = type.returnType.accept(this, null); |
| var parameterTypes = _visitList(type.parameterTypes); |
| var optionalParameterTypes = _visitList(type.optionalParameterTypes); |
| var namedParameterTypes = _visitList(type.namedParameterTypes); |
| List<FunctionTypeVariable> typeVariables = <FunctionTypeVariable>[]; |
| for (FunctionTypeVariable typeVariable in type.typeVariables) { |
| typeVariables.add(_functionTypeVariables[typeVariable] = |
| new FunctionTypeVariable(typeVariable.index)); |
| } |
| for (FunctionTypeVariable typeVariable in type.typeVariables) { |
| _functionTypeVariables[typeVariable].bound = |
| typeVariable.bound?.accept(this, null); |
| } |
| for (FunctionTypeVariable typeVariable in type.typeVariables) { |
| _functionTypeVariables.remove(typeVariable); |
| } |
| return new FunctionType(returnType, parameterTypes, optionalParameterTypes, |
| type.namedParameters, namedParameterTypes, typeVariables); |
| } |
| |
| DartType visitInterfaceType(InterfaceType type, _) { |
| var element = toBackendEntity(type.element); |
| var args = _visitList(type.typeArguments); |
| return new InterfaceType(element, args); |
| } |
| |
| DartType visitTypedefType(TypedefType type, _) { |
| var element = toBackendEntity(type.element); |
| var args = _visitList(type.typeArguments); |
| var unaliased = convert(type.unaliased); |
| return new TypedefType(element, args, unaliased); |
| } |
| |
| List<DartType> _visitList(List<DartType> list) => |
| list.map<DartType>((t) => t.accept(this, null)).toList(); |
| } |
| |
| class TrivialClosureRtiNeed implements ClosureRtiNeed { |
| const TrivialClosureRtiNeed(); |
| |
| @override |
| bool localFunctionNeedsSignature(ir.Node node) => true; |
| |
| @override |
| bool classNeedsTypeArguments(ClassEntity cls) => true; |
| |
| @override |
| bool methodNeedsTypeArguments(FunctionEntity method) => true; |
| |
| @override |
| bool localFunctionNeedsTypeArguments(ir.Node node) => true; |
| |
| @override |
| bool selectorNeedsTypeArguments(Selector selector) => true; |
| |
| @override |
| bool methodNeedsSignature(MemberEntity method) => true; |
| |
| @override |
| bool instantiationNeedsTypeArguments( |
| DartType functionType, int typeArgumentCount) => |
| true; |
| } |
| |
| class JsClosureRtiNeed implements ClosureRtiNeed { |
| final RuntimeTypesNeed rtiNeed; |
| final Set<ir.Node> localFunctionsNodesNeedingTypeArguments; |
| final Set<ir.Node> localFunctionsNodesNeedingSignature; |
| |
| JsClosureRtiNeed(this.rtiNeed, this.localFunctionsNodesNeedingTypeArguments, |
| this.localFunctionsNodesNeedingSignature); |
| |
| @override |
| bool localFunctionNeedsSignature(ir.Node node) { |
| assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression); |
| return localFunctionsNodesNeedingSignature.contains(node); |
| } |
| |
| @override |
| bool classNeedsTypeArguments(ClassEntity cls) => |
| rtiNeed.classNeedsTypeArguments(cls); |
| |
| @override |
| bool methodNeedsTypeArguments(FunctionEntity method) => |
| rtiNeed.methodNeedsTypeArguments(method); |
| |
| @override |
| bool localFunctionNeedsTypeArguments(ir.Node node) { |
| assert(node is ir.FunctionDeclaration || node is ir.FunctionExpression); |
| return localFunctionsNodesNeedingTypeArguments.contains(node); |
| } |
| |
| @override |
| bool selectorNeedsTypeArguments(Selector selector) => |
| rtiNeed.selectorNeedsTypeArguments(selector); |
| |
| @override |
| bool methodNeedsSignature(MemberEntity method) => |
| rtiNeed.methodNeedsSignature(method); |
| |
| @override |
| bool instantiationNeedsTypeArguments( |
| DartType functionType, int typeArgumentCount) => |
| rtiNeed.instantiationNeedsTypeArguments(functionType, typeArgumentCount); |
| } |
| |
| class KernelCodegenWorkItemBuilder implements WorkItemBuilder { |
| final JavaScriptBackend _backend; |
| final JClosedWorld _closedWorld; |
| final GlobalTypeInferenceResults _globalInferenceResults; |
| |
| KernelCodegenWorkItemBuilder( |
| this._backend, this._closedWorld, this._globalInferenceResults); |
| |
| CompilerOptions get _options => _backend.compiler.options; |
| |
| @override |
| CodegenWorkItem createWorkItem(MemberEntity entity) { |
| if (entity.isAbstract) return null; |
| |
| // Codegen inlines field initializers. It only needs to generate |
| // code for checked setters. |
| if (entity.isField && entity.isInstanceMember) { |
| if (!_options.parameterCheckPolicy.isEmitted || |
| entity.enclosingClass.isClosure) { |
| return null; |
| } |
| } |
| |
| return new KernelCodegenWorkItem( |
| _backend, _closedWorld, _globalInferenceResults, entity); |
| } |
| } |
| |
| class KernelCodegenWorkItem extends CodegenWorkItem { |
| final JavaScriptBackend _backend; |
| final JClosedWorld _closedWorld; |
| final MemberEntity element; |
| final CodegenRegistry registry; |
| final GlobalTypeInferenceResults _globalInferenceResults; |
| |
| KernelCodegenWorkItem(this._backend, this._closedWorld, |
| this._globalInferenceResults, this.element) |
| : registry = |
| new CodegenRegistry(_closedWorld.elementEnvironment, element); |
| |
| @override |
| WorldImpact run() { |
| return _backend.codegen(this, _closedWorld, _globalInferenceResults); |
| } |
| } |
| |
| /// Task for building SSA from kernel IR loaded from .dill. |
| class KernelSsaBuilder implements SsaBuilder { |
| final CompilerTask task; |
| final Compiler _compiler; |
| final JsToElementMap _elementMap; |
| FunctionInlineCache _inlineCache; |
| |
| KernelSsaBuilder(this.task, this._compiler, this._elementMap); |
| |
| @override |
| HGraph build(CodegenWorkItem work, JClosedWorld closedWorld, |
| GlobalTypeInferenceResults results) { |
| _inlineCache ??= new FunctionInlineCache(closedWorld.annotationsData); |
| return task.measure(() { |
| KernelSsaGraphBuilder builder = new KernelSsaGraphBuilder( |
| work.element, |
| _elementMap.getMemberThisType(work.element), |
| _compiler, |
| _elementMap, |
| results, |
| closedWorld, |
| _compiler.codegenWorldBuilder, |
| work.registry, |
| _compiler.backend.emitter.nativeEmitter, |
| _compiler.backend.sourceInformationStrategy, |
| _inlineCache); |
| return builder.build(); |
| }); |
| } |
| } |
| |
| class KernelToTypeInferenceMapImpl implements KernelToTypeInferenceMap { |
| final GlobalTypeInferenceResults _globalInferenceResults; |
| GlobalTypeInferenceMemberResult _targetResults; |
| |
| KernelToTypeInferenceMapImpl( |
| MemberEntity target, this._globalInferenceResults) { |
| _targetResults = _resultOf(target); |
| } |
| |
| GlobalTypeInferenceMemberResult _resultOf(MemberEntity e) => |
| _globalInferenceResults |
| .resultOfMember(e is ConstructorBodyEntity ? e.constructor : e); |
| |
| AbstractValue getReturnTypeOf(FunctionEntity function) { |
| return AbstractValueFactory.inferredReturnTypeForElement( |
| function, _globalInferenceResults); |
| } |
| |
| AbstractValue receiverTypeOfInvocation( |
| ir.MethodInvocation node, AbstractValueDomain abstractValueDomain) { |
| return _targetResults.typeOfSend(node); |
| } |
| |
| AbstractValue receiverTypeOfGet(ir.PropertyGet node) { |
| return _targetResults.typeOfSend(node); |
| } |
| |
| AbstractValue receiverTypeOfDirectGet(ir.DirectPropertyGet node) { |
| return _targetResults.typeOfSend(node); |
| } |
| |
| AbstractValue receiverTypeOfSet( |
| ir.PropertySet node, AbstractValueDomain abstractValueDomain) { |
| return _targetResults.typeOfSend(node); |
| } |
| |
| AbstractValue typeOfListLiteral(MemberEntity owner, |
| ir.ListLiteral listLiteral, AbstractValueDomain abstractValueDomain) { |
| return _resultOf(owner).typeOfListLiteral(listLiteral) ?? |
| abstractValueDomain.dynamicType; |
| } |
| |
| AbstractValue typeOfIterator(ir.ForInStatement node) { |
| return _targetResults.typeOfIterator(node); |
| } |
| |
| AbstractValue typeOfIteratorCurrent(ir.ForInStatement node) { |
| return _targetResults.typeOfIteratorCurrent(node); |
| } |
| |
| AbstractValue typeOfIteratorMoveNext(ir.ForInStatement node) { |
| return _targetResults.typeOfIteratorMoveNext(node); |
| } |
| |
| bool isJsIndexableIterator( |
| ir.ForInStatement node, AbstractValueDomain abstractValueDomain) { |
| AbstractValue mask = typeOfIterator(node); |
| return abstractValueDomain.isJsIndexableAndIterable(mask); |
| } |
| |
| AbstractValue inferredIndexType(ir.ForInStatement node) { |
| return AbstractValueFactory.inferredTypeForSelector( |
| new Selector.index(), typeOfIterator(node), _globalInferenceResults); |
| } |
| |
| AbstractValue getInferredTypeOf(MemberEntity member) { |
| return AbstractValueFactory.inferredTypeForMember( |
| member, _globalInferenceResults); |
| } |
| |
| AbstractValue getInferredTypeOfParameter(Local parameter) { |
| return AbstractValueFactory.inferredTypeForParameter( |
| parameter, _globalInferenceResults); |
| } |
| |
| AbstractValue selectorTypeOf(Selector selector, AbstractValue mask) { |
| return AbstractValueFactory.inferredTypeForSelector( |
| selector, mask, _globalInferenceResults); |
| } |
| |
| AbstractValue typeFromNativeBehavior( |
| NativeBehavior nativeBehavior, JClosedWorld closedWorld) { |
| return AbstractValueFactory.fromNativeBehavior(nativeBehavior, closedWorld); |
| } |
| } |
| |
| class KernelSorter implements Sorter { |
| final JsToElementMap elementMap; |
| |
| KernelSorter(this.elementMap); |
| |
| int _compareLibraries(LibraryEntity a, LibraryEntity b) { |
| return utils.compareLibrariesUris(a.canonicalUri, b.canonicalUri); |
| } |
| |
| int _compareSourceSpans(Entity entity1, SourceSpan sourceSpan1, |
| Entity entity2, SourceSpan sourceSpan2) { |
| int r = utils.compareSourceUris(sourceSpan1.uri, sourceSpan2.uri); |
| if (r != 0) return r; |
| return utils.compareEntities( |
| entity1, sourceSpan1.begin, null, entity2, sourceSpan2.begin, null); |
| } |
| |
| @override |
| Iterable<LibraryEntity> sortLibraries(Iterable<LibraryEntity> libraries) { |
| return libraries.toList()..sort(_compareLibraries); |
| } |
| |
| @override |
| Iterable<T> sortMembers<T extends MemberEntity>(Iterable<T> members) { |
| return members.toList()..sort(compareMembersByLocation); |
| } |
| |
| @override |
| Iterable<ClassEntity> sortClasses(Iterable<ClassEntity> classes) { |
| List<ClassEntity> regularClasses = <ClassEntity>[]; |
| List<ClassEntity> unnamedMixins = <ClassEntity>[]; |
| for (ClassEntity cls in classes) { |
| if (elementMap.elementEnvironment.isUnnamedMixinApplication(cls)) { |
| unnamedMixins.add(cls); |
| } else { |
| regularClasses.add(cls); |
| } |
| } |
| List<ClassEntity> sorted = <ClassEntity>[]; |
| regularClasses.sort(compareClassesByLocation); |
| sorted.addAll(regularClasses); |
| unnamedMixins.sort((a, b) { |
| int result = _compareLibraries(a.library, b.library); |
| if (result != 0) return result; |
| result = a.name.compareTo(b.name); |
| assert(result != 0, |
| failedAt(a, "Multiple mixins named ${a.name}: $a vs $b.")); |
| return result; |
| }); |
| sorted.addAll(unnamedMixins); |
| return sorted; |
| } |
| |
| @override |
| Iterable<TypedefEntity> sortTypedefs(Iterable<TypedefEntity> typedefs) { |
| // TODO(redemption): Support this. |
| assert(typedefs.isEmpty); |
| return typedefs; |
| } |
| |
| @override |
| int compareLibrariesByLocation(LibraryEntity a, LibraryEntity b) { |
| return _compareLibraries(a, b); |
| } |
| |
| @override |
| int compareClassesByLocation(ClassEntity a, ClassEntity b) { |
| int r = _compareLibraries(a.library, b.library); |
| if (r != 0) return r; |
| ClassDefinition definition1 = elementMap.getClassDefinition(a); |
| ClassDefinition definition2 = elementMap.getClassDefinition(b); |
| return _compareSourceSpans( |
| a, definition1.location, b, definition2.location); |
| } |
| |
| @override |
| int compareTypedefsByLocation(TypedefEntity a, TypedefEntity b) { |
| // TODO(redemption): Support this. |
| failedAt(a, 'KernelSorter.compareTypedefsByLocation unimplemented'); |
| return 0; |
| } |
| |
| @override |
| int compareMembersByLocation(MemberEntity a, MemberEntity b) { |
| int r = _compareLibraries(a.library, b.library); |
| if (r != 0) return r; |
| MemberDefinition definition1 = elementMap.getMemberDefinition(a); |
| MemberDefinition definition2 = elementMap.getMemberDefinition(b); |
| return _compareSourceSpans( |
| a, definition1.location, b, definition2.location); |
| } |
| } |
| |
| /// [LocalLookup] implementation used to deserialize [JsClosedWorld]. |
| class LocalLookupImpl implements LocalLookup { |
| final GlobalLocalsMap _globalLocalsMap; |
| |
| LocalLookupImpl(this._globalLocalsMap); |
| |
| @override |
| Local getLocalByIndex(MemberEntity memberContext, int index) { |
| KernelToLocalsMapImpl map = _globalLocalsMap.getLocalsMap(memberContext); |
| return map.getLocalByIndex(index); |
| } |
| } |