| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library closureToClassMapper; | 5 library closureToClassMapper; |
| 6 | 6 |
| 7 import "elements/elements.dart"; | 7 import "elements/elements.dart"; |
| 8 import "dart2jslib.dart"; | 8 import "dart2jslib.dart"; |
| 9 import "dart_types.dart"; | 9 import "dart_types.dart"; |
| 10 import "scanner/scannerlib.dart" show Token; | 10 import "scanner/scannerlib.dart" show Token; |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 // TODO(ngeoffray): only do this if the variable is mutated. | 383 // TODO(ngeoffray): only do this if the variable is mutated. |
| 384 closureData.usedVariablesInTry.add(element); | 384 closureData.usedVariablesInTry.add(element); |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 } | 387 } |
| 388 | 388 |
| 389 void declareLocal(Element element) { | 389 void declareLocal(Element element) { |
| 390 scopeVariables.add(element); | 390 scopeVariables.add(element); |
| 391 } | 391 } |
| 392 | 392 |
| 393 void registerNeedsThis() { |
| 394 if (closureData.thisElement != null) { |
| 395 useLocal(closureData.thisElement); |
| 396 } |
| 397 } |
| 398 |
| 393 visit(Node node) => node.accept(this); | 399 visit(Node node) => node.accept(this); |
| 394 | 400 |
| 395 visitNode(Node node) => node.visitChildren(this); | 401 visitNode(Node node) => node.visitChildren(this); |
| 396 | 402 |
| 397 visitVariableDefinitions(VariableDefinitions node) { | 403 visitVariableDefinitions(VariableDefinitions node) { |
| 404 if (node.type != null) { |
| 405 visit(node.type); |
| 406 } |
| 398 for (Link<Node> link = node.definitions.nodes; | 407 for (Link<Node> link = node.definitions.nodes; |
| 399 !link.isEmpty; | 408 !link.isEmpty; |
| 400 link = link.tail) { | 409 link = link.tail) { |
| 401 Node definition = link.head; | 410 Node definition = link.head; |
| 402 Element element = elements[definition]; | 411 Element element = elements[definition]; |
| 403 assert(element != null); | 412 assert(element != null); |
| 404 declareLocal(element); | 413 declareLocal(element); |
| 405 // We still need to visit the right-hand sides of the init-assignments. | 414 // We still need to visit the right-hand sides of the init-assignments. |
| 406 // For SendSets don't visit the left again. Otherwise it would be marked | 415 // For SendSets don't visit the left again. Otherwise it would be marked |
| 407 // as mutated. | 416 // as mutated. |
| 408 if (definition is Send) { | 417 if (definition is Send) { |
| 409 Send assignment = definition; | 418 Send assignment = definition; |
| 410 Node arguments = assignment.argumentsNode; | 419 Node arguments = assignment.argumentsNode; |
| 411 if (arguments != null) { | 420 if (arguments != null) { |
| 412 visit(arguments); | 421 visit(arguments); |
| 413 } | 422 } |
| 414 } else { | 423 } else { |
| 415 visit(definition); | 424 visit(definition); |
| 416 } | 425 } |
| 417 } | 426 } |
| 418 } | 427 } |
| 419 | 428 |
| 429 visitTypeAnnotation(TypeAnnotation node) { |
| 430 if (compiler.enableTypeAssertions && currentElement.isInstanceMember()) { |
| 431 DartType type = elements.getType(node); |
| 432 // In checked mode, using a type variable in a type annotation may lead |
| 433 // to a runtime type check that needs to access the type argument and |
| 434 // therefore the closure needs a this-element. |
| 435 // TODO(karlklose,johnniwinther): if the type is null, the annotation is |
| 436 // from a parameter which has been analyzed before the method has been |
| 437 // resolved and the result has been thrown away. |
| 438 if (type != null && type.containsTypeVariables) { |
| 439 registerNeedsThis(); |
| 440 } |
| 441 } |
| 442 node.visitChildren(this); |
| 443 } |
| 444 |
| 420 visitIdentifier(Identifier node) { | 445 visitIdentifier(Identifier node) { |
| 421 if (node.isThis()) { | 446 if (node.isThis()) { |
| 422 useLocal(closureData.thisElement); | 447 registerNeedsThis(); |
| 423 } else { | 448 } else { |
| 424 Element element = elements[node]; | 449 Element element = elements[node]; |
| 425 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { | 450 if (element != null && element.kind == ElementKind.TYPE_VARIABLE) { |
| 426 useLocal(closureData.thisElement); | 451 registerNeedsThis(); |
| 427 } | 452 } |
| 428 } | 453 } |
| 429 node.visitChildren(this); | 454 node.visitChildren(this); |
| 430 } | 455 } |
| 431 | 456 |
| 432 visitSend(Send node) { | 457 visitSend(Send node) { |
| 433 Element element = elements[node]; | 458 Element element = elements[node]; |
| 434 if (Elements.isLocal(element)) { | 459 if (Elements.isLocal(element)) { |
| 435 useLocal(element); | 460 useLocal(element); |
| 436 } else if (node.receiver == null && | 461 } else if (node.receiver == null && |
| 437 Elements.isInstanceSend(node, elements)) { | 462 Elements.isInstanceSend(node, elements)) { |
| 438 useLocal(closureData.thisElement); | 463 registerNeedsThis(); |
| 439 } else if (node.isSuperCall) { | 464 } else if (node.isSuperCall) { |
| 440 useLocal(closureData.thisElement); | 465 registerNeedsThis(); |
| 441 } else if (node.isParameterCheck) { | 466 } else if (node.isParameterCheck) { |
| 442 Element parameter = elements[node.receiver]; | 467 Element parameter = elements[node.receiver]; |
| 443 FunctionElement enclosing = parameter.enclosingElement; | 468 FunctionElement enclosing = parameter.enclosingElement; |
| 444 FunctionExpression function = enclosing.parseNode(compiler); | 469 FunctionExpression function = enclosing.parseNode(compiler); |
| 445 ClosureClassMap cached = closureMappingCache[function]; | 470 ClosureClassMap cached = closureMappingCache[function]; |
| 446 if (!cached.parametersWithSentinel.containsKey(parameter)) { | 471 if (!cached.parametersWithSentinel.containsKey(parameter)) { |
| 447 SourceString parameterName = parameter.name; | 472 SourceString parameterName = parameter.name; |
| 448 String name = '${parameterName.slowToString()}_check'; | 473 String name = '${parameterName.slowToString()}_check'; |
| 449 Element newElement = new CheckVariableElement(new SourceString(name), | 474 Element newElement = new CheckVariableElement(new SourceString(name), |
| 450 parameter, | 475 parameter, |
| 451 enclosing); | 476 enclosing); |
| 452 useLocal(newElement); | 477 useLocal(newElement); |
| 453 cached.parametersWithSentinel[parameter] = newElement; | 478 cached.parametersWithSentinel[parameter] = newElement; |
| 454 } | 479 } |
| 455 } | 480 } |
| 456 node.visitChildren(this); | 481 node.visitChildren(this); |
| 457 } | 482 } |
| 458 | 483 |
| 459 visitSendSet(SendSet node) { | 484 visitSendSet(SendSet node) { |
| 460 Element element = elements[node]; | 485 Element element = elements[node]; |
| 461 if (Elements.isLocal(element)) { | 486 if (Elements.isLocal(element)) { |
| 462 mutatedVariables.add(element); | 487 mutatedVariables.add(element); |
| 463 } | 488 } |
| 489 if (Elements.isLocal(element) && |
| 490 element.computeType(compiler).containsTypeVariables) { |
| 491 registerNeedsThis(); |
| 492 } |
| 464 super.visitSendSet(node); | 493 super.visitSendSet(node); |
| 465 } | 494 } |
| 466 | 495 |
| 467 visitNewExpression(NewExpression node) { | 496 visitNewExpression(NewExpression node) { |
| 468 DartType type = elements.getType(node); | 497 DartType type = elements.getType(node); |
| 469 | 498 |
| 470 bool hasTypeVariable(DartType type) { | 499 bool hasTypeVariable(DartType type) { |
| 471 if (type is TypeVariableType) { | 500 if (type is TypeVariableType) { |
| 472 return true; | 501 return true; |
| 473 } else if (type is InterfaceType) { | 502 } else if (type is InterfaceType) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 490 analyzeTypeVariables(argument); | 519 analyzeTypeVariables(argument); |
| 491 } | 520 } |
| 492 } | 521 } |
| 493 } | 522 } |
| 494 | 523 |
| 495 if (outermostElement.isMember() && | 524 if (outermostElement.isMember() && |
| 496 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { | 525 compiler.backend.needsRti(outermostElement.getEnclosingClass())) { |
| 497 if (outermostElement.isConstructor() || outermostElement.isField()) { | 526 if (outermostElement.isConstructor() || outermostElement.isField()) { |
| 498 analyzeTypeVariables(type); | 527 analyzeTypeVariables(type); |
| 499 } else if (outermostElement.isInstanceMember()) { | 528 } else if (outermostElement.isInstanceMember()) { |
| 500 if (hasTypeVariable(type)) useLocal(closureData.thisElement); | 529 if (hasTypeVariable(type)) { |
| 530 registerNeedsThis(); |
| 531 } |
| 501 } | 532 } |
| 502 } | 533 } |
| 503 | 534 |
| 504 node.visitChildren(this); | 535 node.visitChildren(this); |
| 505 } | 536 } |
| 506 | 537 |
| 507 // If variables that are declared in the [node] scope are captured and need | 538 // If variables that are declared in the [node] scope are captured and need |
| 508 // to be boxed create a box-element and update the [capturingScopes] in the | 539 // to be boxed create a box-element and update the [capturingScopes] in the |
| 509 // current [closureData]. | 540 // current [closureData]. |
| 510 // The boxed variables are updated in the [capturedVariableMapping]. | 541 // The boxed variables are updated in the [capturedVariableMapping]. |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 662 if (currentElement.isFactoryConstructor() && | 693 if (currentElement.isFactoryConstructor() && |
| 663 compiler.backend.needsRti(currentElement.enclosingElement)) { | 694 compiler.backend.needsRti(currentElement.enclosingElement)) { |
| 664 // Declare the type parameters in the scope. Generative | 695 // Declare the type parameters in the scope. Generative |
| 665 // constructors just use 'this'. | 696 // constructors just use 'this'. |
| 666 ClassElement cls = currentElement.enclosingElement; | 697 ClassElement cls = currentElement.enclosingElement; |
| 667 cls.typeVariables.forEach((TypeVariableType typeVariable) { | 698 cls.typeVariables.forEach((TypeVariableType typeVariable) { |
| 668 declareLocal(typeVariable.element); | 699 declareLocal(typeVariable.element); |
| 669 }); | 700 }); |
| 670 } | 701 } |
| 671 | 702 |
| 703 // Compute the function type and check for type variables in return or |
| 704 // parameter types. |
| 705 if (element.computeType(compiler).containsTypeVariables) { |
| 706 registerNeedsThis(); |
| 707 } |
| 708 |
| 672 visitChildren(); | 709 visitChildren(); |
| 673 }); | 710 }); |
| 674 | 711 |
| 675 | 712 |
| 676 ClosureClassMap savedClosureData = closureData; | 713 ClosureClassMap savedClosureData = closureData; |
| 677 bool savedInsideClosure = insideClosure; | 714 bool savedInsideClosure = insideClosure; |
| 678 | 715 |
| 679 // Restore old values. | 716 // Restore old values. |
| 680 insideClosure = oldInsideClosure; | 717 insideClosure = oldInsideClosure; |
| 681 closureData = oldClosureData; | 718 closureData = oldClosureData; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 719 } | 756 } |
| 720 | 757 |
| 721 visitTryStatement(TryStatement node) { | 758 visitTryStatement(TryStatement node) { |
| 722 // TODO(ngeoffray): implement finer grain state. | 759 // TODO(ngeoffray): implement finer grain state. |
| 723 bool oldInTryStatement = inTryStatement; | 760 bool oldInTryStatement = inTryStatement; |
| 724 inTryStatement = true; | 761 inTryStatement = true; |
| 725 node.visitChildren(this); | 762 node.visitChildren(this); |
| 726 inTryStatement = oldInTryStatement; | 763 inTryStatement = oldInTryStatement; |
| 727 } | 764 } |
| 728 } | 765 } |
| OLD | NEW |