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

Side by Side Diff: pkg/compiler/lib/src/js_backend/no_such_method_analysis.dart

Issue 996263002: Don't generate forwarding hooks if all noSuchMethod implementations (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: More tests Created 5 years, 9 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of js_backend;
6
7 /**
8 * Analyzes `noSuchMethod` implementations.
9 *
10 * If user code includes `noSuchMethod` implementations, type inference is
11 * hindered because (for instance) any selector where the type of the
12 * receiver is not known all implementations of `noSuchMethod` must be taken
13 * into account when inferring the return type.
14 *
15 * The situation can be ameliorated with some heuristics for disregarding some
16 * `noSuchMethod` implementations during type inference. We can partition
17 * `noSuchMethod` implementations into 3 categories.
18 *
19 * Implementations in category A have the form
20 *
21 * noSuchMethod(x) => super.noSuchMethod(x);
22 *
23 * where the `super.noSuchMethod` hits `Object.noSuchMethod`,
24 * `Interceptor.noSuchMethod`, or another implementation in category A.
25 *
26 * Implementations in category B immediately throw, and all other
27 * implementations are in category C. A and B implementations may be safely
28 * ignored during type inference. After type inference, we may further partition
29 * C into C1 and C2, where C1 implementations have no return type (they are
30 * guaranteed to throw) and C2, those with return types.
31 */
32 class NoSuchMethodAnalysis {
floitsch 2015/03/13 15:51:49 I wouldn't call this "Analysis". In the end it's a
Harry Terkelsen 2015/03/17 21:43:11 Done.
33 /// The implementations that fall into category A, described above.
34 final Set<FunctionElement> forwardingImpls = new Set<FunctionElement>();
35 /// The implementations that fall into category B, described above.
36 final Set<FunctionElement> throwingImpls = new Set<FunctionElement>();
37 /// The implementations that fall into category C, described above.
38 final Set<Element> otherImpls = new Set<Element>();
39
40 /// The implementations that have not yet been categorized.
41 final Set<Element> uncategorizedImpls = new Set<Element>();
42
43 final JavaScriptBackend backend;
44 final Compiler compiler;
45
46 NoSuchMethodAnalysis(JavaScriptBackend backend)
47 : this.backend = backend,
48 this.compiler = backend.compiler;
49
50 void registerNoSuchMethod(Element noSuchMethodElement) {
51 uncategorizedImpls.add(noSuchMethodElement);
52 }
53
54 void onQueueEmpty(Enqueuer enqueuer) {
55 uncategorizedImpls.forEach(_categorizeImpl);
56 uncategorizedImpls.clear();
57 if (!compiler.enabledNoSuchMethod &&
Johnni Winther 2015/03/16 14:20:43 Move this to the `CodegenEnqueuer.registerNoSuchMe
Harry Terkelsen 2015/03/17 21:43:11 See earlier comment about how the enqueuers and ba
58 (throwingImpls.isNotEmpty || otherImpls.isNotEmpty)) {
59 backend.enableNoSuchMethod(enqueuer);
floitsch 2015/03/13 15:51:49 I would prefer if the "analysis" didn't have any s
Harry Terkelsen 2015/03/17 21:43:11 Done.
60 compiler.enabledNoSuchMethod = true;
61 }
62 }
63
64 void _categorizeImpl(Element noSuchMethodElement) {
65 assert(noSuchMethodElement.name == Compiler.NO_SUCH_METHOD);
66 if (forwardingImpls.contains(noSuchMethodElement) ||
67 throwingImpls.contains(noSuchMethodElement) ||
68 otherImpls.contains(noSuchMethodElement)) return;
69 if (noSuchMethodElement is! FunctionElement ||
70 !compiler.noSuchMethodSelector.signatureApplies(noSuchMethodElement)) {
71 otherImpls.add(noSuchMethodElement);
72 }
73 FunctionElement noSuchMethodFunc = noSuchMethodElement as FunctionElement;
74 if (isForwarding(noSuchMethodFunc)) {
75 forwardingImpls.add(noSuchMethodFunc);
76 } else if (isThrowing(noSuchMethodFunc)) {
77 throwingImpls.add(noSuchMethodFunc);
78 } else {
79 otherImpls.add(noSuchMethodFunc);
80 }
81 }
82
83 bool isForwarding(FunctionElement element) {
84 if (backend.isDefaultNoSuchMethodImplementation(element)) {
85 return true;
86 }
87
88 if (!hasForwardingSyntax(element)) {
89 return false;
90 }
91
92 // Check if the super call hits a forwarding implementation
93 Element superCall = element.enclosingClass
94 .lookupSuperSelector(compiler.noSuchMethodSelector);
95 _categorizeImpl(superCall);
Johnni Winther 2015/03/16 14:20:43 Maybe [_categorizeImpl] should return an enum resu
Harry Terkelsen 2015/03/17 21:55:16 Done.
96 return forwardingImpls.contains(superCall);
97 }
98
99 bool hasForwardingSyntax(FunctionElement element) {
100 String param = element.parameters.single.name;
101 Statement body = element.node.body;
102 Expression expr;
103 if (body is Return && body.isArrowBody) {
104 expr = body.expression;
105 } else if (body is Block &&
106 !body.statements.isEmpty &&
107 body.statements.nodes.tail.isEmpty) {
108 Statement stmt = body.statements.nodes.head;
109 if (stmt is Return && stmt.hasExpression) {
110 expr = stmt.expression;
111 }
112 }
113 if (expr is Send &&
114 expr.isSuperCall &&
115 expr.selector is Identifier &&
116 (expr.selector as Identifier).source == Compiler.NO_SUCH_METHOD) {
117 var arg = expr.arguments.head;
118 if (arg is Send &&
119 arg.argumentsNode == null &&
120 arg.receiver == null &&
121 arg.selector is Identifier &&
122 arg.selector.source == param) {
123 return true;
124 }
125 }
126 return false;
127 }
128
129 bool isThrowing(FunctionElement element) {
130 Statement body = element.node.body;
131 if (body is Return && body.isArrowBody) {
132 if (body.expression is Throw) {
133 return true;
134 }
135 } else if (body is Block &&
136 !body.statements.isEmpty &&
137 body.statements.nodes.tail.isEmpty) {
138 if (body.statements.nodes.head is Throw) {
139 return true;
140 }
141 }
142 return false;
143 }
144 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698