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

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

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

Powered by Google App Engine
This is Rietveld 408576698