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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart

Issue 692513002: Remove old dart2js code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 part of dart2js.js_emitter;
6
7 const USE_NEW_EMITTER = const bool.fromEnvironment("dart2js.use.new.emitter");
8
9 /**
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.
12 *
13 * The code for the containing (used) methods must exist in the [:universe:].
14 */
15 class CodeEmitterTask extends CompilerTask {
16 // TODO(floitsch): the code-emitter task should not need a namer.
17 final Namer namer;
18 final TypeTestEmitter typeTestEmitter = new TypeTestEmitter();
19 NativeEmitter nativeEmitter;
20 OldEmitter oldEmitter;
21 Emitter emitter;
22
23 final Set<ClassElement> neededClasses = new Set<ClassElement>();
24 final Map<OutputUnit, List<ClassElement>> outputClassLists =
25 new Map<OutputUnit, List<ClassElement>>();
26 final Map<OutputUnit, List<ConstantValue>> outputConstantLists =
27 new Map<OutputUnit, List<ConstantValue>>();
28 final Map<OutputUnit, List<Element>> outputStaticLists =
29 new Map<OutputUnit, List<Element>>();
30 final Map<OutputUnit, Set<LibraryElement>> outputLibraryLists =
31 new Map<OutputUnit, Set<LibraryElement>>();
32
33 /// True, if the output contains a constant list.
34 ///
35 /// This flag is updated in [computeNeededConstants].
36 bool outputContainsConstantList = false;
37
38 final List<ClassElement> nativeClasses = <ClassElement>[];
39
40 /// Records if a type variable is read dynamically for type tests.
41 final Set<TypeVariableElement> readTypeVariables =
42 new Set<TypeVariableElement>();
43
44 List<TypedefElement> typedefsNeededForReflection;
45
46 JavaScriptBackend get backend => compiler.backend;
47
48 CodeEmitterTask(Compiler compiler, Namer namer, bool generateSourceMap)
49 : super(compiler),
50 this.namer = namer {
51 oldEmitter = new OldEmitter(compiler, namer, generateSourceMap, this);
52 emitter = USE_NEW_EMITTER
53 ? new new_js_emitter.Emitter(compiler, namer)
54 : oldEmitter;
55 nativeEmitter = new NativeEmitter(this);
56 typeTestEmitter.emitter = this.oldEmitter;
57 // TODO(18886): Remove this call (and the show in the import) once the
58 // memory-leak in the VM is fixed.
59 templateManager.clear();
60 }
61
62
63 jsAst.Expression generateEmbeddedGlobalAccess(String global) {
64 return emitter.generateEmbeddedGlobalAccess(global);
65 }
66
67 jsAst.Expression constantReference(ConstantValue value) {
68 return emitter.constantReference(value);
69 }
70
71 void registerReadTypeVariable(TypeVariableElement element) {
72 readTypeVariables.add(element);
73 }
74
75 Set<ClassElement> interceptorsReferencedFromConstants() {
76 Set<ClassElement> classes = new Set<ClassElement>();
77 JavaScriptConstantCompiler handler = backend.constants;
78 List<ConstantValue> constants = handler.getConstantsForEmission();
79 for (ConstantValue constant in constants) {
80 if (constant is InterceptorConstantValue) {
81 InterceptorConstantValue interceptorConstant = constant;
82 classes.add(interceptorConstant.dispatchedType.element);
83 }
84 }
85 return classes;
86 }
87
88 /**
89 * Return a function that returns true if its argument is a class
90 * that needs to be emitted.
91 */
92 Function computeClassFilter() {
93 if (backend.isTreeShakingDisabled) return (ClassElement cls) => true;
94
95 Set<ClassElement> unneededClasses = new Set<ClassElement>();
96 // The [Bool] class is not marked as abstract, but has a factory
97 // constructor that always throws. We never need to emit it.
98 unneededClasses.add(compiler.boolClass);
99
100 // Go over specialized interceptors and then constants to know which
101 // interceptors are needed.
102 Set<ClassElement> needed = new Set<ClassElement>();
103 backend.specializedGetInterceptors.forEach(
104 (_, Iterable<ClassElement> elements) {
105 needed.addAll(elements);
106 }
107 );
108
109 // Add interceptors referenced by constants.
110 needed.addAll(interceptorsReferencedFromConstants());
111
112 // Add unneeded interceptors to the [unneededClasses] set.
113 for (ClassElement interceptor in backend.interceptedClasses) {
114 if (!needed.contains(interceptor)
115 && interceptor != compiler.objectClass) {
116 unneededClasses.add(interceptor);
117 }
118 }
119
120 // These classes are just helpers for the backend's type system.
121 unneededClasses.add(backend.jsMutableArrayClass);
122 unneededClasses.add(backend.jsFixedArrayClass);
123 unneededClasses.add(backend.jsExtendableArrayClass);
124 unneededClasses.add(backend.jsUInt32Class);
125 unneededClasses.add(backend.jsUInt31Class);
126 unneededClasses.add(backend.jsPositiveIntClass);
127
128 return (ClassElement cls) => !unneededClasses.contains(cls);
129 }
130
131 /**
132 * Compute all the constants that must be emitted.
133 */
134 void computeNeededConstants() {
135 // Make sure we retain all metadata of all elements. This could add new
136 // constants to the handler.
137 if (backend.mustRetainMetadata) {
138 // TODO(floitsch): verify that we don't run through the same elements
139 // multiple times.
140 for (Element element in backend.generatedCode.keys) {
141 if (backend.isAccessibleByReflection(element)) {
142 bool shouldRetainMetadata = backend.retainMetadataOf(element);
143 if (shouldRetainMetadata && element.isFunction) {
144 FunctionElement function = element;
145 function.functionSignature.forEachParameter(
146 backend.retainMetadataOf);
147 }
148 }
149 }
150 for (ClassElement cls in neededClasses) {
151 final onlyForRti = typeTestEmitter.rtiNeededClasses.contains(cls);
152 if (!onlyForRti) {
153 backend.retainMetadataOf(cls);
154 oldEmitter.classEmitter.visitFields(cls, false,
155 (Element member,
156 String name,
157 String accessorName,
158 bool needsGetter,
159 bool needsSetter,
160 bool needsCheckedSetter) {
161 bool needsAccessor = needsGetter || needsSetter;
162 if (needsAccessor && backend.isAccessibleByReflection(member)) {
163 backend.retainMetadataOf(member);
164 }
165 });
166 }
167 }
168 typedefsNeededForReflection.forEach(backend.retainMetadataOf);
169 }
170
171 JavaScriptConstantCompiler handler = backend.constants;
172 List<ConstantValue> constants = handler.getConstantsForEmission(
173 compiler.hasIncrementalSupport ? null : emitter.compareConstants);
174 for (ConstantValue constant in constants) {
175 if (emitter.isConstantInlinedOrAlreadyEmitted(constant)) continue;
176
177 if (constant.isList) outputContainsConstantList = true;
178
179 OutputUnit constantUnit =
180 compiler.deferredLoadTask.outputUnitForConstant(constant);
181 if (constantUnit == null) {
182 // The back-end introduces some constants, like "InterceptorConstant" or
183 // some list constants. They are emitted in the main output-unit.
184 // TODO(sigurdm): We should track those constants.
185 constantUnit = compiler.deferredLoadTask.mainOutputUnit;
186 }
187 outputConstantLists.putIfAbsent(
188 constantUnit, () => new List<ConstantValue>()).add(constant);
189 }
190 }
191
192 /// Compute all the classes and typedefs that must be emitted.
193 void computeNeededDeclarations() {
194 // Compute needed typedefs.
195 typedefsNeededForReflection = Elements.sortedByPosition(
196 compiler.world.allTypedefs
197 .where(backend.isAccessibleByReflection)
198 .toList());
199
200 // Compute needed classes.
201 Set<ClassElement> instantiatedClasses =
202 compiler.codegenWorld.directlyInstantiatedClasses
203 .where(computeClassFilter()).toSet();
204
205 void addClassWithSuperclasses(ClassElement cls) {
206 neededClasses.add(cls);
207 for (ClassElement superclass = cls.superclass;
208 superclass != null;
209 superclass = superclass.superclass) {
210 neededClasses.add(superclass);
211 }
212 }
213
214 void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
215 for (ClassElement cls in classes) {
216 addClassWithSuperclasses(cls);
217 }
218 }
219
220 // 1. We need to generate all classes that are instantiated.
221 addClassesWithSuperclasses(instantiatedClasses);
222
223 // 2. Add all classes used as mixins.
224 Set<ClassElement> mixinClasses = neededClasses
225 .where((ClassElement element) => element.isMixinApplication)
226 .map(computeMixinClass)
227 .toSet();
228 neededClasses.addAll(mixinClasses);
229
230 // 3. If we need noSuchMethod support, we run through all needed
231 // classes to figure out if we need the support on any native
232 // class. If so, we let the native emitter deal with it.
233 if (compiler.enabledNoSuchMethod) {
234 String noSuchMethodName = Compiler.NO_SUCH_METHOD;
235 Selector noSuchMethodSelector = compiler.noSuchMethodSelector;
236 for (ClassElement element in neededClasses) {
237 if (!element.isNative) continue;
238 Element member = element.lookupLocalMember(noSuchMethodName);
239 if (member == null) continue;
240 if (noSuchMethodSelector.applies(member, compiler.world)) {
241 nativeEmitter.handleNoSuchMethod = true;
242 break;
243 }
244 }
245 }
246
247 // 4. Find all classes needed for rti.
248 // It is important that this is the penultimate step, at this point,
249 // neededClasses must only contain classes that have been resolved and
250 // codegen'd. The rtiNeededClasses may contain additional classes, but
251 // these are thought to not have been instantiated, so we neeed to be able
252 // to identify them later and make sure we only emit "empty shells" without
253 // fields, etc.
254 typeTestEmitter.computeRtiNeededClasses();
255 typeTestEmitter.rtiNeededClasses.removeAll(neededClasses);
256 // rtiNeededClasses now contains only the "empty shells".
257 neededClasses.addAll(typeTestEmitter.rtiNeededClasses);
258
259 // TODO(18175, floitsch): remove once issue 18175 is fixed.
260 if (neededClasses.contains(backend.jsIntClass)) {
261 neededClasses.add(compiler.intClass);
262 }
263 if (neededClasses.contains(backend.jsDoubleClass)) {
264 neededClasses.add(compiler.doubleClass);
265 }
266 if (neededClasses.contains(backend.jsNumberClass)) {
267 neededClasses.add(compiler.numClass);
268 }
269 if (neededClasses.contains(backend.jsStringClass)) {
270 neededClasses.add(compiler.stringClass);
271 }
272 if (neededClasses.contains(backend.jsBoolClass)) {
273 neededClasses.add(compiler.boolClass);
274 }
275 if (neededClasses.contains(backend.jsArrayClass)) {
276 neededClasses.add(compiler.listClass);
277 }
278
279 // 5. Finally, sort the classes.
280 List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
281
282 for (ClassElement element in sortedClasses) {
283 if (Elements.isNativeOrExtendsNative(element) &&
284 !typeTestEmitter.rtiNeededClasses.contains(element)) {
285 // For now, native classes and related classes cannot be deferred.
286 nativeClasses.add(element);
287 if (!element.isNative) {
288 assert(invariant(element,
289 !compiler.deferredLoadTask.isDeferred(element)));
290 outputClassLists.putIfAbsent(compiler.deferredLoadTask.mainOutputUnit,
291 () => new List<ClassElement>()).add(element);
292 }
293 } else {
294 outputClassLists.putIfAbsent(
295 compiler.deferredLoadTask.outputUnitForElement(element),
296 () => new List<ClassElement>())
297 .add(element);
298 }
299 }
300 }
301
302 void computeNeededStatics() {
303 bool isStaticFunction(Element element) =>
304 !element.isInstanceMember && !element.isField;
305
306 Iterable<Element> elements =
307 backend.generatedCode.keys.where(isStaticFunction);
308
309 for (Element element in Elements.sortedByPosition(elements)) {
310 outputStaticLists.putIfAbsent(
311 compiler.deferredLoadTask.outputUnitForElement(element),
312 () => new List<Element>())
313 .add(element);
314 }
315 }
316
317 void computeNeededLibraries() {
318 void addSurroundingLibraryToSet(Element element) {
319 OutputUnit unit = compiler.deferredLoadTask.outputUnitForElement(element);
320 LibraryElement library = element.library;
321 outputLibraryLists.putIfAbsent(unit, () => new Set<LibraryElement>())
322 .add(library);
323 }
324
325 backend.generatedCode.keys.forEach(addSurroundingLibraryToSet);
326 neededClasses.forEach(addSurroundingLibraryToSet);
327 }
328
329 void assembleProgram() {
330 measure(() {
331 emitter.invalidateCaches();
332
333 // Compute the required type checks to know which classes need a
334 // 'is$' method.
335 typeTestEmitter.computeRequiredTypeChecks();
336
337 computeNeededDeclarations();
338 computeNeededConstants();
339 computeNeededStatics();
340 computeNeededLibraries();
341
342
343 Program program;
344 if (USE_NEW_EMITTER) {
345 program = new ProgramBuilder(compiler, namer, this).buildProgram();
346 }
347 emitter.emitProgram(program);
348 });
349 }
350 }
351
352 abstract class Emitter {
353 void emitProgram(Program program);
354
355 jsAst.Expression generateEmbeddedGlobalAccess(String global);
356 jsAst.Expression constantReference(ConstantValue value);
357
358 int compareConstants(ConstantValue a, ConstantValue b);
359 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant);
360
361 void invalidateCaches();
362 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698