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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js_emitter/program_builder.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) 2014, 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 library dart2js.js_emitter.program_builder;
6
7 import 'model.dart';
8 import '../common.dart';
9 import '../js/js.dart' as js;
10
11 import '../js_backend/js_backend.dart' show
12 Namer,
13 JavaScriptBackend,
14 JavaScriptConstantCompiler;
15
16 import '../closure.dart' show ClosureFieldElement;
17
18 import 'js_emitter.dart' as emitterTask show
19 CodeEmitterTask,
20 Emitter,
21 InterceptorStubGenerator;
22
23 import '../universe/universe.dart' show Universe;
24 import '../deferred_load.dart' show DeferredLoadTask, OutputUnit;
25
26 part 'registry.dart';
27
28 class ProgramBuilder {
29 final Compiler _compiler;
30 final Namer namer;
31 final emitterTask.CodeEmitterTask _task;
32
33 final Registry _registry;
34
35 ProgramBuilder(Compiler compiler,
36 this.namer,
37 this._task)
38 : this._compiler = compiler,
39 this._registry = new Registry(compiler);
40
41 JavaScriptBackend get backend => _compiler.backend;
42 Universe get universe => _compiler.codegenWorld;
43
44 /// Mapping from [ClassElement] to constructed [Class]. We need this to
45 /// update the superclass in the [Class].
46 final Map<ClassElement, Class> _classes = <ClassElement, Class>{};
47
48 /// Mapping from [OutputUnit] to constructed [Output]. We need this to
49 /// generate the deferredLoadingMap (to know which hunks to load).
50 final Map<OutputUnit, Output> _outputs = <OutputUnit, Output>{};
51
52 /// Mapping from [ConstantValue] to constructed [Constant]. We need this to
53 /// update field-initializers to point to the ConstantModel.
54 final Map<ConstantValue, Constant> _constants = <ConstantValue, Constant>{};
55
56 Program buildProgram() {
57 _task.outputClassLists.forEach(_registry.registerElements);
58 _task.outputStaticLists.forEach(_registry.registerElements);
59 _task.outputConstantLists.forEach(_registerConstants);
60
61 // TODO(kasperl): There's code that implicitly needs access to the special
62 // $ holder so we have to register that. Can we track if we have to?
63 _registry.registerHolder(r'$');
64
65 MainOutput mainOutput = _buildMainOutput(_registry.mainFragment);
66 Iterable<Output> deferredOutputs = _registry.deferredFragments
67 .map((fragment) => _buildDeferredOutput(mainOutput, fragment));
68
69 List<Output> outputs = new List<Output>(_registry.fragmentCount);
70 outputs[0] = mainOutput;
71 outputs.setAll(1, deferredOutputs);
72
73 Program result =
74 new Program(outputs, _task.outputContainsConstantList, _buildLoadMap());
75
76 // Resolve the superclass references after we've processed all the classes.
77 _classes.forEach((ClassElement element, Class c) {
78 if (element.superclass != null) {
79 c.setSuperclass(_classes[element.superclass]);
80 }
81 });
82
83 _markEagerClasses();
84
85 return result;
86 }
87
88 void _markEagerClasses() {
89 _markEagerInterceptorClasses();
90 }
91
92 /// Builds a map from loadId to outputs-to-load.
93 Map<String, List<Output>> _buildLoadMap() {
94 List<OutputUnit> convertHunks(List<OutputUnit> hunks) {
95 return hunks.map((OutputUnit unit) => _outputs[unit])
96 .toList(growable: false);
97 }
98
99 Map<String, List<Output>> loadMap = <String, List<Output>>{};
100 _compiler.deferredLoadTask.hunksToLoad
101 .forEach((String loadId, List<OutputUnit> outputUnits) {
102 loadMap[loadId] = outputUnits
103 .map((OutputUnit unit) => _outputs[unit])
104 .toList(growable: false);
105 });
106 return loadMap;
107 }
108
109 MainOutput _buildMainOutput(Fragment fragment) {
110 // Construct the main output from the libraries and the registered holders.
111 MainOutput result = new MainOutput(
112 "", // The empty string is the name for the main output file.
113 namer.elementAccess(_compiler.mainFunction),
114 _buildLibraries(fragment),
115 _buildStaticNonFinalFields(fragment),
116 _buildStaticLazilyInitializedFields(fragment),
117 _buildConstants(fragment),
118 _registry.holders.toList(growable: false));
119 _outputs[fragment.outputUnit] = result;
120 return result;
121 }
122
123 /// Returns a name composed of the main output file name and [name].
124 String _outputFileName(String name) {
125 assert(name != "");
126 String outPath = _compiler.outputUri != null
127 ? _compiler.outputUri.path
128 : "out";
129 String outName = outPath.substring(outPath.lastIndexOf('/') + 1);
130 return "${outName}_$name";
131 }
132
133 DeferredOutput _buildDeferredOutput(MainOutput mainOutput,
134 Fragment fragment) {
135 DeferredOutput result = new DeferredOutput(
136 _outputFileName(fragment.name), fragment.name,
137 mainOutput,
138 _buildLibraries(fragment),
139 _buildStaticNonFinalFields(fragment),
140 _buildStaticLazilyInitializedFields(fragment),
141 _buildConstants(fragment));
142 _outputs[fragment.outputUnit] = result;
143 return result;
144 }
145
146 List<Constant> _buildConstants(Fragment fragment) {
147 List<ConstantValue> constantValues =
148 _task.outputConstantLists[fragment.outputUnit];
149 if (constantValues == null) return const <Constant>[];
150 return constantValues.map((ConstantValue value) => _constants[value])
151 .toList(growable: false);
152 }
153
154 List<StaticField> _buildStaticNonFinalFields(Fragment fragment) {
155 // TODO(floitsch): handle static non-final fields correctly with deferred
156 // libraries.
157 if (fragment != _registry.mainFragment) return const <StaticField>[];
158 Iterable<VariableElement> staticNonFinalFields =
159 backend.constants.getStaticNonFinalFieldsForEmission();
160 return Elements.sortedByPosition(staticNonFinalFields)
161 .map(_buildStaticField)
162 .toList(growable: false);
163 }
164
165 StaticField _buildStaticField(Element element) {
166 JavaScriptConstantCompiler handler = backend.constants;
167 ConstantValue initialValue = handler.getInitialValueFor(element).value;
168 js.Expression code = _task.emitter.constantReference(initialValue);
169 String name = namer.getNameOfGlobalField(element);
170 bool isFinal = false;
171 bool isLazy = false;
172 return new StaticField(name, _registry.registerHolder(r'$'), code,
173 isFinal, isLazy);
174 }
175
176 List<StaticField> _buildStaticLazilyInitializedFields(Fragment fragment) {
177 // TODO(floitsch): lazy fields should just be in their respective
178 // libraries.
179 if (fragment != _registry.mainFragment) return const <StaticField>[];
180
181 JavaScriptConstantCompiler handler = backend.constants;
182 List<VariableElement> lazyFields =
183 handler.getLazilyInitializedFieldsForEmission();
184 return Elements.sortedByPosition(lazyFields)
185 .map(_buildLazyField)
186 .where((field) => field != null) // Happens when the field was unused.
187 .toList(growable: false);
188 }
189
190 StaticField _buildLazyField(Element element) {
191 JavaScriptConstantCompiler handler = backend.constants;
192 js.Expression code = backend.generatedCode[element];
193 // The code is null if we ended up not needing the lazily
194 // initialized field after all because of constant folding
195 // before code generation.
196 if (code == null) return null;
197
198 String name = namer.getNameOfGlobalField(element);
199 bool isFinal = element.isFinal;
200 bool isLazy = true;
201 return new StaticField(name, _registry.registerHolder(r'$'), code,
202 isFinal, isLazy);
203 }
204
205 List<Library> _buildLibraries(Fragment fragment) {
206 List<Library> libraries = new List<Library>(fragment.length);
207 int count = 0;
208 fragment.forEach((LibraryElement library, List<Element> elements) {
209 libraries[count++] = _buildLibrary(library, elements);
210 });
211 return libraries;
212 }
213
214 // Note that a library-element may have multiple [Library]s, if it is split
215 // into multiple output units.
216 Library _buildLibrary(LibraryElement library, List<Element> elements) {
217 String uri = library.canonicalUri.toString();
218
219 List<StaticMethod> statics = elements
220 .where((e) => e is FunctionElement).map(_buildStaticMethod).toList();
221
222 statics.addAll(elements
223 .where((e) => e is FunctionElement)
224 .where((e) => universe.staticFunctionsNeedingGetter.contains(e))
225 .map(_buildStaticMethodTearOff));
226
227 if (library == backend.interceptorsLibrary) {
228 statics.addAll(_generateGetInterceptorMethods());
229 statics.addAll(_generateOneShotInterceptors());
230 }
231
232 List<Class> classes = elements
233 .where((e) => e is ClassElement)
234 .map(_buildClass)
235 .toList(growable: false);
236
237 return new Library(uri, statics, classes);
238 }
239
240 Class _buildClass(ClassElement element) {
241 bool isInstantiated =
242 _compiler.codegenWorld.directlyInstantiatedClasses.contains(element);
243
244 List<Method> methods = [];
245 List<InstanceField> fields = [];
246
247 void visitMember(ClassElement enclosing, Element member) {
248 assert(invariant(element, member.isDeclaration));
249 assert(invariant(element, element == enclosing));
250
251 if (Elements.isNonAbstractInstanceMember(member)) {
252 js.Expression code = backend.generatedCode[member];
253 // TODO(kasperl): Figure out under which conditions code is null.
254 if (code != null) methods.add(_buildMethod(member, code));
255 } else if (member.isField && !member.isStatic) {
256 fields.add(_buildInstanceField(member, enclosing));
257 }
258 }
259
260 ClassElement implementation = element.implementation;
261 if (isInstantiated) {
262 implementation.forEachMember(visitMember, includeBackendMembers: true);
263 }
264 String name = namer.getNameOfClass(element);
265 String holderName = namer.globalObjectFor(element);
266 Holder holder = _registry.registerHolder(holderName);
267 Class result = new Class(name, holder, methods, fields);
268 _classes[element] = result;
269 return result;
270 }
271
272 Method _buildMethod(FunctionElement element, js.Expression code) {
273 String name = namer.getNameOfInstanceMember(element);
274 return new Method(name, code);
275 }
276
277 // The getInterceptor methods directly access the prototype of classes.
278 // We must evaluate these classes eagerly so that the prototype is
279 // accessible.
280 void _markEagerInterceptorClasses() {
281 Map<String, Set<ClassElement>> specializedGetInterceptors =
282 backend.specializedGetInterceptors;
283 for (Set<ClassElement> classes in specializedGetInterceptors.values) {
284 for (ClassElement element in classes) {
285 Class cls = _classes[element];
286 if (cls != null) cls.isEager = true;
287 }
288 }
289 }
290
291 Iterable<StaticMethod> _generateGetInterceptorMethods() {
292 emitterTask.InterceptorStubGenerator stubGenerator =
293 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend);
294
295 String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
296 Holder holder = _registry.registerHolder(holderName);
297
298 Map<String, Set<ClassElement>> specializedGetInterceptors =
299 backend.specializedGetInterceptors;
300 List<String> names = specializedGetInterceptors.keys.toList()..sort();
301 return names.map((String name) {
302 Set<ClassElement> classes = specializedGetInterceptors[name];
303 js.Expression code = stubGenerator.generateGetInterceptorMethod(classes);
304 return new StaticMethod(name, holder, code);
305 });
306 }
307
308 bool _fieldNeedsGetter(VariableElement field) {
309 assert(field.isField);
310 if (_fieldAccessNeverThrows(field)) return false;
311 return backend.shouldRetainGetter(field)
312 || _compiler.codegenWorld.hasInvokedGetter(field, _compiler.world);
313 }
314
315 bool _fieldNeedsSetter(VariableElement field) {
316 assert(field.isField);
317 if (_fieldAccessNeverThrows(field)) return false;
318 return (!field.isFinal && !field.isConst)
319 && (backend.shouldRetainSetter(field)
320 || _compiler.codegenWorld.hasInvokedSetter(field, _compiler.world));
321 }
322
323 // We never access a field in a closure (a captured variable) without knowing
324 // that it is there. Therefore we don't need to use a getter (that will throw
325 // if the getter method is missing), but can always access the field directly.
326 bool _fieldAccessNeverThrows(VariableElement field) {
327 return field is ClosureFieldElement;
328 }
329
330 InstanceField _buildInstanceField(VariableElement field,
331 ClassElement holder) {
332 assert(invariant(field, field.isDeclaration));
333 String name = namer.fieldPropertyName(field);
334
335 int getterFlags = 0;
336 if (_fieldNeedsGetter(field)) {
337 bool isIntercepted = backend.fieldHasInterceptedGetter(field);
338 if (isIntercepted) {
339 getterFlags += 2;
340 if (backend.isInterceptorClass(holder)) {
341 getterFlags += 1;
342 }
343 } else {
344 getterFlags = 1;
345 }
346 }
347
348 int setterFlags = 0;
349 if (_fieldNeedsSetter(field)) {
350 bool isIntercepted = backend.fieldHasInterceptedSetter(field);
351 if (isIntercepted) {
352 setterFlags += 2;
353 if (backend.isInterceptorClass(holder)) {
354 setterFlags += 1;
355 }
356 } else {
357 setterFlags = 1;
358 }
359 }
360
361 return new InstanceField(name, getterFlags, setterFlags);
362 }
363
364 Iterable<StaticMethod> _generateOneShotInterceptors() {
365 emitterTask.InterceptorStubGenerator stubGenerator =
366 new emitterTask.InterceptorStubGenerator(_compiler, namer, backend);
367
368 String holderName = namer.globalObjectFor(backend.interceptorsLibrary);
369 Holder holder = _registry.registerHolder(holderName);
370
371 List<String> names = backend.oneShotInterceptors.keys.toList()..sort();
372 return names.map((String name) {
373 js.Expression code = stubGenerator.generateOneShotInterceptor(name);
374 return new StaticMethod(name, holder, code);
375 });
376 }
377
378 StaticMethod _buildStaticMethod(FunctionElement element) {
379 String name = namer.getNameOfMember(element);
380 String holder = namer.globalObjectFor(element);
381 js.Expression code = backend.generatedCode[element];
382 return new StaticMethod(name, _registry.registerHolder(holder), code);
383 }
384
385 StaticMethod _buildStaticMethodTearOff(FunctionElement element) {
386 String name = namer.getStaticClosureName(element);
387 String holder = namer.globalObjectFor(element);
388 // TODO(kasperl): This clearly doesn't work yet.
389 js.Expression code = js.string("<<unimplemented>>");
390 return new StaticMethod(name, _registry.registerHolder(holder), code);
391 }
392
393 void _registerConstants(OutputUnit outputUnit,
394 List<ConstantValue> constantValues) {
395 if (constantValues == null) return;
396 for (ConstantValue constantValue in constantValues) {
397 assert(!_constants.containsKey(constantValue));
398 String name = namer.constantName(constantValue);
399 String constantObject = namer.globalObjectForConstant(constantValue);
400 Holder holder = _registry.registerHolder(constantObject);
401 Constant constant = new Constant(name, holder, constantValue);
402 _constants[constantValue] = constant;
403 };
404 }
405 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698