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

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 // Collect potential subclasses, e.g.
150 //
151 // class B extends foo.A {}
152 //
153 // SourceString "A" has a potential subclass B.
154
155 var potentialExtends = new Map<SourceString, Set<ClassElement>>();
156
157 libraries.forEach((library) {
158 library.implementation.forEachLocalMember((element) {
159 if (element.isClass()) {
160 SourceString name = element.name;
161 SourceString extendsName = findExtendsNameOfClass(element);
162 if (extendsName != null) {
163 Set<ClassElement> potentialSubclasses =
164 potentialExtends.putIfAbsent(
165 extendsName,
166 () => new Set<ClassElement>());
167 potentialSubclasses.add(element);
168 }
169 }
170 });
171 });
172
173 // Resolve all the native classes and any classes that might extend them in
174 // [potentialExtends], and then check that the properly resolved class is in
175 // fact a subclass of a native class.
176
177 ClassElement nativeSuperclassOf(ClassElement classElement) {
178 if (classElement.isNative()) return classElement;
179 if (classElement.superclass == null) return null;
180 return nativeSuperclassOf(classElement.superclass);
181 }
182
183 void walkPotentialSubclasses(ClassElement element) {
184 if (nativeClassesAndSubclasses.contains(element)) return;
185 element.ensureResolved(compiler);
186 ClassElement nativeSuperclass = nativeSuperclassOf(element);
187 if (nativeSuperclass != null) {
188 nativeClassesAndSubclasses.add(element);
189 if (!element.isNative()) {
190 nonNativeSubclasses.putIfAbsent(nativeSuperclass,
191 () => new Set<ClassElement>())
192 .add(element);
193 }
194 Set<ClassElement> potentialSubclasses = potentialExtends[element.name];
195 if (potentialSubclasses != null) {
196 potentialSubclasses.forEach(walkPotentialSubclasses);
197 }
198 }
199 }
200
201 nativeClasses.forEach(walkPotentialSubclasses);
202
203 nativeClasses.addAll(nativeClassesAndSubclasses);
204 unusedClasses.addAll(nativeClassesAndSubclasses);
205 }
206
207 /**
208 * Returns the source string of the class named in the extends clause, or
209 * `null` if there is no extends clause.
210 */
211 SourceString findExtendsNameOfClass(ClassElement classElement) {
212 // "class B extends A ... {}" --> "A"
213 // "class B extends foo.A ... {}" --> "A"
214 // "class B<T> extends foo.A<T,T> with M1, M2 ... {}" --> "A"
215
216 // We want to avoid calling classElement.parseNode on every class. Doing so
217 // will slightly increase parse time and size and cause compiler errors and
218 // warnings to me emitted in more unused code.
219
220 // An alternative to this code is to extend the API of ClassElement to
221 // expose the name of the extended element.
222
223 // Pattern match the above cases in the token stream.
224 // [abstract] class X extends [id.]* id
225
226 Token skipTypeParameters(Token token) {
227 BeginGroupToken beginGroupToken = token;
228 Token endToken = beginGroupToken.endGroup;
229 return endToken.next;
230 //for (;;) {
231 // token = token.next;
232 // if (token.stringValue == '>') return token.next;
233 // if (token.stringValue == '<') return skipTypeParameters(token);
234 //}
235 }
236
237 SourceString scanForExtendsName(Token token) {
238 if (token.stringValue == 'abstract') token = token.next;
239 if (token.stringValue != 'class') return null;
240 token = token.next;
241 if (!token.isIdentifier()) return null;
242 token = token.next;
243 // class F<X extends B<X>> extends ...
244 if (token.stringValue == '<') {
245 token = skipTypeParameters(token);
246 }
247 if (token.stringValue != 'extends') return null;
248 token = token.next;
249 Token id = token;
250 while (token.kind != EOF_TOKEN) {
251 token = token.next;
252 if (token.stringValue != '.') break;
253 token = token.next;
254 if (!token.isIdentifier()) return null;
255 id = token;
256 }
257 // Should be at '{', 'with', 'implements', '<' or 'native'.
258 return id.value;
259 }
260
261 return compiler.withCurrentElement(classElement, () {
262 return scanForExtendsName(classElement.position());
263 });
264 }
265
140 ClassElement get annotationCreatesClass { 266 ClassElement get annotationCreatesClass {
141 findAnnotationClasses(); 267 findAnnotationClasses();
142 return _annotationCreatesClass; 268 return _annotationCreatesClass;
143 } 269 }
144 270
145 ClassElement get annotationReturnsClass { 271 ClassElement get annotationReturnsClass {
146 findAnnotationClasses(); 272 findAnnotationClasses();
147 return _annotationReturnsClass; 273 return _annotationReturnsClass;
148 } 274 }
149 275
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 staticUse(name) => world.registerStaticUse(compiler.findHelper(name)); 504 staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
379 505
380 staticUse(const SourceString('dynamicFunction')); 506 staticUse(const SourceString('dynamicFunction'));
381 staticUse(const SourceString('dynamicSetMetadata')); 507 staticUse(const SourceString('dynamicSetMetadata'));
382 staticUse(const SourceString('defineProperty')); 508 staticUse(const SourceString('defineProperty'));
383 staticUse(const SourceString('toStringForNativeObject')); 509 staticUse(const SourceString('toStringForNativeObject'));
384 staticUse(const SourceString('hashCodeForNativeObject')); 510 staticUse(const SourceString('hashCodeForNativeObject'));
385 staticUse(const SourceString('convertDartClosureToJS')); 511 staticUse(const SourceString('convertDartClosureToJS'));
386 staticUse(const SourceString('defineNativeMethods')); 512 staticUse(const SourceString('defineNativeMethods'));
387 staticUse(const SourceString('defineNativeMethodsNonleaf')); 513 staticUse(const SourceString('defineNativeMethodsNonleaf'));
514 staticUse(const SourceString('defineNativeMethodsExtended'));
388 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with 515 // TODO(9577): Registering `defineNativeMethodsFinish` seems redundant with
389 // respect to the registering in the backend. When the backend registering 516 // 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 517 // is removed as part of fixing Issue 9577, this can be the sole place
391 // registering this methods. 518 // registering this methods.
392 staticUse(const SourceString('defineNativeMethodsFinish')); 519 staticUse(const SourceString('defineNativeMethodsFinish'));
393 520
394 addNativeExceptions(); 521 addNativeExceptions();
395 } 522 }
396 523
397 addNativeExceptions() { 524 addNativeExceptions() {
(...skipping 618 matching lines...) Expand 10 before | Expand all | Expand 10 after
1016 'native "..." syntax is restricted to functions with zero parameters', 1143 'native "..." syntax is restricted to functions with zero parameters',
1017 node: nativeBody); 1144 node: nativeBody);
1018 } 1145 }
1019 LiteralString jsCode = nativeBody.asLiteralString(); 1146 LiteralString jsCode = nativeBody.asLiteralString();
1020 builder.push(new HForeign.statement( 1147 builder.push(new HForeign.statement(
1021 new js.LiteralStatement(jsCode.dartString.slowToString()), 1148 new js.LiteralStatement(jsCode.dartString.slowToString()),
1022 <HInstruction>[], 1149 <HInstruction>[],
1023 new SideEffects())); 1150 new SideEffects()));
1024 } 1151 }
1025 } 1152 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698