Chromium Code Reviews| 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( |
| 2069 emitStaticFunction(buffer, name, code); | 2008 bufferForElement(element, eagerBuffer), compiler, ',$n$n'); |
|
kasperl
2013/10/03 07:08:37
Nit: I'd compute the buffer and throw it in a loca
ahe
2013/10/03 07:20:17
I find code more readable when I can easily see th
| |
| 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(bufferForElement(element, eagerBuffer), compiler, ',$n$n'); | |
| 2097 } | 2021 } |
| 2098 } | 2022 } |
| 2099 | 2023 |
| 2100 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { | 2024 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer) { |
| 2101 ConstantHandler handler = compiler.constantHandler; | 2025 ConstantHandler handler = compiler.constantHandler; |
| 2102 Iterable<VariableElement> staticNonFinalFields = | 2026 Iterable<VariableElement> staticNonFinalFields = |
| 2103 handler.getStaticNonFinalFieldsForEmission(); | 2027 handler.getStaticNonFinalFieldsForEmission(); |
| 2104 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { | 2028 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) { |
| 2105 // [:interceptedNames:] is handled in [emitInterceptedNames]. | 2029 // [:interceptedNames:] is handled in [emitInterceptedNames]. |
| 2106 if (element == backend.interceptedNames) continue; | 2030 if (element == backend.interceptedNames) continue; |
| (...skipping 952 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3059 return addGlobalMetadata('"${name.slowToString()}"'); | 2983 return addGlobalMetadata('"${name.slowToString()}"'); |
| 3060 } | 2984 } |
| 3061 | 2985 |
| 3062 int addGlobalMetadata(String string) { | 2986 int addGlobalMetadata(String string) { |
| 3063 return globalMetadataMap.putIfAbsent(string, () { | 2987 return globalMetadataMap.putIfAbsent(string, () { |
| 3064 globalMetadata.add(string); | 2988 globalMetadata.add(string); |
| 3065 return globalMetadata.length - 1; | 2989 return globalMetadata.length - 1; |
| 3066 }); | 2990 }); |
| 3067 } | 2991 } |
| 3068 | 2992 |
| 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) { | 2993 void emitMetadata(CodeBuffer buffer) { |
| 3097 var literals = backend.typedefTypeLiterals.toList(); | 2994 var literals = backend.typedefTypeLiterals.toList(); |
| 3098 Elements.sortedByPosition(literals); | 2995 Elements.sortedByPosition(literals); |
| 3099 var properties = []; | 2996 var properties = []; |
| 3100 for (TypedefElement literal in literals) { | 2997 for (TypedefElement literal in literals) { |
| 3101 var key = namer.getNameX(literal); | 2998 var key = namer.getNameX(literal); |
| 3102 var value = js.toExpression(reifyType(literal.rawType)); | 2999 var value = js.toExpression(reifyType(literal.rawType)); |
| 3103 properties.add(new jsAst.Property(js.string(key), value)); | 3000 properties.add(new jsAst.Property(js.string(key), value)); |
| 3104 } | 3001 } |
| 3105 var map = new jsAst.ObjectInitializer(properties); | 3002 var map = new jsAst.ObjectInitializer(properties); |
| (...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3598 } | 3495 } |
| 3599 | 3496 |
| 3600 bool isDeferred(Element element) { | 3497 bool isDeferred(Element element) { |
| 3601 return compiler.deferredLoadTask.isDeferred(element); | 3498 return compiler.deferredLoadTask.isDeferred(element); |
| 3602 } | 3499 } |
| 3603 | 3500 |
| 3604 bool get areAnyElementsDeferred { | 3501 bool get areAnyElementsDeferred { |
| 3605 return compiler.deferredLoadTask.areAnyElementsDeferred; | 3502 return compiler.deferredLoadTask.areAnyElementsDeferred; |
| 3606 } | 3503 } |
| 3607 } | 3504 } |
| OLD | NEW |