OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/names.dart'; | 8 import '../common/names.dart'; |
9 import '../compiler.dart'; | 9 import '../compiler.dart'; |
10 import '../constants/values.dart'; | 10 import '../constants/values.dart'; |
11 import '../dart_types.dart'; | 11 import '../dart_types.dart'; |
12 import '../elements/elements.dart'; | 12 import '../elements/elements.dart'; |
13 import '../js_backend/js_backend.dart'; | 13 import '../js_backend/js_backend.dart'; |
14 import '../kernel/kernel.dart'; | 14 import '../kernel/kernel.dart'; |
15 import '../resolution/tree_elements.dart'; | 15 import '../resolution/tree_elements.dart'; |
16 import '../tree/tree.dart' as ast; | 16 import '../tree/tree.dart' as ast; |
17 import '../types/masks.dart'; | 17 import '../types/masks.dart'; |
| 18 import '../types/types.dart'; |
18 import '../universe/call_structure.dart'; | 19 import '../universe/call_structure.dart'; |
19 import '../universe/selector.dart'; | 20 import '../universe/selector.dart'; |
20 import '../universe/side_effects.dart'; | 21 import '../universe/side_effects.dart'; |
| 22 import '../world.dart'; |
| 23 import 'locals_handler.dart'; |
21 import 'types.dart'; | 24 import 'types.dart'; |
22 | 25 |
23 /// A helper class that abstracts all accesses of the AST from Kernel nodes. | 26 /// A helper class that abstracts all accesses of the AST from Kernel nodes. |
24 /// | 27 /// |
25 /// The goal is to remove all need for the AST from the Kernel SSA builder. | 28 /// The goal is to remove all need for the AST from the Kernel SSA builder. |
26 class KernelAstAdapter { | 29 class KernelAstAdapter { |
27 final Kernel kernel; | 30 final Kernel kernel; |
28 final JavaScriptBackend _backend; | 31 final JavaScriptBackend _backend; |
29 final ResolvedAst _resolvedAst; | 32 final ResolvedAst _resolvedAst; |
30 final Map<ir.Node, ast.Node> _nodeToAst; | 33 final Map<ir.Node, ast.Node> _nodeToAst; |
31 final Map<ir.Node, Element> _nodeToElement; | 34 final Map<ir.Node, Element> _nodeToElement; |
| 35 final Map<ir.VariableDeclaration, SyntheticLocal> _syntheticLocals = |
| 36 <ir.VariableDeclaration, SyntheticLocal>{}; |
32 DartTypeConverter _typeConverter; | 37 DartTypeConverter _typeConverter; |
33 | 38 |
34 KernelAstAdapter(this.kernel, this._backend, this._resolvedAst, | 39 KernelAstAdapter(this.kernel, this._backend, this._resolvedAst, |
35 this._nodeToAst, this._nodeToElement) { | 40 this._nodeToAst, this._nodeToElement) { |
36 // TODO(het): Maybe just use all of the kernel maps directly? | 41 // TODO(het): Maybe just use all of the kernel maps directly? |
37 for (FieldElement fieldElement in kernel.fields.keys) { | 42 for (FieldElement fieldElement in kernel.fields.keys) { |
38 _nodeToElement[kernel.fields[fieldElement]] = fieldElement; | 43 _nodeToElement[kernel.fields[fieldElement]] = fieldElement; |
39 } | 44 } |
40 for (FunctionElement functionElement in kernel.functions.keys) { | 45 for (FunctionElement functionElement in kernel.functions.keys) { |
41 _nodeToElement[kernel.functions[functionElement]] = functionElement; | 46 _nodeToElement[kernel.functions[functionElement]] = functionElement; |
42 } | 47 } |
43 for (ClassElement classElement in kernel.classes.keys) { | 48 for (ClassElement classElement in kernel.classes.keys) { |
44 _nodeToElement[kernel.classes[classElement]] = classElement; | 49 _nodeToElement[kernel.classes[classElement]] = classElement; |
45 } | 50 } |
46 for (LibraryElement libraryElement in kernel.libraries.keys) { | 51 for (LibraryElement libraryElement in kernel.libraries.keys) { |
47 _nodeToElement[kernel.libraries[libraryElement]] = libraryElement; | 52 _nodeToElement[kernel.libraries[libraryElement]] = libraryElement; |
48 } | 53 } |
49 for (LocalFunctionElement localFunction in kernel.localFunctions.keys) { | 54 for (LocalFunctionElement localFunction in kernel.localFunctions.keys) { |
50 _nodeToElement[kernel.localFunctions[localFunction]] = localFunction; | 55 _nodeToElement[kernel.localFunctions[localFunction]] = localFunction; |
51 } | 56 } |
52 _typeConverter = new DartTypeConverter(this); | 57 _typeConverter = new DartTypeConverter(this); |
53 } | 58 } |
54 | 59 |
55 Compiler get _compiler => _backend.compiler; | 60 Compiler get _compiler => _backend.compiler; |
56 TreeElements get elements => _resolvedAst.elements; | 61 TreeElements get elements => _resolvedAst.elements; |
| 62 GlobalTypeInferenceResults get _inferenceResults => |
| 63 _compiler.globalInference.results; |
57 | 64 |
58 ConstantValue getConstantForSymbol(ir.SymbolLiteral node) { | 65 ConstantValue getConstantForSymbol(ir.SymbolLiteral node) { |
59 ast.Node astNode = getNode(node); | 66 ast.Node astNode = getNode(node); |
60 ConstantValue constantValue = _backend.constants | 67 ConstantValue constantValue = _backend.constants |
61 .getConstantValueForNode(astNode, _resolvedAst.elements); | 68 .getConstantValueForNode(astNode, _resolvedAst.elements); |
62 assert(invariant(astNode, constantValue != null, | 69 assert(invariant(astNode, constantValue != null, |
63 message: 'No constant computed for $node')); | 70 message: 'No constant computed for $node')); |
64 return constantValue; | 71 return constantValue; |
65 } | 72 } |
66 | 73 |
67 Element getElement(ir.Node node) { | 74 Element getElement(ir.Node node) { |
68 Element result = _nodeToElement[node]; | 75 Element result = _nodeToElement[node]; |
69 assert(result != null); | 76 assert(result != null); |
70 return result; | 77 return result; |
71 } | 78 } |
72 | 79 |
73 ast.Node getNode(ir.Node node) { | 80 ast.Node getNode(ir.Node node) { |
74 ast.Node result = _nodeToAst[node]; | 81 ast.Node result = _nodeToAst[node]; |
75 assert(result != null); | 82 assert(result != null); |
76 return result; | 83 return result; |
77 } | 84 } |
78 | 85 |
| 86 Local getLocal(ir.VariableDeclaration variable) { |
| 87 // If this is a synthetic local, return the synthetic local |
| 88 if (variable.name == null) { |
| 89 return _syntheticLocals.putIfAbsent( |
| 90 variable, () => new SyntheticLocal("x", null)); |
| 91 } |
| 92 return getElement(variable) as LocalElement; |
| 93 } |
| 94 |
79 bool getCanThrow(ir.Node procedure) { | 95 bool getCanThrow(ir.Node procedure) { |
80 FunctionElement function = getElement(procedure); | 96 FunctionElement function = getElement(procedure); |
81 return !_compiler.closedWorld.getCannotThrow(function); | 97 return !_compiler.closedWorld.getCannotThrow(function); |
82 } | 98 } |
83 | 99 |
84 TypeMask returnTypeOf(ir.Member node) { | 100 TypeMask returnTypeOf(ir.Member node) { |
85 return TypeMaskFactory.inferredReturnTypeForElement( | 101 return TypeMaskFactory.inferredReturnTypeForElement( |
86 getElement(node), _compiler); | 102 getElement(node), _compiler); |
87 } | 103 } |
88 | 104 |
89 SideEffects getSideEffects(ir.Node node) { | 105 SideEffects getSideEffects(ir.Node node) { |
90 return _compiler.closedWorld.getSideEffectsOfElement(getElement(node)); | 106 return _compiler.closedWorld.getSideEffectsOfElement(getElement(node)); |
91 } | 107 } |
92 | 108 |
93 CallStructure getCallStructure(ir.Arguments arguments) { | 109 CallStructure getCallStructure(ir.Arguments arguments) { |
94 int argumentCount = arguments.positional.length + arguments.named.length; | 110 int argumentCount = arguments.positional.length + arguments.named.length; |
95 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); | 111 List<String> namedArguments = arguments.named.map((e) => e.name).toList(); |
96 return new CallStructure(argumentCount, namedArguments); | 112 return new CallStructure(argumentCount, namedArguments); |
97 } | 113 } |
98 | 114 |
99 Name getName(ir.Name name) { | 115 Name getName(ir.Name name) { |
100 return new Name( | 116 return new Name( |
101 name.name, name.isPrivate ? getElement(name.library) : null); | 117 name.name, name.isPrivate ? getElement(name.library) : null); |
102 } | 118 } |
103 | 119 |
104 // TODO(het): Create the selector directly from the invocation | 120 Selector getSelector(ir.Expression node) { |
105 Selector getSelector(ir.InvocationExpression invocation) { | 121 if (node is ir.PropertyGet) return getGetterSelector(node); |
| 122 if (node is ir.InvocationExpression) return getInvocationSelector(node); |
| 123 _compiler.reporter.internalError(getNode(node), |
| 124 "Can only get the selector for a property get or an invocation."); |
| 125 return null; |
| 126 } |
| 127 |
| 128 Selector getInvocationSelector(ir.InvocationExpression invocation) { |
106 Name name = getName(invocation.name); | 129 Name name = getName(invocation.name); |
107 SelectorKind kind; | 130 SelectorKind kind; |
108 if (Elements.isOperatorName(invocation.name.name)) { | 131 if (Elements.isOperatorName(invocation.name.name)) { |
109 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) { | 132 if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) { |
110 kind = SelectorKind.INDEX; | 133 kind = SelectorKind.INDEX; |
111 } else { | 134 } else { |
112 kind = SelectorKind.OPERATOR; | 135 kind = SelectorKind.OPERATOR; |
113 } | 136 } |
114 } else { | 137 } else { |
115 kind = SelectorKind.CALL; | 138 kind = SelectorKind.CALL; |
116 } | 139 } |
117 | 140 |
118 CallStructure callStructure = getCallStructure(invocation.arguments); | 141 CallStructure callStructure = getCallStructure(invocation.arguments); |
119 return new Selector(kind, name, callStructure); | 142 return new Selector(kind, name, callStructure); |
120 } | 143 } |
121 | 144 |
122 Selector getGetterSelector(ir.PropertyGet getter) { | 145 Selector getGetterSelector(ir.PropertyGet getter) { |
123 ir.Name irName = getter.name; | 146 ir.Name irName = getter.name; |
124 Name name = new Name( | 147 Name name = new Name( |
125 irName.name, irName.isPrivate ? getElement(irName.library) : null); | 148 irName.name, irName.isPrivate ? getElement(irName.library) : null); |
126 return new Selector.getter(name); | 149 return new Selector.getter(name); |
127 } | 150 } |
128 | 151 |
129 TypeMask typeOfInvocation(ir.MethodInvocation invocation) { | 152 TypeMask typeOfInvocation(ir.Expression send) { |
130 return _compiler.globalInference.results | 153 return _inferenceResults.typeOfSend(getNode(send), elements); |
131 .typeOfSend(getNode(invocation), elements); | |
132 } | 154 } |
133 | 155 |
134 TypeMask typeOfGet(ir.PropertyGet getter) { | 156 TypeMask typeOfGet(ir.PropertyGet getter) { |
135 return _compiler.globalInference.results | 157 return _inferenceResults.typeOfSend(getNode(getter), elements); |
136 .typeOfSend(getNode(getter), elements); | 158 } |
| 159 |
| 160 TypeMask typeOfSend(ir.Expression send) { |
| 161 assert(send is ir.InvocationExpression || send is ir.PropertyGet); |
| 162 return _inferenceResults.typeOfSend(getNode(send), elements); |
| 163 } |
| 164 |
| 165 TypeMask typeOfNewList(Element owner, ir.ListLiteral listLiteral) { |
| 166 return _inferenceResults.typeOfNewList(owner, getNode(listLiteral)) ?? |
| 167 _compiler.commonMasks.dynamicType; |
| 168 } |
| 169 |
| 170 TypeMask typeOfIterator(ir.ForInStatement forInStatement) { |
| 171 return _inferenceResults.typeOfIterator(getNode(forInStatement), elements); |
| 172 } |
| 173 |
| 174 TypeMask typeOfIteratorCurrent(ir.ForInStatement forInStatement) { |
| 175 return _inferenceResults.typeOfIteratorCurrent( |
| 176 getNode(forInStatement), elements); |
| 177 } |
| 178 |
| 179 TypeMask typeOfIteratorMoveNext(ir.ForInStatement forInStatement) { |
| 180 return _inferenceResults.typeOfIteratorMoveNext( |
| 181 getNode(forInStatement), elements); |
| 182 } |
| 183 |
| 184 bool isJsIndexableIterator(ir.ForInStatement forInStatement) { |
| 185 TypeMask mask = typeOfIterator(forInStatement); |
| 186 ClosedWorld closedWorld = _compiler.closedWorld; |
| 187 return mask != null && |
| 188 mask.satisfies(_backend.helpers.jsIndexableClass, closedWorld) && |
| 189 // String is indexable but not iterable. |
| 190 !mask.satisfies(_backend.helpers.jsStringClass, closedWorld); |
| 191 } |
| 192 |
| 193 bool isFixedLength(TypeMask mask) { |
| 194 ClosedWorld closedWorld = _compiler.closedWorld; |
| 195 JavaScriptBackend backend = _compiler.backend; |
| 196 if (mask.isContainer && (mask as ContainerTypeMask).length != null) { |
| 197 // A container on which we have inferred the length. |
| 198 return true; |
| 199 } |
| 200 // TODO(sra): Recognize any combination of fixed length indexables. |
| 201 if (mask.containsOnly(backend.helpers.jsFixedArrayClass) || |
| 202 mask.containsOnly(backend.helpers.jsUnmodifiableArrayClass) || |
| 203 mask.containsOnlyString(closedWorld) || |
| 204 backend.isTypedArray(mask)) { |
| 205 return true; |
| 206 } |
| 207 return false; |
| 208 } |
| 209 |
| 210 TypeMask inferredIndexType(ir.ForInStatement forInStatement) { |
| 211 return TypeMaskFactory.inferredTypeForSelector( |
| 212 new Selector.index(), typeOfIterator(forInStatement), _compiler); |
137 } | 213 } |
138 | 214 |
139 TypeMask inferredTypeOf(ir.Member node) { | 215 TypeMask inferredTypeOf(ir.Member node) { |
140 return TypeMaskFactory.inferredTypeForElement(getElement(node), _compiler); | 216 return TypeMaskFactory.inferredTypeForElement(getElement(node), _compiler); |
141 } | 217 } |
142 | 218 |
143 TypeMask selectorTypeOf(ir.MethodInvocation invocation) { | 219 TypeMask selectorTypeOf(Selector selector, TypeMask mask) { |
144 return TypeMaskFactory.inferredTypeForSelector( | 220 return TypeMaskFactory.inferredTypeForSelector(selector, mask, _compiler); |
145 getSelector(invocation), typeOfInvocation(invocation), _compiler); | |
146 } | |
147 | |
148 TypeMask selectorGetterTypeOf(ir.PropertyGet getter) { | |
149 return TypeMaskFactory.inferredTypeForSelector( | |
150 getGetterSelector(getter), typeOfGet(getter), _compiler); | |
151 } | 221 } |
152 | 222 |
153 ConstantValue getConstantFor(ir.Node node) { | 223 ConstantValue getConstantFor(ir.Node node) { |
154 ConstantValue constantValue = | 224 ConstantValue constantValue = |
155 _backend.constants.getConstantValueForNode(getNode(node), elements); | 225 _backend.constants.getConstantValueForNode(getNode(node), elements); |
156 assert(invariant(getNode(node), constantValue != null, | 226 assert(invariant(getNode(node), constantValue != null, |
157 message: 'No constant computed for $node')); | 227 message: 'No constant computed for $node')); |
158 return constantValue; | 228 return constantValue; |
159 } | 229 } |
160 | 230 |
161 bool isIntercepted(ir.Node node) { | 231 bool isIntercepted(ir.Node node) { |
162 Selector selector; | 232 Selector selector = getSelector(node); |
163 if (node is ir.PropertyGet) { | |
164 selector = getGetterSelector(node); | |
165 } else { | |
166 selector = getSelector(node); | |
167 } | |
168 return _backend.isInterceptedSelector(selector); | 233 return _backend.isInterceptedSelector(selector); |
169 } | 234 } |
170 | 235 |
| 236 bool isInterceptedSelector(Selector selector) { |
| 237 return _backend.isInterceptedSelector(selector); |
| 238 } |
| 239 |
171 JumpTarget getTargetDefinition(ir.Node node) => | 240 JumpTarget getTargetDefinition(ir.Node node) => |
172 elements.getTargetDefinition(getNode(node)); | 241 elements.getTargetDefinition(getNode(node)); |
173 | 242 |
174 ir.Procedure get mapLiteralConstructor => | 243 ir.Procedure get mapLiteralConstructor => |
175 kernel.functions[_backend.helpers.mapLiteralConstructor]; | 244 kernel.functions[_backend.helpers.mapLiteralConstructor]; |
176 | 245 |
177 ir.Procedure get mapLiteralConstructorEmpty => | 246 ir.Procedure get mapLiteralConstructorEmpty => |
178 kernel.functions[_backend.helpers.mapLiteralConstructorEmpty]; | 247 kernel.functions[_backend.helpers.mapLiteralConstructorEmpty]; |
179 | 248 |
| 249 Element get jsIndexableLength => _backend.helpers.jsIndexableLength; |
| 250 |
| 251 ir.Procedure get checkConcurrentModificationError => |
| 252 kernel.functions[_backend.helpers.checkConcurrentModificationError]; |
| 253 |
| 254 TypeMask get checkConcurrentModificationErrorReturnType => |
| 255 TypeMaskFactory.inferredReturnTypeForElement( |
| 256 _backend.helpers.checkConcurrentModificationError, _compiler); |
| 257 |
180 DartType getDartType(ir.DartType type) { | 258 DartType getDartType(ir.DartType type) { |
181 return type.accept(_typeConverter); | 259 return type.accept(_typeConverter); |
182 } | 260 } |
183 | 261 |
184 List<DartType> getDartTypes(List<ir.DartType> types) { | 262 List<DartType> getDartTypes(List<ir.DartType> types) { |
185 return types.map(getDartType).toList(); | 263 return types.map(getDartType).toList(); |
186 } | 264 } |
187 } | 265 } |
188 | 266 |
189 class DartTypeConverter extends ir.DartTypeVisitor<DartType> { | 267 class DartTypeConverter extends ir.DartTypeVisitor<DartType> { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 @override | 309 @override |
232 DartType visitDynamicType(ir.DynamicType node) { | 310 DartType visitDynamicType(ir.DynamicType node) { |
233 return const DynamicType(); | 311 return const DynamicType(); |
234 } | 312 } |
235 | 313 |
236 @override | 314 @override |
237 DartType visitInvalidType(ir.InvalidType node) { | 315 DartType visitInvalidType(ir.InvalidType node) { |
238 throw new UnimplementedError("Invalid types not currently supported"); | 316 throw new UnimplementedError("Invalid types not currently supported"); |
239 } | 317 } |
240 } | 318 } |
OLD | NEW |