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

Side by Side Diff: pkg/compiler/lib/src/js_emitter/code_emitter_task.dart

Issue 1227643003: dart2js: Move most of the code_emitter_task code into the program-builder. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Upload Created 5 years, 5 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
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 const USE_LAZY_EMITTER = const bool.fromEnvironment("dart2js.use.lazy.emitter"); 7 const USE_LAZY_EMITTER = const bool.fromEnvironment("dart2js.use.lazy.emitter");
8 8
9 /** 9 /**
10 * Generates the code for all used classes in the program. Static fields (even 10 * Generates the code for all used classes in the program. Static fields (even
11 * in classes) are ignored, since they can be treated as non-class elements. 11 * in classes) are ignored, since they can be treated as non-class elements.
12 * 12 *
13 * The code for the containing (used) methods must exist in the `universe`. 13 * The code for the containing (used) methods must exist in the `universe`.
14 */ 14 */
15 class CodeEmitterTask extends CompilerTask { 15 class CodeEmitterTask extends CompilerTask {
16 // TODO(floitsch): the code-emitter task should not need a namer. 16 // TODO(floitsch): the code-emitter task should not need a namer.
17 final Namer namer; 17 final Namer namer;
18 final TypeTestRegistry typeTestRegistry; 18 final TypeTestRegistry typeTestRegistry;
19 NativeEmitter nativeEmitter; 19 NativeEmitter nativeEmitter;
20 MetadataCollector metadataCollector; 20 MetadataCollector metadataCollector;
21 OldEmitter oldEmitter; 21 OldEmitter oldEmitter;
22 Emitter emitter; 22 Emitter emitter;
23 23
24 final Set<ClassElement> neededClasses = new Set<ClassElement>();
25 Set<ClassElement> classesOnlyNeededForRti;
26 final Map<OutputUnit, List<ClassElement>> outputClassLists =
27 new Map<OutputUnit, List<ClassElement>>();
28 final Map<OutputUnit, List<ConstantValue>> outputConstantLists =
29 new Map<OutputUnit, List<ConstantValue>>();
30 final Map<OutputUnit, List<Element>> outputStaticLists =
31 new Map<OutputUnit, List<Element>>();
32 final Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists =
33 new Map<OutputUnit, List<VariableElement>>();
34 final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists =
35 new Map<OutputUnit, Set<LibraryElement>>();
36
37 /// True, if the output contains a constant list.
38 ///
39 /// This flag is updated in [computeNeededConstants].
40 bool outputContainsConstantList = false;
41
42 final List<ClassElement> nativeClassesAndSubclasses = <ClassElement>[];
43
44 /// Records if a type variable is read dynamically for type tests. 24 /// Records if a type variable is read dynamically for type tests.
45 final Set<TypeVariableElement> readTypeVariables = 25 final Set<TypeVariableElement> readTypeVariables =
46 new Set<TypeVariableElement>(); 26 new Set<TypeVariableElement>();
47 27
48 List<TypedefElement> typedefsNeededForReflection; 28 JavaScriptBackend get backend => compiler.backend;
49 29
50 JavaScriptBackend get backend => compiler.backend; 30 @deprecated
31 // This field should be removed. It's currently only needed for dump-info and
32 // tests.
33 // The field is set after the program has been emitted.
34 /// Contains a list of all classes that are emitted.
35 Set<ClassElement> neededClasses;
51 36
52 CodeEmitterTask(Compiler compiler, Namer namer, bool generateSourceMap) 37 CodeEmitterTask(Compiler compiler, Namer namer, bool generateSourceMap)
53 : super(compiler), 38 : super(compiler),
54 this.namer = namer, 39 this.namer = namer,
55 this.typeTestRegistry = new TypeTestRegistry(compiler) { 40 this.typeTestRegistry = new TypeTestRegistry(compiler) {
56 nativeEmitter = new NativeEmitter(this); 41 nativeEmitter = new NativeEmitter(this);
57 oldEmitter = new OldEmitter(compiler, namer, generateSourceMap, this); 42 oldEmitter = new OldEmitter(compiler, namer, generateSourceMap, this);
58 emitter = USE_LAZY_EMITTER 43 emitter = USE_LAZY_EMITTER
59 ? new lazy_js_emitter.Emitter(compiler, namer, nativeEmitter) 44 ? new lazy_js_emitter.Emitter(compiler, namer, nativeEmitter)
60 : oldEmitter; 45 : oldEmitter;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 112
128 /// Returns the JS template for the given [builtin]. 113 /// Returns the JS template for the given [builtin].
129 jsAst.Template builtinTemplateFor(JsBuiltin builtin) { 114 jsAst.Template builtinTemplateFor(JsBuiltin builtin) {
130 return emitter.templateForBuiltin(builtin); 115 return emitter.templateForBuiltin(builtin);
131 } 116 }
132 117
133 void registerReadTypeVariable(TypeVariableElement element) { 118 void registerReadTypeVariable(TypeVariableElement element) {
134 readTypeVariables.add(element); 119 readTypeVariables.add(element);
135 } 120 }
136 121
137 Set<ClassElement> computeInterceptorsReferencedFromConstants() { 122 Set<ClassElement> _finalizeRti() {
138 Set<ClassElement> classes = new Set<ClassElement>();
139 JavaScriptConstantCompiler handler = backend.constants;
140 List<ConstantValue> constants = handler.getConstantsForEmission();
141 for (ConstantValue constant in constants) {
142 if (constant is InterceptorConstantValue) {
143 InterceptorConstantValue interceptorConstant = constant;
144 classes.add(interceptorConstant.dispatchedType.element);
145 }
146 }
147 return classes;
148 }
149
150 /**
151 * Return a function that returns true if its argument is a class
152 * that needs to be emitted.
153 */
154 Function computeClassFilter() {
155 if (backend.isTreeShakingDisabled) return (ClassElement cls) => true;
156
157 Set<ClassElement> unneededClasses = new Set<ClassElement>();
158 // The [Bool] class is not marked as abstract, but has a factory
159 // constructor that always throws. We never need to emit it.
160 unneededClasses.add(compiler.boolClass);
161
162 // Go over specialized interceptors and then constants to know which
163 // interceptors are needed.
164 Set<ClassElement> needed = new Set<ClassElement>();
165 backend.specializedGetInterceptors.forEach(
166 (_, Iterable<ClassElement> elements) {
167 needed.addAll(elements);
168 }
169 );
170
171 // Add interceptors referenced by constants.
172 needed.addAll(computeInterceptorsReferencedFromConstants());
173
174 // Add unneeded interceptors to the [unneededClasses] set.
175 for (ClassElement interceptor in backend.interceptedClasses) {
176 if (!needed.contains(interceptor)
177 && interceptor != compiler.objectClass) {
178 unneededClasses.add(interceptor);
179 }
180 }
181
182 // These classes are just helpers for the backend's type system.
183 unneededClasses.add(backend.jsMutableArrayClass);
184 unneededClasses.add(backend.jsFixedArrayClass);
185 unneededClasses.add(backend.jsExtendableArrayClass);
186 unneededClasses.add(backend.jsUInt32Class);
187 unneededClasses.add(backend.jsUInt31Class);
188 unneededClasses.add(backend.jsPositiveIntClass);
189
190 return (ClassElement cls) => !unneededClasses.contains(cls);
191 }
192
193 /**
194 * Compute all the constants that must be emitted.
195 */
196 void computeNeededConstants() {
197 // Make sure we retain all metadata of all elements. This could add new
198 // constants to the handler.
199 if (backend.mustRetainMetadata) {
200 // TODO(floitsch): verify that we don't run through the same elements
201 // multiple times.
202 for (Element element in backend.generatedCode.keys) {
203 if (backend.isAccessibleByReflection(element)) {
204 bool shouldRetainMetadata = backend.retainMetadataOf(element);
205 if (shouldRetainMetadata &&
206 (element.isFunction || element.isConstructor ||
207 element.isSetter)) {
208 FunctionElement function = element;
209 function.functionSignature.forEachParameter(
210 backend.retainMetadataOf);
211 }
212 }
213 }
214 for (ClassElement cls in neededClasses) {
215 final onlyForRti = classesOnlyNeededForRti.contains(cls);
216 if (!onlyForRti) {
217 backend.retainMetadataOf(cls);
218 oldEmitter.classEmitter.visitFields(cls, false,
219 (Element member,
220 jsAst.Name name,
221 jsAst.Name accessorName,
222 bool needsGetter,
223 bool needsSetter,
224 bool needsCheckedSetter) {
225 bool needsAccessor = needsGetter || needsSetter;
226 if (needsAccessor && backend.isAccessibleByReflection(member)) {
227 backend.retainMetadataOf(member);
228 }
229 });
230 }
231 }
232 typedefsNeededForReflection.forEach(backend.retainMetadataOf);
233 }
234
235 JavaScriptConstantCompiler handler = backend.constants;
236 List<ConstantValue> constants = handler.getConstantsForEmission(
237 compiler.hasIncrementalSupport ? null : emitter.compareConstants);
238 for (ConstantValue constant in constants) {
239 if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue;
240
241 if (constant.isList) outputContainsConstantList = true;
242
243 OutputUnit constantUnit =
244 compiler.deferredLoadTask.outputUnitForConstant(constant);
245 if (constantUnit == null) {
246 // The back-end introduces some constants, like "InterceptorConstant" or
247 // some list constants. They are emitted in the main output-unit.
248 // TODO(sigurdm): We should track those constants.
249 constantUnit = compiler.deferredLoadTask.mainOutputUnit;
250 }
251 outputConstantLists.putIfAbsent(
252 constantUnit, () => new List<ConstantValue>()).add(constant);
253 }
254 }
255
256 /// Compute all the classes and typedefs that must be emitted.
257 void computeNeededDeclarations(Set<ClassElement> rtiNeededClasses) {
258 // Compute needed typedefs.
259 typedefsNeededForReflection = Elements.sortedByPosition(
260 compiler.world.allTypedefs
261 .where(backend.isAccessibleByReflection)
262 .toList());
263
264 // Compute needed classes.
265 Set<ClassElement> instantiatedClasses =
266 compiler.codegenWorld.directlyInstantiatedClasses
267 .where(computeClassFilter()).toSet();
268
269 void addClassWithSuperclasses(ClassElement cls) {
270 neededClasses.add(cls);
271 for (ClassElement superclass = cls.superclass;
272 superclass != null;
273 superclass = superclass.superclass) {
274 neededClasses.add(superclass);
275 }
276 }
277
278 void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
279 for (ClassElement cls in classes) {
280 addClassWithSuperclasses(cls);
281 }
282 }
283
284 // 1. We need to generate all classes that are instantiated.
285 addClassesWithSuperclasses(instantiatedClasses);
286
287 // 2. Add all classes used as mixins.
288 Set<ClassElement> mixinClasses = neededClasses
289 .where((ClassElement element) => element.isMixinApplication)
290 .map(computeMixinClass)
291 .toSet();
292 neededClasses.addAll(mixinClasses);
293
294 // 3. Find all classes needed for rti.
295 // It is important that this is the penultimate step, at this point,
296 // neededClasses must only contain classes that have been resolved and
297 // codegen'd. The rtiNeededClasses may contain additional classes, but
298 // these are thought to not have been instantiated, so we neeed to be able
299 // to identify them later and make sure we only emit "empty shells" without
300 // fields, etc.
301 classesOnlyNeededForRti = rtiNeededClasses.difference(neededClasses);
302
303 neededClasses.addAll(classesOnlyNeededForRti);
304
305 // TODO(18175, floitsch): remove once issue 18175 is fixed.
306 if (neededClasses.contains(backend.jsIntClass)) {
307 neededClasses.add(compiler.intClass);
308 }
309 if (neededClasses.contains(backend.jsDoubleClass)) {
310 neededClasses.add(compiler.doubleClass);
311 }
312 if (neededClasses.contains(backend.jsNumberClass)) {
313 neededClasses.add(compiler.numClass);
314 }
315 if (neededClasses.contains(backend.jsStringClass)) {
316 neededClasses.add(compiler.stringClass);
317 }
318 if (neededClasses.contains(backend.jsBoolClass)) {
319 neededClasses.add(compiler.boolClass);
320 }
321 if (neededClasses.contains(backend.jsArrayClass)) {
322 neededClasses.add(compiler.listClass);
323 }
324
325 // 4. Finally, sort the classes.
326 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
327
328 for (ClassElement element in sortedClasses) {
329 if (Elements.isNativeOrExtendsNative(element) &&
330 !classesOnlyNeededForRti.contains(element)) {
331 // For now, native classes and related classes cannot be deferred.
332 nativeClassesAndSubclasses.add(element);
333 assert(invariant(element,
334 !compiler.deferredLoadTask.isDeferred(element)));
335 outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
336 () => new List<ClassElement>()).add(element);
337 } else {
338 outputClassLists.putIfAbsent(
339 compiler.deferredLoadTask.outputUnitForElement(element),
340 () => new List<ClassElement>())
341 .add(element);
342 }
343 }
344 }
345
346 void computeNeededStatics() {
347 bool isStaticFunction(Element element) =>
348 !element.isInstanceMember && !element.isField;
349
350 Iterable<Element> elements =
351 backend.generatedCode.keys.where(isStaticFunction);
352
353 for (Element element in Elements.sortedByPosition(elements)) {
354 List<Element> list = outputStaticLists.putIfAbsent(
355 compiler.deferredLoadTask.outputUnitForElement(element),
356 () => new List<Element>());
357 list.add(element);
358 }
359 }
360
361 void computeNeededStaticNonFinalFields() {
362 JavaScriptConstantCompiler handler = backend.constants;
363 Iterable<VariableElement> staticNonFinalFields = handler
364 .getStaticNonFinalFieldsForEmission()
365 .where(compiler.codegenWorld.allReferencedStaticFields.contains);
366 for (Element element in Elements.sortedByPosition(staticNonFinalFields)) {
367 List<VariableElement> list = outputStaticNonFinalFieldLists.putIfAbsent(
368 compiler.deferredLoadTask.outputUnitForElement(element),
369 () => new List<VariableElement>());
370 list.add(element);
371 }
372 }
373
374 void computeNeededLibraries() {
375 void addSurroundingLibraryToSet(Element element) {
376 OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element);
377 LibraryElement library = element.library;
378 outputLibraryLists.putIfAbsent(unit, () => new Set<LibraryElement>())
379 .add(library);
380 }
381
382 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet);
383 neededClasses.forEach(addSurroundingLibraryToSet);
384 }
385
386 void computeAllNeededEntities() {
387 // Compute the required type checks to know which classes need a 123 // Compute the required type checks to know which classes need a
388 // 'is$' method. 124 // 'is$' method.
389 typeTestRegistry.computeRequiredTypeChecks(); 125 typeTestRegistry.computeRequiredTypeChecks();
390 // Compute the classes needed by RTI. 126 // Compute the classes needed by RTI.
391 Set<ClassElement> rtiClasses = typeTestRegistry.computeRtiNeededClasses(); 127 return typeTestRegistry.computeRtiNeededClasses();
392
393 computeNeededDeclarations(rtiClasses);
394 computeNeededConstants();
395 computeNeededStatics();
396 computeNeededStaticNonFinalFields();
397 computeNeededLibraries();
398 } 128 }
399 129
400 int assembleProgram() { 130 int assembleProgram() {
401 return measure(() { 131 return measure(() {
402 emitter.invalidateCaches(); 132 emitter.invalidateCaches();
403 133
404 computeAllNeededEntities(); 134 Set<ClassElement> rtiNeededClasses = _finalizeRti();
405 135 ProgramBuilder programBuilder = new ProgramBuilder(
406 ProgramBuilder programBuilder = new ProgramBuilder(compiler, namer, this); 136 compiler, namer, this, emitter, oldEmitter, rtiNeededClasses);
407 return emitter.emitProgram(programBuilder); 137 int size = emitter.emitProgram(programBuilder);
138 // TODO(floitsch): we shouldn't need the `neededClasses` anymore.
139 neededClasses = programBuilder.collector.neededClasses;
140 return size;
408 }); 141 });
409 } 142 }
410 } 143 }
411 144
412 abstract class Emitter { 145 abstract class Emitter {
413 /// Uses the [programBuilder] to generate a model of the program, emits 146 /// Uses the [programBuilder] to generate a model of the program, emits
414 /// the program, and returns the size of the generated output. 147 /// the program, and returns the size of the generated output.
415 int emitProgram(ProgramBuilder programBuilder); 148 int emitProgram(ProgramBuilder programBuilder);
416 149
417 /// Returns the JS function that must be invoked to get the value of the 150 /// Returns the JS function that must be invoked to get the value of the
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant); 185 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant);
453 186
454 /// Returns the JS code for accessing the given [constant]. 187 /// Returns the JS code for accessing the given [constant].
455 jsAst.Expression constantReference(ConstantValue constant); 188 jsAst.Expression constantReference(ConstantValue constant);
456 189
457 /// Returns the JS template for the given [builtin]. 190 /// Returns the JS template for the given [builtin].
458 jsAst.Template templateForBuiltin(JsBuiltin builtin); 191 jsAst.Template templateForBuiltin(JsBuiltin builtin);
459 192
460 void invalidateCaches(); 193 void invalidateCaches();
461 } 194 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698