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

Side by Side Diff: pkg/compiler/lib/src/js_backend/no_such_method_registry.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: Return enum result for _categorizeImpl 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 * Categorizes `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 NoSuchMethodRegistry {
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 NoSuchMethodRegistry(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 }
58
59 NsmCategory _categorizeImpl(Element noSuchMethodElement) {
60 assert(noSuchMethodElement.name == Compiler.NO_SUCH_METHOD);
61 if (forwardingImpls.contains(noSuchMethodElement)) {
62 return NsmCategory.FORWARDING;
63 }
64 if (throwingImpls.contains(noSuchMethodElement)) {
65 return NsmCategory.THROWING;
66 }
67 if (otherImpls.contains(noSuchMethodElement)) {
68 return NsmCategory.OTHER;
69 }
70 if (noSuchMethodElement is! FunctionElement ||
71 !compiler.noSuchMethodSelector.signatureApplies(noSuchMethodElement)) {
72 otherImpls.add(noSuchMethodElement);
73 return NsmCategory.OTHER;
74 }
75 FunctionElement noSuchMethodFunc = noSuchMethodElement as FunctionElement;
76 if (isForwarding(noSuchMethodFunc)) {
77 forwardingImpls.add(noSuchMethodFunc);
78 return NsmCategory.FORWARDING;
79 } else if (isThrowing(noSuchMethodFunc)) {
80 throwingImpls.add(noSuchMethodFunc);
81 return NsmCategory.THROWING;
82 } else {
83 otherImpls.add(noSuchMethodFunc);
84 return NsmCategory.OTHER;
85 }
86 }
87
88 bool isForwarding(FunctionElement element) {
89 if (backend.isDefaultNoSuchMethodImplementation(element)) {
90 return true;
91 }
92
93 if (!hasForwardingSyntax(element)) {
94 return false;
95 }
96
97 // Check if the super call hits a forwarding implementation
98 Element superCall = element.enclosingClass
99 .lookupSuperSelector(compiler.noSuchMethodSelector);
100 var category = _categorizeImpl(superCall);
Johnni Winther 2015/03/18 10:47:16 Nit: Replace 'var' with 'NsmCategory'. We only use
Harry Terkelsen 2015/03/18 20:54:50 Done.
101 return category == NsmCategory.FORWARDING;
102 }
103
104 bool hasForwardingSyntax(FunctionElement element) {
105 String param = element.parameters.single.name;
106 Statement body = element.node.body;
107 Expression expr;
108 if (body is Return && body.isArrowBody) {
109 expr = body.expression;
110 } else if (body is Block &&
111 !body.statements.isEmpty &&
112 body.statements.nodes.tail.isEmpty) {
113 Statement stmt = body.statements.nodes.head;
114 if (stmt is Return && stmt.hasExpression) {
115 expr = stmt.expression;
116 }
117 }
118 if (expr is Send &&
119 expr.isSuperCall &&
120 expr.selector is Identifier &&
121 (expr.selector as Identifier).source == Compiler.NO_SUCH_METHOD) {
122 var arg = expr.arguments.head;
123 if (arg is Send &&
124 arg.argumentsNode == null &&
125 arg.receiver == null &&
126 arg.selector is Identifier &&
127 arg.selector.source == param) {
128 return true;
129 }
130 }
131 return false;
132 }
133
134 bool isThrowing(FunctionElement element) {
135 Statement body = element.node.body;
136 if (body is Return && body.isArrowBody) {
137 if (body.expression is Throw) {
138 return true;
139 }
140 } else if (body is Block &&
141 !body.statements.isEmpty &&
142 body.statements.nodes.tail.isEmpty) {
143 if (body.statements.nodes.head is Throw) {
144 return true;
145 }
146 }
147 return false;
148 }
149 }
150
151 enum NsmCategory { FORWARDING, THROWING, OTHER }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698