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

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

Powered by Google App Engine
This is Rietveld 408576698