OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 part of dart2js.js_emitter; | |
6 | |
7 /// This class should morph into something that makes it easy to build | |
8 /// JavaScript representations of libraries, class-sides, and instance-sides. | |
9 /// Initially, it is just a placeholder for code that is moved from | |
10 /// [CodeEmitterTask]. | |
11 class ContainerBuilder extends CodeEmitterHelper { | |
12 | |
13 void addMemberMethod(DartMethod method, ClassBuilder builder) { | |
14 MethodElement member = method.element; | |
15 jsAst.Name name = method.name; | |
16 FunctionSignature parameters = member.functionSignature; | |
17 jsAst.Expression code = method.code; | |
18 bool needsStubs = method.parameterStubs.isNotEmpty; | |
19 bool canBeApplied = method.canBeApplied; | |
20 bool canBeReflected = method.canBeReflected; | |
21 bool canTearOff = method.needsTearOff; | |
22 jsAst.Name tearOffName = method.tearOffName; | |
23 bool isClosure = method is InstanceMethod && method.isClosure; | |
24 jsAst.Name superAlias = method is InstanceMethod ? method.aliasName : null; | |
25 bool hasSuperAlias = superAlias != null; | |
26 jsAst.Expression memberTypeExpression = method.functionType; | |
27 | |
28 bool needStructuredInfo = | |
29 canTearOff || canBeReflected || canBeApplied || hasSuperAlias; | |
30 | |
31 emitter.interceptorEmitter.recordMangledNameOfMemberMethod(member, name); | |
32 | |
33 if (!needStructuredInfo) { | |
34 compiler.dumpInfoTask.registerElementAst(member, | |
35 builder.addProperty(name, code)); | |
36 | |
37 for (ParameterStubMethod stub in method.parameterStubs) { | |
38 assert(stub.callName == null); | |
39 jsAst.Property property = builder.addProperty(stub.name, stub.code); | |
40 compiler.dumpInfoTask.registerElementAst(member, property); | |
41 emitter.interceptorEmitter | |
42 .recordMangledNameOfMemberMethod(member, stub.name); | |
43 } | |
44 return; | |
45 } | |
46 emitter.needsStructuredMemberInfo = true; | |
47 | |
48 // This element is needed for reflection or needs additional stubs or has a | |
49 // super alias. So we need to retain additional information. | |
50 | |
51 // The information is stored in an array with this format: | |
52 // | |
53 // 1. The alias name for this function (optional). | |
54 // 2. The JS function for this member. | |
55 // 3. First stub. | |
56 // 4. Name of first stub. | |
57 // ... | |
58 // M. Call name of this member. | |
59 // M+1. Call name of first stub. | |
60 // ... | |
61 // N. Getter name for tearOff. | |
62 // N+1. (Required parameter count << 1) + (member.isAccessor ? 1 : 0). | |
63 // N+2. (Optional parameter count << 1) + | |
64 // (parameters.optionalParametersAreNamed ? 1 : 0). | |
65 // N+3. Index to function type in constant pool. | |
66 // N+4. First default argument. | |
67 // ... | |
68 // O. First parameter name (if needed for reflection or Function.apply). | |
69 // ... | |
70 // P. Unmangled name (if reflectable). | |
71 // P+1. First metadata (if reflectable). | |
72 // ... | |
73 // TODO(ahe): Consider one of the parameter counts can be replaced by the | |
74 // length property of the JavaScript function object. | |
75 | |
76 List<jsAst.Expression> expressions = <jsAst.Expression>[]; | |
77 | |
78 // Create the optional aliasing entry if this method is called via super. | |
79 if (hasSuperAlias) { | |
80 expressions.add(js.quoteName(superAlias)); | |
81 } | |
82 | |
83 expressions.add(code); | |
84 | |
85 bool onlyNeedsSuperAlias = | |
86 !(canTearOff || canBeReflected || canBeApplied || needsStubs); | |
87 | |
88 if (onlyNeedsSuperAlias) { | |
89 jsAst.ArrayInitializer arrayInit = | |
90 new jsAst.ArrayInitializer(expressions); | |
91 compiler.dumpInfoTask.registerElementAst(member, | |
92 builder.addProperty(name, arrayInit)); | |
93 return; | |
94 } | |
95 | |
96 jsAst.Literal callSelectorString; | |
97 if (method.callName == null) { | |
98 callSelectorString = new jsAst.LiteralNull(); | |
99 } else { | |
100 callSelectorString = js.quoteName(method.callName); | |
101 } | |
102 | |
103 // On [requiredParameterCount], the lower bit is set if this method can be | |
104 // called reflectively. | |
105 int requiredParameterCount = parameters.requiredParameterCount << 1; | |
106 if (member.isAccessor) requiredParameterCount++; | |
107 | |
108 int optionalParameterCount = parameters.optionalParameterCount << 1; | |
109 if (parameters.optionalParametersAreNamed) optionalParameterCount++; | |
110 | |
111 List tearOffInfo = [callSelectorString]; | |
112 | |
113 for (ParameterStubMethod stub in method.parameterStubs) { | |
114 jsAst.Name invocationName = stub.name; | |
115 emitter.interceptorEmitter | |
116 .recordMangledNameOfMemberMethod(member, invocationName); | |
117 | |
118 expressions.add(stub.code); | |
119 if (member.isInstanceMember) { | |
120 expressions.add(js.quoteName(invocationName)); | |
121 } | |
122 jsAst.Name callName = stub.callName; | |
123 jsAst.Literal callSelectorString = | |
124 (callName == null) ? new jsAst.LiteralNull() : js.quoteName(callName); | |
125 tearOffInfo.add(callSelectorString); | |
126 } | |
127 | |
128 expressions | |
129 ..addAll(tearOffInfo) | |
130 ..add((tearOffName == null || member.isAccessor) | |
131 ? js("null") : js.quoteName(tearOffName)) | |
132 ..add(js.number(requiredParameterCount)) | |
133 ..add(js.number(optionalParameterCount)) | |
134 ..add(memberTypeExpression == null ? js("null") : memberTypeExpression) | |
135 ..addAll(task.metadataCollector.reifyDefaultArguments(member)); | |
136 | |
137 if (canBeReflected || canBeApplied) { | |
138 parameters.forEachParameter((Element parameter) { | |
139 expressions.add(task.metadataCollector.reifyName(parameter.name)); | |
140 if (backend.mustRetainMetadata) { | |
141 Iterable<jsAst.Expression> metadataIndices = | |
142 parameter.metadata.map((MetadataAnnotation annotation) { | |
143 ConstantValue constant = | |
144 backend.constants.getConstantValueForMetadata(annotation); | |
145 backend.constants.addCompileTimeConstantForEmission(constant); | |
146 return task.metadataCollector.reifyMetadata(annotation); | |
147 }); | |
148 expressions.add(new jsAst.ArrayInitializer(metadataIndices.toList())); | |
149 } | |
150 }); | |
151 } | |
152 if (canBeReflected) { | |
153 jsAst.LiteralString reflectionName; | |
154 if (member.isConstructor) { | |
155 // TODO(herhut): This registers name as a mangled name. Do we need this | |
156 // given that we use a different name below? | |
157 emitter.getReflectionName(member, name); | |
158 reflectionName = | |
159 new jsAst.LiteralString( | |
160 '"new ${Elements.reconstructConstructorName(member)}"'); | |
161 } else { | |
162 reflectionName = | |
163 js.string(namer.privateName(member.memberName)); | |
164 } | |
165 expressions | |
166 ..add(reflectionName) | |
167 ..addAll(task.metadataCollector.computeMetadata(member)); | |
168 } else if (isClosure && canBeApplied) { | |
169 expressions.add(js.string(namer.privateName(member.memberName))); | |
170 } | |
171 | |
172 jsAst.ArrayInitializer arrayInit = | |
173 new jsAst.ArrayInitializer(expressions.toList()); | |
174 compiler.dumpInfoTask.registerElementAst(member, | |
175 builder.addProperty(name, arrayInit)); | |
176 } | |
177 | |
178 void addMemberField(Field field, ClassBuilder builder) { | |
179 // For now, do nothing. | |
180 } | |
181 } | |
OLD | NEW |