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/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
9 import '../common/names.dart'; | 9 import '../common/names.dart'; |
10 import '../common/tasks.dart' show CompilerTask; | 10 import '../common/tasks.dart' show CompilerTask; |
11 import '../compiler.dart'; | 11 import '../compiler.dart'; |
12 import '../dart_types.dart'; | 12 import '../dart_types.dart'; |
13 import '../elements/elements.dart'; | 13 import '../elements/elements.dart'; |
14 import '../io/source_information.dart'; | 14 import '../io/source_information.dart'; |
15 import '../js_backend/backend.dart' show JavaScriptBackend; | 15 import '../js_backend/backend.dart' show JavaScriptBackend; |
16 import '../kernel/kernel.dart'; | 16 import '../kernel/kernel.dart'; |
17 import '../resolution/tree_elements.dart'; | 17 import '../resolution/tree_elements.dart'; |
18 import '../tree/dartstring.dart'; | 18 import '../tree/dartstring.dart'; |
| 19 import '../tree/nodes.dart' show FunctionExpression, Node; |
19 import '../types/masks.dart'; | 20 import '../types/masks.dart'; |
20 import '../universe/call_structure.dart' show CallStructure; | 21 import '../universe/call_structure.dart' show CallStructure; |
21 import '../universe/selector.dart'; | 22 import '../universe/selector.dart'; |
22 import '../universe/use.dart' show TypeUse; | 23 import '../universe/use.dart' show TypeUse; |
23 import 'graph_builder.dart'; | 24 import 'graph_builder.dart'; |
24 import 'kernel_ast_adapter.dart'; | 25 import 'kernel_ast_adapter.dart'; |
25 import 'kernel_string_builder.dart'; | 26 import 'kernel_string_builder.dart'; |
26 import 'locals_handler.dart'; | 27 import 'locals_handler.dart'; |
27 import 'loop_handler.dart'; | 28 import 'loop_handler.dart'; |
28 import 'nodes.dart'; | 29 import 'nodes.dart'; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 if (typeBuilder.checkOrTrustTypes) { | 133 if (typeBuilder.checkOrTrustTypes) { |
133 return typeBuilder.potentiallyCheckOrTrustType( | 134 return typeBuilder.potentiallyCheckOrTrustType( |
134 value, compiler.coreTypes.boolType, | 135 value, compiler.coreTypes.boolType, |
135 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 136 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
136 } | 137 } |
137 HInstruction result = new HBoolify(value, backend.boolType); | 138 HInstruction result = new HBoolify(value, backend.boolType); |
138 add(result); | 139 add(result); |
139 return result; | 140 return result; |
140 } | 141 } |
141 | 142 |
| 143 /// Builds generative constructors. |
| 144 /// |
| 145 /// Generative constructors are built in two stages. |
| 146 /// |
| 147 /// First, the field values for every instance field for every class in the |
| 148 /// class hierarchy are collected. Then, create a function body that sets |
| 149 /// all of the instance fields to the collected values and call the |
| 150 /// constructor bodies for all constructors in the hierarchy. |
142 void buildConstructor(ir.Constructor constructor) { | 151 void buildConstructor(ir.Constructor constructor) { |
143 // TODO(het): Actually handle this correctly | 152 openFunction(); |
144 HBasicBlock block = graph.addNewBlock(); | 153 |
145 open(graph.entry); | 154 // Collect field values for the current class. |
146 close(new HGoto()).addSuccessor(block); | 155 // TODO(het): Does kernel always put field initializers in the constructor |
147 open(block); | 156 // initializer list? If so then this is unnecessary... |
148 closeAndGotoExit(new HGoto()); | 157 Map<ir.Field, HInstruction> fieldValues = |
149 graph.finalize(); | 158 _collectFieldValues(constructor.enclosingClass); |
| 159 |
| 160 _buildInitializers(constructor, fieldValues); |
| 161 |
| 162 final constructorArguments = <HInstruction>[]; |
| 163 astAdapter.getClass(constructor.enclosingClass).forEachInstanceField( |
| 164 (ClassElement enclosingClass, FieldElement member) { |
| 165 var value = fieldValues[astAdapter.getFieldFromElement(member)]; |
| 166 constructorArguments.add(value); |
| 167 }, includeSuperAndInjectedMembers: true); |
| 168 |
| 169 // TODO(het): If the class needs runtime type information, add it as a |
| 170 // constructor argument. |
| 171 HInstruction create = new HCreate( |
| 172 astAdapter.getClass(constructor.enclosingClass), |
| 173 constructorArguments, |
| 174 new TypeMask.nonNullExact( |
| 175 astAdapter.getClass(constructor.enclosingClass), |
| 176 compiler.closedWorld), |
| 177 instantiatedTypes: <DartType>[ |
| 178 astAdapter.getClass(constructor.enclosingClass).thisType |
| 179 ], |
| 180 hasRtiInput: false); |
| 181 |
| 182 add(create); |
| 183 |
| 184 // Generate calls to the constructor bodies. |
| 185 |
| 186 closeAndGotoExit(new HReturn(create, null)); |
| 187 closeFunction(); |
| 188 } |
| 189 |
| 190 /// Maps the fields of a class to their SSA values. |
| 191 Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) { |
| 192 final fieldValues = <ir.Field, HInstruction>{}; |
| 193 |
| 194 for (var field in clazz.fields) { |
| 195 if (field.initializer == null) { |
| 196 fieldValues[field] = graph.addConstantNull(compiler); |
| 197 } else { |
| 198 field.initializer.accept(this); |
| 199 fieldValues[field] = pop(); |
| 200 } |
| 201 } |
| 202 |
| 203 return fieldValues; |
| 204 } |
| 205 |
| 206 /// Collects field initializers all the way up the inheritance chain. |
| 207 void _buildInitializers( |
| 208 ir.Constructor constructor, Map<ir.Field, HInstruction> fieldValues) { |
| 209 var foundSuperCall = false; |
| 210 for (var initializer in constructor.initializers) { |
| 211 if (initializer is ir.SuperInitializer) { |
| 212 foundSuperCall = true; |
| 213 var superConstructor = initializer.target; |
| 214 var arguments = _normalizeAndBuildArguments( |
| 215 superConstructor.function, initializer.arguments); |
| 216 _buildInlinedSuperInitializers( |
| 217 superConstructor, arguments, fieldValues); |
| 218 } else if (initializer is ir.FieldInitializer) { |
| 219 initializer.value.accept(this); |
| 220 fieldValues[initializer.field] = pop(); |
| 221 } |
| 222 } |
| 223 |
| 224 // TODO(het): does kernel always set the super initializer at the end? |
| 225 // If there was no super-call initializer, then call the default constructor |
| 226 // in the superclass. |
| 227 if (!foundSuperCall) { |
| 228 if (constructor.enclosingClass != astAdapter.objectClass) { |
| 229 var superclass = constructor.enclosingClass.superclass; |
| 230 var defaultConstructor = superclass.constructors |
| 231 .firstWhere((c) => c.name == '', orElse: () => null); |
| 232 if (defaultConstructor == null) { |
| 233 compiler.reporter.internalError( |
| 234 NO_LOCATION_SPANNABLE, 'Could not find default constructor.'); |
| 235 } |
| 236 _buildInlinedSuperInitializers( |
| 237 defaultConstructor, <HInstruction>[], fieldValues); |
| 238 } |
| 239 } |
| 240 } |
| 241 |
| 242 List<HInstruction> _normalizeAndBuildArguments( |
| 243 ir.FunctionNode function, ir.Arguments arguments) { |
| 244 var signature = astAdapter.getFunctionSignature(function); |
| 245 var builtArguments = <HInstruction>[]; |
| 246 var positionalIndex = 0; |
| 247 signature.forEachRequiredParameter((_) { |
| 248 arguments.positional[positionalIndex++].accept(this); |
| 249 builtArguments.add(pop()); |
| 250 }); |
| 251 if (!signature.optionalParametersAreNamed) { |
| 252 signature.forEachOptionalParameter((ParameterElement element) { |
| 253 if (positionalIndex < arguments.positional.length) { |
| 254 arguments.positional[positionalIndex++].accept(this); |
| 255 builtArguments.add(pop()); |
| 256 } else { |
| 257 var constantValue = |
| 258 backend.constants.getConstantValue(element.constant); |
| 259 assert(invariant(element, constantValue != null, |
| 260 message: 'No constant computed for $element')); |
| 261 builtArguments.add(graph.addConstant(constantValue, compiler)); |
| 262 } |
| 263 }); |
| 264 } else { |
| 265 signature.orderedOptionalParameters.forEach((ParameterElement element) { |
| 266 var correspondingNamed = arguments.named.firstWhere( |
| 267 (named) => named.name == element.name, |
| 268 orElse: () => null); |
| 269 if (correspondingNamed != null) { |
| 270 correspondingNamed.value.accept(this); |
| 271 builtArguments.add(pop()); |
| 272 } else { |
| 273 var constantValue = |
| 274 backend.constants.getConstantValue(element.constant); |
| 275 assert(invariant(element, constantValue != null, |
| 276 message: 'No constant computed for $element')); |
| 277 builtArguments.add(graph.addConstant(constantValue, compiler)); |
| 278 } |
| 279 }); |
| 280 } |
| 281 |
| 282 return builtArguments; |
| 283 } |
| 284 |
| 285 /// Inlines the given super [constructor]'s initializers by collecting it's |
| 286 /// field values and building its constructor initializers. We visit super |
| 287 /// constructors all the way up to the [Object] constructor. |
| 288 void _buildInlinedSuperInitializers(ir.Constructor constructor, |
| 289 List<HInstruction> arguments, Map<ir.Field, HInstruction> fieldValues) { |
| 290 // TODO(het): Handle RTI if class needs it |
| 291 fieldValues.addAll(_collectFieldValues(constructor.enclosingClass)); |
| 292 |
| 293 var signature = astAdapter.getFunctionSignature(constructor.function); |
| 294 var index = 0; |
| 295 signature.orderedForEachParameter((ParameterElement parameter) { |
| 296 HInstruction argument = arguments[index++]; |
| 297 // Because we are inlining the initializer, we must update |
| 298 // what was given as parameter. This will be used in case |
| 299 // there is a parameter check expression in the initializer. |
| 300 parameters[parameter] = argument; |
| 301 localsHandler.updateLocal(parameter, argument); |
| 302 }); |
| 303 |
| 304 // TODO(het): set the locals handler state as if we were inlining the |
| 305 // constructor. |
| 306 _buildInitializers(constructor, fieldValues); |
150 } | 307 } |
151 | 308 |
152 HTypeConversion buildFunctionTypeConversion( | 309 HTypeConversion buildFunctionTypeConversion( |
153 HInstruction original, DartType type, int kind) { | 310 HInstruction original, DartType type, int kind) { |
154 String name = | 311 String name = |
155 kind == HTypeConversion.CAST_TYPE_CHECK ? '_asCheck' : '_assertCheck'; | 312 kind == HTypeConversion.CAST_TYPE_CHECK ? '_asCheck' : '_assertCheck'; |
156 | 313 |
157 List<HInstruction> arguments = <HInstruction>[ | 314 List<HInstruction> arguments = <HInstruction>[ |
158 buildFunctionType(type), | 315 buildFunctionType(type), |
159 original | 316 original |
160 ]; | 317 ]; |
161 _pushDynamicInvocation(null, null, arguments, | 318 _pushDynamicInvocation(null, null, arguments, |
162 selector: new Selector.call( | 319 selector: new Selector.call( |
163 new Name(name, astAdapter.jsHelperLibrary), CallStructure.ONE_ARG)); | 320 new Name(name, astAdapter.jsHelperLibrary), CallStructure.ONE_ARG)); |
164 | 321 |
165 return new HTypeConversion(type, kind, original.instructionType, pop()); | 322 return new HTypeConversion(type, kind, original.instructionType, pop()); |
166 } | 323 } |
167 | 324 |
168 /// Builds a SSA graph for [procedure]. | 325 /// Builds a SSA graph for [procedure]. |
169 void buildProcedure(ir.Procedure procedure) { | 326 void buildProcedure(ir.Procedure procedure) { |
170 openFunction(); | 327 openFunction(); |
171 procedure.function.body.accept(this); | 328 procedure.function.body.accept(this); |
172 closeFunction(); | 329 closeFunction(); |
173 } | 330 } |
174 | 331 |
175 void openFunction() { | 332 void openFunction() { |
176 HBasicBlock block = graph.addNewBlock(); | 333 HBasicBlock block = graph.addNewBlock(); |
177 open(graph.entry); | 334 open(graph.entry); |
178 localsHandler.startFunction(targetElement, resolvedAst.node); | 335 |
| 336 Node function; |
| 337 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| 338 function = resolvedAst.node; |
| 339 } |
| 340 localsHandler.startFunction(targetElement, function); |
179 close(new HGoto()).addSuccessor(block); | 341 close(new HGoto()).addSuccessor(block); |
180 | 342 |
181 open(block); | 343 open(block); |
182 } | 344 } |
183 | 345 |
184 void closeFunction() { | 346 void closeFunction() { |
185 if (!isAborted()) closeAndGotoExit(new HGoto()); | 347 if (!isAborted()) closeAndGotoExit(new HGoto()); |
186 graph.finalize(); | 348 graph.finalize(); |
187 } | 349 } |
188 | 350 |
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 push(new HNot(popBoolified(), backend.boolType)); | 1025 push(new HNot(popBoolified(), backend.boolType)); |
864 } | 1026 } |
865 | 1027 |
866 @override | 1028 @override |
867 void visitStringConcatenation(ir.StringConcatenation stringConcat) { | 1029 void visitStringConcatenation(ir.StringConcatenation stringConcat) { |
868 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); | 1030 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); |
869 stringConcat.accept(stringBuilder); | 1031 stringConcat.accept(stringBuilder); |
870 stack.add(stringBuilder.result); | 1032 stack.add(stringBuilder.result); |
871 } | 1033 } |
872 } | 1034 } |
OLD | NEW |