Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 | 6 |
| 7 import '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../compiler.dart'; | 9 import '../constants/constant_system.dart'; |
| 10 import '../elements/entities.dart'; | 10 import '../elements/entities.dart'; |
| 11 import '../kernel/element_map.dart'; | 11 import '../options.dart'; |
| 12 import '../types/constants.dart'; | |
| 12 import '../universe/side_effects.dart' show SideEffects; | 13 import '../universe/side_effects.dart' show SideEffects; |
| 14 import '../world.dart'; | |
| 13 import 'inferrer_engine.dart'; | 15 import 'inferrer_engine.dart'; |
| 14 import 'locals_handler.dart'; | 16 import 'locals_handler.dart'; |
| 15 import 'type_graph_nodes.dart'; | 17 import 'type_graph_nodes.dart'; |
| 16 import 'type_system.dart'; | 18 import 'type_system.dart'; |
| 17 | 19 |
| 18 /// [KernelTypeGraphBuilder] constructs a type-inference graph for a particular | 20 /// [KernelTypeGraphBuilder] constructs a type-inference graph for a particular |
| 19 /// element. | 21 /// element. |
| 20 /// | 22 /// |
| 21 /// Calling [run] will start the work of visiting the body of the code to | 23 /// Calling [run] will start the work of visiting the body of the code to |
| 22 /// construct a set of inference-nodes that abstractly represent what the code | 24 /// construct a set of inference-nodes that abstractly represent what the code |
| 23 /// is doing. | 25 /// is doing. |
| 24 class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> { | 26 class KernelTypeGraphBuilder extends ir.Visitor<TypeInformation> { |
| 25 final Compiler compiler; | 27 final CompilerOptions _options; |
| 26 final MemberEntity analyzedMember; | 28 final ClosedWorld _closedWorld; |
| 27 final ir.Node analyzedNode; | 29 final ClosureDataLookup<ir.Node> _closureDataLookup; |
| 28 final TypeSystem<ir.Node> types; | 30 final InferrerEngine<ir.Node> _inferrer; |
| 29 LocalsHandler locals; | 31 final TypeSystem<ir.Node> _types; |
| 30 final InferrerEngine<ir.Node> inferrer; | 32 final MemberEntity _analyzedMember; |
| 31 SideEffects sideEffects = new SideEffects.empty(); | 33 final ir.Node _analyzedNode; |
| 32 int loopLevel = 0; | 34 LocalsHandler _locals; |
| 33 bool get inLoop => loopLevel > 0; | |
| 34 TypeInformation returnType; | |
| 35 | 35 |
| 36 final Set<Local> capturedVariables = new Set<Local>(); | 36 /// ignore: UNUSED_FIELD |
| 37 SideEffects _sideEffects = new SideEffects.empty(); | |
|
Siggi Cherem (dart-lang)
2017/08/28 22:34:57
nit: remove? I'm guessing you'll start using it in
Johnni Winther
2017/08/29 08:31:24
It wasn't added, just moved and renamed to be priv
| |
| 38 int _loopLevel = 0; | |
| 37 | 39 |
| 38 KernelTypeGraphBuilder.internal(this.analyzedMember, this.inferrer, | 40 /// ignore: UNUSED_ELEMENT |
| 39 this.compiler, this.locals, this.analyzedNode) | 41 bool get _inLoop => _loopLevel > 0; |
| 40 : this.types = inferrer.types { | 42 TypeInformation _returnType; |
| 41 if (locals != null) return; | 43 |
| 44 /// ignore: UNUSED_FIELD | |
| 45 final Set<Local> _capturedVariables = new Set<Local>(); | |
| 46 | |
| 47 KernelTypeGraphBuilder( | |
| 48 this._options, | |
| 49 this._closedWorld, | |
| 50 this._closureDataLookup, | |
| 51 this._inferrer, | |
| 52 this._analyzedMember, | |
| 53 this._analyzedNode, | |
| 54 [this._locals]) | |
| 55 : this._types = _inferrer.types { | |
| 56 if (_locals != null) return; | |
| 42 | 57 |
| 43 FieldInitializationScope<ir.Node> fieldScope = | 58 FieldInitializationScope<ir.Node> fieldScope = |
| 44 analyzedNode is ir.Constructor | 59 _analyzedNode is ir.Constructor |
| 45 ? new FieldInitializationScope(types) | 60 ? new FieldInitializationScope(_types) |
| 46 : null; | 61 : null; |
| 47 locals = new LocalsHandler( | 62 _locals = new LocalsHandler( |
| 48 inferrer, types, compiler.options, analyzedNode, fieldScope); | 63 _inferrer, _types, _options, _analyzedNode, fieldScope); |
| 49 } | |
| 50 | |
| 51 factory KernelTypeGraphBuilder( | |
| 52 MemberEntity element, | |
| 53 Compiler compiler, | |
| 54 KernelToElementMapForBuilding elementMap, | |
| 55 InferrerEngine<ir.Node> inferrer, | |
| 56 ir.TreeNode analyzedNode, | |
| 57 [LocalsHandler<ir.Node> handler]) { | |
| 58 return new KernelTypeGraphBuilder.internal( | |
| 59 element, inferrer, compiler, handler, analyzedNode); | |
| 60 } | 64 } |
| 61 | 65 |
| 62 TypeInformation run() { | 66 TypeInformation run() { |
| 63 if (analyzedMember.isField) { | 67 if (_analyzedMember.isField) { |
| 64 if (analyzedNode == null || analyzedNode is ir.NullLiteral) { | 68 if (_analyzedNode == null || _analyzedNode is ir.NullLiteral) { |
| 65 // Eagerly bailout, because computing the closure data only | 69 // Eagerly bailout, because computing the closure data only |
| 66 // works for functions and field assignments. | 70 // works for functions and field assignments. |
| 67 return types.nullType; | 71 return _types.nullType; |
| 68 } | 72 } |
| 69 } | 73 } |
| 70 | 74 |
| 71 // Update the locals that are boxed in [locals]. These locals will | 75 // Update the locals that are boxed in [locals]. These locals will |
| 72 // be handled specially, in that we are computing their LUB at | 76 // be handled specially, in that we are computing their LUB at |
| 73 // each update, and reading them yields the type that was found in a | 77 // each update, and reading them yields the type that was found in a |
| 74 // previous analysis of [outermostElement]. | 78 // previous analysis of [outermostElement]. |
| 75 ClosureRepresentationInfo closureData = compiler | 79 ClosureRepresentationInfo closureData = |
| 76 .backendStrategy.closureDataLookup | 80 _closureDataLookup.getClosureInfoForMember(_analyzedMember); |
| 77 .getClosureInfoForMember(analyzedMember); | |
| 78 closureData.forEachCapturedVariable((variable, field) { | 81 closureData.forEachCapturedVariable((variable, field) { |
| 79 locals.setCaptured(variable, field); | 82 _locals.setCaptured(variable, field); |
| 80 }); | 83 }); |
| 81 closureData.forEachBoxedVariable((variable, field) { | 84 closureData.forEachBoxedVariable((variable, field) { |
| 82 locals.setCapturedAndBoxed(variable, field); | 85 _locals.setCapturedAndBoxed(variable, field); |
| 83 }); | 86 }); |
| 84 | 87 |
| 85 return analyzedNode.accept(this); | 88 return _analyzedNode.accept(this); |
| 86 } | 89 } |
| 87 | 90 |
| 88 void recordReturnType(TypeInformation type) { | 91 void recordReturnType(TypeInformation type) { |
| 89 FunctionEntity analyzedMethod = analyzedMember; | 92 FunctionEntity analyzedMethod = _analyzedMember; |
| 90 returnType = | 93 _returnType = |
| 91 inferrer.addReturnTypeForMethod(analyzedMethod, returnType, type); | 94 _inferrer.addReturnTypeForMethod(analyzedMethod, _returnType, type); |
| 92 } | 95 } |
| 93 | 96 |
| 94 void initializationIsIndefinite() { | 97 void initializationIsIndefinite() { |
| 95 MemberEntity member = analyzedMember; | 98 MemberEntity member = _analyzedMember; |
| 96 if (member is ConstructorEntity && member.isGenerativeConstructor) { | 99 if (member is ConstructorEntity && member.isGenerativeConstructor) { |
| 97 locals.fieldScope.isIndefinite = true; | 100 _locals.fieldScope.isIndefinite = true; |
| 98 } | 101 } |
| 99 } | 102 } |
| 100 | 103 |
| 101 TypeInformation visit(ir.Node node) { | 104 TypeInformation visit(ir.Node node) { |
| 102 return node == null ? null : node.accept(this); | 105 return node == null ? null : node.accept(this); |
| 103 } | 106 } |
| 104 | 107 |
| 105 @override | 108 @override |
| 106 TypeInformation visitFunctionNode(ir.FunctionNode node) { | 109 TypeInformation visitFunctionNode(ir.FunctionNode node) { |
| 107 // TODO(redemption): Handle constructors. | 110 // TODO(redemption): Handle constructors. |
| 108 // TODO(redemption): Handle native methods. | 111 // TODO(redemption): Handle native methods. |
| 109 // TODO(redemption): Set up parameters. | 112 // TODO(redemption): Set up parameters. |
| 110 visit(node.body); | 113 visit(node.body); |
| 111 switch (node.asyncMarker) { | 114 switch (node.asyncMarker) { |
| 112 case ir.AsyncMarker.Sync: | 115 case ir.AsyncMarker.Sync: |
| 113 if (returnType == null) { | 116 if (_returnType == null) { |
| 114 // No return in the body. | 117 // No return in the body. |
| 115 returnType = locals.seenReturnOrThrow | 118 _returnType = _locals.seenReturnOrThrow |
| 116 ? types.nonNullEmpty() // Body always throws. | 119 ? _types.nonNullEmpty() // Body always throws. |
| 117 : types.nullType; | 120 : _types.nullType; |
| 118 } else if (!locals.seenReturnOrThrow) { | 121 } else if (!_locals.seenReturnOrThrow) { |
| 119 // We haven'TypeInformation seen returns on all branches. So the metho d may | 122 // We haven'TypeInformation seen returns on all branches. So the metho d may |
| 120 // also return null. | 123 // also return null. |
| 121 recordReturnType(types.nullType); | 124 recordReturnType(_types.nullType); |
| 122 } | 125 } |
| 123 break; | 126 break; |
| 124 | 127 |
| 125 case ir.AsyncMarker.SyncStar: | 128 case ir.AsyncMarker.SyncStar: |
| 126 // TODO(asgerf): Maybe make a ContainerTypeMask for these? The type | 129 // TODO(asgerf): Maybe make a ContainerTypeMask for these? The type |
| 127 // contained is the method body's return type. | 130 // contained is the method body's return type. |
| 128 recordReturnType(types.syncStarIterableType); | 131 recordReturnType(_types.syncStarIterableType); |
| 129 break; | 132 break; |
| 130 | 133 |
| 131 case ir.AsyncMarker.Async: | 134 case ir.AsyncMarker.Async: |
| 132 recordReturnType(types.asyncFutureType); | 135 recordReturnType(_types.asyncFutureType); |
| 133 break; | 136 break; |
| 134 | 137 |
| 135 case ir.AsyncMarker.AsyncStar: | 138 case ir.AsyncMarker.AsyncStar: |
| 136 recordReturnType(types.asyncStarStreamType); | 139 recordReturnType(_types.asyncStarStreamType); |
| 137 break; | 140 break; |
| 138 case ir.AsyncMarker.SyncYielding: | 141 case ir.AsyncMarker.SyncYielding: |
| 139 failedAt( | 142 failedAt( |
| 140 analyzedMember, "Unexpected async marker: ${node.asyncMarker}"); | 143 _analyzedMember, "Unexpected async marker: ${node.asyncMarker}"); |
| 141 break; | 144 break; |
| 142 } | 145 } |
| 143 return returnType; | 146 return _returnType; |
| 144 } | 147 } |
| 145 | 148 |
| 146 @override | 149 @override |
| 147 TypeInformation defaultExpression(ir.Expression expression) { | 150 TypeInformation defaultExpression(ir.Expression expression) { |
| 148 // TODO(efortuna): Remove when more is implemented. | 151 // TODO(efortuna): Remove when more is implemented. |
| 149 return types.dynamicType; | 152 return _types.dynamicType; |
| 150 } | 153 } |
| 151 | 154 |
| 152 @override | 155 @override |
| 153 TypeInformation visitNullLiteral(ir.NullLiteral literal) { | 156 TypeInformation visitNullLiteral(ir.NullLiteral literal) { |
| 154 return types.nullType; | 157 return _types.nullType; |
| 155 } | 158 } |
| 156 | 159 |
| 157 @override | 160 @override |
| 158 TypeInformation visitBlock(ir.Block block) { | 161 TypeInformation visitBlock(ir.Block block) { |
| 159 for (ir.Statement statement in block.statements) { | 162 for (ir.Statement statement in block.statements) { |
| 160 statement.accept(this); | 163 statement.accept(this); |
| 161 if (locals.aborts) break; | 164 if (_locals.aborts) break; |
| 162 } | 165 } |
| 163 return null; | 166 return null; |
| 164 } | 167 } |
| 165 | 168 |
| 166 @override | 169 @override |
| 167 TypeInformation visitListLiteral(ir.ListLiteral listLiteral) { | 170 TypeInformation visitListLiteral(ir.ListLiteral listLiteral) { |
| 168 // We only set the type once. We don't need to re-visit the children | 171 // We only set the type once. We don't need to re-visit the children |
| 169 // when re-analyzing the node. | 172 // when re-analyzing the node. |
| 170 return inferrer.concreteTypes.putIfAbsent(listLiteral, () { | 173 return _inferrer.concreteTypes.putIfAbsent(listLiteral, () { |
| 171 TypeInformation elementType; | 174 TypeInformation elementType; |
| 172 int length = 0; | 175 int length = 0; |
| 173 for (ir.Expression element in listLiteral.expressions) { | 176 for (ir.Expression element in listLiteral.expressions) { |
| 174 TypeInformation type = element.accept(this); | 177 TypeInformation type = element.accept(this); |
| 175 elementType = elementType == null | 178 elementType = elementType == null |
| 176 ? types.allocatePhi(null, null, type, isTry: false) | 179 ? _types.allocatePhi(null, null, type, isTry: false) |
| 177 : types.addPhiInput(null, elementType, type); | 180 : _types.addPhiInput(null, elementType, type); |
| 178 length++; | 181 length++; |
| 179 } | 182 } |
| 180 elementType = elementType == null | 183 elementType = elementType == null |
| 181 ? types.nonNullEmpty() | 184 ? _types.nonNullEmpty() |
| 182 : types.simplifyPhi(null, null, elementType); | 185 : _types.simplifyPhi(null, null, elementType); |
| 183 TypeInformation containerType = | 186 TypeInformation containerType = |
| 184 listLiteral.isConst ? types.constListType : types.growableListType; | 187 listLiteral.isConst ? _types.constListType : _types.growableListType; |
| 185 return types.allocateList( | 188 return _types.allocateList( |
| 186 containerType, listLiteral, analyzedMember, elementType, length); | 189 containerType, listLiteral, _analyzedMember, elementType, length); |
| 187 }); | 190 }); |
| 188 } | 191 } |
| 189 | 192 |
| 190 @override | 193 @override |
| 191 TypeInformation visitReturnStatement(ir.ReturnStatement node) { | 194 TypeInformation visitReturnStatement(ir.ReturnStatement node) { |
| 192 ir.Node expression = node.expression; | 195 ir.Node expression = node.expression; |
| 193 recordReturnType( | 196 recordReturnType( |
| 194 expression == null ? types.nullType : expression.accept(this)); | 197 expression == null ? _types.nullType : expression.accept(this)); |
| 195 locals.seenReturnOrThrow = true; | 198 _locals.seenReturnOrThrow = true; |
| 196 initializationIsIndefinite(); | 199 initializationIsIndefinite(); |
| 197 return null; | 200 return null; |
| 198 } | 201 } |
| 202 | |
| 203 @override | |
| 204 TypeInformation visitIntLiteral(ir.IntLiteral node) { | |
| 205 ConstantSystem constantSystem = _closedWorld.constantSystem; | |
| 206 // The JavaScript backend may turn this literal into a double at | |
| 207 // runtime. | |
| 208 return _types.getConcreteTypeFor( | |
| 209 computeTypeMask(_closedWorld, constantSystem.createInt(node.value))); | |
| 210 } | |
| 211 | |
| 212 @override | |
| 213 TypeInformation visitDoubleLiteral(ir.DoubleLiteral node) { | |
| 214 ConstantSystem constantSystem = _closedWorld.constantSystem; | |
| 215 // The JavaScript backend may turn this literal into an integer at | |
| 216 // runtime. | |
| 217 return _types.getConcreteTypeFor( | |
| 218 computeTypeMask(_closedWorld, constantSystem.createDouble(node.value))); | |
| 219 } | |
| 199 } | 220 } |
| OLD | NEW |