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

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

Issue 693183006: Revert "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.new_js_emitter.model_emitter;
6
7 import '../../dart2jslib.dart' show Compiler;
8 import '../../js/js.dart' as js;
9 import '../../js_backend/js_backend.dart' show
10 JavaScriptBackend,
11 Namer,
12 ConstantEmitter;
13
14 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show
15 DEFERRED_LIBRARY_URIS,
16 DEFERRED_LIBRARY_HASHES,
17 INITIALIZE_LOADED_HUNK,
18 IS_HUNK_LOADED;
19
20 import '../model.dart';
21
22 class ModelEmitter {
23 final Compiler compiler;
24 final Namer namer;
25 final ConstantEmitter constantEmitter;
26
27 JavaScriptBackend get backend => compiler.backend;
28
29 /// For deferred loading we communicate the initializers via this global var.
30 static const String deferredInitializersGlobal =
31 r"$__dart_deferred_initializers__";
32
33 static const String deferredExtension = ".part.js";
34
35 ModelEmitter(Compiler compiler, Namer namer)
36 : this.compiler = compiler,
37 this.namer = namer,
38 constantEmitter =
39 new ConstantEmitter(compiler, namer, makeConstantListTemplate);
40
41 void emitProgram(Program program) {
42 List<Output> outputs = program.outputs;
43 MainOutput mainUnit = outputs.first;
44 js.Statement mainAst = emitMainUnit(program);
45 String mainCode = js.prettyPrint(mainAst, compiler).getText();
46 compiler.outputProvider(mainUnit.outputFileName, 'js')
47 ..add(buildGeneratedBy(compiler))
48 ..add(mainCode)
49 ..close();
50 compiler.assembledCode = mainCode;
51
52 outputs.skip(1).forEach((DeferredOutput deferredUnit) {
53 js.Expression ast = emitDeferredUnit(deferredUnit, mainUnit.holders);
54 String code = js.prettyPrint(ast, compiler).getText();
55 compiler.outputProvider(deferredUnit.outputFileName, deferredExtension)
56 ..add(code)
57 ..close();
58 });
59 }
60
61 js.LiteralString unparse(Compiler compiler, js.Expression value) {
62 String text = js.prettyPrint(value, compiler).getText();
63 if (value is js.Fun) text = '($text)';
64 return js.js.escapedString(text);
65 }
66
67 String buildGeneratedBy(compiler) {
68 var suffix = '';
69 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
70 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
71 }
72
73 js.Statement emitMainUnit(Program program) {
74 MainOutput unit = program.outputs.first;
75 List<js.Expression> elements = unit.libraries.map(emitLibrary).toList();
76 elements.add(
77 emitLazilyInitializedStatics(unit.staticLazilyInitializedFields));
78 js.Expression code = new js.ArrayInitializer.from(elements);
79 return js.js.statement(
80 boilerplate,
81 [emitDeferredInitializerGlobal(program.loadMap),
82 emitHolders(unit.holders),
83 namer.elementAccess(backend.getCyclicThrowHelper()),
84 program.outputContainsConstantList,
85 emitEmbeddedGlobals(program.loadMap),
86 emitConstants(unit.constants),
87 emitStaticNonFinalFields(unit.staticNonFinalFields),
88 emitEagerClassInitializations(unit.libraries),
89 unit.main,
90 code]);
91 }
92
93 js.Block emitHolders(List<Holder> holders) {
94 // The top-level variables for holders must *not* be renamed by the
95 // JavaScript pretty printer because a lot of code already uses the
96 // non-renamed names. The generated code looks like this:
97 //
98 // var H = {}, ..., G = {};
99 // var holders = [ H, ..., G ];
100 //
101 // and it is inserted at the top of the top-level function expression
102 // that covers the entire program.
103
104 List<js.Statement> statements = [
105 new js.ExpressionStatement(
106 new js.VariableDeclarationList(holders.map((e) =>
107 new js.VariableInitialization(
108 new js.VariableDeclaration(e.name, allowRename: false),
109 new js.ObjectInitializer(const []))).toList())),
110 js.js.statement('var holders = #', new js.ArrayInitializer.from(
111 holders.map((e) => new js.VariableUse(e.name))))
112 ];
113 return new js.Block(statements);
114 }
115
116 static js.Template get makeConstantListTemplate {
117 // TODO(floitsch): remove hard-coded name.
118 // TODO(floitsch): there is no harm in caching the template.
119 return js.js.uncachedExpressionTemplate('makeConstList(#)');
120 }
121
122 js.Block emitEmbeddedGlobals(Map<String, List<Output>> loadMap) {
123 List<js.Property> globals = <js.Property>[];
124
125 if (loadMap.isNotEmpty) {
126 globals.addAll(emitLoadUrisAndHashes(loadMap));
127 globals.add(emitIsHunkLoadedFunction());
128 globals.add(emitInitializeLoadedHunk());
129 }
130
131 if (globals.isEmpty) return new js.Block.empty();
132
133 js.ObjectInitializer globalsObject = new js.ObjectInitializer(globals);
134
135 List<js.Statement> statements =
136 [new js.ExpressionStatement(
137 new js.VariableDeclarationList(
138 [new js.VariableInitialization(
139 new js.VariableDeclaration(r"init", allowRename: false),
140 globalsObject)]))];
141 return new js.Block(statements);
142 }
143
144 List<js.Property> emitLoadUrisAndHashes(Map<String, List<Output>> loadMap) {
145 js.ArrayInitializer outputUris(List<Output> outputs) {
146 return js.stringArray(outputs.map((DeferredOutput output) =>
147 "${output.outputFileName}$deferredExtension"));
148 }
149 js.ArrayInitializer outputHashes(List<Output> outputs) {
150 // TODO(floitsch): the hash must depend on the generated code.
151 return js.numArray(
152 outputs.map((DeferredOutput output) => output.hashCode));
153 }
154
155 List<js.Property> uris = new List<js.Property>(loadMap.length);
156 List<js.Property> hashes = new List<js.Property>(loadMap.length);
157 int count = 0;
158 loadMap.forEach((String loadId, List<Output> outputList) {
159 uris[count] = new js.Property(js.string(loadId), outputUris(outputList));
160 hashes[count] =
161 new js.Property(js.string(loadId), outputHashes(outputList));
162 count++;
163 });
164
165 return <js.Property>[
166 new js.Property(js.string(DEFERRED_LIBRARY_URIS),
167 new js.ObjectInitializer(uris)),
168 new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
169 new js.ObjectInitializer(hashes))
170 ];
171 }
172
173 js.Statement emitDeferredInitializerGlobal(Map loadMap) {
174 if (loadMap.isEmpty) return new js.Block.empty();
175
176 return js.js.statement("""
177 if (typeof($deferredInitializersGlobal) === 'undefined')
178 var $deferredInitializersGlobal = Object.create(null);""");
179 }
180
181 js.Property emitIsHunkLoadedFunction() {
182 js.Expression function =
183 js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }");
184 return new js.Property(js.string(IS_HUNK_LOADED), function);
185 }
186
187 js.Property emitInitializeLoadedHunk() {
188 js.Expression function =
189 js.js("function(hash) { eval($deferredInitializersGlobal[hash]); }");
190 return new js.Property(js.string(INITIALIZE_LOADED_HUNK), function);
191 }
192
193 js.Expression emitDeferredUnit(DeferredOutput unit, List<Holder> holders) {
194 // TODO(floitsch): initialize eager classes.
195 // TODO(floitsch): the hash must depend on the output.
196 int hash = this.hashCode;
197 if (unit.constants.isNotEmpty) {
198 throw new UnimplementedError("constants in deferred units");
199 }
200 js.ArrayInitializer content =
201 new js.ArrayInitializer.from(unit.libraries.map(emitLibrary));
202 return js.js("$deferredInitializersGlobal[$hash] = #", content);
203 }
204
205 js.Block emitConstants(List<Constant> constants) {
206 Iterable<js.Statement> statements = constants.map((Constant constant) {
207 js.Expression code =
208 constantEmitter.initializationExpression(constant.value);
209 return js.js.statement("#.# = #;",
210 [constant.holder.name, constant.name, code]);
211 });
212 return new js.Block(statements.toList());
213 }
214
215 js.Block emitStaticNonFinalFields(List<StaticField> fields) {
216 Iterable<js.Statement> statements = fields.map((StaticField field) {
217 return js.js.statement("#.# = #;",
218 [field.holder.name, field.name, field.code]);
219 });
220 return new js.Block(statements.toList());
221 }
222
223 js.Expression emitLazilyInitializedStatics(List<StaticField> fields) {
224 Iterable fieldDescriptors = fields.expand((field) =>
225 [ js.string(field.name),
226 js.string("${namer.getterPrefix}${field.name}"),
227 js.number(field.holder.index),
228 emitLazyInitializer(field) ]);
229 return new js.ArrayInitializer.from(fieldDescriptors);
230 }
231
232 js.Block emitEagerClassInitializations(List<Library> libraries) {
233 js.Statement createInstantiation(Class cls) {
234 return js.js.statement('new #.#()', [cls.holder.name, cls.name]);
235 }
236
237 List<js.Statement> instantiations =
238 libraries.expand((Library library) => library.classes)
239 .where((Class cls) => cls.isEager)
240 .map(createInstantiation)
241 .toList(growable: false);
242 return new js.Block(instantiations);
243 }
244
245 js.Expression emitLibrary(Library library) {
246 Iterable staticDescriptors = library.statics.expand((e) =>
247 [ js.string(e.name), js.number(e.holder.index), emitStaticMethod(e) ]);
248 Iterable classDescriptors = library.classes.expand((e) =>
249 [ js.string(e.name), js.number(e.holder.index), emitClass(e) ]);
250
251 js.Expression staticArray = new js.ArrayInitializer.from(staticDescriptors);
252 js.Expression classArray = new js.ArrayInitializer.from(classDescriptors);
253
254 return new js.ArrayInitializer.from([staticArray, classArray]);
255 }
256
257 js.Expression _generateConstructor(Class cls) {
258 List<String> allFieldNames = <String>[];
259 Class currentClass = cls;
260 while (currentClass != null) {
261 allFieldNames.addAll(
262 currentClass.fields.map((InstanceField field) => field.name));
263 currentClass = currentClass.superclass;
264 }
265 String name = cls.name;
266 String parameters = allFieldNames.join(', ');
267 String assignments = allFieldNames
268 .map((String field) => "this.$field = $field;\n")
269 .join();
270 String code = 'function $name($parameters) { $assignments }';
271 js.Template template = js.js.uncachedExpressionTemplate(code);
272 return template.instantiate(const []);
273 }
274
275 Method _generateGetter(InstanceField field) {
276 String getterTemplateFor(int flags) {
277 switch (flags) {
278 case 1: return "function() { return this[#]; }";
279 case 2: return "function(receiver) { return receiver[#]; }";
280 case 3: return "function(receiver) { return this[#]; }";
281 }
282 return null;
283 }
284
285 js.Expression fieldName = js.string(field.name);
286 js.Expression code = js.js(getterTemplateFor(field.getterFlags), fieldName);
287 String getterName = "${namer.getterPrefix}${field.name}";
288 return new Method(getterName, code);
289 }
290
291 Method _generateSetter(InstanceField field) {
292 String setterTemplateFor(int flags) {
293 switch (flags) {
294 case 1: return "function(val) { return this[#] = val; }";
295 case 2: return "function(receiver, val) { return receiver[#] = val; }";
296 case 3: return "function(receiver, val) { return this[#] = val; }";
297 }
298 return null;
299 }
300 js.Expression fieldName = js.string(field.name);
301 js.Expression code = js.js(setterTemplateFor(field.setterFlags), fieldName);
302 String setterName = "${namer.setterPrefix}${field.name}";
303 return new Method(setterName, code);
304 }
305
306 Iterable<Method> _generateGettersSetters(Class cls) {
307 Iterable<Method> getters = cls.fields
308 .where((InstanceField field) => field.needsGetter)
309 .map(_generateGetter);
310
311 Iterable<Method> setters = cls.fields
312 .where((InstanceField field) => field.needsSetter)
313 .map(_generateSetter);
314
315 return [getters, setters].expand((x) => x);
316 }
317
318 js.Expression emitClass(Class cls) {
319 List elements = [ js.string(cls.superclassName),
320 js.number(cls.superclassHolderIndex),
321 _generateConstructor(cls) ];
322 Iterable<Method> methods = cls.methods;
323 Iterable<Method> gettersSetters = _generateGettersSetters(cls);
324 Iterable<Method> allMethods = [methods, gettersSetters].expand((x) => x);
325 elements.addAll(allMethods.expand((e) => [ js.string(e.name), e.code ]));
326 return unparse(compiler, new js.ArrayInitializer.from(elements));
327 }
328
329 js.Expression emitLazyInitializer(StaticField field) {
330 assert(field.isLazy);
331 return unparse(compiler, field.code);
332 }
333
334 js.Expression emitStaticMethod(StaticMethod method) {
335 return unparse(compiler, method.code);
336 }
337 }
338
339 final String boilerplate = r"""
340 {
341 // Declare deferred-initializer global.
342 #;
343
344 !function(start, program) {
345
346 // Initialize holder objects.
347 #;
348
349 function setupProgram() {
350 for (var i = 0; i < program.length - 1; i++) {
351 setupLibrary(program[i]);
352 }
353 setupLazyStatics(program[i]);
354 }
355
356 function setupLibrary(library) {
357 var statics = library[0];
358 for (var i = 0; i < statics.length; i += 3) {
359 var holderIndex = statics[i + 1];
360 setupStatic(statics[i], holders[holderIndex], statics[i + 2]);
361 }
362
363 var classes = library[1];
364 for (var i = 0; i < classes.length; i += 3) {
365 var holderIndex = classes[i + 1];
366 setupClass(classes[i], holders[holderIndex], classes[i + 2]);
367 }
368 }
369
370 function setupLazyStatics(statics) {
371 for (var i = 0; i < statics.length; i += 4) {
372 var name = statics[i];
373 var getterName = statics[i + 1];
374 var holderIndex = statics[i + 2];
375 var initializer = statics[i + 3];
376 setupLazyStatic(name, getterName, holders[holderIndex], initializer);
377 }
378 }
379
380 function setupStatic(name, holder, descriptor) {
381 holder[name] = function() {
382 var method = compile(name, descriptor);
383 holder[name] = method;
384 return method.apply(this, arguments);
385 };
386 }
387
388 function setupLazyStatic(name, getterName, holder, descriptor) {
389 holder[name] = null;
390 holder[getterName] = function() {
391 var initializer = compile(name, descriptor);
392 holder[getterName] = function() { #(name) }; // cyclicThrowHelper
393 var result;
394 var sentinelInProgress = descriptor;
395 try {
396 result = holder[name] = sentinelInProgress;
397 result = holder[name] = initializer();
398 } finally {
399 // Use try-finally, not try-catch/throw as it destroys the stack trace.
400 if (result === sentinelInProgress) {
401 // The lazy static (holder[name]) might have been set to a different
402 // value. According to spec we still have to reset it to null, if the
403 // initialization failed.
404 holder[name] = null;
405 }
406 holder[getterName] = function() { return this[name]; };
407 }
408 return result;
409 };
410 }
411
412 function setupClass(name, holder, descriptor) {
413 var resolve = function() {
414 var constructor = compileConstructor(name, descriptor);
415 holder[name] = constructor;
416 return constructor;
417 };
418
419 var patch = function() {
420 var constructor = resolve();
421 var object = new constructor();
422 constructor.apply(object, arguments);
423 return object;
424 };
425
426 // We store the resolve function on the patch function to make it possible
427 // to resolve superclass references without constructing instances. The
428 // resolve property also serves as a marker that indicates whether or not
429 // a class has been resolved yet.
430 patch.resolve = resolve;
431 holder[name] = patch;
432 }
433
434 function compileConstructor(name, descriptor) {
435 descriptor = compile(name, descriptor);
436 var prototype = determinePrototype(descriptor);
437 var constructor = descriptor[2];
438 for (var i = 3; i < descriptor.length; i += 2) {
439 prototype[descriptor[i]] = descriptor[i + 1];
440 }
441 constructor.prototype = prototype;
442 return constructor;
443 }
444
445 function determinePrototype(descriptor) {
446 var superclassName = descriptor[0];
447 if (!superclassName) return { };
448
449 // Look up the superclass constructor function in the right holder.
450 var holderIndex = descriptor[1];
451 var superclass = holders[holderIndex][superclassName];
452 if (superclass.resolve) superclass = superclass.resolve();
453
454 // Create a new prototype object chained to the superclass prototype.
455 var intermediate = function() { };
456 intermediate.prototype = superclass.prototype;
457 return new intermediate();
458 }
459
460 function compile(__name__, __s__) {
461 'use strict';
462 // TODO(floitsch): evaluate the performance impact of the string
463 // concatenations.
464 return eval(__s__ + "\n//# sourceURL=" + __name__ + ".js");
465 }
466
467 if (#) { // outputContainsConstantList
468 function makeConstList(list) {
469 // By assigning a function to the properties they become part of the
470 // hidden class. The actual values of the fields don't matter, since we
471 // only check if they exist.
472 list.immutable$list = Array;
473 list.fixed$length = Array;
474 return list;
475 }
476 }
477
478 setupProgram();
479
480 // Initialize globals.
481 #;
482
483 // Initialize constants.
484 #;
485
486 // Initialize static non-final fields.
487 #;
488
489 // Initialize eager classes.
490 #;
491
492 var end = Date.now();
493 print('Setup: ' + (end - start) + ' ms.');
494
495 if (true) #(); // Start main.
496
497 }(Date.now(), #)
498 }""";
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698