| 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 |