| 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 /** | 7 /** |
| 8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
| 9 * from the given element. | 9 * from the given element. |
| 10 */ | 10 */ |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 */ | 52 */ |
| 53 final Map<int, String> boundClosureCache; | 53 final Map<int, String> boundClosureCache; |
| 54 | 54 |
| 55 /** | 55 /** |
| 56 * A cache of closures that are used to closurize instance methods | 56 * A cache of closures that are used to closurize instance methods |
| 57 * of interceptors. These closures are dynamically bound to the | 57 * of interceptors. These closures are dynamically bound to the |
| 58 * interceptor instance, and the actual receiver of the method. | 58 * interceptor instance, and the actual receiver of the method. |
| 59 */ | 59 */ |
| 60 final Map<int, String> interceptorClosureCache; | 60 final Map<int, String> interceptorClosureCache; |
| 61 Set<ClassElement> checkedClasses; | 61 Set<ClassElement> checkedClasses; |
| 62 Set<TypedefElement> checkedTypedefs; |
| 62 | 63 |
| 63 final bool generateSourceMap; | 64 final bool generateSourceMap; |
| 64 | 65 |
| 65 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) | 66 CodeEmitterTask(Compiler compiler, Namer namer, this.generateSourceMap) |
| 66 : boundClosureBuffer = new CodeBuffer(), | 67 : boundClosureBuffer = new CodeBuffer(), |
| 67 mainBuffer = new CodeBuffer(), | 68 mainBuffer = new CodeBuffer(), |
| 68 this.namer = namer, | 69 this.namer = namer, |
| 69 boundClosureCache = new Map<int, String>(), | 70 boundClosureCache = new Map<int, String>(), |
| 70 interceptorClosureCache = new Map<int, String>(), | 71 interceptorClosureCache = new Map<int, String>(), |
| 71 constantEmitter = new ConstantEmitter(compiler, namer), | 72 constantEmitter = new ConstantEmitter(compiler, namer), |
| 72 super(compiler) { | 73 super(compiler) { |
| 73 nativeEmitter = new NativeEmitter(this); | 74 nativeEmitter = new NativeEmitter(this); |
| 74 } | 75 } |
| 75 | 76 |
| 76 void computeRequiredTypeChecks() { | 77 void computeRequiredTypeChecks() { |
| 77 assert(checkedClasses == null); | 78 assert(checkedClasses == null); |
| 78 checkedClasses = new Set<ClassElement>(); | 79 checkedClasses = new Set<ClassElement>(); |
| 80 checkedTypedefs = new Set<TypedefElement>(); |
| 79 compiler.codegenWorld.isChecks.forEach((DartType t) { | 81 compiler.codegenWorld.isChecks.forEach((DartType t) { |
| 80 if (t is InterfaceType) checkedClasses.add(t.element); | 82 if (t is InterfaceType) { |
| 83 checkedClasses.add(t.element); |
| 84 } else if (t is TypedefType) { |
| 85 checkedTypedefs.add(t.element); |
| 86 } |
| 81 }); | 87 }); |
| 82 } | 88 } |
| 83 | 89 |
| 84 js.Expression constantReference(Constant value) { | 90 js.Expression constantReference(Constant value) { |
| 85 return constantEmitter.reference(value); | 91 return constantEmitter.reference(value); |
| 86 } | 92 } |
| 87 | 93 |
| 88 js.Expression constantInitializerExpression(Constant value) { | 94 js.Expression constantInitializerExpression(Constant value) { |
| 89 return constantEmitter.initializationExpression(value); | 95 return constantEmitter.initializationExpression(value); |
| 90 } | 96 } |
| (...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 715 | 721 |
| 716 classElement.implementation.forEachMember( | 722 classElement.implementation.forEachMember( |
| 717 (ClassElement enclosing, Element member) { | 723 (ClassElement enclosing, Element member) { |
| 718 assert(invariant(classElement, member.isDeclaration)); | 724 assert(invariant(classElement, member.isDeclaration)); |
| 719 if (member.isInstanceMember()) { | 725 if (member.isInstanceMember()) { |
| 720 addInstanceMember(member, defineInstanceMember); | 726 addInstanceMember(member, defineInstanceMember); |
| 721 } | 727 } |
| 722 }, | 728 }, |
| 723 includeBackendMembers: true); | 729 includeBackendMembers: true); |
| 724 | 730 |
| 725 generateIsTestsOn(classElement, (ClassElement other) { | 731 generateIsTestsOn(classElement, (Element other) { |
| 726 String code; | 732 String code; |
| 727 if (other.isObject(compiler)) return; | 733 if (compiler.objectClass == other) return; |
| 728 if (nativeEmitter.requiresNativeIsCheck(other)) { | 734 if (nativeEmitter.requiresNativeIsCheck(other)) { |
| 729 code = 'function() { return true; }'; | 735 code = 'function() { return true; }'; |
| 730 } else { | 736 } else { |
| 731 code = 'true'; | 737 code = 'true'; |
| 732 } | 738 } |
| 733 CodeBuffer typeTestBuffer = new CodeBuffer(); | 739 CodeBuffer typeTestBuffer = new CodeBuffer(); |
| 734 typeTestBuffer.add(code); | 740 typeTestBuffer.add(code); |
| 735 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); | 741 defineInstanceMember(namer.operatorIs(other), typeTestBuffer); |
| 736 }); | 742 }); |
| 737 | 743 |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1016 defineInstanceMember(name, code); | 1022 defineInstanceMember(name, code); |
| 1017 } | 1023 } |
| 1018 } | 1024 } |
| 1019 | 1025 |
| 1020 /** | 1026 /** |
| 1021 * Generate "is tests" for [cls]: itself, and the "is tests" for the | 1027 * Generate "is tests" for [cls]: itself, and the "is tests" for the |
| 1022 * classes it implements. We don't need to add the "is tests" of the | 1028 * classes it implements. We don't need to add the "is tests" of the |
| 1023 * super class because they will be inherited at runtime. | 1029 * super class because they will be inherited at runtime. |
| 1024 */ | 1030 */ |
| 1025 void generateIsTestsOn(ClassElement cls, | 1031 void generateIsTestsOn(ClassElement cls, |
| 1026 void emitIsTest(ClassElement element)) { | 1032 void emitIsTest(Element element)) { |
| 1027 if (checkedClasses.contains(cls)) { | 1033 if (checkedClasses.contains(cls)) { |
| 1028 emitIsTest(cls); | 1034 emitIsTest(cls); |
| 1029 } | 1035 } |
| 1036 |
| 1030 Set<Element> generated = new Set<Element>(); | 1037 Set<Element> generated = new Set<Element>(); |
| 1031 // A class that defines a [:call:] method implicitly implements | 1038 // A class that defines a [:call:] method implicitly implements |
| 1032 // [Function]. | 1039 // [Function] and needs checks for all typedefs that are used in is-checks. |
| 1033 if (checkedClasses.contains(compiler.functionClass) | 1040 if (checkedClasses.contains(compiler.functionClass) || |
| 1034 && cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME) != null) { | 1041 !checkedTypedefs.isEmpty) { |
| 1035 generateInterfacesIsTests(compiler.functionClass, emitIsTest, generated); | 1042 FunctionElement call = cls.lookupLocalMember(Compiler.CALL_OPERATOR_NAME); |
| 1043 if (call != null) { |
| 1044 generateInterfacesIsTests(compiler.functionClass, |
| 1045 emitIsTest, |
| 1046 generated); |
| 1047 FunctionType callType = call.computeType(compiler); |
| 1048 for (TypedefElement typedef in checkedTypedefs) { |
| 1049 FunctionType typedefType = |
| 1050 typedef.computeType(compiler).unalias(compiler); |
| 1051 if (compiler.types.isSubtype(callType, typedefType)) { |
| 1052 emitIsTest(typedef); |
| 1053 } |
| 1054 } |
| 1055 } |
| 1036 } | 1056 } |
| 1037 for (DartType interfaceType in cls.interfaces) { | 1057 for (DartType interfaceType in cls.interfaces) { |
| 1038 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); | 1058 generateInterfacesIsTests(interfaceType.element, emitIsTest, generated); |
| 1039 } | 1059 } |
| 1040 } | 1060 } |
| 1041 | 1061 |
| 1042 /** | 1062 /** |
| 1043 * Generate "is tests" where [cls] is being implemented. | 1063 * Generate "is tests" where [cls] is being implemented. |
| 1044 */ | 1064 */ |
| 1045 void generateInterfacesIsTests(ClassElement cls, | 1065 void generateInterfacesIsTests(ClassElement cls, |
| (...skipping 915 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1961 const String HOOKS_API_USAGE = """ | 1981 const String HOOKS_API_USAGE = """ |
| 1962 // Generated by dart2js, the Dart to JavaScript compiler. | 1982 // Generated by dart2js, the Dart to JavaScript compiler. |
| 1963 // The code supports the following hooks: | 1983 // The code supports the following hooks: |
| 1964 // dartPrint(message) - if this function is defined it is called | 1984 // dartPrint(message) - if this function is defined it is called |
| 1965 // instead of the Dart [print] method. | 1985 // instead of the Dart [print] method. |
| 1966 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1986 // dartMainRunner(main) - if this function is defined, the Dart [main] |
| 1967 // method will not be invoked directly. | 1987 // method will not be invoked directly. |
| 1968 // Instead, a closure that will invoke [main] is | 1988 // Instead, a closure that will invoke [main] is |
| 1969 // passed to [dartMainRunner]. | 1989 // passed to [dartMainRunner]. |
| 1970 """; | 1990 """; |
| OLD | NEW |