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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
6 | 6 |
7 /** | 7 /** |
8 * Generates the code for all used classes in the program. Static fields (even | 8 * Generates the code for all used classes in the program. Static fields (even |
9 * in classes) are ignored, since they can be treated as non-class elements. | 9 * in classes) are ignored, since they can be treated as non-class elements. |
10 * | 10 * |
(...skipping 893 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
904 || compiler.codegenWorld.hasInvokedSetter(field, compiler)); | 904 || compiler.codegenWorld.hasInvokedSetter(field, compiler)); |
905 } | 905 } |
906 | 906 |
907 // We never access a field in a closure (a captured variable) without knowing | 907 // We never access a field in a closure (a captured variable) without knowing |
908 // that it is there. Therefore we don't need to use a getter (that will throw | 908 // that it is there. Therefore we don't need to use a getter (that will throw |
909 // if the getter method is missing), but can always access the field directly. | 909 // if the getter method is missing), but can always access the field directly. |
910 static bool fieldAccessNeverThrows(VariableElement field) { | 910 static bool fieldAccessNeverThrows(VariableElement field) { |
911 return field is ClosureFieldElement; | 911 return field is ClosureFieldElement; |
912 } | 912 } |
913 | 913 |
914 /** | |
915 * Documentation wanted -- johnniwinther | |
916 * | |
917 * Invariant: [member] must be a declaration element. | |
918 */ | |
919 void addInstanceMember(Element member, ClassBuilder builder) { | |
920 assert(invariant(member, member.isDeclaration)); | |
921 // TODO(floitsch): we don't need to deal with members of | |
922 // uninstantiated classes, that have been overwritten by subclasses. | |
923 | |
924 if (member.isFunction() | |
925 || member.isGenerativeConstructorBody() | |
926 || member.isAccessor()) { | |
927 if (member.isAbstract(compiler)) return; | |
928 jsAst.Expression code = backend.generatedCode[member]; | |
929 if (code == null) return; | |
930 String name = namer.getNameOfInstanceMember(member); | |
931 if (backend.isInterceptedMethod(member)) { | |
932 interceptorInvocationNames.add(name); | |
933 } | |
934 code = extendWithMetadata(member, code); | |
935 builder.addProperty(name, code); | |
936 String reflectionName = getReflectionName(member, name); | |
937 if (reflectionName != null) { | |
938 var reflectable = | |
939 js(backend.isAccessibleByReflection(member) ? '1' : '0'); | |
940 builder.addProperty('+$reflectionName', reflectable); | |
941 jsAst.Node defaultValues = reifyDefaultArguments(member); | |
942 if (defaultValues != null) { | |
943 String unmangledName = member.name.slowToString(); | |
944 builder.addProperty('*$unmangledName', defaultValues); | |
945 } | |
946 } | |
947 code = backend.generatedBailoutCode[member]; | |
948 if (code != null) { | |
949 builder.addProperty(namer.getBailoutName(member), code); | |
950 } | |
951 FunctionElement function = member; | |
952 FunctionSignature parameters = function.computeSignature(compiler); | |
953 if (!parameters.optionalParameters.isEmpty) { | |
954 containerBuilder.addParameterStubs(function, builder.addProperty); | |
955 } | |
956 } else if (!member.isField()) { | |
957 compiler.internalError('unexpected kind: "${member.kind}"', | |
958 element: member); | |
959 } | |
960 containerBuilder.emitExtraAccessors(member, builder); | |
961 } | |
962 | |
963 /// Returns the "reflection name" of an [Element] or [Selector]. | 914 /// Returns the "reflection name" of an [Element] or [Selector]. |
964 /// The reflection name of a getter 'foo' is 'foo'. | 915 /// The reflection name of a getter 'foo' is 'foo'. |
965 /// The reflection name of a setter 'foo' is 'foo='. | 916 /// The reflection name of a setter 'foo' is 'foo='. |
966 /// The reflection name of a method 'foo' is 'foo:N:M:O', where N is the | 917 /// The reflection name of a method 'foo' is 'foo:N:M:O', where N is the |
967 /// number of required arguments, M is the number of optional arguments, and | 918 /// number of required arguments, M is the number of optional arguments, and |
968 /// O is the named arguments. | 919 /// O is the named arguments. |
969 /// The reflection name of a constructor is similar to a regular method but | 920 /// The reflection name of a constructor is similar to a regular method but |
970 /// starts with 'new '. | 921 /// starts with 'new '. |
971 /// The reflection name of class 'C' is 'C'. | 922 /// The reflection name of class 'C' is 'C'. |
972 /// An anonymous mixin application has no reflection name. | 923 /// An anonymous mixin application has no reflection name. |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1075 * | 1026 * |
1076 * Invariant: [classElement] must be a declaration element. | 1027 * Invariant: [classElement] must be a declaration element. |
1077 */ | 1028 */ |
1078 void emitInstanceMembers(ClassElement classElement, | 1029 void emitInstanceMembers(ClassElement classElement, |
1079 ClassBuilder builder) { | 1030 ClassBuilder builder) { |
1080 assert(invariant(classElement, classElement.isDeclaration)); | 1031 assert(invariant(classElement, classElement.isDeclaration)); |
1081 | 1032 |
1082 void visitMember(ClassElement enclosing, Element member) { | 1033 void visitMember(ClassElement enclosing, Element member) { |
1083 assert(invariant(classElement, member.isDeclaration)); | 1034 assert(invariant(classElement, member.isDeclaration)); |
1084 if (member.isInstanceMember()) { | 1035 if (member.isInstanceMember()) { |
1085 addInstanceMember(member, builder); | 1036 containerBuilder.addMember(member, builder); |
1086 } | 1037 } |
1087 } | 1038 } |
1088 | 1039 |
1089 classElement.implementation.forEachMember( | 1040 classElement.implementation.forEachMember( |
1090 visitMember, | 1041 visitMember, |
1091 includeBackendMembers: true); | 1042 includeBackendMembers: true); |
1092 | 1043 |
1093 if (identical(classElement, compiler.objectClass) | 1044 if (identical(classElement, compiler.objectClass) |
1094 && compiler.enabledNoSuchMethod) { | 1045 && compiler.enabledNoSuchMethod) { |
1095 // Emit the noSuchMethod handlers on the Object prototype now, | 1046 // Emit the noSuchMethod handlers on the Object prototype now, |
(...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2031 if (needsDefineClass) { | 1982 if (needsDefineClass) { |
2032 buffer.write('$finishClassesName($classesCollector,' | 1983 buffer.write('$finishClassesName($classesCollector,' |
2033 '$_$isolateProperties,' | 1984 '$_$isolateProperties,' |
2034 '${_}null)$N'); | 1985 '${_}null)$N'); |
2035 | 1986 |
2036 // Reset the map. | 1987 // Reset the map. |
2037 buffer.write("$classesCollector$_=${_}null$N$n"); | 1988 buffer.write("$classesCollector$_=${_}null$N$n"); |
2038 } | 1989 } |
2039 } | 1990 } |
2040 | 1991 |
2041 void emitStaticFunction(CodeBuffer buffer, | |
2042 String name, | |
2043 jsAst.Expression functionExpression) { | |
2044 // TODO(ahe): This method (emitStaticFunction) should return a | |
2045 // jsAst.Expression. | |
2046 if (!buffer.isEmpty) { | |
2047 buffer.write(',$n$n'); | |
2048 } | |
2049 buffer.write('$name:$_'); | |
2050 buffer.write(jsAst.prettyPrint(functionExpression, compiler)); | |
2051 } | |
2052 | |
2053 void emitStaticFunctions(CodeBuffer eagerBuffer) { | 1992 void emitStaticFunctions(CodeBuffer eagerBuffer) { |
2054 bool isStaticFunction(Element element) => | 1993 bool isStaticFunction(Element element) => |
2055 !element.isInstanceMember() && !element.isField(); | 1994 !element.isInstanceMember() && !element.isField(); |
2056 | 1995 |
2057 Iterable<Element> elements = | 1996 Iterable<Element> elements = |
2058 backend.generatedCode.keys.where(isStaticFunction); | 1997 backend.generatedCode.keys.where(isStaticFunction); |
2059 Set<Element> pendingElementsWithBailouts = | 1998 Set<Element> pendingElementsWithBailouts = |
2060 backend.generatedBailoutCode.keys | 1999 backend.generatedBailoutCode.keys |
2061 .where(isStaticFunction) | 2000 .where(isStaticFunction) |
2062 .toSet(); | 2001 .toSet(); |
2063 | 2002 |
2064 for (Element element in Elements.sortedByPosition(elements)) { | 2003 for (Element element in Elements.sortedByPosition(elements)) { |
2065 CodeBuffer buffer = bufferForElement(element, eagerBuffer); | 2004 pendingElementsWithBailouts.remove(element); |
2066 jsAst.Expression code = backend.generatedCode[element]; | 2005 ClassBuilder builder = new ClassBuilder(); |
2067 String name = namer.getNameOfGlobalFunction(element); | 2006 containerBuilder.addMember(element, builder); |
2068 code = extendWithMetadata(element, code); | 2007 builder.writeOn_DO_NOT_USE( |
2069 emitStaticFunction(buffer, name, code); | 2008 bufferForElement(element, eagerBuffer), compiler, ',$n$n'); |
2070 String reflectionName = getReflectionName(element, name); | |
2071 if (reflectionName != null) { | |
2072 var reflectable = backend.isAccessibleByReflection(element) ? 1 : 0; | |
2073 buffer.write(',$n$n"+$reflectionName":${_}$reflectable'); | |
2074 jsAst.Node defaultValues = reifyDefaultArguments(element); | |
2075 if (defaultValues != null) { | |
2076 String unmangledName = element.name.slowToString(); | |
2077 buffer.write(',$n$n"*$unmangledName":${_}'); | |
2078 buffer.write(jsAst.prettyPrint(defaultValues, compiler)); | |
2079 } | |
2080 } | |
2081 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; | |
2082 if (bailoutCode != null) { | |
2083 pendingElementsWithBailouts.remove(element); | |
2084 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | |
2085 } | |
2086 } | 2009 } |
2087 | 2010 |
2088 if (!pendingElementsWithBailouts.isEmpty) { | 2011 if (!pendingElementsWithBailouts.isEmpty) { |
2089 addComment('pendingElementsWithBailouts', eagerBuffer); | 2012 addComment('pendingElementsWithBailouts', eagerBuffer); |
2090 } | 2013 } |
2091 // Is it possible the primary function was inlined but the bailout was not? | 2014 // Is it possible the primary function was inlined but the bailout was not? |
2092 for (Element element in | 2015 for (Element element in |
2093 Elements.sortedByPosition(pendingElementsWithBailouts)) { | 2016 Elements.sortedByPosition(pendingElementsWithBailouts)) { |
2094 CodeBuffer buffer = bufferForElement(element, eagerBuffer); | |
2095 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; | 2017 jsAst.Expression bailoutCode = backend.generatedBailoutCode[element]; |
2096 emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode); | 2018 new ClassBuilder() |
| 2019 ..addProperty(namer.getBailoutName(element), bailoutCode) |
| 2020 ..writeOn_DO_NOT_USE( |
| 2021 bufferForElement(element, eagerBuffer), compiler, ',$n$n'); |
2097 } | 2022 } |
2098 } | 2023 } |
2099 | 2024 |
2100 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { | 2025 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { |
2101 ConstantHandler handler = compiler.constantHandler; | 2026 ConstantHandler handler = compiler.constantHandler; |
2102 Iterable<VariableElement> staticNonFinalFields = | 2027 Iterable<VariableElement> staticNonFinalFields = |
2103 handler.getStaticNonFinalFieldsForEmission(); | 2028 handler.getStaticNonFinalFieldsForEmission(); |
2104 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { | 2029 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
2105 // [:interceptedNames:] is handled in [emitInterceptedNames]. | 2030 // [:interceptedNames:] is handled in [emitInterceptedNames]. |
2106 if (element == backend.interceptedNames) continue; | 2031 if (element == backend.interceptedNames) continue; |
(...skipping 952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3059 return addGlobalMetadata('"${name.slowToString()}"'); | 2984 return addGlobalMetadata('"${name.slowToString()}"'); |
3060 } | 2985 } |
3061 | 2986 |
3062 int addGlobalMetadata(String string) { | 2987 int addGlobalMetadata(String string) { |
3063 return globalMetadataMap.putIfAbsent(string, () { | 2988 return globalMetadataMap.putIfAbsent(string, () { |
3064 globalMetadata.add(string); | 2989 globalMetadata.add(string); |
3065 return globalMetadata.length - 1; | 2990 return globalMetadata.length - 1; |
3066 }); | 2991 }); |
3067 } | 2992 } |
3068 | 2993 |
3069 jsAst.Fun extendWithMetadata(FunctionElement element, jsAst.Fun code) { | |
3070 if (!backend.retainMetadataOf(element)) return code; | |
3071 return compiler.withCurrentElement(element, () { | |
3072 List<int> metadata = <int>[]; | |
3073 FunctionSignature signature = element.functionSignature; | |
3074 if (element.isConstructor()) { | |
3075 metadata.add(reifyType(element.getEnclosingClass().thisType)); | |
3076 } else { | |
3077 metadata.add(reifyType(signature.returnType)); | |
3078 } | |
3079 signature.forEachParameter((Element parameter) { | |
3080 metadata | |
3081 ..add(reifyName(parameter.name)) | |
3082 ..add(reifyType(parameter.computeType(compiler))); | |
3083 }); | |
3084 Link link = element.metadata; | |
3085 // TODO(ahe): Why is metadata sometimes null? | |
3086 if (link != null) { | |
3087 for (; !link.isEmpty; link = link.tail) { | |
3088 metadata.add(reifyMetadata(link.head)); | |
3089 } | |
3090 } | |
3091 code.body.statements.add(js.string(metadata.join(',')).toStatement()); | |
3092 return code; | |
3093 }); | |
3094 } | |
3095 | |
3096 void emitMetadata(CodeBuffer buffer) { | 2994 void emitMetadata(CodeBuffer buffer) { |
3097 var literals = backend.typedefTypeLiterals.toList(); | 2995 var literals = backend.typedefTypeLiterals.toList(); |
3098 Elements.sortedByPosition(literals); | 2996 Elements.sortedByPosition(literals); |
3099 var properties = []; | 2997 var properties = []; |
3100 for (TypedefElement literal in literals) { | 2998 for (TypedefElement literal in literals) { |
3101 var key = namer.getNameX(literal); | 2999 var key = namer.getNameX(literal); |
3102 var value = js.toExpression(reifyType(literal.rawType)); | 3000 var value = js.toExpression(reifyType(literal.rawType)); |
3103 properties.add(new jsAst.Property(js.string(key), value)); | 3001 properties.add(new jsAst.Property(js.string(key), value)); |
3104 } | 3002 } |
3105 var map = new jsAst.ObjectInitializer(properties); | 3003 var map = new jsAst.ObjectInitializer(properties); |
(...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3598 } | 3496 } |
3599 | 3497 |
3600 bool isDeferred(Element element) { | 3498 bool isDeferred(Element element) { |
3601 return compiler.deferredLoadTask.isDeferred(element); | 3499 return compiler.deferredLoadTask.isDeferred(element); |
3602 } | 3500 } |
3603 | 3501 |
3604 bool get areAnyElementsDeferred { | 3502 bool get areAnyElementsDeferred { |
3605 return compiler.deferredLoadTask.areAnyElementsDeferred; | 3503 return compiler.deferredLoadTask.areAnyElementsDeferred; |
3606 } | 3504 } |
3607 } | 3505 } |
OLD | NEW |