OLD | NEW |
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 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 class NativeEmitter { | 7 class NativeEmitter { |
8 | 8 |
9 final Map<Element, ClassBuilder> cachedBuilders; | 9 final Map<Element, ClassBuilder> cachedBuilders; |
10 | 10 |
11 final CodeEmitterTask emitterTask; | 11 final CodeEmitterTask emitterTask; |
12 CodeBuffer nativeBuffer; | |
13 | 12 |
14 // Native classes found in the application. | 13 // Native classes found in the application. |
15 Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 14 Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
16 | 15 |
17 // Caches the native subtypes of a native class. | 16 // Caches the native subtypes of a native class. |
18 Map<ClassElement, List<ClassElement>> subtypes; | 17 Map<ClassElement, List<ClassElement>> subtypes; |
19 | 18 |
20 // Caches the direct native subtypes of a native class. | 19 // Caches the direct native subtypes of a native class. |
21 Map<ClassElement, List<ClassElement>> directSubtypes; | 20 Map<ClassElement, List<ClassElement>> directSubtypes; |
22 | 21 |
23 // Caches the methods that have a native body. | 22 // Caches the methods that have a native body. |
24 Set<FunctionElement> nativeMethods; | 23 Set<FunctionElement> nativeMethods; |
25 | 24 |
26 // Do we need the native emitter to take care of handling | 25 // Do we need the native emitter to take care of handling |
27 // noSuchMethod for us? This flag is set to true in the emitter if | 26 // noSuchMethod for us? This flag is set to true in the emitter if |
28 // it finds any native class that needs noSuchMethod handling. | 27 // it finds any native class that needs noSuchMethod handling. |
29 bool handleNoSuchMethod = false; | 28 bool handleNoSuchMethod = false; |
30 | 29 |
31 NativeEmitter(CodeEmitterTask emitterTask) | 30 NativeEmitter(CodeEmitterTask emitterTask) |
32 : this.emitterTask = emitterTask, | 31 : this.emitterTask = emitterTask, |
33 subtypes = new Map<ClassElement, List<ClassElement>>(), | 32 subtypes = new Map<ClassElement, List<ClassElement>>(), |
34 directSubtypes = new Map<ClassElement, List<ClassElement>>(), | 33 directSubtypes = new Map<ClassElement, List<ClassElement>>(), |
35 nativeMethods = new Set<FunctionElement>(), | 34 nativeMethods = new Set<FunctionElement>(), |
36 nativeBuffer = new CodeBuffer(), | |
37 cachedBuilders = emitterTask.compiler.cacheStrategy.newMap(); | 35 cachedBuilders = emitterTask.compiler.cacheStrategy.newMap(); |
38 | 36 |
39 Compiler get compiler => emitterTask.compiler; | 37 Compiler get compiler => emitterTask.compiler; |
40 JavaScriptBackend get backend => compiler.backend; | 38 JavaScriptBackend get backend => compiler.backend; |
41 | 39 |
42 jsAst.Expression get defPropFunction { | 40 jsAst.Expression get defPropFunction { |
43 Element element = backend.findHelper('defineProperty'); | 41 Element element = backend.findHelper('defineProperty'); |
44 return emitterTask.staticFunctionAccess(element); | 42 return emitterTask.staticFunctionAccess(element); |
45 } | 43 } |
46 | 44 |
47 /** | 45 /** |
48 * Writes the class definitions for the interceptors to [mainBuffer]. | |
49 * Writes code to associate dispatch tags with interceptors to [nativeBuffer]. | 46 * Writes code to associate dispatch tags with interceptors to [nativeBuffer]. |
50 * | 47 * |
51 * The interceptors are filtered to avoid emitting trivial interceptors. For | 48 * The interceptors are filtered to avoid emitting trivial interceptors. For |
52 * example, if the program contains no code that can distinguish between the | 49 * example, if the program contains no code that can distinguish between the |
53 * numerous subclasses of `Element` then we can pretend that `Element` is a | 50 * numerous subclasses of `Element` then we can pretend that `Element` is a |
54 * leaf class, and all instances of subclasses of `Element` are instances of | 51 * leaf class, and all instances of subclasses of `Element` are instances of |
55 * `Element`. | 52 * `Element`. |
56 * | 53 * |
57 * There is also a performance benefit (in addition to the obvious code size | 54 * There is also a performance benefit (in addition to the obvious code size |
58 * benefit), due to how [getNativeInterceptor] works. Finding the interceptor | 55 * benefit), due to how [getNativeInterceptor] works. Finding the interceptor |
59 * of a leaf class in the hierarchy is more efficient that a non-leaf, so it | 56 * of a leaf class in the hierarchy is more efficient that a non-leaf, so it |
60 * improves performance when more classes can be treated as leaves. | 57 * improves performance when more classes can be treated as leaves. |
61 * | 58 * |
62 * [classes] contains native classes, mixin applications, and user subclasses | 59 * [classes] contains native classes, mixin applications, and user subclasses |
63 * of native classes. ONLY the native classes are generated here. [classes] | 60 * of native classes. ONLY the native classes are generated here. [classes] |
64 * is sorted in desired output order. | 61 * is sorted in desired output order. |
65 * | 62 * |
66 * [additionalProperties] is used to collect properties that are pushed up | 63 * [additionalProperties] is used to collect properties that are pushed up |
67 * from the above optimizations onto a non-native class, e.g, `Interceptor`. | 64 * from the above optimizations onto a non-native class, e.g, `Interceptor`. |
68 */ | 65 */ |
69 void generateNativeClasses( | 66 void generateNativeClasses( |
70 List<ClassElement> classes, | 67 List<ClassElement> classes, |
71 CodeBuffer mainBuffer, | |
72 Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties) { | 68 Map<ClassElement, Map<String, jsAst.Expression>> additionalProperties) { |
73 // Compute a pre-order traversal of the subclass forest. We actually want a | 69 // Compute a pre-order traversal of the subclass forest. We actually want a |
74 // post-order traversal but it is easier to compute the pre-order and use it | 70 // post-order traversal but it is easier to compute the pre-order and use it |
75 // in reverse. | 71 // in reverse. |
76 | 72 |
77 List<ClassElement> preOrder = <ClassElement>[]; | 73 List<ClassElement> preOrder = <ClassElement>[]; |
78 Set<ClassElement> seen = new Set<ClassElement>(); | 74 Set<ClassElement> seen = new Set<ClassElement>(); |
79 seen..add(compiler.objectClass) | 75 seen..add(compiler.objectClass) |
80 ..add(backend.jsInterceptorClass); | 76 ..add(backend.jsInterceptorClass); |
81 void walk(ClassElement element) { | 77 void walk(ClassElement element) { |
(...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 // used. We should also use an interceptor if the check can't be satisfied | 431 // used. We should also use an interceptor if the check can't be satisfied |
436 // by a native class in case we get a native instance that tries to spoof | 432 // by a native class in case we get a native instance that tries to spoof |
437 // the type info. i.e the criteria for whether or not to use an interceptor | 433 // the type info. i.e the criteria for whether or not to use an interceptor |
438 // is whether the receiver can be native, not the type of the test. | 434 // is whether the receiver can be native, not the type of the test. |
439 if (element == null || !element.isClass) return false; | 435 if (element == null || !element.isClass) return false; |
440 ClassElement cls = element; | 436 ClassElement cls = element; |
441 if (Elements.isNativeOrExtendsNative(cls)) return true; | 437 if (Elements.isNativeOrExtendsNative(cls)) return true; |
442 return isSupertypeOfNativeClass(element); | 438 return isSupertypeOfNativeClass(element); |
443 } | 439 } |
444 | 440 |
445 void assembleCode(CodeBuffer targetBuffer) { | 441 void assembleCode(CodeOutput targetOutput) { |
446 List<jsAst.Property> objectProperties = <jsAst.Property>[]; | 442 List<jsAst.Property> objectProperties = <jsAst.Property>[]; |
447 | 443 |
448 jsAst.Property addProperty(String name, jsAst.Expression value) { | 444 jsAst.Property addProperty(String name, jsAst.Expression value) { |
449 jsAst.Property prop = new jsAst.Property(js.string(name), value); | 445 jsAst.Property prop = new jsAst.Property(js.string(name), value); |
450 objectProperties.add(prop); | 446 objectProperties.add(prop); |
451 return prop; | 447 return prop; |
452 } | 448 } |
453 | 449 |
454 if (!nativeClasses.isEmpty) { | 450 if (!nativeClasses.isEmpty) { |
455 // If the native emitter has been asked to take care of the | 451 // If the native emitter has been asked to take care of the |
456 // noSuchMethod handlers, we do that now. | 452 // noSuchMethod handlers, we do that now. |
457 if (handleNoSuchMethod) { | 453 if (handleNoSuchMethod) { |
458 emitterTask.oldEmitter.nsmEmitter.emitNoSuchMethodHandlers(addProperty); | 454 emitterTask.oldEmitter.nsmEmitter.emitNoSuchMethodHandlers(addProperty); |
459 } | 455 } |
460 } | 456 } |
461 | 457 |
462 // If we have any properties to add to Object.prototype, we run | 458 // If we have any properties to add to Object.prototype, we run |
463 // through them and add them using defineProperty. | 459 // through them and add them using defineProperty. |
464 if (!objectProperties.isEmpty) { | 460 if (!objectProperties.isEmpty) { |
465 jsAst.Expression init = js(r''' | 461 jsAst.Expression init = js(r''' |
466 (function(table) { | 462 (function(table) { |
467 for(var key in table) | 463 for(var key in table) |
468 #(Object.prototype, key, table[key]); | 464 #(Object.prototype, key, table[key]); |
469 })(#)''', | 465 })(#)''', |
470 [ defPropFunction, | 466 [ defPropFunction, |
471 new jsAst.ObjectInitializer(objectProperties)]); | 467 new jsAst.ObjectInitializer(objectProperties)]); |
472 | 468 |
473 if (emitterTask.compiler.enableMinification) targetBuffer.write(';'); | 469 if (emitterTask.compiler.enableMinification) { |
474 targetBuffer.write(jsAst.prettyPrint( | 470 targetOutput.add(';'); |
| 471 } |
| 472 targetOutput.addBuffer(jsAst.prettyPrint( |
475 new jsAst.ExpressionStatement(init), compiler)); | 473 new jsAst.ExpressionStatement(init), compiler)); |
476 targetBuffer.write('\n'); | 474 targetOutput.add('\n'); |
477 } | 475 } |
478 | 476 |
479 targetBuffer.write(nativeBuffer); | 477 targetOutput.add('\n'); |
480 targetBuffer.write('\n'); | |
481 } | 478 } |
482 } | 479 } |
OLD | NEW |