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

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

Issue 11304021: Add NativeEnqueuer to work with the Enqueuer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add --enable-native-live-type-analysis Created 8 years, 1 month 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:uri'; 7 import 'dart:uri';
8 import 'dart2jslib.dart' hide SourceString; 8 import 'dart2jslib.dart' hide SourceString;
9 import 'elements/elements.dart'; 9 import 'elements/elements.dart';
10 import 'js_backend/js_backend.dart'; 10 import 'js_backend/js_backend.dart';
11 import 'scanner/scannerlib.dart'; 11 import 'scanner/scannerlib.dart';
12 import 'ssa/ssa.dart'; 12 import 'ssa/ssa.dart';
13 import 'tree/tree.dart'; 13 import 'tree/tree.dart';
14 import 'util/util.dart'; 14 import 'util/util.dart';
15 15
16 void processNativeClasses(Enqueuer world, 16
17 CodeEmitterTask emitter, 17 // This class is a temporary work-around until we get a more powerful DartType.
ahe 2012/11/14 13:51:30 Not a proper documentation comment. That is, use
sra1 2012/11/15 00:09:10 Done.
18 Collection<LibraryElement> libraries) { 18 class SpecialType {
ahe 2012/11/14 13:51:30 Can we use ConcreteType from dart/sdk/lib/_interna
sra1 2012/11/15 00:09:10 Lets keep it separate for now. It is not clear tha
19 for (LibraryElement library in libraries) { 19 final String name;
20 processNativeClassesInLibrary(world, emitter, library); 20 const SpecialType._(this.name);
21 } 21
22 } 22 // Object, but no subtypes:
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
23 23 static const JsObject = const SpecialType._('=Object');
24 void addSubtypes(ClassElement cls, 24
25 NativeEmitter emitter) { 25 // The specific implementation of List that is JavaScript Array:
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
26 for (DartType type in cls.allSupertypes) { 26 static const JsArray = const SpecialType._('=List');
27 List<Element> subtypes = emitter.subtypes.putIfAbsent( 27 }
28 type.element, 28
29
30 // This could be an abstract class but we use it as a stub for the dart_backend.
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
31 class NativeEnqueuer {
32 void processNativeClasses(Collection<LibraryElement> libraries) {}
33
34 void registerElement(Element element) {}
35
36 // Method is a member of a native class.
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
37 void registerMethod(Element method) {}
38
39 // Field is a member of a native class.
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
40 void registerFieldLoad(Element field) {}
41 void registerFieldStore(Element field) {}
42
43 // JS-form code can be an instantiation point for types.
ahe 2012/11/14 13:51:30 This comment needs a bit of work to become a prope
sra1 2012/11/15 00:09:10 Done.
44 //
45 // JS('_DOMWindowImpl', 'window');
46 //
47 void registerJsCall(Send node, resolver) {}
48
49 // Emits a summary log line.
ahe 2012/11/14 13:51:30 ///
sra1 2012/11/15 00:09:10 Done.
50 void logSummary(log(message)) {}
51 }
52
53
54 class NativeEnqueuerBase implements NativeEnqueuer {
55
56 final Set<ClassElement> nativeClasses = new Set<ClassElement>();
57
58 // Each class is exactly one of these sets.
ahe 2012/11/14 13:51:30 I think this comment applies to the following fiel
sra1 2012/11/15 00:09:10 Done.
59 final Set<ClassElement> registeredClasses = new Set<ClassElement>();
60 final Set<ClassElement> unusedClasses = new Set<ClassElement>();
61 final Set<ClassElement> pendingClasses = new Set<ClassElement>();
62
63 // Once a type constraint (SpecialType, DartType) has been matched, there is
64 // no need to match it again.
ahe 2012/11/14 13:51:30 /// Perhaps also reword the comment. For exampl
sra1 2012/11/15 00:09:10 Done.
65 final Set matchedTypeConstraints = new Set();
66
67 final queue = new Queue(); // Classes in pendingClasse have thunks in queue.
ahe 2012/11/14 13:51:30 Move comment to previous line and use ///.
ngeoffray 2012/11/14 21:17:39 Explain what those thunks are.
sra1 2012/11/15 00:09:10 Done.
sra1 2012/11/15 00:09:10 Done.
68 bool flushing = false;
69
70
71 final Enqueuer world;
72 final Compiler compiler;
73 final bool enableLiveTypeAnalysis;
74
75 Element annotationCreatesClass;
76 Element annotationReturnsClass;
77
78 // constructed by backend.
ahe 2012/11/14 13:51:30 /// Also, start sentence with an uppercase letter
sra1 2012/11/15 00:09:10 Done.
79 NativeEnqueuerBase(this.world, this.compiler, this.enableLiveTypeAnalysis);
80
81 void processNativeClasses(Collection<LibraryElement> libraries) {
82 Element find(name) {
83 Element e = compiler.coreLibrary.find(name);
ahe 2012/11/14 13:51:30 Should be compiler.findHelper
sra1 2012/11/15 00:09:10 Done.
84 if (e == null) {
85 compiler.cancel("Core library missing class '${name}'");
ahe 2012/11/14 13:51:30 How about: "Could not find implementation class '$
sra1 2012/11/15 00:09:10 Done.
86 }
87 return e;
88 }
89 annotationCreatesClass = find(const SourceString('Creates'));
90 annotationReturnsClass = find(const SourceString('Returns'));
91
92 libraries.forEach(processNativeClassesInLibrary);
93
94 if (!enableLiveTypeAnalysis) {
95 nativeClasses.forEach((c) => enqueueClass(c, 'forced'));
96 flushQueue();
97 }
98 }
99
100 void processNativeClassesInLibrary(LibraryElement library) {
101 // Use implementation to ensure the inclusion of injected members.
102 library.implementation.forEachLocalMember((Element element) {
103 if (element.kind == ElementKind.CLASS) {
ngeoffray 2012/11/14 21:17:39 too much indentation.
sra1 2012/11/15 00:09:10 OK. I think we should change the style, though.
104 ClassElement classElement = element;
105 if (classElement.isNative()) {
106 nativeClasses.add(classElement);
107 unusedClasses.add(classElement);
ngeoffray 2012/11/14 21:17:39 Add a comment why you're also adding it to 'unused
sra1 2012/11/15 00:09:10 I added a comment on nativeClasses.
108
109 // Resolve class to ensure the class has valid inheritance info.
110 classElement.ensureResolved(compiler);
111 }
112 }
113 });
114 }
115
116 enqueueClass(ClassElement classElement, cause) {
ngeoffray 2012/11/14 21:17:39 String cause?
sra1 2012/11/15 00:09:10 It can be a member.
117 assert(unusedClasses.contains(classElement));
118 // compiler.log(
ngeoffray 2012/11/14 21:17:39 Remove debugging code
sra1 2012/11/15 00:09:10 Done.
119 // 'Adding native class ${classElement.name.slowToString()},'
120 // ' why: $cause');
121 unusedClasses.remove(classElement);
122 pendingClasses.add(classElement);
123 queue.add(() { processClass(classElement, cause); });
124 }
125
126 void flushQueue() {
127 if (flushing) return;
128 flushing = true;
129 while (!queue.isEmpty) {
130 (queue.removeFirst())();
131 }
132 flushing = false;
133 }
134
135 processClass(ClassElement classElement, cause) {
136 assert(!registeredClasses.contains(classElement));
137
138 bool firstTime = registeredClasses.isEmpty;
139 pendingClasses.remove(classElement);
140 registeredClasses.add(classElement);
141
142 // print('processClass $classElement $cause');
ngeoffray 2012/11/14 21:17:39 Remove debugging code.
sra1 2012/11/15 00:09:10 Done.
143 world.registerInstantiatedClass(classElement);
144
145 // Also parse the node to know all its methods because otherwise it will
146 // only be parsed if there is a call to one of its constructors.
147 classElement.parseNode(compiler);
148
149 if (firstTime) {
150 queue.add(onFirstNativeClass);
151 }
152 }
153
154 registerElement(Element element) {
155 if (element.isFunction()) return registerMethod(element);
156 }
157
158 registerMethod(Element method) {
159 if (isNativeMethod(method)) {
160 // print('Native method call $method');
ngeoffray 2012/11/14 21:17:39 Remove debugging code.
sra1 2012/11/15 00:09:10 Done.
161 processNativeBehavior(
162 NativeBehavior.ofMethod(method, compiler),
163 method);
164 flushQueue();
165 }
166 }
167
168 bool isNativeMethod(Element element) {
169 // Native method?
170 Node node = element.parseNode(compiler);
171 if (node is! FunctionExpression) return false;
172 node = node.body;
173 Token token = node.getBeginToken();
174 if (token.stringValue == 'native') return true;
175 return false;
176 }
177
178 void registerFieldLoad(Element field) {
179 // print('Native load field $field');
ngeoffray 2012/11/14 21:17:39 Remove
sra1 2012/11/15 00:09:10 Done.
180 processNativeBehavior(
181 NativeBehavior.ofFieldLoad(field, compiler),
182 field);
183 flushQueue();
184 }
185
186 void registerFieldStore(Element field) {
187 // print('Native store field $field');
ngeoffray 2012/11/14 21:17:39 Remove
sra1 2012/11/15 00:09:10 Done.
188 processNativeBehavior(
189 NativeBehavior.ofFieldStore(field, compiler),
190 field);
191 flushQueue();
192 }
193
194 void registerJsCall(Send node, resolver) {
ngeoffray 2012/11/14 21:17:39 Add type annotation to resolver.
sra1 2012/11/15 00:09:10 Done.
195 processNativeBehavior(
196 NativeBehavior.ofJsCall(node, compiler, resolver),
197 node);
198 flushQueue();
199 }
200
201 processNativeBehavior(NativeBehavior behavior, cause) {
202 bool allUsedBefore = unusedClasses.isEmpty;
203 for (var type in behavior.typesInstantiated) {
204 if (matchedTypeConstraints.contains(type)) continue;
205 matchedTypeConstraints.add(type);
206 if (type is SpecialType) {
207 // These two special types are always instantiated.
ngeoffray 2012/11/14 21:17:39 What are these two? Add them in the comment.
sra1 2012/11/15 00:09:10 Done.
208 continue;
209 }
210 assert(type is DartType);
211 enqueueUnusedClassesMatching(
212 (nativeClass) => compiler.types.isSubtype(nativeClass.type, type),
213 cause,
214 'subtypeof($type)');
215 }
216
217 // Give an info so that library developers can compile with -v to find why
218 // all the native classes are included.
219 if (unusedClasses.isEmpty && !allUsedBefore) {
220 if (cause is Node) {
ngeoffray 2012/11/14 21:17:39 What is the difference between this if and the nex
sra1 2012/11/15 00:09:10 Done.
221 // throw 'Eugh $cause';
ngeoffray 2012/11/14 21:17:39 Remove throw
sra1 2012/11/15 00:09:10 Done.
222 compiler.log('All native types marked as used due to $cause.');
223 } else if (cause.position() != null) {
224 //compiler.cancel('Eugh!', token: cause.position());
ngeoffray 2012/11/14 21:17:39 Remove cancel
sra1 2012/11/15 00:09:10 Done.
225 compiler.log('All native types marked used due to $cause.');
226 } else {
227 compiler.log('All native types marked used due to $type.');
ngeoffray 2012/11/14 21:17:39 What is type here?
sra1 2012/11/15 00:09:10 Old debugging code.
228 }
229 }
230 }
231
232 enqueueUnusedClassesMatching(predicate, cause, [reason]) {
ngeoffray 2012/11/14 21:17:39 Types please
sra1 2012/11/15 00:09:10 Done.
233 var matches = unusedClasses.filter(predicate);
ngeoffray 2012/11/14 21:17:39 ditto
sra1 2012/11/15 00:09:10 Done.
234 // print('${matches.length} matches: $matches\n.. $reason $world');
ngeoffray 2012/11/14 21:17:39 Remove
sra1 2012/11/15 00:09:10 Done.
235 matches.forEach((c) => enqueueClass(c, cause));
236 }
237
238 onFirstNativeClass() {
239 staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
240
241 staticUse(const SourceString('dynamicFunction'));
242 staticUse(const SourceString('dynamicSetMetadata'));
243 staticUse(const SourceString('defineProperty'));
244 staticUse(const SourceString('toStringForNativeObject'));
245 staticUse(const SourceString('hashCodeForNativeObject'));
246
247 addNativeExceptions();
248 }
249
250 addNativeExceptions() {
251 enqueueUnusedClassesMatching((classElement) {
252 // TODO(sra): Annotate exception classes in dart:html.
253 var name = classElement.name.slowToString();
ngeoffray 2012/11/14 21:17:39 String name
sra1 2012/11/15 00:09:10 Done.
254 if (name.contains('Exception')) return true;
255 if (name.contains('Error')) return true;
256 return false;
257 },
258 'native exception');
259 }
260 }
261
262
263 class NativeResolutionEnqueuer extends NativeEnqueuerBase {
264
265 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler,
266 bool enableLiveTypeAnalysis)
267 : super(world, compiler, enableLiveTypeAnalysis);
268
269 void logSummary(log(message)) {
270 log('Resolved ${registeredClasses.length} native elements used, '
271 '${unusedClasses.length} native elements dead.');
272 }
273 }
274
275
276 class NativeCodegenEnqueuer extends NativeEnqueuerBase {
277
278 final CodeEmitterTask emitter;
279
280 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter,
281 bool enableLiveTypeAnalysis)
282 : super(world, compiler, enableLiveTypeAnalysis);
283
284 void processNativeClasses(Collection<LibraryElement> libraries) {
285 super.processNativeClasses(libraries);
286
287 // HACK HACK - add all the resolved classes.
288 for (final classElement
289 in compiler.enqueuer.resolution.nativeEnqueuer.registeredClasses) {
290 if (unusedClasses.contains(classElement)) {
291 enqueueClass(classElement, 'was resolved');
292 }
293 }
294 flushQueue();
295 }
296
297 processClass(ClassElement classElement, cause) {
298 super.processClass(classElement, cause);
299 // Add the information that this class is a subtype of its supertypes. The
300 // code emitter and the ssa builder use that information.
301 addSubtypes(classElement, emitter.nativeEmitter);
302 }
303
304 void addSubtypes(ClassElement cls, NativeEmitter emitter) {
305 for (DartType type in cls.allSupertypes) {
306 List<Element> subtypes = emitter.subtypes.putIfAbsent(
307 type.element,
308 () => <ClassElement>[]);
309 subtypes.add(cls);
310 }
311
312 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent(
313 cls.superclass,
29 () => <ClassElement>[]); 314 () => <ClassElement>[]);
30 subtypes.add(cls); 315 directSubtypes.add(cls);
31 } 316 }
32 317
33 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( 318 void logSummary(log(message)) {
34 cls.superclass, 319 log('Compiled ${registeredClasses.length} native classes, '
35 () => <ClassElement>[]); 320 '${unusedClasses.length} native classes omitted.');
36 directSubtypes.add(cls); 321 }
37 } 322 }
38 323
39 void processNativeClassesInLibrary(Enqueuer world,
40 CodeEmitterTask emitter,
41 LibraryElement library) {
42 bool hasNativeClass = false;
43 final compiler = emitter.compiler;
44 // Use implementation to ensure the inclusion of injected members.
45 library.implementation.forEachLocalMember((Element element) {
46 if (element.kind == ElementKind.CLASS) {
47 ClassElement classElement = element;
48 if (classElement.isNative()) {
49 hasNativeClass = true;
50 world.registerInstantiatedClass(classElement);
51 // Also parse the node to know all its methods because
52 // otherwise it will only be parsed if there is a call to
53 // one of its constructor.
54 classElement.parseNode(compiler);
55 // Resolve to setup the inheritance.
56 classElement.ensureResolved(compiler);
57 // Add the information that this class is a subtype of
58 // its supertypes. The code emitter and the ssa builder use that
59 // information.
60 addSubtypes(classElement, emitter.nativeEmitter);
61 }
62 }
63 });
64 if (hasNativeClass) {
65 world.registerStaticUse(compiler.findHelper(
66 const SourceString('dynamicFunction')));
67 world.registerStaticUse(compiler.findHelper(
68 const SourceString('dynamicSetMetadata')));
69 world.registerStaticUse(compiler.findHelper(
70 const SourceString('defineProperty')));
71 world.registerStaticUse(compiler.findHelper(
72 const SourceString('toStringForNativeObject')));
73 world.registerStaticUse(compiler.findHelper(
74 const SourceString('hashCodeForNativeObject')));
75 }
76 }
77
78 void maybeEnableNative(Compiler compiler, 324 void maybeEnableNative(Compiler compiler,
79 LibraryElement library, 325 LibraryElement library,
80 Uri uri) { 326 Uri uri) {
81 String libraryName = uri.toString(); 327 String libraryName = uri.toString();
82 if (library.entryCompilationUnit.script.name.contains( 328 if (library.entryCompilationUnit.script.name.contains(
83 'dart/tests/compiler/dart2js_native') 329 'dart/tests/compiler/dart2js_native')
84 || libraryName == 'dart:isolate' 330 || libraryName == 'dart:isolate'
85 || libraryName == 'dart:html' 331 || libraryName == 'dart:html'
86 || libraryName == 'dart:svg') { 332 || libraryName == 'dart:svg') {
87 library.canUseNative = true; 333 library.canUseNative = true;
88 } 334 }
89 } 335 }
90 336
337 class NativeBehavior {
338 // Native code can return values of one type and cause native subtypes of
339 // another type to be instantiated. By default, we compute both from the
340 // declared type.
341 //
342 // A field might yield any native type that 'is' the field type.
343 //
344 // A method might create and return instances of native subclasses its
ngeoffray 2012/11/14 21:17:39 of its
sra1 2012/11/15 00:09:10 Done.
345 // declared return type, and a callback argument may be called with
346 // instances of the callback parameter type (e.g. Event).
347 //
348 // If there is one or more @Creates annotations, the union of the named types
349 // replaces the inferred instantiated type, and the return type is ignored for
350 // the purpose of inferring instantiated types.
351 //
352 // @Creates(IDBCursor) // Created asynchronously.
353 // @Creates(IDBRequest) // Created synchronously (for return value).
354 // IDBRequest request = objectStore.openCursor();
355 //
356 // If there is one or more @Returns annotations, the union of the named types
357 // replaces the declared return type.
358 //
359 // @Returns(IDBRequest)
360 // IDBRequest request = objectStore.openCursor();
361 //
362
363 // These collections contain DartTypes or SpecialTypes.
364 final Collection typesReturned = [];
365 final Collection typesInstantiated = [];
366
367 const NativeBehavior();
368
369 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
370 // The first argument of a JS-call is a string encoding various attributes
371 // of the code.
372 //
373 // 'Type1|Type2'. A union type.
374 // '=Object'. A JavaScript Object, no subtype.
375 // '=List'. A JavaScript Array, no subtype.
376
377 var argNodes = jsCall.arguments;
378 if (argNodes.isEmpty) {
379 compiler.cancel("JS expression has no type", node: node);
380 }
381
382 var firstArg = argNodes.head;
383 LiteralString specLiteral = firstArg.asLiteralString();
384 if (specLiteral != null) {
385 String specString = specLiteral.dartString.slowToString();
386 // Various things that are not in fact types.
387 if (specString == 'void') return const NativeBehavior();
388 if (specString == '' || specString == 'var') {
389 var behavior = new NativeBehavior();
390 behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
391 return behavior;
392 }
393 var behavior = new NativeBehavior();
394 for (final typeString in specString.split('|')) {
395 var type = _parseType(typeString, compiler,
396 (name) => resolver.resolveTypeFromString(name),
397 jsCall);
398 behavior.typesInstantiated.add(type);
399 behavior.typesReturned.add(type);
400 }
401 return behavior;
402 }
403
404 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
405 // is not very satisfactory because it does not work for void, dynamic.
406
407 compiler.cancel("Unexpected JS first argument", node: firstArg);
408 }
409
410 static NativeBehavior ofMethod(Element method, Compiler compiler) {
411 DartType type = method.computeType(compiler);
412 var behavior = new NativeBehavior();
413 behavior.typesReturned.add(type.returnType);
414 behavior._capture(type, compiler);
415
416 // TODO(sra): Optional arguments are currently missing from the
417 // DartType. This should be fixed so the following work-around can be
418 // removed.
419 method.computeSignature(compiler).forEachOptionalParameter(
420 (Element parameter) {
421 behavior._escape(parameter.computeType(compiler), compiler);
422 });
423
424 behavior._overrideWithAnnotations(method, compiler);
425 return behavior;
426 }
427
428 static NativeBehavior ofFieldLoad(Element field, Compiler compiler) {
429 DartType type = field.computeType(compiler);
430 var behavior = new NativeBehavior();
431 behavior.typesReturned.add(type);
432 behavior._capture(type, compiler);
433 behavior._overrideWithAnnotations(field, compiler);
434 return behavior;
435 }
436
437 static NativeBehavior ofFieldStore(Element field, Compiler compiler) {
438 DartType type = field.computeType(compiler);
439 var behavior = new NativeBehavior();
440 behavior._escape(type, compiler);
441 // We don't override the default behaviour - the annotations apply to
442 // loading the field.
443 return behavior;
444 }
445
446 void _overrideWithAnnotations(Element element, Compiler compiler) {
447 if (element.metadata.isEmpty) return;
448
449 DartType lookup(String name) {
ngeoffray 2012/11/14 21:17:39 You could move this method into _collect.
sra1 2012/11/15 00:09:10 But then I allocate two closures .. I think it is
450 Element e = element.buildScope().lookup(new SourceString(name));
451 if (e == null) return null;
452 if (e is! ClassElement) return null;
453 e.ensureResolved(compiler);
454 return e.computeType(compiler);
455 }
456
457 var creates =
458 _collect(element, compiler,
459 compiler.enqueuer.resolution.nativeEnqueuer.annotationCreatesClass,
460 lookup);
461 var returns =
462 _collect(element, compiler,
463 compiler.enqueuer.resolution.nativeEnqueuer.annotationReturnsClass,
464 lookup);
465
466 if (creates != null) {
467 typesInstantiated..clear()..addAll(creates);
ngeoffray 2012/11/14 21:17:39 First use of cascaded calls in dart2js I see! Cong
sra1 2012/11/15 00:09:10 Done.
468 }
469 if (returns != null) {
470 typesReturned..clear()..addAll(returns);
ngeoffray 2012/11/14 21:17:39 And second :)
sra1 2012/11/15 00:09:10 Done.
471 }
472 }
473
474 /**
475 * Returns a list of type constraints from the annotations of
476 * [annotationClass].
477 * Returns [:null:] if no constraints.
478 */
479 static _collect(Element element, Compiler compiler, Element annotationClass,
480 lookup(str)) {
481 var types = null;
482 for (Link<MetadataAnnotation> link = element.metadata;
483 !link.isEmpty;
484 link = link.tail) {
485 MetadataAnnotation annotation = link.head.ensureResolved(compiler);
486 var value = annotation.value;
487 if (value is! ConstructedConstant) continue;
488 if (value.type is! InterfaceType) continue;
489 if (!identical(value.type.element, annotationClass)) continue;
490
491 var fields = value.fields;
492 // TODO(sra): Better validation of the constant.
493 if (fields.length != 1 ||
494 fields[0] is! StringConstant) {
495 compiler.cancel(
496 'Annotations needs one string: ${annotation.parseNode(compiler)}');
497 }
498 String specString = fields[0].toDartString().slowToString();
499 for (final typeString in specString.split('|')) {
500 var type = _parseType(typeString, compiler, lookup, annotation);
501 if (types == null) types = [];
502 types.add(type);
503 }
504 }
505 return types;
506 }
507
508 void _escape(DartType type, Compiler compiler) {
ngeoffray 2012/11/14 21:17:39 Please add comments on what this function does.
sra1 2012/11/15 00:09:10 Done.
509 type = type.unalias(compiler);
510 if (type is FunctionType) {
511 _escape(type.returnType, compiler);
512 for (Link<DartType> parameters = type.parameterTypes;
513 !parameters.isEmpty;
514 parameters = parameters.tail) {
515 _capture(parameters.head, compiler);
516 }
517 }
518 }
519
520 void _capture(DartType type, Compiler compiler) {
ngeoffray 2012/11/14 21:17:39 ditto
sra1 2012/11/15 00:09:10 Done.
521 type = type.unalias(compiler);
522 if (type is FunctionType) {
523 _capture(type.returnType, compiler);
524 for (Link<DartType> parameters = type.parameterTypes;
525 !parameters.isEmpty;
526 parameters = parameters.tail) {
527 _escape(parameters.head, compiler);
528 }
529 } else {
530 typesInstantiated.add(type);
531 }
532 }
533
534 static _parseType(String typeString, Compiler compiler,
535 lookup(name), locationNodeOrElement) {
536 if (typeString == '=Object') return SpecialType.JsObject;
537 if (typeString == '=List') return SpecialType.JsArray;
538 if (typeString == 'dynamic') {
539 return compiler.dynamicClass.computeType(compiler);
540 }
541 DartType type = lookup(typeString);
542 if (type != null) return type;
543
544 int index = typeString.indexOf('<');
545 if (index < 1) {
546 compiler.cancel("Type '$typeString' not found",
547 node: _errorNode(locationNodeOrElement, compiler));
548 }
549 type = lookup(typeString.substring(0, index));
550 if (type != null) {
551 // TODO(sra): Parse type parameters.
552 return type;
553 }
554 compiler.cancel("Type '$typeString' not found",
555 node: _errorNode(locationNodeOrElement, compiler));
556 }
557
558 static _errorNode(locationNodeOrElement, compiler) {
559 if (locationNodeOrElement is Node) return locationNodeOrElement;
560 return locationNodeOrElement.parseNode(compiler);
561 }
562 }
563
91 void checkAllowedLibrary(ElementListener listener, Token token) { 564 void checkAllowedLibrary(ElementListener listener, Token token) {
92 LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary(); 565 LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary();
93 if (!currentLibrary.canUseNative) { 566 if (!currentLibrary.canUseNative) {
94 listener.recoverableError("Unexpected token", token: token); 567 listener.recoverableError("Unexpected token", token: token);
95 } 568 }
96 } 569 }
97 570
98 Token handleNativeBlockToSkip(Listener listener, Token token) { 571 Token handleNativeBlockToSkip(Listener listener, Token token) {
99 checkAllowedLibrary(listener, token); 572 checkAllowedLibrary(listener, token);
100 token = token.next; 573 token = token.next;
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
333 String parameters) { 806 String parameters) {
334 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty"); 807 buffer.add(" if (Object.getPrototypeOf(this).hasOwnProperty");
335 buffer.add("('$methodName')) {\n"); 808 buffer.add("('$methodName')) {\n");
336 buffer.add(" $code"); 809 buffer.add(" $code");
337 buffer.add(" } else {\n"); 810 buffer.add(" } else {\n");
338 buffer.add(" return Object.prototype.$methodName.call(this"); 811 buffer.add(" return Object.prototype.$methodName.call(this");
339 buffer.add(parameters == '' ? '' : ', $parameters'); 812 buffer.add(parameters == '' ? '' : ', $parameters');
340 buffer.add(");\n"); 813 buffer.add(");\n");
341 buffer.add(" }\n"); 814 buffer.add(" }\n");
342 } 815 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698