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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/native_handler.dart

Issue 15026006: Support for extending native classes (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 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
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 native; 5 library native;
6 6
7 import 'dart:collection' show Queue; 7 import 'dart:collection' show Queue;
8 import 'dart2jslib.dart' hide SourceString; 8 import 'dart2jslib.dart' hide SourceString;
9 import 'dart_types.dart'; 9 import 'dart_types.dart';
10 import 'elements/elements.dart'; 10 import 'elements/elements.dart';
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
79 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. 79 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses].
80 */ 80 */
81 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); 81 final Set<ClassElement> nativeClasses = new Set<ClassElement>();
82 82
83 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); 83 final Set<ClassElement> registeredClasses = new Set<ClassElement>();
84 final Set<ClassElement> pendingClasses = new Set<ClassElement>(); 84 final Set<ClassElement> pendingClasses = new Set<ClassElement>();
85 final Set<ClassElement> unusedClasses = new Set<ClassElement>(); 85 final Set<ClassElement> unusedClasses = new Set<ClassElement>();
86 86
87 bool hasInstantiatedNativeClasses() => !registeredClasses.isEmpty; 87 bool hasInstantiatedNativeClasses() => !registeredClasses.isEmpty;
88 88
89 final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>();
90
91 final Map<ClassElement, Set<ClassElement>> nonNativeSubclasses =
92 new Map<ClassElement, Set<ClassElement>>();
93
89 /** 94 /**
90 * Records matched constraints ([SpecialType] or [DartType]). Once a type 95 * Records matched constraints ([SpecialType] or [DartType]). Once a type
91 * constraint has been matched, there is no need to match it again. 96 * constraint has been matched, there is no need to match it again.
92 */ 97 */
93 final Set matchedTypeConstraints = new Set(); 98 final Set matchedTypeConstraints = new Set();
94 99
95 /// Pending actions. Classes in [pendingClasses] have action thunks in 100 /// Pending actions. Classes in [pendingClasses] have action thunks in
96 /// [queue] to register the class. 101 /// [queue] to register the class.
97 final queue = new Queue(); 102 final queue = new Queue();
98 bool flushing = false; 103 bool flushing = false;
99 104
100 /// Maps JS foreign calls to their computed native behavior. 105 /// Maps JS foreign calls to their computed native behavior.
101 final Map<Node, NativeBehavior> nativeBehaviors = 106 final Map<Node, NativeBehavior> nativeBehaviors =
102 new Map<Node, NativeBehavior>(); 107 new Map<Node, NativeBehavior>();
103 108
104 final Enqueuer world; 109 final Enqueuer world;
105 final Compiler compiler; 110 final Compiler compiler;
106 final bool enableLiveTypeAnalysis; 111 final bool enableLiveTypeAnalysis;
107 112
108 ClassElement _annotationCreatesClass; 113 ClassElement _annotationCreatesClass;
109 ClassElement _annotationReturnsClass; 114 ClassElement _annotationReturnsClass;
110 ClassElement _annotationJsNameClass; 115 ClassElement _annotationJsNameClass;
111 116
112 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. 117 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
113 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis); 118 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis);
114 119
115 void processNativeClasses(Iterable<LibraryElement> libraries) { 120 void processNativeClasses(Iterable<LibraryElement> libraries) {
116 libraries.forEach(processNativeClassesInLibrary); 121 libraries.forEach(processNativeClassesInLibrary);
117 processNativeClassesInLibrary(compiler.isolateHelperLibrary); 122 processNativeClassesInLibrary(compiler.isolateHelperLibrary);
123
124 processSubclassesOfNativeClasses(libraries);
125
118 if (!enableLiveTypeAnalysis) { 126 if (!enableLiveTypeAnalysis) {
119 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); 127 nativeClasses.forEach((c) => enqueueClass(c, 'forced'));
120 flushQueue(); 128 flushQueue();
121 } 129 }
122 } 130 }
123 131
124 void processNativeClassesInLibrary(LibraryElement library) { 132 void processNativeClassesInLibrary(LibraryElement library) {
125 // Use implementation to ensure the inclusion of injected members. 133 // Use implementation to ensure the inclusion of injected members.
126 library.implementation.forEachLocalMember((Element element) { 134 library.implementation.forEachLocalMember((Element element) {
127 if (element.isClass() && element.isNative()) { 135 if (element.isClass() && element.isNative()) {
128 processNativeClass(element); 136 processNativeClass(element);
129 } 137 }
130 }); 138 });
131 } 139 }
132 140
133 void processNativeClass(ClassElement classElement) { 141 void processNativeClass(ClassElement classElement) {
134 nativeClasses.add(classElement); 142 nativeClasses.add(classElement);
135 unusedClasses.add(classElement); 143 unusedClasses.add(classElement);
136 // Resolve class to ensure the class has valid inheritance info. 144 // Resolve class to ensure the class has valid inheritance info.
137 classElement.ensureResolved(compiler); 145 classElement.ensureResolved(compiler);
138 } 146 }
139 147
148 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) {
149 // class B extends foo.A {}
ahe 2013/08/13 18:31:47 This comment is weird.
sra1 2013/08/14 04:36:47 Done.
150
151 var potentialExtends = new Map<SourceString, Set<ClassElement>>();
152
153 libraries.forEach((library) {
154 library.implementation.forEachLocalMember((element) {
155 if (element.isClass()) {
156 SourceString name = element.name;
157 SourceString extendsName = findExtendsNameOfClass(element);
158 if (extendsName != null) {
159 Set<ClassElement> potentialSubclasses =
160 potentialExtends.putIfAbsent(
161 extendsName,
162 () => new Set<ClassElement>());
163 potentialSubclasses.add(element);
164 }
165 }
166 });
167 });
168
169 ClassElement nativeSuperclassOf(ClassElement classElement) {
170 if (classElement.isNative()) return classElement;
171 if (classElement.superclass == null) return null;
172 return nativeSuperclassOf(classElement.superclass);
ahe 2013/08/13 18:31:47 How does this cope with cycles in the inheritance
sra1 2013/08/14 04:36:47 Called after resolving.
ahe 2013/08/14 10:52:47 Sorry, I forgot we had solved this problem.
173 }
174
175 void walkPotentialSubclasses(ClassElement element) {
176 if (nativeClassesAndSubclasses.contains(element)) return;
177 //print('Force resolve $element');
ahe 2013/08/13 18:31:47 Remove comment.
sra1 2013/08/14 04:36:47 Done.
178 element.ensureResolved(compiler);
179 ClassElement nativeSuperclass = nativeSuperclassOf(element);
180 if (nativeSuperclass != null) {
181 nativeClassesAndSubclasses.add(element);
182 if (!element.isNative()) {
183 nonNativeSubclasses.putIfAbsent(nativeSuperclass,
184 () => new Set<ClassElement>())
185 .add(element);
186 }
187 Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
188 if (potentialSubclasses != null) {
189 potentialSubclasses.forEach(walkPotentialSubclasses);
190 }
191 }
192 }
193
194 nativeClasses.forEach(walkPotentialSubclasses);
195
196 // print(nativeClassesAndSubclasses);
197
198 nativeClasses.addAll(nativeClassesAndSubclasses);
199 unusedClasses.addAll(nativeClassesAndSubclasses);
200
201 // NEXT: make subclassed classes use different register function; add in a
ahe 2013/08/13 18:31:47 We normally use // TODO(username): ...
sra1 2013/08/14 04:36:47 Removed, since it is done.
202 // hook that the DOM runtime can use.
203 }
204
205 /**
206 * Returns the source string of the class named in the extends clause, or
207 * `null` if there is no extends clause.
208 */
209 SourceString findExtendsNameOfClass(ClassElement classElement) {
ahe 2013/08/13 18:31:47 I'm concerned about this method, and I would reall
210 // "class B extends A ... {}" --> "A"
211 // "class B extends foo.A ... {}" --> "A"
212 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A"
213
214 // We want to avoid calling classElement.parseNode on every class. Doing so
215 // will slightly increase parse time and size and cause compiler errors and
216 // warnings to me emitted in more unused code.
217
218 // An alternative to this code is to extend the API of ClassElement to
219 // expose the name of the extended element.
220
221 // Pattern match the above cases in the token stream.
222 // [abstract] class X extends [id.]* id
223
224 Token skipTypeParameters(Token token) {
ahe 2013/08/13 18:31:47 This should be: BeginGroupToken beginGroupTok
225 for (;;) {
226 token = token.next;
227 if (token.stringValue == '>') return token.next;
228 if (token.stringValue == '<') return skipTypeParameters(token);
229 }
230 }
231
232 SourceString scanForExtendsName(Token token) {
233 if (token.stringValue == 'abstract') token = token.next;
ahe 2013/08/13 18:31:47 You need to use identical, not ==. Otherwise, you
sra1 2013/08/14 04:36:47 What guarantees they are the same instance of Stri
ahe 2013/08/14 10:52:47 That is guaranteed by the language specification (
234 if (token.stringValue != 'class') return null;
ahe 2013/08/13 18:31:47 Ditto.
235 token = token.next;
236 if (!token.isIdentifier()) return null;
237 token = token.next;
238 // class F<X extends B<X>> extends ...
239 if (token.stringValue == '<') {
ahe 2013/08/13 18:31:47 Ditto.
240 token = skipTypeParameters(token);
241 }
242 if (token.stringValue != 'extends') return null;
ahe 2013/08/13 18:31:47 Ditto.
243 token = token.next;
244 Token id = token;
245 for (;;) {
ahe 2013/08/13 18:31:47 As a general rule, infinite loops on user data is
sra1 2013/08/14 04:36:47 Done.
246 token = token.next;
247 if (token.stringValue != '.') break;
ahe 2013/08/13 18:31:47 identical.
248 token = token.next;
249 if (!token.isIdentifier()) return null;
250 id = token;
251 }
252 // Should be at '{', 'with', 'implements', '<' or 'native'.
253 return id.value;
254 }
255
256 return compiler.withCurrentElement(classElement, () {
257 return scanForExtendsName(classElement.position());
258 });
259 }
260
140 ClassElement get annotationCreatesClass { 261 ClassElement get annotationCreatesClass {
141 findAnnotationClasses(); 262 findAnnotationClasses();
142 return _annotationCreatesClass; 263 return _annotationCreatesClass;
143 } 264 }
144 265
145 ClassElement get annotationReturnsClass { 266 ClassElement get annotationReturnsClass {
146 findAnnotationClasses(); 267 findAnnotationClasses();
147 return _annotationReturnsClass; 268 return _annotationReturnsClass;
148 } 269 }
149 270
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 staticUse(name) => world.registerStaticUse(compiler.findHelper(name)); 499 staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
379 500
380 staticUse(const SourceString('dynamicFunction')); 501 staticUse(const SourceString('dynamicFunction'));
381 staticUse(const SourceString('dynamicSetMetadata')); 502 staticUse(const SourceString('dynamicSetMetadata'));
382 staticUse(const SourceString('defineProperty')); 503 staticUse(const SourceString('defineProperty'));
383 staticUse(const SourceString('toStringForNativeObject')); 504 staticUse(const SourceString('toStringForNativeObject'));
384 staticUse(const SourceString('hashCodeForNativeObject')); 505 staticUse(const SourceString('hashCodeForNativeObject'));
385 staticUse(const SourceString('convertDartClosureToJS')); 506 staticUse(const SourceString('convertDartClosureToJS'));
386 staticUse(const SourceString('defineNativeMethods')); 507 staticUse(const SourceString('defineNativeMethods'));
387 staticUse(const SourceString('defineNativeMethodsNonleaf')); 508 staticUse(const SourceString('defineNativeMethodsNonleaf'));
509 staticUse(const SourceString('defineNativeMethodsExtended'));
388 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with 510 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with
389 // respect to the registering in the backend. When the backend registering 511 // respect to the registering in the backend. When the backend registering
390 // is removed as part of fixing Issue 9577, this can be the sole place 512 // is removed as part of fixing Issue 9577, this can be the sole place
391 // registering this methods. 513 // registering this methods.
392 staticUse(const SourceString('defineNativeMethodsFinish')); 514 staticUse(const SourceString('defineNativeMethodsFinish'));
393 515
394 addNativeExceptions(); 516 addNativeExceptions();
395 } 517 }
396 518
397 addNativeExceptions() { 519 addNativeExceptions() {
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 'native "..." syntax is restricted to functions with zero parameters', 1138 'native "..." syntax is restricted to functions with zero parameters',
1017 node: nativeBody); 1139 node: nativeBody);
1018 } 1140 }
1019 LiteralString jsCode = nativeBody.asLiteralString(); 1141 LiteralString jsCode = nativeBody.asLiteralString();
1020 builder.push(new HForeign.statement( 1142 builder.push(new HForeign.statement(
1021 new js.LiteralStatement(jsCode.dartString.slowToString()), 1143 new js.LiteralStatement(jsCode.dartString.slowToString()),
1022 <HInstruction>[], 1144 <HInstruction>[],
1023 new SideEffects())); 1145 new SideEffects()));
1024 } 1146 }
1025 } 1147 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698