Chromium Code Reviews| 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 '../closure.dart'; | 7 import '../closure.dart'; |
| 8 import '../common.dart'; | 8 import '../common.dart'; |
| 9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 9 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| 10 import '../common/names.dart'; | 10 import '../common/names.dart'; |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 151 graph.sourceInformation = | 151 graph.sourceInformation = |
| 152 sourceInformationBuilder.buildVariableDeclaration(); | 152 sourceInformationBuilder.buildVariableDeclaration(); |
| 153 this.localsHandler = new LocalsHandler( | 153 this.localsHandler = new LocalsHandler( |
| 154 this, targetElement, null, nativeData, interceptorData); | 154 this, targetElement, null, nativeData, interceptorData); |
| 155 this.astAdapter = new KernelAstAdapter(kernel, compiler.backend, | 155 this.astAdapter = new KernelAstAdapter(kernel, compiler.backend, |
| 156 resolvedAst, kernel.nodeToAst, kernel.nodeToElement); | 156 resolvedAst, kernel.nodeToAst, kernel.nodeToElement); |
| 157 target = astAdapter.getInitialKernelNode(targetElement); | 157 target = astAdapter.getInitialKernelNode(targetElement); |
| 158 if (targetElement is ConstructorBodyElement) { | 158 if (targetElement is ConstructorBodyElement) { |
| 159 _targetIsConstructorBody = true; | 159 _targetIsConstructorBody = true; |
| 160 } | 160 } |
| 161 _targetStack.add(target); | |
| 161 } | 162 } |
| 162 | 163 |
| 163 HGraph build() { | 164 HGraph build() { |
| 164 // TODO(het): no reason to do this here... | 165 // TODO(het): no reason to do this here... |
| 165 HInstruction.idCounter = 0; | 166 HInstruction.idCounter = 0; |
| 166 if (target is ir.Procedure) { | 167 if (target is ir.Procedure) { |
| 167 _targetFunction = (target as ir.Procedure).function; | 168 _targetFunction = (target as ir.Procedure).function; |
| 168 buildFunctionNode(_targetFunction); | 169 buildFunctionNode(_targetFunction); |
| 169 } else if (target is ir.Field) { | 170 } else if (target is ir.Field) { |
| 170 buildField(target); | 171 buildField(target); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 212 if (typeBuilder.checkOrTrustTypes) { | 213 if (typeBuilder.checkOrTrustTypes) { |
| 213 ResolutionInterfaceType type = commonElements.boolType; | 214 ResolutionInterfaceType type = commonElements.boolType; |
| 214 return typeBuilder.potentiallyCheckOrTrustType(value, type, | 215 return typeBuilder.potentiallyCheckOrTrustType(value, type, |
| 215 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); | 216 kind: HTypeConversion.BOOLEAN_CONVERSION_CHECK); |
| 216 } | 217 } |
| 217 HInstruction result = new HBoolify(value, commonMasks.boolType); | 218 HInstruction result = new HBoolify(value, commonMasks.boolType); |
| 218 add(result); | 219 add(result); |
| 219 return result; | 220 return result; |
| 220 } | 221 } |
| 221 | 222 |
| 223 /// Extend current method parameters with parameters for the class type | |
| 224 /// parameters. If the class has type parameters but does not need them, bind | |
| 225 /// to `dynamic` (represented as `null`) so the bindings are available for | |
| 226 /// building types up the inheritance chain of generative constructors. | |
| 222 void _addClassTypeVariablesIfNeeded(ir.Member constructor) { | 227 void _addClassTypeVariablesIfNeeded(ir.Member constructor) { |
| 223 var enclosing = constructor.enclosingClass; | 228 var enclosing = constructor.enclosingClass; |
| 224 if (rtiNeed.classNeedsRti(astAdapter.getElement(enclosing))) { | 229 bool needParameters; |
| 225 enclosing.typeParameters.forEach((ir.TypeParameter typeParameter) { | 230 enclosing.typeParameters.forEach((ir.TypeParameter typeParameter) { |
| 226 var typeParamElement = astAdapter.getElement(typeParameter); | 231 var typeParamElement = astAdapter.getElement(typeParameter); |
| 227 HParameterValue param = | 232 HInstruction param; |
| 228 addParameter(typeParamElement, commonMasks.nonNullType); | 233 needParameters ??= |
| 229 // This is a little bit wacky (and n^2) until we make the localsHandler | 234 rtiNeed.classNeedsRti(astAdapter.getElement(enclosing)); |
| 230 // take Kernel DartTypes instead of just the AST DartTypes. | 235 if (needParameters) { |
| 231 var typeVariableType = astAdapter | 236 param = addParameter(typeParamElement, commonMasks.nonNullType); |
| 232 .getClass(enclosing) | 237 } else { |
| 233 .typeVariables | 238 // Unused, so bind to `dynamic`. |
| 234 .firstWhere( | 239 param = graph.addConstantNull(closedWorld); |
| 235 (ResolutionTypeVariableType i) => i.name == typeParameter.name); | 240 } |
| 236 localsHandler.directLocals[ | 241 // This is a little bit wacky (and n^2) until we make the localsHandler |
| 237 localsHandler.getTypeVariableAsLocal(typeVariableType)] = param; | 242 // take Kernel DartTypes instead of just the AST DartTypes. |
| 238 }); | 243 var typeVariableType = astAdapter |
| 239 } | 244 .getClass(enclosing) |
| 245 .typeVariables | |
| 246 .firstWhere( | |
| 247 (ResolutionTypeVariableType i) => i.name == typeParameter.name); | |
| 248 localsHandler.directLocals[ | |
| 249 localsHandler.getTypeVariableAsLocal(typeVariableType)] = param; | |
| 250 }); | |
| 240 } | 251 } |
| 241 | 252 |
| 242 /// Builds generative constructors. | 253 /// Builds a generative constructor. |
| 243 /// | 254 /// |
| 244 /// Generative constructors are built in two stages. | 255 /// Generative constructors are built in stages, in effect inlining the |
| 256 /// initializers and constructor bodies up the inheritance chain. | |
| 245 /// | 257 /// |
| 246 /// First, the field values for every instance field for every class in the | 258 /// 1. Extend method parameters with parameters the class's type parameters. |
|
Siggi Cherem (dart-lang)
2017/04/27 00:32:27
with parameters the => with the
| |
| 247 /// class hierarchy are collected. Then, create a function body that sets | 259 /// |
| 248 /// all of the instance fields to the collected values and call the | 260 /// 2. Add type checks for value parameters (might need result of (1)). |
| 249 /// constructor bodies for all constructors in the hierarchy. | 261 /// |
| 262 /// 3. Walk inheritance chain to build bindings for type parameters of | |
| 263 /// superclasses and mixed-in classes. | |
| 264 /// | |
| 265 /// 4. Collect initializer values. Walk up inheritance chain to collect field | |
| 266 /// initializers from field declarations, initializing parameters and | |
| 267 /// initializer. | |
|
Siggi Cherem (dart-lang)
2017/04/27 00:32:27
"intializer" => "initializer assignments"? or "ini
| |
| 268 /// | |
| 269 /// 5. Create reified type information for instance. | |
|
Siggi Cherem (dart-lang)
2017/04/27 00:32:27
nit: for instance => for the object instance? (I r
| |
| 270 /// | |
| 271 /// 6. Allocate instance and assign initializers and reified type information | |
|
Siggi Cherem (dart-lang)
2017/04/27 00:32:27
instance => object instance
| |
| 272 /// to fields by calling JavaScript constructor. | |
| 273 /// | |
| 274 /// 7. Walk inheritance chain to call or inline constructor bodies. | |
| 275 /// | |
| 276 /// All the bindings are put in the constructor's locals handler. The | |
| 277 /// implication is that a class cannot be extended or mixed-in twice. If we in | |
| 278 /// future support repeated uses of a mixin class, we should do so by cloning | |
|
Siggi Cherem (dart-lang)
2017/04/27 00:32:27
in future => in the future
| |
| 279 /// the mixin class in the Kernel input. | |
| 250 void buildConstructor(ir.Constructor constructor) { | 280 void buildConstructor(ir.Constructor constructor) { |
| 281 ir.Class constructedClass = constructor.enclosingClass; | |
| 282 | |
| 251 openFunction(); | 283 openFunction(); |
| 252 _addClassTypeVariablesIfNeeded(constructor); | 284 _addClassTypeVariablesIfNeeded(constructor); |
| 253 | 285 |
| 286 // TODO(sra): Type parameter constraint checks. | |
| 287 | |
| 288 // TODO(sra): Checked mode parameter checks. | |
| 289 | |
| 254 // Collect field values for the current class. | 290 // Collect field values for the current class. |
| 255 // TODO(het): Does kernel always put field initializers in the constructor | |
| 256 // initializer list? If so then this is unnecessary... | |
| 257 Map<ir.Field, HInstruction> fieldValues = | 291 Map<ir.Field, HInstruction> fieldValues = |
| 258 _collectFieldValues(constructor.enclosingClass); | 292 _collectFieldValues(constructedClass); |
| 259 List<ir.Constructor> constructorChain = <ir.Constructor>[]; | 293 List<ir.Constructor> constructorChain = <ir.Constructor>[]; |
| 260 | |
| 261 _buildInitializers(constructor, constructorChain, fieldValues); | 294 _buildInitializers(constructor, constructorChain, fieldValues); |
| 262 | 295 |
| 263 final constructorArguments = <HInstruction>[]; | 296 final constructorArguments = <HInstruction>[]; |
| 264 // Doing this instead of fieldValues.forEach because we haven't defined the | 297 // Doing this instead of fieldValues.forEach because we haven't defined the |
| 265 // order of the arguments here. We can define that with JElements. | 298 // order of the arguments here. We can define that with JElements. |
| 266 astAdapter.getClass(constructor.enclosingClass).forEachInstanceField( | 299 astAdapter.getClass(constructedClass).forEachInstanceField( |
| 267 (ClassElement enclosingClass, FieldElement member) { | 300 (ClassElement enclosingClass, FieldElement member) { |
| 268 var value = fieldValues[astAdapter.getFieldFromElement(member)]; | 301 var value = fieldValues[astAdapter.getFieldFromElement(member)]; |
| 302 assert(value != null, | |
| 303 'No value for field ${member} aka ${astAdapter.getFieldFromElement(mem ber)}'); | |
| 269 constructorArguments.add(value); | 304 constructorArguments.add(value); |
| 270 }, includeSuperAndInjectedMembers: true); | 305 }, includeSuperAndInjectedMembers: true); |
| 271 | 306 |
| 272 // TODO(het): If the class needs runtime type information, add it as a | 307 // Create the runtime type information, if needed. |
| 273 // constructor argument. | 308 bool hasRtiInput = backend.rtiNeed |
| 309 .classNeedsRtiField(astAdapter.getClass(constructedClass)); | |
| 310 if (hasRtiInput) { | |
| 311 // Read the values of the type arguments and create a HTypeInfoExpression | |
| 312 // to set on the newly create object. | |
| 313 List<HInstruction> typeArguments = <HInstruction>[]; | |
| 314 for (ir.DartType typeParameter | |
| 315 in constructedClass.thisType.typeArguments) { | |
| 316 HInstruction argument = localsHandler.readLocal(localsHandler | |
| 317 .getTypeVariableAsLocal(astAdapter.getDartType(typeParameter) | |
| 318 as ResolutionTypeVariableType)); | |
| 319 typeArguments.add(argument); | |
| 320 } | |
| 321 | |
| 322 HInstruction typeInfo = new HTypeInfoExpression( | |
| 323 TypeInfoExpressionKind.INSTANCE, | |
| 324 astAdapter.getClass(constructedClass).thisType, | |
| 325 typeArguments, | |
| 326 commonMasks.dynamicType); | |
| 327 add(typeInfo); | |
| 328 constructorArguments.add(typeInfo); | |
| 329 } | |
| 330 | |
| 274 HInstruction newObject = new HCreate( | 331 HInstruction newObject = new HCreate( |
| 275 astAdapter.getClass(constructor.enclosingClass), | 332 astAdapter.getClass(constructedClass), |
| 276 constructorArguments, | 333 constructorArguments, |
| 277 new TypeMask.nonNullExact( | 334 new TypeMask.nonNullExact( |
| 278 astAdapter.getClass(constructor.enclosingClass), closedWorld), | 335 astAdapter.getClass(constructedClass), closedWorld), |
| 279 instantiatedTypes: <ResolutionInterfaceType>[ | 336 instantiatedTypes: <ResolutionInterfaceType>[ |
| 280 astAdapter.getClass(constructor.enclosingClass).thisType | 337 astAdapter.getClass(constructedClass).thisType |
| 281 ], | 338 ], |
| 282 hasRtiInput: false); | 339 hasRtiInput: hasRtiInput); |
| 283 | 340 |
| 284 add(newObject); | 341 add(newObject); |
| 285 | 342 |
| 286 // Generate calls to the constructor bodies. | 343 // Generate calls to the constructor bodies. |
| 287 | 344 |
| 288 for (ir.Constructor body in constructorChain.reversed) { | 345 for (ir.Constructor body in constructorChain.reversed) { |
| 289 if (_isEmptyStatement(body.function.body)) continue; | 346 if (_isEmptyStatement(body.function.body)) continue; |
| 290 | 347 |
| 291 List<HInstruction> bodyCallInputs = <HInstruction>[]; | 348 List<HInstruction> bodyCallInputs = <HInstruction>[]; |
| 292 bodyCallInputs.add(newObject); | 349 bodyCallInputs.add(newObject); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 309 }); | 366 }); |
| 310 | 367 |
| 311 // If there are locals that escape (i.e. mutated in closures), we pass the | 368 // If there are locals that escape (i.e. mutated in closures), we pass the |
| 312 // box to the constructor. | 369 // box to the constructor. |
| 313 ClosureScope scopeData = parameterClosureData | 370 ClosureScope scopeData = parameterClosureData |
| 314 .capturingScopes[constructorElement.resolvedAst.node]; | 371 .capturingScopes[constructorElement.resolvedAst.node]; |
| 315 if (scopeData != null) { | 372 if (scopeData != null) { |
| 316 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); | 373 bodyCallInputs.add(localsHandler.readLocal(scopeData.boxElement)); |
| 317 } | 374 } |
| 318 | 375 |
| 319 // TODO(sra): Pass type arguments. | 376 // Pass type arguments. |
| 377 ir.Class currentClass = body.enclosingClass; | |
| 378 if (backend.rtiNeed.classNeedsRti(astAdapter.getClass(currentClass))) { | |
| 379 for (ir.DartType typeParameter in currentClass.thisType.typeArguments) { | |
| 380 HInstruction argument = localsHandler.readLocal(localsHandler | |
| 381 .getTypeVariableAsLocal(astAdapter.getDartType(typeParameter) | |
| 382 as ResolutionTypeVariableType)); | |
| 383 bodyCallInputs.add(argument); | |
| 384 } | |
| 385 } | |
| 320 | 386 |
| 321 _invokeConstructorBody(body, bodyCallInputs); | 387 _invokeConstructorBody(body, bodyCallInputs); |
| 322 } | 388 } |
| 323 | 389 |
| 324 closeAndGotoExit(new HReturn(newObject, null)); | 390 closeAndGotoExit(new HReturn(newObject, null)); |
| 325 closeFunction(); | 391 closeFunction(); |
| 326 } | 392 } |
| 327 | 393 |
| 328 static bool _isEmptyStatement(ir.Statement body) { | 394 static bool _isEmptyStatement(ir.Statement body) { |
| 329 if (body is ir.EmptyStatement) return true; | 395 if (body is ir.EmptyStatement) return true; |
| 330 if (body is ir.Block) return body.statements.every(_isEmptyStatement); | 396 if (body is ir.Block) return body.statements.every(_isEmptyStatement); |
| 331 return false; | 397 return false; |
| 332 } | 398 } |
| 333 | 399 |
| 334 void _invokeConstructorBody( | 400 void _invokeConstructorBody( |
| 335 ir.Constructor constructor, List<HInstruction> inputs) { | 401 ir.Constructor constructor, List<HInstruction> inputs) { |
| 336 // TODO(sra): Inline the constructor body. | 402 // TODO(sra): Inline the constructor body. |
| 337 MemberEntity constructorBody = | 403 MemberEntity constructorBody = |
| 338 astAdapter.getConstructorBodyEntity(constructor); | 404 astAdapter.getConstructorBodyEntity(constructor); |
| 339 HInvokeConstructorBody invoke = new HInvokeConstructorBody( | 405 HInvokeConstructorBody invoke = new HInvokeConstructorBody( |
| 340 constructorBody, inputs, commonMasks.nonNullType); | 406 constructorBody, inputs, commonMasks.nonNullType); |
| 341 add(invoke); | 407 add(invoke); |
| 342 } | 408 } |
| 343 | 409 |
| 410 withCurrentIrNode(ir.Node node, f()) { | |
| 411 compiler.reporter.withCurrentElement(astAdapter.getElement(node), f); | |
| 412 } | |
| 413 | |
| 414 /// Sets context for generating code that is the result of inlining | |
| 415 /// [inlinedTarget]. | |
| 416 inlinedFrom(ir.TreeNode inlinedTarget, f()) { | |
| 417 withCurrentIrNode(inlinedTarget, () { | |
| 418 SourceInformationBuilder oldSourceInformationBuilder = | |
| 419 sourceInformationBuilder; | |
| 420 // TODO(sra): Update sourceInformationBuilder to Kernel. | |
| 421 // sourceInformationBuilder = | |
| 422 // sourceInformationBuilder.forContext(resolvedAst); | |
| 423 _targetStack.add(inlinedTarget); | |
| 424 var result = f(); | |
| 425 sourceInformationBuilder = oldSourceInformationBuilder; | |
| 426 _targetStack.removeLast(); | |
| 427 return result; | |
| 428 }); | |
| 429 } | |
| 430 | |
| 344 /// Maps the instance fields of a class to their SSA values. | 431 /// Maps the instance fields of a class to their SSA values. |
| 345 Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) { | 432 Map<ir.Field, HInstruction> _collectFieldValues(ir.Class clazz) { |
| 346 final fieldValues = <ir.Field, HInstruction>{}; | 433 final fieldValues = <ir.Field, HInstruction>{}; |
| 347 | 434 |
| 348 for (var field in clazz.fields) { | 435 for (var field in clazz.fields) { |
| 349 if (field.isInstanceMember) { | 436 if (field.isInstanceMember) { |
| 350 if (field.initializer == null) { | 437 if (field.initializer == null) { |
| 351 fieldValues[field] = graph.addConstantNull(closedWorld); | 438 fieldValues[field] = graph.addConstantNull(closedWorld); |
| 352 } else { | 439 } else { |
| 353 // Gotta update the resolvedAst when we're looking at field values | 440 // Gotta update the resolvedAst when we're looking at field values |
| 354 // outside the constructor. | 441 // outside the constructor. |
| 355 astAdapter.pushResolvedAst(field); | 442 astAdapter.pushResolvedAst(field); |
| 356 field.initializer.accept(this); | 443 inlinedFrom(field, () { |
| 357 fieldValues[field] = pop(); | 444 field.initializer.accept(this); |
| 445 fieldValues[field] = pop(); | |
| 446 }); | |
| 358 astAdapter.popResolvedAstStack(); | 447 astAdapter.popResolvedAstStack(); |
| 359 } | 448 } |
| 360 } | 449 } |
| 361 } | 450 } |
| 362 | 451 |
| 363 return fieldValues; | 452 return fieldValues; |
| 364 } | 453 } |
| 365 | 454 |
| 366 /// Collects field initializers all the way up the inheritance chain. | 455 /// Collects field initializers all the way up the inheritance chain. |
| 367 void _buildInitializers( | 456 void _buildInitializers( |
| 368 ir.Constructor constructor, | 457 ir.Constructor constructor, |
| 369 List<ir.Constructor> constructorChain, | 458 List<ir.Constructor> constructorChain, |
| 370 Map<ir.Field, HInstruction> fieldValues) { | 459 Map<ir.Field, HInstruction> fieldValues) { |
| 460 astAdapter.assertAtResolvedAstFor(constructor); | |
| 371 constructorChain.add(constructor); | 461 constructorChain.add(constructor); |
| 462 | |
| 372 var foundSuperOrRedirectCall = false; | 463 var foundSuperOrRedirectCall = false; |
| 373 for (var initializer in constructor.initializers) { | 464 for (var initializer in constructor.initializers) { |
| 374 if (initializer is ir.SuperInitializer || | 465 if (initializer is ir.FieldInitializer) { |
| 375 initializer is ir.RedirectingInitializer) { | |
| 376 foundSuperOrRedirectCall = true; | |
| 377 var superOrRedirectConstructor = initializer.target; | |
| 378 var arguments = _normalizeAndBuildArguments( | |
| 379 superOrRedirectConstructor.function, initializer.arguments); | |
| 380 _buildInlinedInitializers(superOrRedirectConstructor, arguments, | |
| 381 constructorChain, fieldValues); | |
| 382 } else if (initializer is ir.FieldInitializer) { | |
| 383 initializer.value.accept(this); | 466 initializer.value.accept(this); |
| 384 fieldValues[initializer.field] = pop(); | 467 fieldValues[initializer.field] = pop(); |
| 468 } else if (initializer is ir.SuperInitializer) { | |
| 469 assert(!foundSuperOrRedirectCall); | |
| 470 foundSuperOrRedirectCall = true; | |
| 471 _inlineSuperInitializer( | |
| 472 initializer, constructorChain, fieldValues, constructor); | |
| 473 } else if (initializer is ir.RedirectingInitializer) { | |
| 474 assert(!foundSuperOrRedirectCall); | |
| 475 foundSuperOrRedirectCall = true; | |
| 476 _inlineRedirectingInitializer( | |
| 477 initializer, constructorChain, fieldValues, constructor); | |
| 478 } else if (initializer is ir.LocalInitializer) { | |
| 479 assert(false, 'ir.LocalInitializer not handled'); | |
| 480 } else if (initializer is ir.InvalidInitializer) { | |
| 481 assert(false, 'ir.InvalidInitializer not handled'); | |
| 385 } | 482 } |
| 386 } | 483 } |
| 387 | 484 |
| 388 if (!foundSuperOrRedirectCall) { | 485 if (!foundSuperOrRedirectCall) { |
| 389 assert(constructor.enclosingClass == astAdapter.objectClass, | 486 assert( |
| 390 'All constructors have super-constructor initializers, except Object() '); | 487 constructor.enclosingClass == astAdapter.objectClass, |
| 488 'All constructors should have super- or redirecting- initializers,' | |
| 489 ' except Object()'); | |
| 391 } | 490 } |
| 392 } | 491 } |
| 393 | 492 |
| 394 List<HInstruction> _normalizeAndBuildArguments( | 493 List<HInstruction> _normalizeAndBuildArguments( |
| 395 ir.FunctionNode function, ir.Arguments arguments) { | 494 ir.FunctionNode function, ir.Arguments arguments) { |
| 396 var signature = astAdapter.getFunctionSignature(function); | 495 var signature = astAdapter.getFunctionSignature(function); |
| 397 var builtArguments = <HInstruction>[]; | 496 var builtArguments = <HInstruction>[]; |
| 398 var positionalIndex = 0; | 497 var positionalIndex = 0; |
| 399 signature.forEachRequiredParameter((_) { | 498 signature.forEachRequiredParameter((_) { |
| 400 arguments.positional[positionalIndex++].accept(this); | 499 arguments.positional[positionalIndex++].accept(this); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 425 assert(invariant(element, constantValue != null, | 524 assert(invariant(element, constantValue != null, |
| 426 message: 'No constant computed for $element')); | 525 message: 'No constant computed for $element')); |
| 427 builtArguments.add(graph.addConstant(constantValue, closedWorld)); | 526 builtArguments.add(graph.addConstant(constantValue, closedWorld)); |
| 428 } | 527 } |
| 429 }); | 528 }); |
| 430 } | 529 } |
| 431 | 530 |
| 432 return builtArguments; | 531 return builtArguments; |
| 433 } | 532 } |
| 434 | 533 |
| 534 /// Creates localsHandler bindings for type parameters of a Supertype. | |
| 535 void _bindSupertypeTypeParameters(ir.Supertype supertype) { | |
| 536 ir.Class cls = supertype.classNode; | |
| 537 var parameters = cls.typeParameters; | |
| 538 var arguments = supertype.typeArguments; | |
| 539 assert(arguments.length == parameters.length); | |
| 540 | |
| 541 for (int i = 0; i < parameters.length; i++) { | |
| 542 ir.DartType argument = arguments[i]; | |
| 543 ir.TypeParameter parameter = parameters[i]; | |
| 544 | |
| 545 localsHandler.updateLocal( | |
| 546 localsHandler.getTypeVariableAsLocal( | |
| 547 astAdapter.getDartType(new ir.TypeParameterType(parameter))), | |
| 548 typeBuilder.analyzeTypeArgument( | |
| 549 astAdapter.getDartType(argument), sourceElement)); | |
| 550 } | |
| 551 } | |
| 552 | |
| 553 /// Inlines the given redirecting [constructor]'s initializers by collecting | |
| 554 /// its field values and building its constructor initializers. We visit super | |
| 555 /// constructors all the way up to the [Object] constructor. | |
| 556 void _inlineRedirectingInitializer( | |
| 557 ir.RedirectingInitializer initializer, | |
| 558 List<ir.Constructor> constructorChain, | |
| 559 Map<ir.Field, HInstruction> fieldValues, | |
| 560 ir.Constructor caller) { | |
| 561 var superOrRedirectConstructor = initializer.target; | |
| 562 var arguments = _normalizeAndBuildArguments( | |
| 563 superOrRedirectConstructor.function, initializer.arguments); | |
| 564 | |
| 565 // Redirecting initializer already has [localsHandler] bindings for type | |
| 566 // parameters from the redirecting constructor. | |
| 567 | |
| 568 // For redirecting constructors, the fields will be initialized later by the | |
| 569 // effective target, so we don't do it here. | |
| 570 | |
| 571 _inlineSuperOrRedirectCommon(initializer, superOrRedirectConstructor, | |
| 572 arguments, constructorChain, fieldValues, caller); | |
| 573 } | |
| 574 | |
| 435 /// Inlines the given super [constructor]'s initializers by collecting its | 575 /// Inlines the given super [constructor]'s initializers by collecting its |
| 436 /// field values and building its constructor initializers. We visit super | 576 /// field values and building its constructor initializers. We visit super |
| 437 /// constructors all the way up to the [Object] constructor. | 577 /// constructors all the way up to the [Object] constructor. |
| 438 void _buildInlinedInitializers( | 578 void _inlineSuperInitializer( |
| 579 ir.SuperInitializer initializer, | |
| 580 List<ir.Constructor> constructorChain, | |
| 581 Map<ir.Field, HInstruction> fieldValues, | |
| 582 ir.Constructor caller) { | |
| 583 var target = initializer.target; | |
| 584 var arguments = | |
| 585 _normalizeAndBuildArguments(target.function, initializer.arguments); | |
| 586 | |
| 587 ir.Class callerClass = caller.enclosingClass; | |
| 588 _bindSupertypeTypeParameters(callerClass.supertype); | |
| 589 if (callerClass.mixedInType != null) { | |
| 590 _bindSupertypeTypeParameters(callerClass.mixedInType); | |
| 591 } | |
| 592 | |
| 593 ir.Class cls = target.enclosingClass; | |
| 594 | |
| 595 inlinedFrom(target, () { | |
| 596 fieldValues.addAll(_collectFieldValues(cls)); | |
| 597 }); | |
| 598 | |
| 599 _inlineSuperOrRedirectCommon( | |
| 600 initializer, target, arguments, constructorChain, fieldValues, caller); | |
| 601 } | |
| 602 | |
| 603 void _inlineSuperOrRedirectCommon( | |
| 604 ir.Initializer initializer, | |
| 439 ir.Constructor constructor, | 605 ir.Constructor constructor, |
| 440 List<HInstruction> arguments, | 606 List<HInstruction> arguments, |
| 441 List<ir.Constructor> constructorChain, | 607 List<ir.Constructor> constructorChain, |
| 442 Map<ir.Field, HInstruction> fieldValues) { | 608 Map<ir.Field, HInstruction> fieldValues, |
| 443 // TODO(het): Handle RTI if class needs it | 609 ir.Constructor caller) { |
| 444 fieldValues.addAll(_collectFieldValues(constructor.enclosingClass)); | |
| 445 | |
| 446 var signature = astAdapter.getFunctionSignature(constructor.function); | 610 var signature = astAdapter.getFunctionSignature(constructor.function); |
| 447 var index = 0; | 611 var index = 0; |
| 448 signature.orderedForEachParameter((ParameterElement parameter) { | 612 signature.orderedForEachParameter((ParameterElement parameter) { |
| 449 HInstruction argument = arguments[index++]; | 613 HInstruction argument = arguments[index++]; |
| 450 // Because we are inlining the initializer, we must update | 614 // Because we are inlining the initializer, we must update |
| 451 // what was given as parameter. This will be used in case | 615 // what was given as parameter. This will be used in case |
| 452 // there is a parameter check expression in the initializer. | 616 // there is a parameter check expression in the initializer. |
| 453 parameters[parameter] = argument; | 617 parameters[parameter] = argument; |
| 454 localsHandler.updateLocal(parameter, argument); | 618 localsHandler.updateLocal(parameter, argument); |
| 455 }); | 619 }); |
| 456 | 620 |
| 457 // TODO(het): set the locals handler state as if we were inlining the | 621 // Set the locals handler state as if we were inlining the constructor. |
| 458 // constructor. | 622 astAdapter.pushResolvedAst(constructor); |
| 459 _buildInitializers(constructor, constructorChain, fieldValues); | 623 ResolvedAst resolvedAst = astAdapter.getElement(constructor).resolvedAst; |
| 624 ClosureClassMap oldClosureData = localsHandler.closureData; | |
| 625 ClosureClassMap newClosureData = | |
| 626 compiler.closureToClassMapper.getClosureToClassMapping(resolvedAst); | |
| 627 localsHandler.closureData = newClosureData; | |
| 628 if (resolvedAst.kind == ResolvedAstKind.PARSED) { | |
| 629 localsHandler.enterScope( | |
| 630 resolvedAst.node, astAdapter.getElement(constructor)); | |
| 631 } | |
| 632 inlinedFrom(constructor, () { | |
| 633 _buildInitializers(constructor, constructorChain, fieldValues); | |
| 634 }); | |
| 635 localsHandler.closureData = oldClosureData; | |
| 636 astAdapter.popResolvedAstStack(); | |
| 460 } | 637 } |
| 461 | 638 |
| 462 /// Builds generative constructor body. | 639 /// Builds generative constructor body. |
| 463 void buildConstructorBody(ir.Constructor constructor) { | 640 void buildConstructorBody(ir.Constructor constructor) { |
| 464 openFunction(); | 641 openFunction(); |
| 642 _addClassTypeVariablesIfNeeded(constructor); | |
| 465 constructor.function.body.accept(this); | 643 constructor.function.body.accept(this); |
| 466 closeFunction(); | 644 closeFunction(); |
| 467 } | 645 } |
| 468 | 646 |
| 469 /// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and | 647 /// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and |
| 470 /// Procedures. | 648 /// Procedures. |
| 471 void buildFunctionNode(ir.FunctionNode functionNode) { | 649 void buildFunctionNode(ir.FunctionNode functionNode) { |
| 472 openFunction(); | 650 openFunction(); |
| 473 if (functionNode.parent is ir.Procedure && | 651 if (functionNode.parent is ir.Procedure && |
| 474 (functionNode.parent as ir.Procedure).kind == | 652 (functionNode.parent as ir.Procedure).kind == |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 push(trap); | 718 push(trap); |
| 541 } | 719 } |
| 542 | 720 |
| 543 /// Returns the current source element. This is used by the type builder. | 721 /// Returns the current source element. This is used by the type builder. |
| 544 /// | 722 /// |
| 545 /// The returned element is a declaration element. | 723 /// The returned element is a declaration element. |
| 546 // TODO(efortuna): Update this when we implement inlining. | 724 // TODO(efortuna): Update this when we implement inlining. |
| 547 // TODO(sra): Re-implement type builder using Kernel types and the | 725 // TODO(sra): Re-implement type builder using Kernel types and the |
| 548 // `target` for context. | 726 // `target` for context. |
| 549 @override | 727 @override |
| 550 Element get sourceElement => _sourceElementForTarget(target); | 728 Element get sourceElement => _sourceElementForTarget(_targetStack.last); |
| 729 | |
| 730 List<ir.Node> _targetStack = <ir.Node>[]; | |
| 551 | 731 |
| 552 Element _sourceElementForTarget(ir.Node target) { | 732 Element _sourceElementForTarget(ir.Node target) { |
| 553 // For closure-converted (i.e. local functions) the source element is the | 733 // For closure-converted (i.e. local functions) the source element is the |
| 554 // 'call' method of the class that represents the closure. | 734 // 'call' method of the class that represents the closure. |
| 555 if (target is ir.FunctionExpression) { | 735 Element callMethodOfClosureClass() { |
| 556 LocalFunctionElement element = astAdapter.getElement(target); | 736 LocalFunctionElement element = astAdapter.getElement(target); |
| 557 ClosureClassMap classMap = | 737 ClosureClassMap classMap = |
| 558 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); | 738 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); |
| 559 return classMap.callElement; | 739 return classMap.callElement; |
| 560 } | 740 } |
| 741 | |
| 742 if (target is ir.FunctionExpression) { | |
| 743 return callMethodOfClosureClass(); | |
| 744 } | |
| 561 if (target is ir.FunctionDeclaration) { | 745 if (target is ir.FunctionDeclaration) { |
| 562 LocalFunctionElement element = astAdapter.getElement(target); | 746 return callMethodOfClosureClass(); |
| 563 ClosureClassMap classMap = | |
| 564 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); | |
| 565 return classMap.callElement; | |
| 566 } | 747 } |
| 567 Element element = astAdapter.getElement(target); | 748 Element element = astAdapter.getElement(target); |
| 568 return element; | 749 return element; |
| 569 } | 750 } |
| 570 | 751 |
| 571 @override | 752 @override |
| 572 void visitCheckLibraryIsLoaded(ir.CheckLibraryIsLoaded checkLoad) { | 753 void visitCheckLibraryIsLoaded(ir.CheckLibraryIsLoaded checkLoad) { |
| 573 HInstruction prefixConstant = graph.addConstantString( | 754 HInstruction prefixConstant = graph.addConstantString( |
| 574 new DartString.literal(checkLoad.import.name), closedWorld); | 755 new DartString.literal(checkLoad.import.name), closedWorld); |
| 575 var prefixElement = astAdapter.getElement(checkLoad.import); | 756 var prefixElement = astAdapter.getElement(checkLoad.import); |
| (...skipping 1437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2013 ir.FunctionNode target, ir.Arguments arguments) { | 2194 ir.FunctionNode target, ir.Arguments arguments) { |
| 2014 // Visit arguments in source order, then re-order and fill in defaults. | 2195 // Visit arguments in source order, then re-order and fill in defaults. |
| 2015 var values = _visitPositionalArguments(arguments); | 2196 var values = _visitPositionalArguments(arguments); |
| 2016 | 2197 |
| 2017 while (values.length < target.positionalParameters.length) { | 2198 while (values.length < target.positionalParameters.length) { |
| 2018 ir.VariableDeclaration parameter = | 2199 ir.VariableDeclaration parameter = |
| 2019 target.positionalParameters[values.length]; | 2200 target.positionalParameters[values.length]; |
| 2020 values.add(_defaultValueForParameter(parameter)); | 2201 values.add(_defaultValueForParameter(parameter)); |
| 2021 } | 2202 } |
| 2022 | 2203 |
| 2023 if (arguments.named.isEmpty) return values; | 2204 if (arguments.named.isNotEmpty) { |
| 2205 var namedValues = <String, HInstruction>{}; | |
| 2206 for (ir.NamedExpression argument in arguments.named) { | |
| 2207 argument.value.accept(this); | |
| 2208 namedValues[argument.name] = pop(); | |
| 2209 } | |
| 2024 | 2210 |
| 2025 var namedValues = <String, HInstruction>{}; | 2211 // Visit named arguments in parameter-position order, selecting provided |
| 2026 for (ir.NamedExpression argument in arguments.named) { | 2212 // or default value. |
| 2027 argument.value.accept(this); | 2213 // TODO(sra): Ensure the stored order is canonical so we don't have to |
| 2028 namedValues[argument.name] = pop(); | 2214 // sort. The old builder uses CallStructure.makeArgumentList which depends |
| 2215 // on the old element model. | |
| 2216 var namedParameters = target.namedParameters.toList() | |
| 2217 ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) => | |
| 2218 a.name.compareTo(b.name)); | |
| 2219 for (ir.VariableDeclaration parameter in namedParameters) { | |
| 2220 HInstruction value = namedValues[parameter.name]; | |
| 2221 if (value == null) { | |
| 2222 values.add(_defaultValueForParameter(parameter)); | |
| 2223 } else { | |
| 2224 values.add(value); | |
| 2225 namedValues.remove(parameter.name); | |
| 2226 } | |
| 2227 } | |
| 2228 assert(namedValues.isEmpty); | |
| 2029 } | 2229 } |
| 2030 | 2230 |
| 2031 // Visit named arguments in parameter-position order, selecting provided or | 2231 return values; |
| 2032 // default value. | 2232 } |
| 2033 // TODO(sra): Ensure the stored order is canonical so we don't have to | 2233 |
| 2034 // sort. The old builder uses CallStructure.makeArgumentList which depends | 2234 void _addTypeArguments(List<HInstruction> values, ir.Arguments arguments) { |
| 2035 // on the old element model. | 2235 // need to translate type to |
| 2036 var namedParameters = target.namedParameters.toList() | 2236 for (ir.DartType type in arguments.types) { |
| 2037 ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) => | 2237 values.add(typeBuilder.analyzeTypeArgument( |
| 2038 a.name.compareTo(b.name)); | 2238 astAdapter.getDartType(type), sourceElement)); |
| 2039 for (ir.VariableDeclaration parameter in namedParameters) { | |
| 2040 HInstruction value = namedValues[parameter.name]; | |
| 2041 if (value == null) { | |
| 2042 values.add(_defaultValueForParameter(parameter)); | |
| 2043 } else { | |
| 2044 values.add(value); | |
| 2045 namedValues.remove(parameter.name); | |
| 2046 } | |
| 2047 } | 2239 } |
| 2048 assert(namedValues.isEmpty); | |
| 2049 | |
| 2050 return values; | |
| 2051 } | 2240 } |
| 2052 | 2241 |
| 2053 HInstruction _defaultValueForParameter(ir.VariableDeclaration parameter) { | 2242 HInstruction _defaultValueForParameter(ir.VariableDeclaration parameter) { |
| 2054 ir.Expression initializer = parameter.initializer; | 2243 ir.Expression initializer = parameter.initializer; |
| 2055 if (initializer == null) return graph.addConstantNull(closedWorld); | 2244 if (initializer == null) return graph.addConstantNull(closedWorld); |
| 2056 // TODO(sra): Evaluate constant in ir.Node domain. | 2245 // TODO(sra): Evaluate constant in ir.Node domain. |
| 2057 ConstantValue constant = | 2246 ConstantValue constant = |
| 2058 astAdapter.getConstantForParameterDefaultValue(initializer); | 2247 astAdapter.getConstantForParameterDefaultValue(initializer); |
| 2059 if (constant == null) return graph.addConstantNull(closedWorld); | 2248 if (constant == null) return graph.addConstantNull(closedWorld); |
| 2060 return graph.addConstant(constant, closedWorld); | 2249 return graph.addConstant(constant, closedWorld); |
| 2061 } | 2250 } |
| 2062 | 2251 |
| 2063 @override | 2252 @override |
| 2064 void visitStaticInvocation(ir.StaticInvocation invocation) { | 2253 void visitStaticInvocation(ir.StaticInvocation invocation) { |
| 2065 ir.Procedure target = invocation.target; | 2254 ir.Procedure target = invocation.target; |
| 2066 if (astAdapter.isInForeignLibrary(target)) { | 2255 if (astAdapter.isInForeignLibrary(target)) { |
| 2067 handleInvokeStaticForeign(invocation, target); | 2256 handleInvokeStaticForeign(invocation, target); |
| 2068 return; | 2257 return; |
| 2069 } | 2258 } |
| 2070 TypeMask typeMask = astAdapter.returnTypeOf(target); | 2259 TypeMask typeMask = astAdapter.returnTypeOf(target); |
| 2071 | 2260 |
| 2072 // TODO(sra): For JS interop external functions, use a different function to | 2261 // TODO(sra): For JS interop external functions, use a different function to |
| 2073 // build arguments. | 2262 // build arguments. |
| 2074 List<HInstruction> arguments = | 2263 List<HInstruction> arguments = |
| 2075 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 2264 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 2076 | 2265 |
| 2266 // Factory constructors take type parameters; other static methods ignore | |
| 2267 // them. | |
| 2268 if (target.kind == ir.ProcedureKind.Factory) { | |
| 2269 if (backend.rtiNeed | |
| 2270 .classNeedsRti(astAdapter.getClass(target.enclosingClass))) { | |
| 2271 _addTypeArguments(arguments, invocation.arguments); | |
| 2272 } | |
| 2273 } | |
| 2274 | |
| 2077 _pushStaticInvocation(target, arguments, typeMask); | 2275 _pushStaticInvocation(target, arguments, typeMask); |
| 2078 } | 2276 } |
| 2079 | 2277 |
| 2080 void handleInvokeStaticForeign( | 2278 void handleInvokeStaticForeign( |
| 2081 ir.StaticInvocation invocation, ir.Procedure target) { | 2279 ir.StaticInvocation invocation, ir.Procedure target) { |
| 2082 String name = target.name.name; | 2280 String name = target.name.name; |
| 2083 if (name == 'JS') { | 2281 if (name == 'JS') { |
| 2084 handleForeignJs(invocation); | 2282 handleForeignJs(invocation); |
| 2085 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { | 2283 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { |
| 2086 handleForeignJsCurrentIsolateContext(invocation); | 2284 handleForeignJsCurrentIsolateContext(invocation); |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2779 _buildInvokeSuper(astAdapter.getSelector(invocation), | 2977 _buildInvokeSuper(astAdapter.getSelector(invocation), |
| 2780 _containingClass(invocation), invocation.interfaceTarget, arguments); | 2978 _containingClass(invocation), invocation.interfaceTarget, arguments); |
| 2781 } | 2979 } |
| 2782 | 2980 |
| 2783 @override | 2981 @override |
| 2784 void visitConstructorInvocation(ir.ConstructorInvocation invocation) { | 2982 void visitConstructorInvocation(ir.ConstructorInvocation invocation) { |
| 2785 ir.Constructor target = invocation.target; | 2983 ir.Constructor target = invocation.target; |
| 2786 // TODO(sra): For JS-interop targets, process arguments differently. | 2984 // TODO(sra): For JS-interop targets, process arguments differently. |
| 2787 List<HInstruction> arguments = | 2985 List<HInstruction> arguments = |
| 2788 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 2986 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 2987 if (backend.rtiNeed | |
| 2988 .classNeedsRti(astAdapter.getClass(target.enclosingClass))) { | |
| 2989 _addTypeArguments(arguments, invocation.arguments); | |
| 2990 } | |
| 2789 TypeMask typeMask = new TypeMask.nonNullExact( | 2991 TypeMask typeMask = new TypeMask.nonNullExact( |
| 2790 astAdapter.getClass(target.enclosingClass), closedWorld); | 2992 astAdapter.getClass(target.enclosingClass), closedWorld); |
| 2791 _pushStaticInvocation(target, arguments, typeMask); | 2993 _pushStaticInvocation(target, arguments, typeMask); |
| 2792 } | 2994 } |
| 2793 | 2995 |
| 2794 @override | 2996 @override |
| 2795 void visitIsExpression(ir.IsExpression isExpression) { | 2997 void visitIsExpression(ir.IsExpression isExpression) { |
| 2796 isExpression.operand.accept(this); | 2998 isExpression.operand.accept(this); |
| 2797 HInstruction expression = pop(); | 2999 HInstruction expression = pop(); |
| 2798 pushIsTest(isExpression, isExpression.type, expression); | 3000 pushIsTest(isExpression, isExpression.type, expression); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3218 enterBlock.setBlockFlow( | 3420 enterBlock.setBlockFlow( |
| 3219 new HTryBlockInformation( | 3421 new HTryBlockInformation( |
| 3220 kernelBuilder.wrapStatementGraph(bodyGraph), | 3422 kernelBuilder.wrapStatementGraph(bodyGraph), |
| 3221 exception, | 3423 exception, |
| 3222 kernelBuilder.wrapStatementGraph(catchGraph), | 3424 kernelBuilder.wrapStatementGraph(catchGraph), |
| 3223 kernelBuilder.wrapStatementGraph(finallyGraph)), | 3425 kernelBuilder.wrapStatementGraph(finallyGraph)), |
| 3224 exitBlock); | 3426 exitBlock); |
| 3225 kernelBuilder.inTryStatement = previouslyInTryStatement; | 3427 kernelBuilder.inTryStatement = previouslyInTryStatement; |
| 3226 } | 3428 } |
| 3227 } | 3429 } |
| OLD | NEW |