Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(571)

Side by Side Diff: lib/compiler/implementation/js_backend/backend.dart

Issue 10854066: Start moving the JavaScript backend related code into a separate library (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add missing import Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 class InvocationInfo {
6 int parameterCount;
7 List<HType> providedTypes;
8 List<Element> compiledFunctions;
9
10 InvocationInfo(List<HType> types)
11 : parameterCount = types != null ? types.length : -1,
12 providedTypes = types,
13 compiledFunctions = new List<Element>();
14
15 addCompiledFunction(FunctionElement function) =>
16 compiledFunctions.add(function);
17
18 void clearTypeInformation() => providedTypes = null;
19 bool get hasTypeInformation() => providedTypes != null;
20
21 }
22
23 class JavaScriptBackend extends Backend {
24 SsaBuilderTask builder;
25 SsaOptimizerTask optimizer;
26 SsaCodeGeneratorTask generator;
27 CodeEmitterTask emitter;
28 final Map<Element, Map<Element, HType>> fieldInitializers;
29 final Map<Element, Map<Element, HType>> fieldConstructorSetters;
30 final Map<Element, Map<Element, HType>> fieldSettersType;
31
32 final Map<SourceString, Map<Selector, InvocationInfo>> invocationInfo;
33
34 List<CompilerTask> get tasks() {
35 return <CompilerTask>[builder, optimizer, generator, emitter];
36 }
37
38 JavaScriptBackend(Compiler compiler, bool generateSourceMap)
39 : emitter = new CodeEmitterTask(compiler, generateSourceMap),
40 fieldInitializers = new Map<Element, Map<Element, HType>>(),
41 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(),
42 fieldSettersType = new Map<Element, Map<Element, HType>>(),
43 invocationInfo = new Map<SourceString, Map<Selector, InvocationInfo>>(),
44 super(compiler) {
45 builder = new SsaBuilderTask(this);
46 optimizer = new SsaOptimizerTask(this);
47 generator = new SsaCodeGeneratorTask(this);
48 }
49
50 void enqueueHelpers(Enqueuer world) {
51 enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world);
52 enqueueAllTopLevelFunctions(compiler.interceptorsLibrary, world);
53 for (var helper in [const SourceString('Closure'),
54 const SourceString('ConstantMap'),
55 const SourceString('ConstantProtoMap')]) {
56 var e = compiler.findHelper(helper);
57 if (e !== null) world.registerInstantiatedClass(e);
58 }
59 }
60
61 CodeBuffer codegen(WorkItem work) {
62 HGraph graph = builder.build(work);
63 optimizer.optimize(work, graph);
64 if (work.allowSpeculativeOptimization
65 && optimizer.trySpeculativeOptimizations(work, graph)) {
66 CodeBuffer codeBuffer = generator.generateBailoutMethod(work, graph);
67 compiler.codegenWorld.addBailoutCode(work, codeBuffer);
68 optimizer.prepareForSpeculativeOptimizations(work, graph);
69 optimizer.optimize(work, graph);
70 }
71 return generator.generateMethod(work, graph);
72 }
73
74 void processNativeClasses(Enqueuer world,
75 Collection<LibraryElement> libraries) {
76 native.processNativeClasses(world, emitter, libraries);
77 }
78
79 void assembleProgram() {
80 emitter.assembleProgram();
81 }
82
83 void updateFieldInitializers(Element field, HType propagatedType) {
84 assert(field.isField());
85 assert(field.isMember());
86 Map<Element, HType> fields =
87 fieldInitializers.putIfAbsent(
88 field.getEnclosingClass(), () => new Map<Element, HType>());
89 if (!fields.containsKey(field)) {
90 fields[field] = propagatedType;
91 } else {
92 fields[field] = fields[field].union(propagatedType);
93 }
94 }
95
96 HType typeFromInitializersSoFar(Element field) {
97 assert(field.isField());
98 assert(field.isMember());
99 if (!fieldInitializers.containsKey(field.getEnclosingClass())) {
100 return HType.CONFLICTING;
101 }
102 Map<Element, HType> fields = fieldInitializers[field.getEnclosingClass()];
103 return fields[field];
104 }
105
106 void updateFieldConstructorSetters(Element field, HType type) {
107 assert(field.isField());
108 assert(field.isMember());
109 Map<Element, HType> fields =
110 fieldConstructorSetters.putIfAbsent(
111 field.getEnclosingClass(), () => new Map<Element, HType>());
112 if (!fields.containsKey(field)) {
113 fields[field] = type;
114 } else {
115 fields[field] = fields[field].union(type);
116 }
117 }
118
119 // Check if this field is set in the constructor body.
120 bool hasConstructorBodyFieldSetter(Element field) {
121 ClassElement enclosingClass = field.getEnclosingClass();
122 if (!fieldConstructorSetters.containsKey(enclosingClass)) {
123 return false;
124 }
125 return fieldConstructorSetters[enclosingClass][field] != null;
126 }
127
128 // Provide an optimistic estimate of the type of a field after construction.
129 // If the constructor body has setters for fields returns HType.UNKNOWN.
130 // This only takes the initializer lists and field assignments in the
131 // constructor body into account. The constructor body might have method calls
132 // that could alter the field.
133 HType optimisticFieldTypeAfterConstruction(Element field) {
134 assert(field.isField());
135 assert(field.isMember());
136
137 ClassElement classElement = field.getEnclosingClass();
138 if (hasConstructorBodyFieldSetter(field)) {
139 // If there are field setters but there is only constructor then the type
140 // of the field is determined by the assignments in the constructor
141 // body.
142 if (classElement.constructors.length == 1) {
143 return fieldConstructorSetters[classElement][field];
144 } else {
145 return HType.UNKNOWN;
146 }
147 } else if (fieldInitializers.containsKey(classElement)) {
148 HType type = fieldInitializers[classElement][field];
149 return type == null ? HType.CONFLICTING : type;
150 } else {
151 return HType.CONFLICTING;
152 }
153 }
154
155 void updateFieldSetters(Element field, HType type) {
156 assert(field.isField());
157 assert(field.isMember());
158 Map<Element, HType> fields =
159 fieldSettersType.putIfAbsent(
160 field.getEnclosingClass(), () => new Map<Element, HType>());
161 if (!fields.containsKey(field)) {
162 fields[field] = type;
163 } else {
164 fields[field] = fields[field].union(type);
165 }
166 }
167
168 // Returns the type that field setters are setting the field to based on what
169 // have been seen during compilation so far.
170 HType fieldSettersTypeSoFar(Element field) {
171 assert(field.isField());
172 assert(field.isMember());
173 ClassElement enclosingClass = field.getEnclosingClass();
174 if (!fieldSettersType.containsKey(enclosingClass)) {
175 return HType.CONFLICTING;
176 }
177 Map<Element, HType> fields = fieldSettersType[enclosingClass];
178 if (!fields.containsKey(field)) return HType.CONFLICTING;
179 return fields[field];
180 }
181
182 /**
183 * Register a dynamic invocation and collect the provided types for the
184 * named selector.
185 */
186 void registerDynamicInvocation(HInvokeDynamicMethod node, Selector selector) {
187 Map<Selector, InvocationInfo> invocationInfos =
188 invocationInfo.putIfAbsent(node.name,
189 () => new Map<Selector, InvocationInfo>());
190 InvocationInfo info = invocationInfos[selector];
191 if (info != null) {
192 // If we don't know anything useful about the types adding more
193 // information will not help.
194 if (!info.hasTypeInformation) return;
195
196 // Update the type information with the provided types.
197 bool typesChanged = false;
198 List<HType> types = info.providedTypes;
199 bool allUnknown = true;
200 for (int i = 0; i < types.length; i++) {
201 HType newType = types[i].union(node.inputs[i + 1].propagatedType);
202 if (newType != types[i]) {
203 typesChanged = true;
204 types[i] = newType;
205 }
206 if (types[i] != HType.UNKNOWN) allUnknown = false;
207 }
208 // If the provided types change we need to recompile all functions which
209 // have been compiled under the now invalidated assumptions.
210 if (typesChanged && info.compiledFunctions.length != 0) {
211 if (compiler.phase == Compiler.PHASE_COMPILING) {
212 info.compiledFunctions.forEach(
213 compiler.enqueuer.codegen.eagerRecompile);
214 info.compiledFunctions.clear();
215 }
216 }
217 // If all information is lost no need to keep it around.
218 if (allUnknown) info.clearTypeInformation();
219 } else {
220 // Gather the type information provided. If the types contains no useful
221 // information there is no need to actually store them.
222 bool allUnknown = true;
223 for (int i = 1; i < node.inputs.length; i++) {
224 if (node.inputs[i].propagatedType != HType.UNKNOWN) {
225 allUnknown = false;
226 break;
227 }
228 }
229 List<HType> types = null;
230 if (!allUnknown) {
231 types = new List<HType>(node.inputs.length - 1);
232 for (int i = 0; i < types.length; i++) {
233 types[i] = node.inputs[i + 1].propagatedType;
234 }
235 }
236 InvocationInfo info = new InvocationInfo(types);
237 invocationInfos[selector] = info;
238 }
239 }
240
241 /**
242 * Retreive the types of the parameters used for calling the [element]
243 * function. The types are optimistic in the sense as they are based on the
244 * possible invocations of the function seen so far. As compiling more
245 * code can invalidate this asumption the function is registered for being
246 * re-compiled if new possible invocations of this function invalidate these
247 * asumptions.
248 */
249 List<HType> optimisticParameterTypesWithRecompilationOnTypeChange(
250 FunctionElement element) {
251 Map<Selector, InvocationInfo> invocationInfos =
252 invocationInfo[element.name];
253 if (invocationInfos == null) return null;
254
255 int foundCount = 0;
256 InvocationInfo found = null;
257 invocationInfos.forEach((Selector selector, InvocationInfo info) {
258 if (selector.applies(element, compiler)) {
259 found = info;
260 foundCount++;
261 }
262 });
263
264 if (foundCount == 1 && found.hasTypeInformation) {
265 FunctionSignature signature = element.computeSignature(compiler);
266 if (signature.parameterCount == found.parameterCount) {
267 found.addCompiledFunction(element);
268 return found.providedTypes;
269 }
270 }
271 return null;
272 }
273 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/emitter.dart ('k') | lib/compiler/implementation/js_backend/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698