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

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

Issue 1140703006: dart2js: Construct the entire output as a single AST before printing. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Comments Created 5 years, 7 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 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 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 7
8 class OldEmitter implements Emitter { 8 class OldEmitter implements Emitter {
9 final Compiler compiler; 9 final Compiler compiler;
10 final CodeEmitterTask task; 10 final CodeEmitterTask task;
11 11
12 final ContainerBuilder containerBuilder = new ContainerBuilder(); 12 final ContainerBuilder containerBuilder = new ContainerBuilder();
13 final ClassEmitter classEmitter = new ClassEmitter(); 13 final ClassEmitter classEmitter = new ClassEmitter();
14 final NsmEmitter nsmEmitter = new NsmEmitter(); 14 final NsmEmitter nsmEmitter = new NsmEmitter();
15 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter(); 15 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter();
16 16
17 // TODO(johnniwinther): Wrap these fields in a caching strategy. 17 // TODO(johnniwinther): Wrap these fields in a caching strategy.
18 final Set<ConstantValue> cachedEmittedConstants; 18 final Set<ConstantValue> cachedEmittedConstants;
19 final CodeBuffer cachedEmittedConstantsBuffer = new CodeBuffer(); 19 final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[];
20 final Map<Element, ClassBuilder> cachedClassBuilders; 20 final Map<Element, ClassBuilder> cachedClassBuilders;
21 final Set<Element> cachedElements; 21 final Set<Element> cachedElements;
22 22
23 bool needsClassSupport = false; 23 bool needsClassSupport = false;
24 bool needsMixinSupport = false; 24 bool needsMixinSupport = false;
25 bool needsLazyInitializer = false; 25 bool needsLazyInitializer = false;
26 26
27 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info", 27 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info",
28 /// that is, some function was needed for reflection, had stubs, or had a 28 /// that is, some function was needed for reflection, had stubs, or had a
29 /// super alias. 29 /// super alias.
30 bool needsStructuredMemberInfo = false; 30 bool needsStructuredMemberInfo = false;
31 31
32 final Namer namer; 32 final Namer namer;
33 ConstantEmitter constantEmitter; 33 ConstantEmitter constantEmitter;
34 NativeEmitter get nativeEmitter => task.nativeEmitter; 34 NativeEmitter get nativeEmitter => task.nativeEmitter;
35 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry; 35 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry;
36 36
37 // The full code that is written to each hunk part-file. 37 // The full code that is written to each hunk part-file.
38 Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>(); 38 Map<OutputUnit, CodeOutput> outputBuffers = new Map<OutputUnit, CodeOutput>();
39 39
40 /** Shorter access to [isolatePropertiesName]. Both here in the code, as
41 well as in the generated code. */
42 String isolateProperties;
43 String classesCollector; 40 String classesCollector;
44 Set<ClassElement> get neededClasses => task.neededClasses; 41 Set<ClassElement> get neededClasses => task.neededClasses;
45 Map<OutputUnit, List<ClassElement>> get outputClassLists 42 Map<OutputUnit, List<ClassElement>> get outputClassLists
46 => task.outputClassLists; 43 => task.outputClassLists;
47 Map<OutputUnit, List<ConstantValue>> get outputConstantLists 44 Map<OutputUnit, List<ConstantValue>> get outputConstantLists
48 => task.outputConstantLists; 45 => task.outputConstantLists;
49 final Map<String, String> mangledFieldNames = <String, String>{}; 46 final Map<String, String> mangledFieldNames = <String, String>{};
50 final Map<String, String> mangledGlobalFieldNames = <String, String>{}; 47 final Map<String, String> mangledGlobalFieldNames = <String, String>{};
51 final Set<String> recordedMangledNames = new Set<String>(); 48 final Set<String> recordedMangledNames = new Set<String>();
52 49
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
116 () => new List<jsAst.Expression>()); 113 () => new List<jsAst.Expression>());
117 } 114 }
118 115
119 /// Erases the precompiled information for csp mode for all output units. 116 /// Erases the precompiled information for csp mode for all output units.
120 /// Used by the incremental compiler. 117 /// Used by the incremental compiler.
121 void clearCspPrecompiledNodes() { 118 void clearCspPrecompiledNodes() {
122 _cspPrecompiledFunctions.clear(); 119 _cspPrecompiledFunctions.clear();
123 _cspPrecompiledConstructorNames.clear(); 120 _cspPrecompiledConstructorNames.clear();
124 } 121 }
125 122
126 void addComment(String comment, CodeOutput output) {
127 output.addBuffer(jsAst.prettyPrint(js.comment(comment), compiler));
128 }
129
130 @override 123 @override
131 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { 124 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) {
132 if (constant.isFunction) return true; // Already emitted. 125 if (constant.isFunction) return true; // Already emitted.
133 if (constant.isPrimitive) return true; // Inlined. 126 if (constant.isPrimitive) return true; // Inlined.
134 if (constant.isDummy) return true; // Inlined. 127 if (constant.isDummy) return true; // Inlined.
135 // The name is null when the constant is already a JS constant. 128 // The name is null when the constant is already a JS constant.
136 // TODO(floitsch): every constant should be registered, so that we can 129 // TODO(floitsch): every constant should be registered, so that we can
137 // share the ones that take up too much space (like some strings). 130 // share the ones that take up too much space (like some strings).
138 if (namer.constantName(constant) == null) return true; 131 if (namer.constantName(constant) == null) return true;
139 return false; 132 return false;
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 String get initName => 'init'; 188 String get initName => 'init';
196 189
197 String get makeConstListProperty => namer.internalGlobal('makeConstantList'); 190 String get makeConstListProperty => namer.internalGlobal('makeConstantList');
198 191
199 /// The name of the property that contains all field names. 192 /// The name of the property that contains all field names.
200 /// 193 ///
201 /// This property is added to constructors when isolate support is enabled. 194 /// This property is added to constructors when isolate support is enabled.
202 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__"; 195 static const String FIELD_NAMES_PROPERTY_NAME = r"$__fields__";
203 196
204 /// For deferred loading we communicate the initializers via this global var. 197 /// For deferred loading we communicate the initializers via this global var.
205 final String deferredInitializers = r"$dart_deferred_initializers"; 198 final String deferredInitializers = r"$dart_deferred_initializers$";
206 199
207 /// Contains the global state that is needed to initialize and load a 200 /// Contains the global state that is needed to initialize and load a
208 /// deferred library. 201 /// deferred library.
209 String get globalsHolder => namer.internalGlobal("globalsHolder"); 202 String get globalsHolder => namer.internalGlobal("globalsHolder");
210 203
211 @override 204 @override
212 jsAst.Expression generateEmbeddedGlobalAccess(String global) { 205 jsAst.Expression generateEmbeddedGlobalAccess(String global) {
213 return js(generateEmbeddedGlobalAccessString(global)); 206 return js(generateEmbeddedGlobalAccessString(global));
214 } 207 }
215 208
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 return nativeEmitter.buildNativeInfoHandler(infoAccess, constructorAccess, 329 return nativeEmitter.buildNativeInfoHandler(infoAccess, constructorAccess,
337 subclassReadGenerator, 330 subclassReadGenerator,
338 interceptorsByTagAccess, 331 interceptorsByTagAccess,
339 leafTagsAccess); 332 leafTagsAccess);
340 } 333 }
341 334
342 jsAst.ObjectInitializer generateInterceptedNamesSet() { 335 jsAst.ObjectInitializer generateInterceptedNamesSet() {
343 return interceptorEmitter.generateInterceptedNamesSet(); 336 return interceptorEmitter.generateInterceptedNamesSet();
344 } 337 }
345 338
346 void emitFinishIsolateConstructorInvocation(CodeOutput output) {
347 String isolate = namer.isolateName;
348 output.add("$isolate = $finishIsolateConstructorName($isolate)$N");
349 }
350
351 /// In minified mode we want to keep the name for the most common core types. 339 /// In minified mode we want to keep the name for the most common core types.
352 bool _isNativeTypeNeedingReflectionName(Element element) { 340 bool _isNativeTypeNeedingReflectionName(Element element) {
353 if (!element.isClass) return false; 341 if (!element.isClass) return false;
354 return (element == compiler.intClass || 342 return (element == compiler.intClass ||
355 element == compiler.doubleClass || 343 element == compiler.doubleClass ||
356 element == compiler.numClass || 344 element == compiler.numClass ||
357 element == compiler.stringClass || 345 element == compiler.stringClass ||
358 element == compiler.boolClass || 346 element == compiler.boolClass ||
359 element == compiler.nullClass || 347 element == compiler.nullClass ||
360 element == compiler.listClass); 348 element == compiler.listClass);
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 } 452 }
465 453
466 String namedParametersAsReflectionNames(CallStructure structure) { 454 String namedParametersAsReflectionNames(CallStructure structure) {
467 if (structure.isUnnamed) return ''; 455 if (structure.isUnnamed) return '';
468 String names = structure.getOrderedNamedArguments().join(':'); 456 String names = structure.getOrderedNamedArguments().join(':');
469 return ':$names'; 457 return ':$names';
470 } 458 }
471 459
472 jsAst.Statement buildCspPrecompiledFunctionFor( 460 jsAst.Statement buildCspPrecompiledFunctionFor(
473 OutputUnit outputUnit) { 461 OutputUnit outputUnit) {
474 // TODO(ahe): Compute a hash code. 462 if (compiler.useContentSecurityPolicy) {
475 // TODO(sigurdm): Avoid this precompiled function. Generated 463 // TODO(ahe): Compute a hash code.
476 // constructor-functions and getter/setter functions can be stored in the 464 // TODO(sigurdm): Avoid this precompiled function. Generated
477 // library-description table. Setting properties on these can be moved to 465 // constructor-functions and getter/setter functions can be stored in the
478 // finishClasses. 466 // library-description table. Setting properties on these can be moved to
479 return js.statement(''' 467 // finishClasses.
480 # = function (\$collectedClasses) { 468 return js.statement('''
481 var \$desc; 469 # = function (\$collectedClasses) {
482 #; 470 var \$desc;
483 return #; 471 #;
484 };''', 472 return #;
485 [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED), 473 };''',
486 cspPrecompiledFunctionFor(outputUnit), 474 [generateEmbeddedGlobalAccess(embeddedNames.PRECOMPILED),
487 new jsAst.ArrayInitializer( 475 cspPrecompiledFunctionFor(outputUnit),
488 cspPrecompiledConstructorNamesFor(outputUnit))]); 476 new jsAst.ArrayInitializer(
477 cspPrecompiledConstructorNamesFor(outputUnit))]);
478 } else {
479 return js.comment("Constructors are generated at runtime.");
480 }
489 } 481 }
490 482
491 void assembleClass(Class cls, ClassBuilder enclosingBuilder, 483 void assembleClass(Class cls, ClassBuilder enclosingBuilder,
492 Fragment fragment) { 484 Fragment fragment) {
493 ClassElement classElement = cls.element; 485 ClassElement classElement = cls.element;
494 compiler.withCurrentElement(classElement, () { 486 compiler.withCurrentElement(classElement, () {
495 if (compiler.hasIncrementalSupport) { 487 if (compiler.hasIncrementalSupport) {
496 ClassBuilder cachedBuilder = 488 ClassBuilder cachedBuilder =
497 cachedClassBuilders.putIfAbsent(classElement, () { 489 cachedClassBuilders.putIfAbsent(classElement, () {
498 ClassBuilder builder = new ClassBuilder(classElement, namer); 490 ClassBuilder builder = new ClassBuilder(classElement, namer);
(...skipping 20 matching lines...) Expand all
519 // We need to filter out null-elements for the interceptors. 511 // We need to filter out null-elements for the interceptors.
520 // TODO(floitsch): use the precomputed interceptors here. 512 // TODO(floitsch): use the precomputed interceptors here.
521 if (element == null) continue; 513 if (element == null) continue;
522 ClassBuilder builder = new ClassBuilder(element, namer); 514 ClassBuilder builder = new ClassBuilder(element, namer);
523 containerBuilder.addMemberMethod(method, builder); 515 containerBuilder.addMemberMethod(method, builder);
524 getElementDescriptor(element, fragment).properties 516 getElementDescriptor(element, fragment).properties
525 .addAll(builder.properties); 517 .addAll(builder.properties);
526 } 518 }
527 } 519 }
528 520
529 void emitStaticNonFinalFieldInitializations(CodeOutput output, 521 jsAst.Statement buildStaticNonFinalFieldInitializations(
530 OutputUnit outputUnit) { 522 OutputUnit outputUnit) {
531 void emitInitialization(Element element, jsAst.Expression initialValue) { 523 jsAst.Statement buildInitialization(Element element,
532 jsAst.Expression init = 524 jsAst.Expression initialValue) {
533 js('$isolateProperties.# = #', 525 // Note: `namer.currentIsolate` refers to the isolate properties here.
534 [namer.globalPropertyName(element), initialValue]); 526 return js.statement('${namer.currentIsolate}.# = #',
535 output.addBuffer(jsAst.prettyPrint(init, compiler, 527 [namer.globalPropertyName(element), initialValue]);
536 monitor: compiler.dumpInfoTask));
537 output.add('$N');
538 } 528 }
539 529
540 bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit); 530 bool inMainUnit = (outputUnit == compiler.deferredLoadTask.mainOutputUnit);
541 JavaScriptConstantCompiler handler = backend.constants; 531 JavaScriptConstantCompiler handler = backend.constants;
532 List<jsAst.Statement> parts = <jsAst.Statement>[];
542 533
543 Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit]; 534 Iterable<Element> fields = task.outputStaticNonFinalFieldLists[outputUnit];
544 // If the outputUnit does not contain any static non-final fields, then 535 // If the outputUnit does not contain any static non-final fields, then
545 // [fields] is `null`. 536 // [fields] is `null`.
546 if (fields != null) { 537 if (fields != null) {
547 for (Element element in fields) { 538 for (Element element in fields) {
548 compiler.withCurrentElement(element, () { 539 compiler.withCurrentElement(element, () {
549 ConstantValue constant = handler.getInitialValueFor(element).value; 540 ConstantValue constant = handler.getInitialValueFor(element).value;
550 emitInitialization(element, constantReference(constant)); 541 parts.add(buildInitialization(element, constantReference(constant)));
551 }); 542 });
552 } 543 }
553 } 544 }
554 545
555 if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) { 546 if (inMainUnit && task.outputStaticNonFinalFieldLists.length > 1) {
556 // In the main output-unit we output a stub initializer for deferred 547 // In the main output-unit we output a stub initializer for deferred
557 // variables, so that `isolateProperties` stays a fast object. 548 // variables, so that `isolateProperties` stays a fast object.
558 task.outputStaticNonFinalFieldLists.forEach( 549 task.outputStaticNonFinalFieldLists.forEach(
559 (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) { 550 (OutputUnit fieldsOutputUnit, Iterable<VariableElement> fields) {
560 if (fieldsOutputUnit == outputUnit) return; // Skip the main unit. 551 if (fieldsOutputUnit == outputUnit) return; // Skip the main unit.
561 for (Element element in fields) { 552 for (Element element in fields) {
562 compiler.withCurrentElement(element, () { 553 compiler.withCurrentElement(element, () {
563 emitInitialization(element, jsAst.number(0)); 554 parts.add(buildInitialization(element, jsAst.number(0)));
564 }); 555 });
565 } 556 }
566 }); 557 });
567 } 558 }
559
560 return new jsAst.Block(parts);
568 } 561 }
569 562
570 void emitLazilyInitializedStaticFields(CodeOutput output) { 563 jsAst.Statement buildLazilyInitializedStaticFields() {
571 JavaScriptConstantCompiler handler = backend.constants; 564 JavaScriptConstantCompiler handler = backend.constants;
572 List<VariableElement> lazyFields = 565 List<VariableElement> lazyFields =
573 handler.getLazilyInitializedFieldsForEmission(); 566 handler.getLazilyInitializedFieldsForEmission();
574 if (!lazyFields.isEmpty) { 567 if (lazyFields.isNotEmpty) {
575 needsLazyInitializer = true; 568 needsLazyInitializer = true;
576 List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields); 569 List<jsAst.Expression> laziesInfo = buildLaziesInfo(lazyFields);
577 jsAst.Statement code = js.statement(''' 570 return js.statement('''
578 (function(lazies) { 571 (function(lazies) {
579 if (#notInMinifiedMode) { 572 if (#notInMinifiedMode) {
580 var descriptorLength = 4; 573 var descriptorLength = 4;
581 } else { 574 } else {
582 var descriptorLength = 3; 575 var descriptorLength = 3;
583 } 576 }
584 577
585 for (var i = 0; i < lazies.length; i += descriptorLength) { 578 for (var i = 0; i < lazies.length; i += descriptorLength) {
586 var fieldName = lazies [i]; 579 var fieldName = lazies [i];
587 var getterName = lazies[i + 1]; 580 var getterName = lazies[i + 1];
588 var lazyValue = lazies[i + 2]; 581 var lazyValue = lazies[i + 2];
589 if (#notInMinifiedMode) { 582 if (#notInMinifiedMode) {
590 var staticName = lazies[i + 3]; 583 var staticName = lazies[i + 3];
591 } 584 }
592 585
593 // We build the lazy-check here: 586 // We build the lazy-check here:
594 // lazyInitializer(fieldName, getterName, lazyValue, staticName); 587 // lazyInitializer(fieldName, getterName, lazyValue, staticName);
595 // 'staticName' is used for error reporting in non-minified mode. 588 // 'staticName' is used for error reporting in non-minified mode.
596 // 'lazyValue' must be a closure that constructs the initial value. 589 // 'lazyValue' must be a closure that constructs the initial value.
597 if (#notInMinifiedMode) { 590 if (#notInMinifiedMode) {
598 #lazy(fieldName, getterName, lazyValue, staticName); 591 #lazy(fieldName, getterName, lazyValue, staticName);
599 } else { 592 } else {
600 #lazy(fieldName, getterName, lazyValue); 593 #lazy(fieldName, getterName, lazyValue);
601 } 594 }
602 } 595 }
603 })(#laziesInfo) 596 })(#laziesInfo)
604 ''', {'notInMinifiedMode': !compiler.enableMinification, 597 ''', {'notInMinifiedMode': !compiler.enableMinification,
605 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo), 598 'laziesInfo': new jsAst.ArrayInitializer(laziesInfo),
606 'lazy': js(lazyInitializerName)}); 599 'lazy': js(lazyInitializerName)});
607 600 } else {
608 output.addBuffer( 601 return js.comment("No lazy statics.");
609 jsAst.prettyPrint(code, compiler, monitor: compiler.dumpInfoTask));
610 output.add("$N");
611 } 602 }
612 } 603 }
613 604
614 List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) { 605 List<jsAst.Expression> buildLaziesInfo(List<VariableElement> lazies) {
615 List<jsAst.Expression> laziesInfo = <jsAst.Expression>[]; 606 List<jsAst.Expression> laziesInfo = <jsAst.Expression>[];
616 for (VariableElement element in Elements.sortedByPosition(lazies)) { 607 for (VariableElement element in Elements.sortedByPosition(lazies)) {
617 jsAst.Expression code = backend.generatedCode[element]; 608 jsAst.Expression code = backend.generatedCode[element];
618 // The code is null if we ended up not needing the lazily 609 // The code is null if we ended up not needing the lazily
619 // initialized field after all because of constant folding 610 // initialized field after all because of constant folding
620 // before code generation. 611 // before code generation.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
666 } else { 657 } else {
667 return js('#(#,#,#,#)', 658 return js('#(#,#,#,#)',
668 [js(lazyInitializerName), 659 [js(lazyInitializerName),
669 js.string(namer.globalPropertyName(element)), 660 js.string(namer.globalPropertyName(element)),
670 js.string(namer.lazyInitializerName(element)), 661 js.string(namer.lazyInitializerName(element)),
671 code, 662 code,
672 js.string(element.name)]); 663 js.string(element.name)]);
673 } 664 }
674 } 665 }
675 666
676 void emitMetadata(Program program, CodeOutput output, OutputUnit outputUnit) { 667 jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) {
668 List<jsAst.Statement> parts = <jsAst.Statement>[];
677 669
678 jsAst.Expression constructList(List<jsAst.Expression> list) { 670 jsAst.Expression constructList(List<jsAst.Expression> list) {
679 return new jsAst.ArrayInitializer(list == null ? [] : list); 671 return new jsAst.ArrayInitializer(list == null ? [] : list);
680 } 672 }
681 673
682 List<jsAst.Expression> types = program.metadataTypes[outputUnit]; 674 List<jsAst.Expression> types = program.metadataTypes[outputUnit];
683 675
684 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) { 676 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) {
685 jsAst.Expression metadataAccess = 677 jsAst.Expression metadataAccess =
686 generateEmbeddedGlobalAccess(embeddedNames.METADATA); 678 generateEmbeddedGlobalAccess(embeddedNames.METADATA);
687 jsAst.Expression typesAccess = 679 jsAst.Expression typesAccess =
688 generateEmbeddedGlobalAccess(embeddedNames.TYPES); 680 generateEmbeddedGlobalAccess(embeddedNames.TYPES);
689 681
690 output.addBuffer( 682 parts..add(js.statement('# = #;', [metadataAccess,
691 jsAst.prettyPrint(new jsAst.Block([ 683 constructList(program.metadata)]))
692 js.statement('# = #;', [metadataAccess, 684 ..add(js.statement('# = #;', [typesAccess, constructList(types)]));
693 constructList(program.metadata)]),
694 js.statement('# = #;', [typesAccess, constructList(types)])]),
695 compiler, monitor: compiler.dumpInfoTask));
696 output.add(n);
697 } else if (types != null) { 685 } else if (types != null) {
698 output.addBuffer( 686 parts.add(js.statement('var ${namer.deferredTypesName} = #;',
699 jsAst.prettyPrint( 687 constructList(types)));
700 js.statement('var ${namer.deferredTypesName} = #;',
701 constructList(types)),
702 compiler, monitor: compiler.dumpInfoTask));
703 if (compiler.enableMinification) {
704 output.add('\n');
705 }
706 } 688 }
689 return new jsAst.Block(parts);
707 } 690 }
708 691
709 void emitCompileTimeConstants(CodeOutput output, 692 jsAst.Statement buildCompileTimeConstants(List<Constant> constants,
710 List<Constant> constants, 693 {bool isMainFragment}) {
711 {bool isMainFragment}) {
712 assert(isMainFragment != null); 694 assert(isMainFragment != null);
713 695
714 if (constants.isEmpty) return; 696 if (constants.isEmpty) return js.comment("No constants in program.");
715 CodeOutput constantOutput = output; 697 List<jsAst.Statement> parts = <jsAst.Statement>[];
716 if (compiler.hasIncrementalSupport && isMainFragment) { 698 if (compiler.hasIncrementalSupport && isMainFragment) {
717 constantOutput = cachedEmittedConstantsBuffer; 699 parts = cachedEmittedConstantsAst;
718 } 700 }
719 for (Constant constant in constants) { 701 for (Constant constant in constants) {
720 ConstantValue constantValue = constant.value; 702 ConstantValue constantValue = constant.value;
721 if (compiler.hasIncrementalSupport && isMainFragment) { 703 if (compiler.hasIncrementalSupport && isMainFragment) {
722 if (cachedEmittedConstants.contains(constantValue)) continue; 704 if (cachedEmittedConstants.contains(constantValue)) continue;
723 cachedEmittedConstants.add(constantValue); 705 cachedEmittedConstants.add(constantValue);
724 } 706 }
725 jsAst.Expression init = buildConstantInitializer(constantValue); 707 parts.add(buildConstantInitializer(constantValue));
726 constantOutput.addBuffer(
727 jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
728 constantOutput.add('$N');
729 } 708 }
730 if (compiler.hasIncrementalSupport && isMainFragment) { 709
731 output.addBuffer(constantOutput); 710 return new jsAst.Block(parts);
732 }
733 } 711 }
734 712
735 jsAst.Expression buildConstantInitializer(ConstantValue constant) { 713 jsAst.Statement buildConstantInitializer(ConstantValue constant) {
736 String name = namer.constantName(constant); 714 String name = namer.constantName(constant);
737 return js('#.# = #', 715 return js.statement('#.# = #',
738 [namer.globalObjectForConstant(constant), name, 716 [namer.globalObjectForConstant(constant), name,
739 constantInitializerExpression(constant)]); 717 constantInitializerExpression(constant)]);
740 } 718 }
741 719
742 jsAst.Template get makeConstantListTemplate { 720 jsAst.Template get makeConstantListTemplate {
743 // TODO(floitsch): there is no harm in caching the template. 721 // TODO(floitsch): there is no harm in caching the template.
744 return jsAst.js.uncachedExpressionTemplate( 722 return jsAst.js.uncachedExpressionTemplate(
745 '${namer.isolateName}.$makeConstListProperty(#)'); 723 '${namer.isolateName}.$makeConstListProperty(#)');
746 } 724 }
747 725
748 void emitMakeConstantList(CodeOutput output) { 726 jsAst.Statement buildMakeConstantList() {
749 output.addBuffer( 727 if (task.outputContainsConstantList) {
750 jsAst.prettyPrint( 728 return js.statement(r'''
751 // Functions are stored in the hidden class and not as properties in 729 // Functions are stored in the hidden class and not as properties in
752 // the object. We never actually look at the value, but only want 730 // the object. We never actually look at the value, but only want
753 // to know if the property exists. 731 // to know if the property exists.
754 js.statement(r'''#.# = function(list) { 732 #.# = function (list) {
755 list.immutable$list = Array; 733 list.immutable$list = Array;
756 list.fixed$length = Array; 734 list.fixed$length = Array;
757 return list; 735 return list;
758 }''', 736 }''',
759 [namer.isolateName, makeConstListProperty]), 737 [namer.isolateName, makeConstListProperty]);
760 compiler, monitor: compiler.dumpInfoTask)); 738 } else {
761 output.add(N); 739 return js.comment("Output contains no constant list.");
740 }
762 } 741 }
763 742
764 void emitFunctionThatReturnsNull(CodeOutput output) { 743 jsAst.Statement buildFunctionThatReturnsNull() {
765 output.addBuffer( 744 return js.statement('# = function() {}',
766 jsAst.prettyPrint( 745 [backend.rti.getFunctionThatReturnsNullName]);
767 js.statement('#.# = function() {}',
768 [backend.namer.currentIsolate,
769 backend.rti.getFunctionThatReturnsNullName]),
770 compiler, monitor: compiler.dumpInfoTask));
771 output.add(N);
772 } 746 }
773 747
774 jsAst.Expression generateFunctionThatReturnsNull() { 748 jsAst.Expression generateFunctionThatReturnsNull() {
775 return js("#.#", [backend.namer.currentIsolate, 749 return js("#", [backend.rti.getFunctionThatReturnsNullName]);
776 backend.rti.getFunctionThatReturnsNullName]);
777 } 750 }
778 751
779 emitMain(CodeOutput output, jsAst.Statement invokeMain) { 752 buildMain(jsAst.Statement invokeMain) {
780 if (compiler.isMockCompilation) return; 753 if (compiler.isMockCompilation) return js.comment("Mock compilation");
754
755 List<jsAst.Statement> parts = <jsAst.Statement>[];
781 756
782 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) { 757 if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
783 jsAst.Statement nativeBoilerPlate = 758 parts.add(
784 NativeGenerator.generateIsolateAffinityTagInitialization( 759 NativeGenerator.generateIsolateAffinityTagInitialization(
785 backend, 760 backend,
786 generateEmbeddedGlobalAccess, 761 generateEmbeddedGlobalAccess,
787 js("convertToFastObject", [])); 762 js("convertToFastObject", [])));
788 output.addBuffer(jsAst.prettyPrint(
789 nativeBoilerPlate, compiler, monitor: compiler.dumpInfoTask));
790 } 763 }
791 764
792 output.add(';'); 765 parts..add(js.comment('BEGIN invoke [main].'))
793 addComment('BEGIN invoke [main].', output); 766 ..add(invokeMain)
794 output.addBuffer(jsAst.prettyPrint(invokeMain, 767 ..add(js.comment('END invoke [main].'));
795 compiler, monitor: compiler.dumpInfoTask)); 768
796 output.add(N); 769 return new jsAst.Block(parts);
797 addComment('END invoke [main].', output);
798 } 770 }
799 771
800 void emitInitFunction(CodeOutput output) { 772 jsAst.Statement buildInitFunction() {
801 jsAst.Expression allClassesAccess = 773 jsAst.Expression allClassesAccess =
802 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES); 774 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
803 jsAst.Expression getTypeFromNameAccess = 775 jsAst.Expression getTypeFromNameAccess =
804 generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME); 776 generateEmbeddedGlobalAccess(embeddedNames.GET_TYPE_FROM_NAME);
805 jsAst.Expression interceptorsByTagAccess = 777 jsAst.Expression interceptorsByTagAccess =
806 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG); 778 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
807 jsAst.Expression leafTagsAccess = 779 jsAst.Expression leafTagsAccess =
808 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS); 780 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
809 jsAst.Expression finishedClassesAccess = 781 jsAst.Expression finishedClassesAccess =
810 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES); 782 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
811 jsAst.Expression cyclicThrow = 783 jsAst.Expression cyclicThrow =
812 staticFunctionAccess(backend.getCyclicThrowHelper()); 784 staticFunctionAccess(backend.getCyclicThrowHelper());
813 jsAst.Expression laziesAccess = 785 jsAst.Expression laziesAccess =
814 generateEmbeddedGlobalAccess(embeddedNames.LAZIES); 786 generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
815 787
816 jsAst.FunctionDeclaration decl = js.statement(''' 788 return js.statement('''
817 function init() { 789 function init() {
818 $isolateProperties = Object.create(null); 790 $isolatePropertiesName = Object.create(null);
819 #allClasses = Object.create(null); 791 #allClasses = Object.create(null);
820 #getTypeFromName = function(name) {return #allClasses[name];}; 792 #getTypeFromName = function(name) {return #allClasses[name];};
821 #interceptorsByTag = Object.create(null); 793 #interceptorsByTag = Object.create(null);
822 #leafTags = Object.create(null); 794 #leafTags = Object.create(null);
823 #finishedClasses = Object.create(null); 795 #finishedClasses = Object.create(null);
824 796
825 if (#needsLazyInitializer) { 797 if (#needsLazyInitializer) {
826 // [staticName] is only provided in non-minified mode. If missing, we 798 // [staticName] is only provided in non-minified mode. If missing, we
827 // fall back to [fieldName]. Likewise, [prototype] is optional and 799 // fall back to [fieldName]. Likewise, [prototype] is optional and
828 // defaults to the isolateProperties object. 800 // defaults to the isolateProperties object.
829 $lazyInitializerName = function (fieldName, getterName, lazyValue, 801 $lazyInitializerName = function (fieldName, getterName, lazyValue,
830 staticName, prototype) { 802 staticName, prototype) {
831 if (!#lazies) #lazies = Object.create(null); 803 if (!#lazies) #lazies = Object.create(null);
832 #lazies[fieldName] = getterName; 804 #lazies[fieldName] = getterName;
833 805
834 // 'prototype' will be undefined except if we are doing an update 806 // 'prototype' will be undefined except if we are doing an update
835 // during incremental compilation. In this case we put the lazy 807 // during incremental compilation. In this case we put the lazy
836 // field directly on the isolate instead of the isolateProperties. 808 // field directly on the isolate instead of the isolateProperties.
837 prototype = prototype || $isolateProperties; 809 prototype = prototype || $isolatePropertiesName;
838 var sentinelUndefined = {}; 810 var sentinelUndefined = {};
839 var sentinelInProgress = {}; 811 var sentinelInProgress = {};
840 prototype[fieldName] = sentinelUndefined; 812 prototype[fieldName] = sentinelUndefined;
841 813
842 prototype[getterName] = function () { 814 prototype[getterName] = function () {
843 var result = this[fieldName]; 815 var result = this[fieldName];
844 try { 816 try {
845 if (result === sentinelUndefined) { 817 if (result === sentinelUndefined) {
846 this[fieldName] = sentinelInProgress; 818 this[fieldName] = sentinelInProgress;
847 819
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
926 'interceptorsByTag': interceptorsByTagAccess, 898 'interceptorsByTag': interceptorsByTagAccess,
927 'leafTags': leafTagsAccess, 899 'leafTags': leafTagsAccess,
928 'finishedClasses': finishedClassesAccess, 900 'finishedClasses': finishedClassesAccess,
929 'needsLazyInitializer': needsLazyInitializer, 901 'needsLazyInitializer': needsLazyInitializer,
930 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow, 902 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow,
931 'isolatePropertiesName': namer.isolatePropertiesName, 903 'isolatePropertiesName': namer.isolatePropertiesName,
932 'outputContainsConstantList': task.outputContainsConstantList, 904 'outputContainsConstantList': task.outputContainsConstantList,
933 'makeConstListProperty': makeConstListProperty, 905 'makeConstListProperty': makeConstListProperty,
934 'hasIncrementalSupport': compiler.hasIncrementalSupport, 906 'hasIncrementalSupport': compiler.hasIncrementalSupport,
935 'lazyInitializerProperty': lazyInitializerProperty,}); 907 'lazyInitializerProperty': lazyInitializerProperty,});
936
937 output.addBuffer(
938 jsAst.prettyPrint(decl, compiler, monitor: compiler.dumpInfoTask));
939 if (compiler.enableMinification) {
940 output.add('\n');
941 }
942 } 908 }
943 909
944 void emitConvertToFastObjectFunction(CodeOutput output) { 910 jsAst.Statement buildConvertToFastObjectFunction() {
945 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; 911 List<jsAst.Statement> debugCode = <jsAst.Statement>[];
946 if (DEBUG_FAST_OBJECTS) { 912 if (DEBUG_FAST_OBJECTS) {
947 debugCode.add(js.statement(r''' 913 debugCode.add(js.statement(r'''
948 // The following only works on V8 when run with option 914 // The following only works on V8 when run with option
949 // "--allow-natives-syntax". We use'new Function' because the 915 // "--allow-natives-syntax". We use'new Function' because the
950 // miniparser does not understand V8 native syntax. 916 // miniparser does not understand V8 native syntax.
951 if (typeof print === "function") { 917 if (typeof print === "function") {
952 var HasFastProperties = 918 var HasFastProperties =
953 new Function("a", "return %HasFastProperties(a)"); 919 new Function("a", "return %HasFastProperties(a)");
954 print("Size of global object: " 920 print("Size of global object: "
955 + String(Object.getOwnPropertyNames(properties).length) 921 + String(Object.getOwnPropertyNames(properties).length)
956 + ", fast properties " + HasFastProperties(properties)); 922 + ", fast properties " + HasFastProperties(properties));
957 }''')); 923 }'''));
958 } 924 }
959 925
960 jsAst.Statement convertToFastObject = js.statement(r''' 926 return js.statement(r'''
961 function convertToFastObject(properties) { 927 function convertToFastObject(properties) {
962 // Create an instance that uses 'properties' as prototype. This should 928 // Create an instance that uses 'properties' as prototype. This should
963 // make 'properties' a fast object. 929 // make 'properties' a fast object.
964 function MyClass() {}; 930 function MyClass() {};
965 MyClass.prototype = properties; 931 MyClass.prototype = properties;
966 new MyClass(); 932 new MyClass();
967 #; 933 #;
968 return properties; 934 return properties;
969 }''', [debugCode]); 935 }''', [debugCode]);
970
971 output.addBuffer(jsAst.prettyPrint(convertToFastObject, compiler));
972 output.add(N);
973 } 936 }
974 937
975 void emitConvertToSlowObjectFunction(CodeOutput output) { 938 jsAst.Statement buildConvertToSlowObjectFunction() {
976 jsAst.Statement convertToSlowObject = js.statement(r''' 939 return js.statement(r'''
977 function convertToSlowObject(properties) { 940 function convertToSlowObject(properties) {
978 // Add and remove a property to make the object transition into hashmap 941 // Add and remove a property to make the object transition into hashmap
979 // mode. 942 // mode.
980 properties.__MAGIC_SLOW_PROPERTY = 1; 943 properties.__MAGIC_SLOW_PROPERTY = 1;
981 delete properties.__MAGIC_SLOW_PROPERTY; 944 delete properties.__MAGIC_SLOW_PROPERTY;
982 return properties; 945 return properties;
983 }'''); 946 }''');
984
985 output.addBuffer(jsAst.prettyPrint(convertToSlowObject, compiler));
986 output.add(N);
987 } 947 }
988 948
989 void emitSupportsDirectProtoAccess(CodeOutput output) { 949 jsAst.Statement buildSupportsDirectProtoAccess() {
990 jsAst.Statement supportsDirectProtoAccess; 950 jsAst.Statement supportsDirectProtoAccess;
991 951
992 if (compiler.hasIncrementalSupport) { 952 if (compiler.hasIncrementalSupport) {
993 supportsDirectProtoAccess = js.statement(r''' 953 supportsDirectProtoAccess = js.statement(r'''
994 var supportsDirectProtoAccess = false; 954 var supportsDirectProtoAccess = false;
995 '''); 955 ''');
996 } else { 956 } else {
997 supportsDirectProtoAccess = js.statement(r''' 957 supportsDirectProtoAccess = js.statement(r'''
998 var supportsDirectProtoAccess = (function () { 958 var supportsDirectProtoAccess = (function () {
999 var cls = function () {}; 959 var cls = function () {};
1000 cls.prototype = {'p': {}}; 960 cls.prototype = {'p': {}};
1001 var object = new cls(); 961 var object = new cls();
1002 return object.__proto__ && 962 return object.__proto__ &&
1003 object.__proto__.p === cls.prototype.p; 963 object.__proto__.p === cls.prototype.p;
1004 })(); 964 })();
1005 '''); 965 ''');
1006 } 966 }
1007 967
1008 output.addBuffer(jsAst.prettyPrint(supportsDirectProtoAccess, compiler)); 968 return supportsDirectProtoAccess;
1009 output.add(N);
1010 } 969 }
1011 970
1012 jsAst.Expression generateLibraryDescriptor(LibraryElement library, 971 jsAst.Expression generateLibraryDescriptor(LibraryElement library,
1013 Fragment fragment) { 972 Fragment fragment) {
1014 var uri = ""; 973 var uri = "";
1015 if (!compiler.enableMinification || backend.mustPreserveUris) { 974 if (!compiler.enableMinification || backend.mustPreserveUris) {
1016 uri = library.canonicalUri; 975 uri = library.canonicalUri;
1017 if (uri.scheme == 'file' && compiler.outputUri != null) { 976 if (uri.scheme == 'file' && compiler.outputUri != null) {
1018 uri = relativize(compiler.outputUri, library.canonicalUri, false); 977 uri = relativize(compiler.outputUri, library.canonicalUri, false);
1019 } 978 }
(...skipping 19 matching lines...) Expand all
1039 initializer = descriptor.toObjectInitializer(); 998 initializer = descriptor.toObjectInitializer();
1040 } 999 }
1041 1000
1042 compiler.dumpInfoTask.registerElementAst(library, metadata); 1001 compiler.dumpInfoTask.registerElementAst(library, metadata);
1043 compiler.dumpInfoTask.registerElementAst(library, initializer); 1002 compiler.dumpInfoTask.registerElementAst(library, initializer);
1044 1003
1045 List<jsAst.Expression> parts = <jsAst.Expression>[]; 1004 List<jsAst.Expression> parts = <jsAst.Expression>[];
1046 parts..add(js.string(libraryName)) 1005 parts..add(js.string(libraryName))
1047 ..add(js.string(uri.toString())) 1006 ..add(js.string(uri.toString()))
1048 ..add(metadata == null ? new jsAst.ArrayHole() : metadata) 1007 ..add(metadata == null ? new jsAst.ArrayHole() : metadata)
1049 ..add(js.name(namer.globalObjectFor(library))) 1008 ..add(js('#', namer.globalObjectFor(library)))
1050 ..add(initializer); 1009 ..add(initializer);
1051 if (library == compiler.mainApp) { 1010 if (library == compiler.mainApp) {
1052 parts.add(js.number(1)); 1011 parts.add(js.number(1));
1053 } 1012 }
1054 1013
1055 return new jsAst.ArrayInitializer(parts); 1014 return new jsAst.ArrayInitializer(parts);
1056 } 1015 }
1057 1016
1058 void assemblePrecompiledConstructor(OutputUnit outputUnit, 1017 void assemblePrecompiledConstructor(OutputUnit outputUnit,
1059 String constructorName, 1018 String constructorName,
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
1125 String constructorName = mangledName; 1084 String constructorName = mangledName;
1126 jsAst.Expression constructorAst = js('function() {}'); 1085 jsAst.Expression constructorAst = js('function() {}');
1127 List<String> fieldNames = []; 1086 List<String> fieldNames = [];
1128 assemblePrecompiledConstructor(mainOutputUnit, 1087 assemblePrecompiledConstructor(mainOutputUnit,
1129 constructorName, 1088 constructorName,
1130 constructorAst, 1089 constructorAst,
1131 fieldNames); 1090 fieldNames);
1132 } 1091 }
1133 } 1092 }
1134 1093
1135 void emitMangledNames(CodeOutput output) { 1094 jsAst.Statement buildGlobalObjectSetup(bool isProgramSplit) {
1095 List<jsAst.Statement> parts = <jsAst.Statement>[];
1096
1097 parts.add(js.comment("""
1098 // The global objects start as so-called "slow objects". For V8, this
1099 // means that it won't try to make map transitions as we add properties
1100 // to these objects. Later on, we attempt to turn these objects into
1101 // fast objects by calling "convertToFastObject" (see
1102 // [emitConvertToFastObjectFunction]).
1103 """));
1104
1105 for (String globalObject in Namer.reservedGlobalObjectNames) {
1106 if (isProgramSplit) {
1107 String template =
1108 "var #globalObject = #globalsHolder.#globalObject = map();";
1109 parts.add(js.statement(template, {"globalObject": globalObject,
1110 "globalsHolder": globalsHolder}));
1111 } else {
1112 parts.add(js.statement("var #globalObject = map();",
1113 {"globalObject": globalObject}));
1114 }
1115
1116 }
1117
1118 return new jsAst.Block(parts);
1119 }
1120
1121 jsAst.Statement buildConvertGlobalObjectToFastObjects() {
1122 List<jsAst.Statement> parts = <jsAst.Statement>[];
1123
1124 for (String globalObject in Namer.reservedGlobalObjectNames) {
1125 parts.add(js.statement(
1126 '#globalObject = convertToFastObject(#globalObject);',
1127 {"globalObject": globalObject}));
1128 }
1129
1130 return new jsAst.Block(parts);
1131 }
1132
1133 jsAst.Statement buildDebugFastObjectCode() {
1134 List<jsAst.Statement> parts = <jsAst.Statement>[];
1135
1136 if (DEBUG_FAST_OBJECTS) {
1137 parts.add(js.statement(r'''
1138 // The following only works on V8 when run with option
1139 // "--allow-natives-syntax". We use'new Function' because the
1140 // miniparser does not understand V8 native syntax.
1141 if (typeof print === "function") {
1142 var HasFastProperties =
1143 new Function("a", "return %HasFastProperties(a)");
1144 print("Size of global helper object: "
1145 + String(Object.getOwnPropertyNames(H).length)
1146 + ", fast properties " + HasFastProperties(H));
1147 print("Size of global platform object: "
1148 + String(Object.getOwnPropertyNames(P).length)
1149 + ", fast properties " + HasFastProperties(P));
1150 print("Size of global dart:html object: "
1151 + String(Object.getOwnPropertyNames(W).length)
1152 + ", fast properties " + HasFastProperties(W));
1153 print("Size of isolate properties object: "
1154 + String(Object.getOwnPropertyNames($).length)
1155 + ", fast properties " + HasFastProperties($));
1156 print("Size of constant object: "
1157 + String(Object.getOwnPropertyNames(C).length)
1158 + ", fast properties " + HasFastProperties(C));
1159 var names = Object.getOwnPropertyNames($);
1160 for (var i = 0; i < names.length; i++) {
1161 print("$." + names[i]);
1162 }
1163 }
1164 '''));
1165
1166 for (String object in Namer.userGlobalObjects) {
1167 parts.add(js.statement('''
1168 if (typeof print === "function") {
1169 print("Size of " + #objectString + ": "
1170 + String(Object.getOwnPropertyNames(#object).length)
1171 + ", fast properties " + HasFastProperties(#object));
1172 }
1173 ''', {"object": object, "objectString": js.string(object)}));
1174 }
1175 }
1176
1177 return new jsAst.Block(parts);
1178 }
1179
1180 jsAst.Statement buildMangledNames() {
1181 List<jsAst.Statement> parts = <jsAst.Statement>[];
1182
1136 if (!mangledFieldNames.isEmpty) { 1183 if (!mangledFieldNames.isEmpty) {
1137 var keys = mangledFieldNames.keys.toList(); 1184 var keys = mangledFieldNames.keys.toList();
1138 keys.sort(); 1185 keys.sort();
1139 var properties = []; 1186 var properties = [];
1140 for (String key in keys) { 1187 for (String key in keys) {
1141 var value = js.string('${mangledFieldNames[key]}'); 1188 var value = js.string('${mangledFieldNames[key]}');
1142 properties.add(new jsAst.Property(js.string(key), value)); 1189 properties.add(new jsAst.Property(js.string(key), value));
1143 } 1190 }
1144 1191
1145 jsAst.Expression mangledNamesAccess = 1192 jsAst.Expression mangledNamesAccess =
1146 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES); 1193 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_NAMES);
1147 var map = new jsAst.ObjectInitializer(properties); 1194 var map = new jsAst.ObjectInitializer(properties);
1148 output.addBuffer( 1195 parts.add(js.statement('# = #', [mangledNamesAccess, map]));
1149 jsAst.prettyPrint(
1150 js.statement('# = #', [mangledNamesAccess, map]),
1151 compiler,
1152 monitor: compiler.dumpInfoTask));
1153 if (compiler.enableMinification) {
1154 output.add(';');
1155 }
1156 } 1196 }
1197
1157 if (!mangledGlobalFieldNames.isEmpty) { 1198 if (!mangledGlobalFieldNames.isEmpty) {
1158 var keys = mangledGlobalFieldNames.keys.toList(); 1199 var keys = mangledGlobalFieldNames.keys.toList();
1159 keys.sort(); 1200 keys.sort();
1160 var properties = []; 1201 var properties = [];
1161 for (String key in keys) { 1202 for (String key in keys) {
1162 var value = js.string('${mangledGlobalFieldNames[key]}'); 1203 var value = js.string('${mangledGlobalFieldNames[key]}');
1163 properties.add(new jsAst.Property(js.string(key), value)); 1204 properties.add(new jsAst.Property(js.string(key), value));
1164 } 1205 }
1165 jsAst.Expression mangledGlobalNamesAccess = 1206 jsAst.Expression mangledGlobalNamesAccess =
1166 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); 1207 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES);
1167 var map = new jsAst.ObjectInitializer(properties); 1208 var map = new jsAst.ObjectInitializer(properties);
1168 output.addBuffer( 1209 parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map]));
1169 jsAst.prettyPrint(
1170 js.statement('# = #', [mangledGlobalNamesAccess, map]),
1171 compiler,
1172 monitor: compiler.dumpInfoTask));
1173 if (compiler.enableMinification) {
1174 output.add(';');
1175 }
1176 } 1210 }
1211
1212 return new jsAst.Block(parts);
1177 } 1213 }
1178 1214
1179 void checkEverythingEmitted(Iterable<Element> elements) { 1215 void checkEverythingEmitted(Iterable<Element> elements) {
1180 List<Element> pendingStatics; 1216 List<Element> pendingStatics;
1181 if (!compiler.hasIncrementalSupport) { 1217 if (!compiler.hasIncrementalSupport) {
1182 pendingStatics = 1218 pendingStatics =
1183 Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); 1219 Elements.sortedByPosition(elements.where((e) => !e.isLibrary));
1184 1220
1185 pendingStatics.forEach((element) => 1221 pendingStatics.forEach((element) =>
1186 compiler.reportInfo( 1222 compiler.reportInfo(
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1228 codeOutputListeners = <CodeOutputListener>[lineColumnCollector]; 1264 codeOutputListeners = <CodeOutputListener>[lineColumnCollector];
1229 } 1265 }
1230 1266
1231 CodeOutput mainOutput = 1267 CodeOutput mainOutput =
1232 new StreamCodeOutput(compiler.outputProvider('', 'js'), 1268 new StreamCodeOutput(compiler.outputProvider('', 'js'),
1233 codeOutputListeners); 1269 codeOutputListeners);
1234 outputBuffers[mainOutputUnit] = mainOutput; 1270 outputBuffers[mainOutputUnit] = mainOutput;
1235 1271
1236 bool isProgramSplit = program.isSplit; 1272 bool isProgramSplit = program.isSplit;
1237 1273
1238 mainOutput.add(buildGeneratedBy()); 1274 List<jsAst.Statement> statements = <jsAst.Statement>[];
1239 addComment(HOOKS_API_USAGE, mainOutput); 1275
1276 statements..add(buildGeneratedBy())
1277 ..add(js.comment(HOOKS_API_USAGE));
1240 1278
1241 if (isProgramSplit) { 1279 if (isProgramSplit) {
1242 /// For deferred loading we communicate the initializers via this global 1280 /// For deferred loading we communicate the initializers via this global
1243 /// variable. The deferred hunks will add their initialization to this. 1281 /// variable. The deferred hunks will add their initialization to this.
1244 /// The semicolon is important in minified mode, without it the 1282 /// The semicolon is important in minified mode, without it the
1245 /// following parenthesis looks like a call to the object literal. 1283 /// following parenthesis looks like a call to the object literal.
1246 mainOutput.add( 1284 statements.add(
1247 'self.${deferredInitializers} = self.${deferredInitializers} || ' 1285 js.statement('self.#deferredInitializers = '
1248 'Object.create(null);$n'); 1286 'self.#deferredInitializers || Object.create(null);',
1287 {'deferredInitializers': deferredInitializers}));
1249 } 1288 }
1250 1289
1251 // Using a named function here produces easier to read stack traces in 1290 // Collect the AST for the decriptors
1252 // Chrome/V8.
1253 mainOutput.add('(function(${namer.currentIsolate})$_{\n');
1254 emitSupportsDirectProtoAccess(mainOutput);
1255 if (compiler.hasIncrementalSupport) {
1256 mainOutput.addBuffer(jsAst.prettyPrint(js.statement(
1257 """
1258 {
1259 #helper = #helper || Object.create(null);
1260 #helper.patch = function(a) { eval(a)};
1261 #helper.schemaChange = #schemaChange;
1262 #helper.addMethod = #addMethod;
1263 #helper.extractStubs = function(array, name, isStatic, originalDescriptor) {
1264 var descriptor = Object.create(null);
1265 this.addStubs(descriptor, array, name, isStatic, []);
1266 return descriptor;
1267 };
1268 }""",
1269 { 'helper': js('this.#', [namer.incrementalHelperName]),
1270 'schemaChange': buildSchemaChangeFunction(),
1271 'addMethod': buildIncrementalAddMethod() }), compiler));
1272 }
1273 if (isProgramSplit) {
1274 /// We collect all the global state, so it can be passed to the
1275 /// initializer of deferred files.
1276 mainOutput.add('var ${globalsHolder}$_=${_}Object.create(null)$N');
1277 }
1278
1279 jsAst.Statement mapFunction = js.statement('''
1280 // [map] returns an object that V8 shouldn't try to optimize with a hidden
1281 // class. This prevents a potential performance problem where V8 tries to build
1282 // a hidden class for an object used as a hashMap.
1283 // It requires fewer characters to declare a variable as a parameter than
1284 // with `var`.
1285 function map(x) {
1286 x = Object.create(null);
1287 x.x = 0;
1288 delete x.x;
1289 return x;
1290 }
1291 ''');
1292 mainOutput.addBuffer(jsAst.prettyPrint(mapFunction, compiler));
1293 for (String globalObject in Namer.reservedGlobalObjectNames) {
1294 // The global objects start as so-called "slow objects". For V8, this
1295 // means that it won't try to make map transitions as we add properties
1296 // to these objects. Later on, we attempt to turn these objects into
1297 // fast objects by calling "convertToFastObject" (see
1298 // [emitConvertToFastObjectFunction]).
1299 mainOutput.add('var ${globalObject}$_=${_}');
1300 if(isProgramSplit) {
1301 mainOutput.add('${globalsHolder}.$globalObject$_=${_}');
1302 }
1303 mainOutput.add('map()$N');
1304 }
1305
1306 mainOutput.add('function ${namer.isolateName}()$_{}\n');
1307 if (isProgramSplit) {
1308 mainOutput.add(
1309 '${globalsHolder}.${namer.isolateName}$_=$_${namer.isolateName}$N'
1310 '${globalsHolder}.$initName$_=${_}$initName$N'
1311 '${globalsHolder}.$setupProgramName$_=$_'
1312 '$setupProgramName$N');
1313 }
1314 mainOutput.add('init()$N$n');
1315 mainOutput.add('$isolateProperties$_=$_$isolatePropertiesName$N');
1316
1317 emitFunctionThatReturnsNull(mainOutput);
1318
1319 Iterable<LibraryElement> libraries =
1320 task.outputLibraryLists[mainOutputUnit];
1321 if (libraries == null) libraries = [];
1322 emitMangledNames(mainOutput);
1323
1324 Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment]; 1291 Map<Element, ClassBuilder> descriptors = elementDescriptors[mainFragment];
1325 if (descriptors == null) descriptors = const {}; 1292 if (descriptors == null) descriptors = const {};
1326 1293
1327 checkEverythingEmitted(descriptors.keys); 1294 checkEverythingEmitted(descriptors.keys);
1328 1295
1296 Iterable<LibraryElement> libraries =
1297 task.outputLibraryLists[mainOutputUnit];
1298 if (libraries == null) libraries = [];
1299
1329 List<jsAst.Expression> parts = <jsAst.Expression>[]; 1300 List<jsAst.Expression> parts = <jsAst.Expression>[];
1330 for (LibraryElement library in Elements.sortedByPosition(libraries)) { 1301 for (LibraryElement library in Elements.sortedByPosition(libraries)) {
1331 parts.add(generateLibraryDescriptor(library, mainFragment)); 1302 parts.add(generateLibraryDescriptor(library, mainFragment));
1332 descriptors.remove(library); 1303 descriptors.remove(library);
1333 } 1304 }
1334 1305
1335 if (descriptors.isNotEmpty) { 1306 if (descriptors.isNotEmpty) {
1336 List<Element> remainingLibraries = descriptors.keys 1307 List<Element> remainingLibraries = descriptors.keys
1337 .where((Element e) => e is LibraryElement) 1308 .where((Element e) => e is LibraryElement)
1338 .toList(); 1309 .toList();
1339 1310
1340 // The remaining descriptors are only accessible through reflection. 1311 // The remaining descriptors are only accessible through reflection.
1341 // The program builder does not collect libraries that only 1312 // The program builder does not collect libraries that only
1342 // contain typedefs that are used for reflection. 1313 // contain typedefs that are used for reflection.
1343 for (LibraryElement element in remainingLibraries) { 1314 for (LibraryElement element in remainingLibraries) {
1344 assert(element is LibraryElement || compiler.hasIncrementalSupport); 1315 assert(element is LibraryElement || compiler.hasIncrementalSupport);
1345 if (element is LibraryElement) { 1316 if (element is LibraryElement) {
1346 parts.add(generateLibraryDescriptor(element, mainFragment)); 1317 parts.add(generateLibraryDescriptor(element, mainFragment));
1347 descriptors.remove(element); 1318 descriptors.remove(element);
1348 } 1319 }
1349 } 1320 }
1350 } 1321 }
1351 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts); 1322 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts);
1352 1323
1353 bool needsNativeSupport = program.needsNativeSupport; 1324 // Using a named function here produces easier to read stack traces in
1354 mainOutput.addBuffer( 1325 // Chrome/V8.
1355 jsAst.prettyPrint( 1326 statements.add(js.statement("""
1356 buildSetupProgram(program, compiler, backend, namer, this), 1327 (function() {
1357 compiler)); 1328 // No renaming in the top-level function to save the locals for the
1329 // nested context where they will be used more. We have to put the
1330 // comment into a hole as the parser strips out comments right away.
1331 #disableVariableRenaming;
1332 #supportsDirectProtoAccess;
1358 1333
1359 // The argument to reflectionDataParser is assigned to a temporary 'dart' 1334 if (#hasIncrementalSupport) {
1360 // so that 'dart.' will appear as the prefix to dart methods in stack 1335 #helper = #helper || Object.create(null);
1361 // traces and profile entries. 1336 #helper.patch = function(a) { eval(a)};
1362 mainOutput..add('var dart =') 1337 #helper.schemaChange = #schemaChange;
1363 ..addBuffer(jsAst.prettyPrint(descriptorsAst, compiler, 1338 #helper.addMethod = #addMethod;
1364 monitor: compiler.dumpInfoTask)) 1339 #helper.extractStubs =
1365 ..add('$N'); 1340 function(array, name, isStatic, originalDescriptor) {
1366 if (compiler.useContentSecurityPolicy) { 1341 var descriptor = Object.create(null);
1367 jsAst.Statement precompiledFunctionAst = 1342 this.addStubs(descriptor, array, name, isStatic, []);
1368 buildCspPrecompiledFunctionFor(mainOutputUnit); 1343 return descriptor;
1369 mainOutput.addBuffer( 1344 };
1370 jsAst.prettyPrint( 1345 }
1371 precompiledFunctionAst,
1372 compiler,
1373 monitor: compiler.dumpInfoTask,
1374 allowVariableMinification: false));
1375 mainOutput.add(N);
1376 }
1377 1346
1378 mainOutput.add('$setupProgramName(dart, 0)$N'); 1347 if (#isProgramSplit) {
1348 /// We collect all the global state, so it can be passed to the
1349 /// initializer of deferred files.
1350 var #globalsHolder = Object.create(null)
1351 }
1379 1352
1380 interceptorEmitter.emitGetInterceptorMethods(mainOutput); 1353 // [map] returns an object that V8 shouldn't try to optimize with a
1381 interceptorEmitter.emitOneShotInterceptors(mainOutput); 1354 // hidden class. This prevents a potential performance problem where V8
1355 // tries to build a hidden class for an object used as a hashMap.
1356 // It requires fewer characters to declare a variable as a parameter than
1357 // with `var`.
1358 function map(x) {
1359 x = Object.create(null);
1360 x.x = 0;
1361 delete x.x;
1362 return x;
1363 }
1382 1364
1383 if (task.outputContainsConstantList) { 1365 #globalObjectSetup;
1384 emitMakeConstantList(mainOutput);
1385 }
1386 1366
1387 // Constants in checked mode call into RTI code to set type information 1367 function #isolateName() {}
1388 // which may need getInterceptor (and one-shot interceptor) methods, so
1389 // we have to make sure that [emitGetInterceptorMethods] and
1390 // [emitOneShotInterceptors] have been called.
1391 emitCompileTimeConstants(
1392 mainOutput, mainFragment.constants, isMainFragment: true);
1393 1368
1394 emitDeferredBoilerPlate(mainOutput, deferredLoadHashes); 1369 if (#isProgramSplit) {
1370 #globalsHolder.#isolateName = #isolateName;
1371 #globalsHolder.#initName = #initName;
1372 #globalsHolder.#setupProgramName = #setupProgramName;
1373 }
1374
1375 init();
1376
1377 #mangledNames;
1378
1379 #setupProgram;
1380
1381 #functionThatReturnsNull;
1382
1383 // The argument to reflectionDataParser is assigned to a temporary 'dart'
1384 // so that 'dart.' will appear as the prefix to dart methods in stack
1385 // traces and profile entries.
1386 var dart = #descriptors;
1387
1388 #setupProgramName(dart, 0);
1389
1390 #cspPrecompiledFunctions;
1391
1392 #getInterceptorMethods;
1393 #oneShotInterceptors;
1394
1395 #makeConstantList;
1396
1397 // We abuse the short name used for the isolate here to store
1398 // the isolate properties. This is safe as long as the real isolate
1399 // object does not exist yet.
1400 var ${namer.currentIsolate} = #isolatePropertiesName;
1401
1402 // Constants in checked mode call into RTI code to set type information
1403 // which may need getInterceptor (and one-shot interceptor) methods, so
1404 // we have to make sure that [emitGetInterceptorMethods] and
1405 // [emitOneShotInterceptors] have been called.
1406 #compileTimeConstants;
1407
1408 // Static field initializations require the classes and compile-time
1409 // constants to be set up.
1410 #staticNonFinalInitializers;
1411
1412 ${namer.currentIsolate} = null;
1413
1414 #deferredBoilerPlate;
1415
1416 #typeToInterceptorMap;
1417
1418 #lazyStaticFields;
1419
1420 #isolateName = $finishIsolateConstructorName(#isolateName);
1421
1422 ${namer.currentIsolate} = new #isolateName();
1423
1424 #metadata;
1425
1426 #convertToFastObject;
1427 #convertToSlowObject;
1428
1429 #convertGlobalObjectsToFastObjects;
1430 #debugFastObjects;
1431
1432 #init;
1433
1434 #main;
1435 })();
1436 """, {
1437 "disableVariableRenaming": js.comment("/* ::norenaming:: */"),
1438 "hasIncrementalSupport": compiler.hasIncrementalSupport,
1439 "helper": js('this.#', [namer.incrementalHelperName]),
1440 "schemaChange": buildSchemaChangeFunction(),
1441 "addMethod": buildIncrementalAddMethod(),
1442 "isProgramSplit": isProgramSplit,
1443 "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(),
1444 "globalsHolder": globalsHolder,
1445 "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit),
1446 "isolateName": namer.isolateName,
1447 "isolatePropertiesName": js(isolatePropertiesName),
1448 "initName": initName,
1449 "functionThatReturnsNull": buildFunctionThatReturnsNull(),
1450 "mangledNames": buildMangledNames(),
1451 "setupProgram": buildSetupProgram(program, compiler, backend, namer, this) ,
1452 "setupProgramName": setupProgramName,
1453 "descriptors": descriptorsAst,
1454 "cspPrecompiledFunctions": buildCspPrecompiledFunctionFor(mainOutputUnit),
1455 "getInterceptorMethods": interceptorEmitter.buildGetInterceptorMethods(),
1456 "oneShotInterceptors": interceptorEmitter.buildOneShotInterceptors(),
1457 "makeConstantList": buildMakeConstantList(),
1458 "compileTimeConstants": buildCompileTimeConstants(mainFragment.constants,
1459 isMainFragment: true),
1460 "deferredBoilerPlate": buildDeferredBoilerPlate(deferredLoadHashes),
1461 "staticNonFinalInitializers": buildStaticNonFinalFieldInitializations(
1462 mainOutputUnit),
1463 "typeToInterceptorMap":
1464 interceptorEmitter.buildTypeToInterceptorMap(program),
1465 "lazyStaticFields": buildLazilyInitializedStaticFields(),
1466 "metadata": buildMetadata(program, mainOutputUnit),
1467 "convertToFastObject": buildConvertToFastObjectFunction(),
1468 "convertToSlowObject": buildConvertToSlowObjectFunction(),
1469 "convertGlobalObjectsToFastObjects":
1470 buildConvertGlobalObjectToFastObjects(),
1471 "debugFastObjects": buildDebugFastObjectCode(),
1472 "init": buildInitFunction(),
1473 "main": buildMain(mainFragment.invokeMain)
1474 }));
1475
1476 mainOutput.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements),
1477 compiler,
1478 monitor: compiler.dumpInfoTask));
1395 1479
1396 if (compiler.deferredMapUri != null) { 1480 if (compiler.deferredMapUri != null) {
1397 outputDeferredMap(); 1481 outputDeferredMap();
1398 } 1482 }
1399 1483
1400 // Static field initializations require the classes and compile-time
1401 // constants to be set up.
1402 emitStaticNonFinalFieldInitializations(mainOutput, mainOutputUnit);
1403 interceptorEmitter.emitTypeToInterceptorMap(program, mainOutput);
1404 if (compiler.enableMinification) {
1405 mainOutput.add(';');
1406 }
1407 emitLazilyInitializedStaticFields(mainOutput);
1408
1409 mainOutput.add('\n');
1410
1411 emitMetadata(program, mainOutput, mainOutputUnit);
1412
1413 isolateProperties = isolatePropertiesName;
1414 // The following code should not use the short-hand for the
1415 // initialStatics.
1416 mainOutput.add('${namer.currentIsolate}$_=${_}null$N');
1417
1418 emitFinishIsolateConstructorInvocation(mainOutput);
1419 mainOutput.add(
1420 '${namer.currentIsolate}$_=${_}new ${namer.isolateName}()$N');
1421
1422 emitConvertToFastObjectFunction(mainOutput);
1423 emitConvertToSlowObjectFunction(mainOutput);
1424
1425 for (String globalObject in Namer.reservedGlobalObjectNames) {
1426 mainOutput.add('$globalObject = convertToFastObject($globalObject)$N');
1427 }
1428 if (DEBUG_FAST_OBJECTS) {
1429 mainOutput.add(r'''
1430 // The following only works on V8 when run with option
1431 // "--allow-natives-syntax". We use'new Function' because the
1432 // miniparser does not understand V8 native syntax.
1433 if (typeof print === "function") {
1434 var HasFastProperties =
1435 new Function("a", "return %HasFastProperties(a)");
1436 print("Size of global helper object: "
1437 + String(Object.getOwnPropertyNames(H).length)
1438 + ", fast properties " + HasFastProperties(H));
1439 print("Size of global platform object: "
1440 + String(Object.getOwnPropertyNames(P).length)
1441 + ", fast properties " + HasFastProperties(P));
1442 print("Size of global dart:html object: "
1443 + String(Object.getOwnPropertyNames(W).length)
1444 + ", fast properties " + HasFastProperties(W));
1445 print("Size of isolate properties object: "
1446 + String(Object.getOwnPropertyNames($).length)
1447 + ", fast properties " + HasFastProperties($));
1448 print("Size of constant object: "
1449 + String(Object.getOwnPropertyNames(C).length)
1450 + ", fast properties " + HasFastProperties(C));
1451 var names = Object.getOwnPropertyNames($);
1452 for (var i = 0; i < names.length; i++) {
1453 print("$." + names[i]);
1454 }
1455 }
1456 ''');
1457 for (String object in Namer.userGlobalObjects) {
1458 mainOutput.add('''
1459 if (typeof print === "function") {
1460 print("Size of $object: "
1461 + String(Object.getOwnPropertyNames($object).length)
1462 + ", fast properties " + HasFastProperties($object));
1463 }
1464 ''');
1465 }
1466 }
1467
1468 emitInitFunction(mainOutput);
1469 emitMain(mainOutput, mainFragment.invokeMain);
1470
1471 mainOutput.add('})()\n');
1472
1473
1474 if (generateSourceMap) { 1484 if (generateSourceMap) {
1475 mainOutput.add( 1485 mainOutput.add(
1476 generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri)); 1486 generateSourceMapTag(compiler.sourceMapUri, compiler.outputUri));
1477 } 1487 }
1478 1488
1479 mainOutput.close(); 1489 mainOutput.close();
1480 1490
1481 if (generateSourceMap) { 1491 if (generateSourceMap) {
1482 outputSourceMap(mainOutput, lineColumnCollector, '', 1492 outputSourceMap(mainOutput, lineColumnCollector, '',
1483 compiler.sourceMapUri, compiler.outputUri); 1493 compiler.sourceMapUri, compiler.outputUri);
1484 } 1494 }
1485 } 1495 }
1486 1496
1487 /// Used by incremental compilation to patch up the prototype of 1497 /// Used by incremental compilation to patch up the prototype of
1488 /// [oldConstructor] for use as prototype of [newConstructor]. 1498 /// [oldConstructor] for use as prototype of [newConstructor].
1489 jsAst.Fun buildSchemaChangeFunction() { 1499 jsAst.Fun buildSchemaChangeFunction() {
1500 if (!compiler.hasIncrementalSupport) return null;
1490 return js(''' 1501 return js('''
1491 function(newConstructor, oldConstructor, superclass) { 1502 function(newConstructor, oldConstructor, superclass) {
1492 // Invariant: newConstructor.prototype has no interesting properties besides 1503 // Invariant: newConstructor.prototype has no interesting properties besides
1493 // generated accessors. These are copied to oldPrototype which will be 1504 // generated accessors. These are copied to oldPrototype which will be
1494 // updated by other incremental changes. 1505 // updated by other incremental changes.
1495 if (superclass != null) { 1506 if (superclass != null) {
1496 this.inheritFrom(newConstructor, superclass); 1507 this.inheritFrom(newConstructor, superclass);
1497 } 1508 }
1498 var oldPrototype = oldConstructor.prototype; 1509 var oldPrototype = oldConstructor.prototype;
1499 var newPrototype = newConstructor.prototype; 1510 var newPrototype = newConstructor.prototype;
(...skipping 12 matching lines...) Expand all
1512 } 1523 }
1513 1524
1514 /// Used by incremental compilation to patch up an object ([holder]) with a 1525 /// Used by incremental compilation to patch up an object ([holder]) with a
1515 /// new (or updated) method. [arrayOrFunction] is either the new method, or 1526 /// new (or updated) method. [arrayOrFunction] is either the new method, or
1516 /// an array containing the method (see 1527 /// an array containing the method (see
1517 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the 1528 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the
1518 /// new method. [isStatic] tells if method is static (or 1529 /// new method. [isStatic] tells if method is static (or
1519 /// top-level). [globalFunctionsAccess] is a reference to 1530 /// top-level). [globalFunctionsAccess] is a reference to
1520 /// [embeddedNames.GLOBAL_FUNCTIONS]. 1531 /// [embeddedNames.GLOBAL_FUNCTIONS].
1521 jsAst.Fun buildIncrementalAddMethod() { 1532 jsAst.Fun buildIncrementalAddMethod() {
1533 if (!compiler.hasIncrementalSupport) return null;
1522 return js(r""" 1534 return js(r"""
1523 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { 1535 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) {
1524 var arrayOrFunction = originalDescriptor[name]; 1536 var arrayOrFunction = originalDescriptor[name];
1525 var method; 1537 var method;
1526 if (arrayOrFunction.constructor === Array) { 1538 if (arrayOrFunction.constructor === Array) {
1527 var existing = holder[name]; 1539 var existing = holder[name];
1528 var array = arrayOrFunction; 1540 var array = arrayOrFunction;
1529 1541
1530 // Each method may have a number of stubs associated. For example, if an 1542 // Each method may have a number of stubs associated. For example, if an
1531 // instance method supports multiple arguments, a stub for each matching 1543 // instance method supports multiple arguments, a stub for each matching
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1632 1644
1633 return emitDeferredCode(program, outputs); 1645 return emitDeferredCode(program, outputs);
1634 } 1646 }
1635 1647
1636 int emitProgram(ProgramBuilder programBuilder) { 1648 int emitProgram(ProgramBuilder programBuilder) {
1637 Program program = programBuilder.buildProgram( 1649 Program program = programBuilder.buildProgram(
1638 storeFunctionTypesInMetadata: true); 1650 storeFunctionTypesInMetadata: true);
1639 1651
1640 assembleProgram(program); 1652 assembleProgram(program);
1641 1653
1642 // Shorten the code by using [namer.currentIsolate] as temporary.
1643 isolateProperties = namer.currentIsolate;
1644
1645 // Emit deferred units first, so we have their hashes. 1654 // Emit deferred units first, so we have their hashes.
1646 // Map from OutputUnit to a hash of its content. The hash uniquely 1655 // Map from OutputUnit to a hash of its content. The hash uniquely
1647 // identifies the code of the output-unit. It does not include 1656 // identifies the code of the output-unit. It does not include
1648 // boilerplate JS code, like the sourcemap directives or the hash 1657 // boilerplate JS code, like the sourcemap directives or the hash
1649 // itself. 1658 // itself.
1650 Map<OutputUnit, String> deferredLoadHashes = 1659 Map<OutputUnit, String> deferredLoadHashes =
1651 emitDeferredOutputUnits(program); 1660 emitDeferredOutputUnits(program);
1652 emitMainOutputUnit(program, deferredLoadHashes); 1661 emitMainOutputUnit(program, deferredLoadHashes);
1653 1662
1654 if (backend.requiresPreamble && 1663 if (backend.requiresPreamble &&
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1687 } 1696 }
1688 if (owner == null) { 1697 if (owner == null) {
1689 compiler.internalError(element, 'Owner is null.'); 1698 compiler.internalError(element, 'Owner is null.');
1690 } 1699 }
1691 return elementDescriptors 1700 return elementDescriptors
1692 .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>()) 1701 .putIfAbsent(fragment, () => new Map<Element, ClassBuilder>())
1693 .putIfAbsent(owner, () => new ClassBuilder(owner, namer)); 1702 .putIfAbsent(owner, () => new ClassBuilder(owner, namer));
1694 } 1703 }
1695 1704
1696 /// Emits support-code for deferred loading into [output]. 1705 /// Emits support-code for deferred loading into [output].
1697 void emitDeferredBoilerPlate(CodeOutput output, 1706 jsAst.Statement buildDeferredBoilerPlate(
1698 Map<OutputUnit, String> deferredLoadHashes) { 1707 Map<OutputUnit, String> deferredLoadHashes) {
1699 jsAst.Statement functions = js.statement(''' 1708 List<jsAst.Statement> parts = <jsAst.Statement>[];
1709
1710 parts.add(js.statement('''
1700 { 1711 {
1701 // Function for checking if a hunk is loaded given its hash. 1712 // Function for checking if a hunk is loaded given its hash.
1702 #isHunkLoaded = function(hunkHash) { 1713 #isHunkLoaded = function(hunkHash) {
1703 return !!$deferredInitializers[hunkHash]; 1714 return !!$deferredInitializers[hunkHash];
1704 }; 1715 };
1705 #deferredInitialized = new Object(null); 1716 #deferredInitialized = new Object(null);
1706 // Function for checking if a hunk is initialized given its hash. 1717 // Function for checking if a hunk is initialized given its hash.
1707 #isHunkInitialized = function(hunkHash) { 1718 #isHunkInitialized = function(hunkHash) {
1708 return #deferredInitialized[hunkHash]; 1719 return #deferredInitialized[hunkHash];
1709 }; 1720 };
1710 // Function for initializing a loaded hunk, given its hash. 1721 // Function for initializing a loaded hunk, given its hash.
1711 #initializeLoadedHunk = function(hunkHash) { 1722 #initializeLoadedHunk = function(hunkHash) {
1712 $deferredInitializers[hunkHash]( 1723 $deferredInitializers[hunkHash](
1713 $globalsHolder, ${namer.currentIsolate}); 1724 $globalsHolder, ${namer.currentIsolate});
1714 #deferredInitialized[hunkHash] = true; 1725 #deferredInitialized[hunkHash] = true;
1715 }; 1726 };
1716 } 1727 }
1717 ''', {"isHunkLoaded": generateEmbeddedGlobalAccess( 1728 ''', {"isHunkLoaded": generateEmbeddedGlobalAccess(
1718 embeddedNames.IS_HUNK_LOADED), 1729 embeddedNames.IS_HUNK_LOADED),
1719 "isHunkInitialized": generateEmbeddedGlobalAccess( 1730 "isHunkInitialized": generateEmbeddedGlobalAccess(
1720 embeddedNames.IS_HUNK_INITIALIZED), 1731 embeddedNames.IS_HUNK_INITIALIZED),
1721 "initializeLoadedHunk": generateEmbeddedGlobalAccess( 1732 "initializeLoadedHunk": generateEmbeddedGlobalAccess(
1722 embeddedNames.INITIALIZE_LOADED_HUNK), 1733 embeddedNames.INITIALIZE_LOADED_HUNK),
1723 "deferredInitialized": generateEmbeddedGlobalAccess( 1734 "deferredInitialized": generateEmbeddedGlobalAccess(
1724 embeddedNames.DEFERRED_INITIALIZED)}); 1735 embeddedNames.DEFERRED_INITIALIZED)}));
1725 output.addBuffer(jsAst.prettyPrint(functions, 1736
1726 compiler, monitor: compiler.dumpInfoTask));
1727 // Write a javascript mapping from Deferred import load ids (derrived 1737 // Write a javascript mapping from Deferred import load ids (derrived
1728 // from the import prefix.) to a list of lists of uris of hunks to load, 1738 // from the import prefix.) to a list of lists of uris of hunks to load,
1729 // and a corresponding mapping to a list of hashes used by 1739 // and a corresponding mapping to a list of hashes used by
1730 // INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED. 1740 // INITIALIZE_LOADED_HUNK and IS_HUNK_LOADED.
1731 Map<String, List<String>> deferredLibraryUris = 1741 Map<String, List<String>> deferredLibraryUris =
1732 new Map<String, List<String>>(); 1742 new Map<String, List<String>>();
1733 Map<String, List<String>> deferredLibraryHashes = 1743 Map<String, List<String>> deferredLibraryHashes =
1734 new Map<String, List<String>>(); 1744 new Map<String, List<String>>();
1735 compiler.deferredLoadTask.hunksToLoad.forEach( 1745 compiler.deferredLoadTask.hunksToLoad.forEach(
1736 (String loadId, List<OutputUnit>outputUnits) { 1746 (String loadId, List<OutputUnit>outputUnits) {
(...skipping 13 matching lines...) Expand all
1750 List<jsAst.Property> properties = new List<jsAst.Property>(); 1760 List<jsAst.Property> properties = new List<jsAst.Property>();
1751 mapping.forEach((String key, List<String> values) { 1761 mapping.forEach((String key, List<String> values) {
1752 properties.add(new jsAst.Property(js.escapedString(key), 1762 properties.add(new jsAst.Property(js.escapedString(key),
1753 new jsAst.ArrayInitializer( 1763 new jsAst.ArrayInitializer(
1754 values.map(js.escapedString).toList()))); 1764 values.map(js.escapedString).toList())));
1755 }); 1765 });
1756 jsAst.Node initializer = 1766 jsAst.Node initializer =
1757 new jsAst.ObjectInitializer(properties, isOneLiner: true); 1767 new jsAst.ObjectInitializer(properties, isOneLiner: true);
1758 1768
1759 jsAst.Node globalName = generateEmbeddedGlobalAccess(name); 1769 jsAst.Node globalName = generateEmbeddedGlobalAccess(name);
1760 output.addBuffer(jsAst.prettyPrint( 1770 parts.add(js.statement("# = #", [globalName, initializer]));
1761 js("# = #", [globalName, initializer]),
1762 compiler, monitor: compiler.dumpInfoTask));
1763 output.add('$N');
1764 } 1771 }
1765 1772
1766 emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris); 1773 emitMapping(embeddedNames.DEFERRED_LIBRARY_URIS, deferredLibraryUris);
1767 emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES, 1774 emitMapping(embeddedNames.DEFERRED_LIBRARY_HASHES,
1768 deferredLibraryHashes); 1775 deferredLibraryHashes);
1776
1777 return new jsAst.Block(parts);
1769 } 1778 }
1770 1779
1771 /// Emits code for all output units except the main. 1780 /// Emits code for all output units except the main.
1772 /// Returns a mapping from outputUnit to a hash of the corresponding hunk that 1781 /// Returns a mapping from outputUnit to a hash of the corresponding hunk that
1773 /// can be used for calling the initializer. 1782 /// can be used for calling the initializer.
1774 Map<OutputUnit, String> emitDeferredCode( 1783 Map<OutputUnit, String> emitDeferredCode(
1775 Program program, 1784 Program program,
1776 Map<OutputUnit, jsAst.Expression> deferredAsts) { 1785 Map<OutputUnit, jsAst.Expression> deferredAsts) {
1777 1786
1778 Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>(); 1787 Map<OutputUnit, String> hunkHashes = new Map<OutputUnit, String>();
(...skipping 14 matching lines...) Expand all
1793 } 1802 }
1794 1803
1795 String partPrefix = 1804 String partPrefix =
1796 backend.deferredPartFileName(outputUnit.name, addExtension: false); 1805 backend.deferredPartFileName(outputUnit.name, addExtension: false);
1797 CodeOutput output = new StreamCodeOutput( 1806 CodeOutput output = new StreamCodeOutput(
1798 compiler.outputProvider(partPrefix, 'part.js'), 1807 compiler.outputProvider(partPrefix, 'part.js'),
1799 outputListeners); 1808 outputListeners);
1800 1809
1801 outputBuffers[outputUnit] = output; 1810 outputBuffers[outputUnit] = output;
1802 1811
1803 output 1812 List<jsAst.Statement> body = <jsAst.Statement>[];
1804 ..add(buildGeneratedBy()) 1813
1805 ..add('${deferredInitializers}.current$_=$_' 1814 // No renaming in the top-level function to save the locals for the
1806 'function$_(${globalsHolder}) {$N'); 1815 // nested context where they will be used more.
1816 body.add(js.comment("/* ::norenaming:: "));
1817
1807 for (String globalObject in Namer.reservedGlobalObjectNames) { 1818 for (String globalObject in Namer.reservedGlobalObjectNames) {
1808 output 1819 body.add(js.statement('var #object = ${globalsHolder}.#object;',
1809 .add('var $globalObject$_=$_' 1820 {'object': globalObject}));
1810 '${globalsHolder}.$globalObject$N');
1811 } 1821 }
1812 output 1822 body..add(js.statement('var init = ${globalsHolder}.init;'))
1813 ..add('var init$_=$_${globalsHolder}.init$N') 1823 ..add(js.statement('var $setupProgramName = '
1814 ..add('var $setupProgramName$_=$_' 1824 '$globalsHolder.$setupProgramName;'))
1815 '$globalsHolder.$setupProgramName$N') 1825 ..add(js.statement('var ${namer.isolateName} = '
1816 ..add('var ${namer.isolateName}$_=$_' 1826 '${globalsHolder}.${namer.isolateName};'));
1817 '${globalsHolder}.${namer.isolateName}$N');
1818 String typesAccess = 1827 String typesAccess =
1819 generateEmbeddedGlobalAccessString(embeddedNames.TYPES); 1828 generateEmbeddedGlobalAccessString(embeddedNames.TYPES);
1820 if (libraryDescriptor != null) { 1829 if (libraryDescriptor != null) {
1821 // TODO(ahe): This defines a lot of properties on the 1830 // The argument to reflectionDataParser is assigned to a temporary
1822 // Isolate.prototype object. We know this will turn it into a 1831 // 'dart' so that 'dart.' will appear as the prefix to dart methods
1823 // slow object in V8, so instead we should do something similar 1832 // in stack traces and profile entries.
1824 // to Isolate.$finishIsolateConstructor. 1833 body.add(js.statement('var dart = #', libraryDescriptor));
1825 output
1826 ..add('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N')
1827 // The argument to reflectionDataParser is assigned to a temporary
1828 // 'dart' so that 'dart.' will appear as the prefix to dart methods
1829 // in stack traces and profile entries.
1830 ..add('var dart = $n ')
1831 ..addBuffer(jsAst.prettyPrint(libraryDescriptor, compiler,
1832 monitor: compiler.dumpInfoTask))
1833 ..add('$N');
1834 1834
1835 if (compiler.useContentSecurityPolicy) { 1835 if (compiler.useContentSecurityPolicy) {
1836 jsAst.Statement precompiledFunctionAst = 1836 body.add(buildCspPrecompiledFunctionFor(outputUnit));
1837 buildCspPrecompiledFunctionFor(outputUnit);
1838
1839 output.addBuffer(
1840 jsAst.prettyPrint(
1841 precompiledFunctionAst, compiler,
1842 monitor: compiler.dumpInfoTask,
1843 allowVariableMinification: false));
1844 output.add(N);
1845 } 1837 }
1846 output.add('$setupProgramName(dart, ${typesAccess}.length)$N'); 1838 body.add(
1839 js.statement('$setupProgramName(dart, ${typesAccess}.length);'));
1847 } 1840 }
1848 1841
1849 if (task.metadataCollector.types[outputUnit] != null) { 1842 if (task.metadataCollector.types[outputUnit] != null) {
1850 emitMetadata(program, output, outputUnit); 1843 body..add(buildMetadata(program, outputUnit))
1851 output.add('${typesAccess}.' 1844 ..add(js.statement('${typesAccess}.push.apply(${typesAccess}, '
1852 'push.apply(${typesAccess},$_${namer.deferredTypesName})$N'); 1845 '${namer.deferredTypesName});'));
1853 } 1846 }
1854 1847
1855 // Set the currentIsolate variable to the current isolate (which is 1848 // Set the currentIsolate variable to the current isolate (which is
1856 // provided as second argument). 1849 // provided as second argument).
1857 // We need to do this, because we use the same variable for setting up 1850 body.add(js.statement("${namer.currentIsolate} = arguments[1];"));
1858 // the isolate-properties and for storing the current isolate. During
1859 // the setup (the code above this lines) we must set the variable to
1860 // the isolate-properties.
1861 // After we have done the setup it must point to the current Isolate.
1862 // Otherwise all methods/functions accessing isolate variables will
1863 // access the wrong object.
1864 output.add("${namer.currentIsolate}$_=${_}arguments[1]$N");
1865 1851
1866 emitCompileTimeConstants( 1852 body.add(buildCompileTimeConstants(fragment.constants,
1867 output, fragment.constants, isMainFragment: false); 1853 isMainFragment: false));
1868 emitStaticNonFinalFieldInitializations(output, outputUnit); 1854 body.add(buildStaticNonFinalFieldInitializations(outputUnit));
1869 1855
1870 output.add('}$N'); 1856 List<jsAst.Statement> statements = <jsAst.Statement>[];
1857
1858 statements..add(buildGeneratedBy())
1859 ..add(js.statement('${deferredInitializers}.current = '
1860 """function (${globalsHolder}) {
1861 #
1862 }
1863 """, [body]));
1864
1865 output.addBuffer(jsAst.prettyPrint(new jsAst.Program(statements),
1866 compiler,
1867 monitor: compiler.dumpInfoTask));
1868
1871 // Make a unique hash of the code (before the sourcemaps are added) 1869 // Make a unique hash of the code (before the sourcemaps are added)
1872 // This will be used to retrieve the initializing function from the global 1870 // This will be used to retrieve the initializing function from the global
1873 // variable. 1871 // variable.
1874 String hash = hasher.getHash(); 1872 String hash = hasher.getHash();
1875 1873
1876 output.add('${deferredInitializers}["$hash"]$_=$_' 1874 output.add('$N${deferredInitializers}["$hash"]$_=$_'
1877 '${deferredInitializers}.current$N'); 1875 '${deferredInitializers}.current$N');
1878 1876
1879 if (generateSourceMap) { 1877 if (generateSourceMap) {
1880
1881 Uri mapUri, partUri; 1878 Uri mapUri, partUri;
1882 Uri sourceMapUri = compiler.sourceMapUri; 1879 Uri sourceMapUri = compiler.sourceMapUri;
1883 Uri outputUri = compiler.outputUri; 1880 Uri outputUri = compiler.outputUri;
1884 1881
1885 String partName = "$partPrefix.part"; 1882 String partName = "$partPrefix.part";
1886 1883
1887 if (sourceMapUri != null) { 1884 if (sourceMapUri != null) {
1888 String mapFileName = partName + ".js.map"; 1885 String mapFileName = partName + ".js.map";
1889 List<String> mapSegments = sourceMapUri.pathSegments.toList(); 1886 List<String> mapSegments = sourceMapUri.pathSegments.toList();
1890 mapSegments[mapSegments.length - 1] = mapFileName; 1887 mapSegments[mapSegments.length - 1] = mapFileName;
(...skipping 13 matching lines...) Expand all
1904 mapUri, partUri); 1901 mapUri, partUri);
1905 } else { 1902 } else {
1906 output.close(); 1903 output.close();
1907 } 1904 }
1908 1905
1909 hunkHashes[outputUnit] = hash; 1906 hunkHashes[outputUnit] = hash;
1910 } 1907 }
1911 return hunkHashes; 1908 return hunkHashes;
1912 } 1909 }
1913 1910
1914 String buildGeneratedBy() { 1911 jsAst.Comment buildGeneratedBy() {
1915 var suffix = ''; 1912 String suffix = '';
1916 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}'; 1913 if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
1917 return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n'; 1914 String msg = '// Generated by dart2js, the Dart to JavaScript '
1915 'compiler$suffix.';
1916 return new jsAst.Comment(msg);
1918 } 1917 }
1919 1918
1920 void outputSourceMap(CodeOutput output, 1919 void outputSourceMap(CodeOutput output,
1921 LineColumnProvider lineColumnProvider, 1920 LineColumnProvider lineColumnProvider,
1922 String name, 1921 String name,
1923 [Uri sourceMapUri, 1922 [Uri sourceMapUri,
1924 Uri fileUri]) { 1923 Uri fileUri]) {
1925 if (!generateSourceMap) return; 1924 if (!generateSourceMap) return;
1926 // Create a source file for the compilation output. This allows using 1925 // Create a source file for the compilation output. This allows using
1927 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder]. 1926 // [:getLine:] to transform offsets to line numbers in [SourceMapBuilder].
(...skipping 24 matching lines...) Expand all
1952 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { 1951 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) {
1953 if (element.isInstanceMember) { 1952 if (element.isInstanceMember) {
1954 cachedClassBuilders.remove(element.enclosingClass); 1953 cachedClassBuilders.remove(element.enclosingClass);
1955 1954
1956 nativeEmitter.cachedBuilders.remove(element.enclosingClass); 1955 nativeEmitter.cachedBuilders.remove(element.enclosingClass);
1957 1956
1958 } 1957 }
1959 } 1958 }
1960 } 1959 }
1961 } 1960 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698