Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(562)

Side by Side Diff: pkg/kernel/lib/transformations/closure/converter.dart

Issue 2986553002: Remove dead code for closure-converting tearoffs. (Closed)
Patch Set: Removing more code. Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/info.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 library kernel.transformations.closure.converter; 5 library kernel.transformations.closure.converter;
6 6
7 import '../../ast.dart' 7 import '../../ast.dart'
8 show 8 show
9 Arguments, 9 Arguments,
10 Block, 10 Block,
(...skipping 22 matching lines...) Expand all
33 MethodInvocation, 33 MethodInvocation,
34 Name, 34 Name,
35 NamedExpression, 35 NamedExpression,
36 NamedType, 36 NamedType,
37 NullLiteral, 37 NullLiteral,
38 Procedure, 38 Procedure,
39 ProcedureKind, 39 ProcedureKind,
40 PropertyGet, 40 PropertyGet,
41 ReturnStatement, 41 ReturnStatement,
42 Statement, 42 Statement,
43 StaticGet,
44 StaticInvocation, 43 StaticInvocation,
45 ThisExpression, 44 ThisExpression,
46 Transformer, 45 Transformer,
47 TreeNode, 46 TreeNode,
48 TypeParameter, 47 TypeParameter,
49 TypeParameterType, 48 TypeParameterType,
50 VariableDeclaration, 49 VariableDeclaration,
51 VariableGet, 50 VariableGet,
52 VariableSet, 51 VariableSet,
53 VectorType, 52 VectorType,
(...skipping 19 matching lines...) Expand all
73 final CoreTypes coreTypes; 72 final CoreTypes coreTypes;
74 final Set<VariableDeclaration> capturedVariables; 73 final Set<VariableDeclaration> capturedVariables;
75 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables; 74 final Map<FunctionNode, Set<TypeParameter>> capturedTypeVariables;
76 final Map<FunctionNode, VariableDeclaration> thisAccess; 75 final Map<FunctionNode, VariableDeclaration> thisAccess;
77 final Map<FunctionNode, String> localNames; 76 final Map<FunctionNode, String> localNames;
78 77
79 /// Records place-holders for cloning contexts. See [visitForStatement]. 78 /// Records place-holders for cloning contexts. See [visitForStatement].
80 final Set<InvalidExpression> contextClonePlaceHolders = 79 final Set<InvalidExpression> contextClonePlaceHolders =
81 new Set<InvalidExpression>(); 80 new Set<InvalidExpression>();
82 81
83 /// Maps the names of all instance methods that may be torn off (aka
84 /// implicitly closurized) to `${name.name}#get`.
85 final Map<Name, Name> tearOffGetterNames;
86
87 final CloneVisitor cloner = new CloneWithoutBody(); 82 final CloneVisitor cloner = new CloneWithoutBody();
88 83
89 /// New members to add to [currentLibrary] after it has been 84 /// New members to add to [currentLibrary] after it has been
90 /// transformed. These members will not be transformed themselves. 85 /// transformed. These members will not be transformed themselves.
91 final List<TreeNode> newLibraryMembers = <TreeNode>[]; 86 final List<TreeNode> newLibraryMembers = <TreeNode>[];
92 87
93 /// New members to add to [currentClass] after it has been transformed. These 88 /// New members to add to [currentClass] after it has been transformed. These
94 /// members will not be transformed themselves. 89 /// members will not be transformed themselves.
95 final List<Member> newClassMembers = <Member>[]; 90 final List<Member> newClassMembers = <Member>[];
96 91
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 /// 124 ///
130 /// In this example, `typeSubstitution[T].parameter == T_` when transforming 125 /// In this example, `typeSubstitution[T].parameter == T_` when transforming
131 /// the closure in `f`. 126 /// the closure in `f`.
132 Map<TypeParameter, DartType> typeSubstitution = 127 Map<TypeParameter, DartType> typeSubstitution =
133 const <TypeParameter, DartType>{}; 128 const <TypeParameter, DartType>{};
134 129
135 ClosureConverter(this.coreTypes, ClosureInfo info) 130 ClosureConverter(this.coreTypes, ClosureInfo info)
136 : this.capturedVariables = info.variables, 131 : this.capturedVariables = info.variables,
137 this.capturedTypeVariables = info.typeVariables, 132 this.capturedTypeVariables = info.typeVariables,
138 this.thisAccess = info.thisAccess, 133 this.thisAccess = info.thisAccess,
139 this.localNames = info.localNames, 134 this.localNames = info.localNames;
140 this.tearOffGetterNames = info.tearOffGetterNames;
141 135
142 bool get isOuterMostContext { 136 bool get isOuterMostContext {
143 return currentFunction == null || currentMemberFunction == currentFunction; 137 return currentFunction == null || currentMemberFunction == currentFunction;
144 } 138 }
145 139
146 String get currentFileUri { 140 String get currentFileUri {
147 if (currentMember is Constructor) return currentClass.fileUri; 141 if (currentMember is Constructor) return currentClass.fileUri;
148 if (currentMember is Field) return (currentMember as Field).fileUri; 142 if (currentMember is Field) return (currentMember as Field).fileUri;
149 if (currentMember is Procedure) return (currentMember as Procedure).fileUri; 143 if (currentMember is Procedure) return (currentMember as Procedure).fileUri;
150 throw "No file uri for ${currentMember.runtimeType}"; 144 throw "No file uri for ${currentMember.runtimeType}";
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
363 .map((VariableDeclaration decl) => 357 .map((VariableDeclaration decl) =>
364 new NamedType(decl.name, decl.type)) 358 new NamedType(decl.name, decl.type))
365 .toList(), 359 .toList(),
366 typeParameters: function.typeParameters, 360 typeParameters: function.typeParameters,
367 requiredParameterCount: function.requiredParameterCount - 1); 361 requiredParameterCount: function.requiredParameterCount - 1);
368 362
369 return new ClosureCreation( 363 return new ClosureCreation(
370 closedTopLevelFunction, accessContext, closureType); 364 closedTopLevelFunction, accessContext, closureType);
371 } 365 }
372 366
373 TreeNode visitField(Field node) {
374 currentMember = node;
375 context = new NoContext(this);
376 if (node.isInstanceMember) {
377 Name tearOffName = tearOffGetterNames[node.name];
378 if (tearOffName != null) {
379 // TODO(ahe): If we rewrite setters, we can rename the field to avoid
380 // an indirection in most cases.
381 addFieldForwarder(tearOffName, node);
382 }
383 }
384 node = super.visitField(node);
385 context = null;
386 currentMember = null;
387 return node;
388 }
389
390 TreeNode visitProcedure(Procedure node) { 367 TreeNode visitProcedure(Procedure node) {
391 assert(isEmptyContext); 368 assert(isEmptyContext);
392 369
393 currentMember = node; 370 currentMember = node;
394 371
395 if (node.isInstanceMember) {
396 Name tearOffName = tearOffGetterNames[node.name];
397 if (tearOffName != null) {
398 if (node.isGetter) {
399 // We rename the getter to avoid an indirection in most cases.
400 Name oldName = node.name;
401 node.name = tearOffName;
402 node.canonicalName?.unbind();
403 addGetterForwarder(oldName, node);
404 } else if (node.kind == ProcedureKind.Method) {
405 addTearOffMethod(tearOffName, node);
406 }
407 }
408 }
409
410 FunctionNode function = node.function; 372 FunctionNode function = node.function;
411 if (function.body != null) { 373 if (function.body != null) {
412 setupContextForFunctionBody(function); 374 setupContextForFunctionBody(function);
413 VariableDeclaration self = thisAccess[currentMemberFunction]; 375 VariableDeclaration self = thisAccess[currentMemberFunction];
414 if (self != null) { 376 if (self != null) {
415 context.extend(self, new ThisExpression()); 377 context.extend(self, new ThisExpression());
416 } 378 }
417 node.transformChildren(this); 379 node.transformChildren(this);
418 resetContext(); 380 resetContext();
419 } 381 }
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
604 } 566 }
605 return super.visitForInStatement(node); 567 return super.visitForInStatement(node);
606 } 568 }
607 569
608 TreeNode visitThisExpression(ThisExpression node) { 570 TreeNode visitThisExpression(ThisExpression node) {
609 return isOuterMostContext 571 return isOuterMostContext
610 ? node 572 ? node
611 : context.lookup(thisAccess[currentMemberFunction]); 573 : context.lookup(thisAccess[currentMemberFunction]);
612 } 574 }
613 575
614 TreeNode visitStaticGet(StaticGet node) {
615 Member target = node.target;
616 if (target is Procedure && target.kind == ProcedureKind.Method) {
617 VariableDeclaration contextVariable = new VariableDeclaration(
618 "#contextParameter",
619 type: const VectorType());
620 Expression expression = getTearOffExpression(
621 null, node.target, contextVariable, new NullLiteral());
622 expression.transformChildren(this);
623 return expression;
624 }
625 return super.visitStaticGet(node);
626 }
627
628 TreeNode visitPropertyGet(PropertyGet node) {
629 Name tearOffName = tearOffGetterNames[node.name];
630 if (tearOffName != null) {
631 MethodInvocation replacement = new MethodInvocation(
632 node.receiver, tearOffName, new Arguments(<Expression>[]));
633 return super.visitMethodInvocation(replacement);
634 }
635 return super.visitPropertyGet(node);
636 }
637
638 TreeNode visitCatch(Catch node) { 576 TreeNode visitCatch(Catch node) {
639 VariableDeclaration exception = node.exception; 577 VariableDeclaration exception = node.exception;
640 VariableDeclaration stackTrace = node.stackTrace; 578 VariableDeclaration stackTrace = node.stackTrace;
641 if (stackTrace != null && capturedVariables.contains(stackTrace)) { 579 if (stackTrace != null && capturedVariables.contains(stackTrace)) {
642 Block block = node.body = ensureBlock(node.body); 580 Block block = node.body = ensureBlock(node.body);
643 block.parent = node; 581 block.parent = node;
644 node.stackTrace = new VariableDeclaration(null); 582 node.stackTrace = new VariableDeclaration(null);
645 node.stackTrace.parent = node; 583 node.stackTrace.parent = node;
646 stackTrace.initializer = new VariableGet(node.stackTrace); 584 stackTrace.initializer = new VariableGet(node.stackTrace);
647 block.statements.insert(0, stackTrace); 585 block.statements.insert(0, stackTrace);
648 stackTrace.parent = block; 586 stackTrace.parent = block;
649 } 587 }
650 if (exception != null && capturedVariables.contains(exception)) { 588 if (exception != null && capturedVariables.contains(exception)) {
651 Block block = node.body = ensureBlock(node.body); 589 Block block = node.body = ensureBlock(node.body);
652 block.parent = node; 590 block.parent = node;
653 node.exception = new VariableDeclaration(null); 591 node.exception = new VariableDeclaration(null);
654 node.exception.parent = node; 592 node.exception.parent = node;
655 exception.initializer = new VariableGet(node.exception); 593 exception.initializer = new VariableGet(node.exception);
656 block.statements.insert(0, exception); 594 block.statements.insert(0, exception);
657 exception.parent = block; 595 exception.parent = block;
658 } 596 }
659 return super.visitCatch(node); 597 return super.visitCatch(node);
660 } 598 }
661 599
662 Block ensureBlock(Statement statement) { 600 Block ensureBlock(Statement statement) {
663 return statement is Block ? statement : new Block(<Statement>[statement]); 601 return statement is Block ? statement : new Block(<Statement>[statement]);
664 } 602 }
665 603
666 /// Creates a closure that will invoke method [procedure] of [receiver] and
667 /// return an expression that instantiates that closure.
668 Expression getTearOffExpression(
669 VariableDeclaration receiver,
670 Procedure procedure,
671 VariableDeclaration contextVariable,
672 Expression accessContext) {
673 Map<TypeParameter, DartType> substitution = procedure.isInstanceMember
674 // Note: we do not attempt to avoid copying type variables that aren't
675 // used in the signature of [procedure]. It might be more economical to
676 // only copy type variables that are used. However, we assume that
677 // passing type arguments that match the enclosing class' type
678 // variables will be handled most efficiently.
679 ? copyTypeVariables(procedure.enclosingClass.typeParameters)
680 : const <TypeParameter, DartType>{};
681
682 // TODO(29181): remove variable `dynamicSubstitution` and replace its usages
683 // with `substitution`.
684
685 Map<TypeParameter, DartType> dynamicSubstitution =
686 <TypeParameter, DartType>{};
687 for (TypeParameter parameter in substitution.keys) {
688 dynamicSubstitution[parameter] = const DynamicType();
689 }
690 for (TypeParameter parameter in substitution.keys) {
691 if (!isObject(parameter.bound)) {
692 dynamicSubstitution[parameter] =
693 substitute(parameter.bound, dynamicSubstitution);
694 }
695 }
696
697 // Find the closure class for the function. If there isn't one, create it.
698 String closedTopLevelFunctionName =
699 createNameForClosedTopLevelFunction(procedure.function);
700 Procedure closedTopLevelFunction = null;
701 for (TreeNode node in newLibraryMembers) {
702 if (node is Procedure && node.name.name == closedTopLevelFunctionName) {
703 closedTopLevelFunction = node;
704 }
705 }
706 if (closedTopLevelFunction == null) {
707 closedTopLevelFunction = new Procedure(
708 new Name(closedTopLevelFunctionName),
709 ProcedureKind.Method,
710 forwardFunction(
711 procedure, receiver, contextVariable, dynamicSubstitution),
712 isStatic: true,
713 fileUri: currentFileUri);
714 newLibraryMembers.add(closedTopLevelFunction);
715 }
716
717 return new ClosureCreation(
718 closedTopLevelFunction, accessContext, procedure.function.functionType);
719 }
720
721 /// Creates a function that has the same signature as `procedure.function` 604 /// Creates a function that has the same signature as `procedure.function`
722 /// and which forwards all arguments to `procedure`. 605 /// and which forwards all arguments to `procedure`.
723 FunctionNode forwardFunction( 606 FunctionNode forwardFunction(
724 Procedure procedure, 607 Procedure procedure,
725 VariableDeclaration receiver, 608 VariableDeclaration receiver,
726 VariableDeclaration contextVariable, 609 VariableDeclaration contextVariable,
727 Map<TypeParameter, DartType> substitution) { 610 Map<TypeParameter, DartType> substitution) {
728 CloneVisitor cloner = substitution.isEmpty 611 CloneVisitor cloner = substitution.isEmpty
729 ? this.cloner 612 ? this.cloner
730 : new CloneWithoutBody(typeSubstitution: substitution); 613 : new CloneWithoutBody(typeSubstitution: substitution);
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
809 copy.function.body = body; 692 copy.function.body = body;
810 copy.function.body.parent = copy.function; 693 copy.function.body.parent = copy.function;
811 return copy; 694 return copy;
812 } 695 }
813 696
814 void addGetterForwarder(Name name, Procedure getter) { 697 void addGetterForwarder(Name name, Procedure getter) {
815 assert(getter.isGetter); 698 assert(getter.isGetter);
816 newClassMembers 699 newClassMembers
817 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name); 700 .add(copyWithBody(getter, forwardToThisProperty(getter))..name = name);
818 } 701 }
819
820 void addTearOffMethod(Name name, Procedure procedure) {
821 // [addTearOffMethod] generates a method along with a context that captures
822 // `this`. The work with contexts is typically done using the data gathered
823 // by a [ClosureInfo] instance. In absence of this information, we need to
824 // create some variables, like `#self` and `#context`, and manipulate
825 // contexts directly in some cases.
826 //
827 // Also, the tear-off method is generated during a visit to the AST node
828 // of the procedure being torn off, so we need to save and restore some
829 // auxiliary variables like `currentMember` and `currentMemberFunction`
830 // and use [saveContext], so that those variables have proper values when
831 // the procedure itself is being transformed.
832 Member oldCurrentMember = currentMember;
833 FunctionNode oldCurrentMemberFunction = currentMemberFunction;
834 try {
835 saveContext(() {
836 Block body = new Block(<Statement>[]);
837 FunctionNode tearOffMethodFunction = new FunctionNode(body);
838 setupContextForFunctionBody(tearOffMethodFunction);
839
840 // We need a variable that refers to `this` to put it into the context.
841 VariableDeclaration self = new VariableDeclaration("#self",
842 type: procedure.enclosingClass.rawType);
843 context.extend(self, new ThisExpression());
844
845 // The `#context` variable is used to access the context in the closed
846 // top-level function that represents the closure and is generated in
847 // [getTearOffExpression].
848 VariableDeclaration contextVariable = new VariableDeclaration(
849 "#contextParameter",
850 type: const VectorType());
851 Context parent = context;
852 context = context.toNestedContext(
853 new VariableAccessor(contextVariable, null, TreeNode.noOffset));
854
855 body.addStatement(new ReturnStatement(getTearOffExpression(
856 self, procedure, contextVariable, parent.expression)));
857
858 Procedure tearOffMethod = new Procedure(
859 name, ProcedureKind.Method, tearOffMethodFunction,
860 fileUri: currentFileUri);
861 newClassMembers.add(tearOffMethod);
862
863 resetContext();
864 });
865 } finally {
866 currentMember = oldCurrentMember;
867 currentMemberFunction = oldCurrentMemberFunction;
868 }
869 }
870 } 702 }
OLDNEW
« no previous file with comments | « no previous file | pkg/kernel/lib/transformations/closure/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698