| 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. |
| 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. |
| 268 /// |
| 269 /// 5. Create reified type information for instance. |
| 270 /// |
| 271 /// 6. Allocate instance and assign initializers and reified type information |
| 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 |
| 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 AstElement astElement = astAdapter.getElement(constructor); |
| 624 ResolvedAst resolvedAst = astElement.resolvedAst; |
| 625 ClosureClassMap oldClosureData = localsHandler.closureData; |
| 626 ClosureClassMap newClosureData = |
| 627 compiler.closureToClassMapper.getClosureToClassMapping(resolvedAst); |
| 628 localsHandler.closureData = newClosureData; |
| 629 if (resolvedAst.kind == ResolvedAstKind.PARSED) { |
| 630 localsHandler.enterScope( |
| 631 resolvedAst.node, astAdapter.getElement(constructor)); |
| 632 } |
| 633 inlinedFrom(constructor, () { |
| 634 _buildInitializers(constructor, constructorChain, fieldValues); |
| 635 }); |
| 636 localsHandler.closureData = oldClosureData; |
| 637 astAdapter.popResolvedAstStack(); |
| 460 } | 638 } |
| 461 | 639 |
| 462 /// Builds generative constructor body. | 640 /// Builds generative constructor body. |
| 463 void buildConstructorBody(ir.Constructor constructor) { | 641 void buildConstructorBody(ir.Constructor constructor) { |
| 464 openFunction(); | 642 openFunction(); |
| 643 _addClassTypeVariablesIfNeeded(constructor); |
| 465 constructor.function.body.accept(this); | 644 constructor.function.body.accept(this); |
| 466 closeFunction(); | 645 closeFunction(); |
| 467 } | 646 } |
| 468 | 647 |
| 469 /// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and | 648 /// Builds a SSA graph for FunctionNodes, found in FunctionExpressions and |
| 470 /// Procedures. | 649 /// Procedures. |
| 471 void buildFunctionNode(ir.FunctionNode functionNode) { | 650 void buildFunctionNode(ir.FunctionNode functionNode) { |
| 472 openFunction(); | 651 openFunction(); |
| 473 if (functionNode.parent is ir.Procedure && | 652 if (functionNode.parent is ir.Procedure && |
| 474 (functionNode.parent as ir.Procedure).kind == | 653 (functionNode.parent as ir.Procedure).kind == |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 push(trap); | 719 push(trap); |
| 541 } | 720 } |
| 542 | 721 |
| 543 /// Returns the current source element. This is used by the type builder. | 722 /// Returns the current source element. This is used by the type builder. |
| 544 /// | 723 /// |
| 545 /// The returned element is a declaration element. | 724 /// The returned element is a declaration element. |
| 546 // TODO(efortuna): Update this when we implement inlining. | 725 // TODO(efortuna): Update this when we implement inlining. |
| 547 // TODO(sra): Re-implement type builder using Kernel types and the | 726 // TODO(sra): Re-implement type builder using Kernel types and the |
| 548 // `target` for context. | 727 // `target` for context. |
| 549 @override | 728 @override |
| 550 Element get sourceElement => _sourceElementForTarget(target); | 729 Element get sourceElement => _sourceElementForTarget(_targetStack.last); |
| 730 |
| 731 List<ir.Node> _targetStack = <ir.Node>[]; |
| 551 | 732 |
| 552 Element _sourceElementForTarget(ir.Node target) { | 733 Element _sourceElementForTarget(ir.Node target) { |
| 553 // For closure-converted (i.e. local functions) the source element is the | 734 // For closure-converted (i.e. local functions) the source element is the |
| 554 // 'call' method of the class that represents the closure. | 735 // 'call' method of the class that represents the closure. |
| 555 if (target is ir.FunctionExpression) { | 736 Element callMethodOfClosureClass() { |
| 556 LocalFunctionElement element = astAdapter.getElement(target); | 737 LocalFunctionElement element = astAdapter.getElement(target); |
| 557 ClosureClassMap classMap = | 738 ClosureClassMap classMap = |
| 558 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); | 739 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); |
| 559 return classMap.callElement; | 740 return classMap.callElement; |
| 560 } | 741 } |
| 742 |
| 743 if (target is ir.FunctionExpression) { |
| 744 return callMethodOfClosureClass(); |
| 745 } |
| 561 if (target is ir.FunctionDeclaration) { | 746 if (target is ir.FunctionDeclaration) { |
| 562 LocalFunctionElement element = astAdapter.getElement(target); | 747 return callMethodOfClosureClass(); |
| 563 ClosureClassMap classMap = | |
| 564 closureToClassMapper.getClosureToClassMapping(element.resolvedAst); | |
| 565 return classMap.callElement; | |
| 566 } | 748 } |
| 567 Element element = astAdapter.getElement(target); | 749 Element element = astAdapter.getElement(target); |
| 568 return element; | 750 return element; |
| 569 } | 751 } |
| 570 | 752 |
| 571 @override | 753 @override |
| 572 void visitCheckLibraryIsLoaded(ir.CheckLibraryIsLoaded checkLoad) { | 754 void visitCheckLibraryIsLoaded(ir.CheckLibraryIsLoaded checkLoad) { |
| 573 HInstruction prefixConstant = graph.addConstantString( | 755 HInstruction prefixConstant = graph.addConstantString( |
| 574 new DartString.literal(checkLoad.import.name), closedWorld); | 756 new DartString.literal(checkLoad.import.name), closedWorld); |
| 575 var prefixElement = astAdapter.getElement(checkLoad.import); | 757 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) { | 2195 ir.FunctionNode target, ir.Arguments arguments) { |
| 2014 // Visit arguments in source order, then re-order and fill in defaults. | 2196 // Visit arguments in source order, then re-order and fill in defaults. |
| 2015 var values = _visitPositionalArguments(arguments); | 2197 var values = _visitPositionalArguments(arguments); |
| 2016 | 2198 |
| 2017 while (values.length < target.positionalParameters.length) { | 2199 while (values.length < target.positionalParameters.length) { |
| 2018 ir.VariableDeclaration parameter = | 2200 ir.VariableDeclaration parameter = |
| 2019 target.positionalParameters[values.length]; | 2201 target.positionalParameters[values.length]; |
| 2020 values.add(_defaultValueForParameter(parameter)); | 2202 values.add(_defaultValueForParameter(parameter)); |
| 2021 } | 2203 } |
| 2022 | 2204 |
| 2023 if (arguments.named.isEmpty) return values; | 2205 if (arguments.named.isNotEmpty) { |
| 2206 var namedValues = <String, HInstruction>{}; |
| 2207 for (ir.NamedExpression argument in arguments.named) { |
| 2208 argument.value.accept(this); |
| 2209 namedValues[argument.name] = pop(); |
| 2210 } |
| 2024 | 2211 |
| 2025 var namedValues = <String, HInstruction>{}; | 2212 // Visit named arguments in parameter-position order, selecting provided |
| 2026 for (ir.NamedExpression argument in arguments.named) { | 2213 // or default value. |
| 2027 argument.value.accept(this); | 2214 // TODO(sra): Ensure the stored order is canonical so we don't have to |
| 2028 namedValues[argument.name] = pop(); | 2215 // sort. The old builder uses CallStructure.makeArgumentList which depends |
| 2216 // on the old element model. |
| 2217 var namedParameters = target.namedParameters.toList() |
| 2218 ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) => |
| 2219 a.name.compareTo(b.name)); |
| 2220 for (ir.VariableDeclaration parameter in namedParameters) { |
| 2221 HInstruction value = namedValues[parameter.name]; |
| 2222 if (value == null) { |
| 2223 values.add(_defaultValueForParameter(parameter)); |
| 2224 } else { |
| 2225 values.add(value); |
| 2226 namedValues.remove(parameter.name); |
| 2227 } |
| 2228 } |
| 2229 assert(namedValues.isEmpty); |
| 2029 } | 2230 } |
| 2030 | 2231 |
| 2031 // Visit named arguments in parameter-position order, selecting provided or | 2232 return values; |
| 2032 // default value. | 2233 } |
| 2033 // TODO(sra): Ensure the stored order is canonical so we don't have to | 2234 |
| 2034 // sort. The old builder uses CallStructure.makeArgumentList which depends | 2235 void _addTypeArguments(List<HInstruction> values, ir.Arguments arguments) { |
| 2035 // on the old element model. | 2236 // need to translate type to |
| 2036 var namedParameters = target.namedParameters.toList() | 2237 for (ir.DartType type in arguments.types) { |
| 2037 ..sort((ir.VariableDeclaration a, ir.VariableDeclaration b) => | 2238 values.add(typeBuilder.analyzeTypeArgument( |
| 2038 a.name.compareTo(b.name)); | 2239 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 } | 2240 } |
| 2048 assert(namedValues.isEmpty); | |
| 2049 | |
| 2050 return values; | |
| 2051 } | 2241 } |
| 2052 | 2242 |
| 2053 HInstruction _defaultValueForParameter(ir.VariableDeclaration parameter) { | 2243 HInstruction _defaultValueForParameter(ir.VariableDeclaration parameter) { |
| 2054 ir.Expression initializer = parameter.initializer; | 2244 ir.Expression initializer = parameter.initializer; |
| 2055 if (initializer == null) return graph.addConstantNull(closedWorld); | 2245 if (initializer == null) return graph.addConstantNull(closedWorld); |
| 2056 // TODO(sra): Evaluate constant in ir.Node domain. | 2246 // TODO(sra): Evaluate constant in ir.Node domain. |
| 2057 ConstantValue constant = | 2247 ConstantValue constant = |
| 2058 astAdapter.getConstantForParameterDefaultValue(initializer); | 2248 astAdapter.getConstantForParameterDefaultValue(initializer); |
| 2059 if (constant == null) return graph.addConstantNull(closedWorld); | 2249 if (constant == null) return graph.addConstantNull(closedWorld); |
| 2060 return graph.addConstant(constant, closedWorld); | 2250 return graph.addConstant(constant, closedWorld); |
| 2061 } | 2251 } |
| 2062 | 2252 |
| 2063 @override | 2253 @override |
| 2064 void visitStaticInvocation(ir.StaticInvocation invocation) { | 2254 void visitStaticInvocation(ir.StaticInvocation invocation) { |
| 2065 ir.Procedure target = invocation.target; | 2255 ir.Procedure target = invocation.target; |
| 2066 if (astAdapter.isInForeignLibrary(target)) { | 2256 if (astAdapter.isInForeignLibrary(target)) { |
| 2067 handleInvokeStaticForeign(invocation, target); | 2257 handleInvokeStaticForeign(invocation, target); |
| 2068 return; | 2258 return; |
| 2069 } | 2259 } |
| 2070 TypeMask typeMask = astAdapter.returnTypeOf(target); | 2260 TypeMask typeMask = astAdapter.returnTypeOf(target); |
| 2071 | 2261 |
| 2072 // TODO(sra): For JS interop external functions, use a different function to | 2262 // TODO(sra): For JS interop external functions, use a different function to |
| 2073 // build arguments. | 2263 // build arguments. |
| 2074 List<HInstruction> arguments = | 2264 List<HInstruction> arguments = |
| 2075 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 2265 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 2076 | 2266 |
| 2267 // Factory constructors take type parameters; other static methods ignore |
| 2268 // them. |
| 2269 if (target.kind == ir.ProcedureKind.Factory) { |
| 2270 if (backend.rtiNeed |
| 2271 .classNeedsRti(astAdapter.getClass(target.enclosingClass))) { |
| 2272 _addTypeArguments(arguments, invocation.arguments); |
| 2273 } |
| 2274 } |
| 2275 |
| 2077 _pushStaticInvocation(target, arguments, typeMask); | 2276 _pushStaticInvocation(target, arguments, typeMask); |
| 2078 } | 2277 } |
| 2079 | 2278 |
| 2080 void handleInvokeStaticForeign( | 2279 void handleInvokeStaticForeign( |
| 2081 ir.StaticInvocation invocation, ir.Procedure target) { | 2280 ir.StaticInvocation invocation, ir.Procedure target) { |
| 2082 String name = target.name.name; | 2281 String name = target.name.name; |
| 2083 if (name == 'JS') { | 2282 if (name == 'JS') { |
| 2084 handleForeignJs(invocation); | 2283 handleForeignJs(invocation); |
| 2085 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { | 2284 } else if (name == 'JS_CURRENT_ISOLATE_CONTEXT') { |
| 2086 handleForeignJsCurrentIsolateContext(invocation); | 2285 handleForeignJsCurrentIsolateContext(invocation); |
| (...skipping 692 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2779 _buildInvokeSuper(astAdapter.getSelector(invocation), | 2978 _buildInvokeSuper(astAdapter.getSelector(invocation), |
| 2780 _containingClass(invocation), invocation.interfaceTarget, arguments); | 2979 _containingClass(invocation), invocation.interfaceTarget, arguments); |
| 2781 } | 2980 } |
| 2782 | 2981 |
| 2783 @override | 2982 @override |
| 2784 void visitConstructorInvocation(ir.ConstructorInvocation invocation) { | 2983 void visitConstructorInvocation(ir.ConstructorInvocation invocation) { |
| 2785 ir.Constructor target = invocation.target; | 2984 ir.Constructor target = invocation.target; |
| 2786 // TODO(sra): For JS-interop targets, process arguments differently. | 2985 // TODO(sra): For JS-interop targets, process arguments differently. |
| 2787 List<HInstruction> arguments = | 2986 List<HInstruction> arguments = |
| 2788 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 2987 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 2988 if (backend.rtiNeed |
| 2989 .classNeedsRti(astAdapter.getClass(target.enclosingClass))) { |
| 2990 _addTypeArguments(arguments, invocation.arguments); |
| 2991 } |
| 2789 TypeMask typeMask = new TypeMask.nonNullExact( | 2992 TypeMask typeMask = new TypeMask.nonNullExact( |
| 2790 astAdapter.getClass(target.enclosingClass), closedWorld); | 2993 astAdapter.getClass(target.enclosingClass), closedWorld); |
| 2791 _pushStaticInvocation(target, arguments, typeMask); | 2994 _pushStaticInvocation(target, arguments, typeMask); |
| 2792 } | 2995 } |
| 2793 | 2996 |
| 2794 @override | 2997 @override |
| 2795 void visitIsExpression(ir.IsExpression isExpression) { | 2998 void visitIsExpression(ir.IsExpression isExpression) { |
| 2796 isExpression.operand.accept(this); | 2999 isExpression.operand.accept(this); |
| 2797 HInstruction expression = pop(); | 3000 HInstruction expression = pop(); |
| 2798 pushIsTest(isExpression, isExpression.type, expression); | 3001 pushIsTest(isExpression, isExpression.type, expression); |
| (...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3218 enterBlock.setBlockFlow( | 3421 enterBlock.setBlockFlow( |
| 3219 new HTryBlockInformation( | 3422 new HTryBlockInformation( |
| 3220 kernelBuilder.wrapStatementGraph(bodyGraph), | 3423 kernelBuilder.wrapStatementGraph(bodyGraph), |
| 3221 exception, | 3424 exception, |
| 3222 kernelBuilder.wrapStatementGraph(catchGraph), | 3425 kernelBuilder.wrapStatementGraph(catchGraph), |
| 3223 kernelBuilder.wrapStatementGraph(finallyGraph)), | 3426 kernelBuilder.wrapStatementGraph(finallyGraph)), |
| 3224 exitBlock); | 3427 exitBlock); |
| 3225 kernelBuilder.inTryStatement = previouslyInTryStatement; | 3428 kernelBuilder.inTryStatement = previouslyInTryStatement; |
| 3226 } | 3429 } |
| 3227 } | 3430 } |
| OLD | NEW |