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

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

Issue 816113005: Revert "dart2js OldEmitter: inline FinishClasses." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 11 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 | Annotate | Revision Log
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 TypeTestEmitter typeTestEmitter = new TypeTestEmitter(); 15 final TypeTestEmitter typeTestEmitter = new TypeTestEmitter();
16 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter(); 16 final InterceptorEmitter interceptorEmitter = new InterceptorEmitter();
17 final MetadataEmitter metadataEmitter = new MetadataEmitter(); 17 final MetadataEmitter metadataEmitter = new MetadataEmitter();
18 18
19 final Set<ConstantValue> cachedEmittedConstants; 19 final Set<ConstantValue> cachedEmittedConstants;
20 final CodeBuffer cachedEmittedConstantsBuffer = new CodeBuffer(); 20 final CodeBuffer cachedEmittedConstantsBuffer = new CodeBuffer();
21 final Map<Element, ClassBuilder> cachedClassBuilders; 21 final Map<Element, ClassBuilder> cachedClassBuilders;
22 final Set<Element> cachedElements; 22 final Set<Element> cachedElements;
23 23
24 bool needsClassSupport = false; 24 bool needsDefineClass = false;
25 bool needsMixinSupport = false; 25 bool needsMixinSupport = false;
26 bool needsLazyInitializer = false; 26 bool needsLazyInitializer = false;
27 final Namer namer; 27 final Namer namer;
28 ConstantEmitter constantEmitter; 28 ConstantEmitter constantEmitter;
29 NativeEmitter get nativeEmitter => task.nativeEmitter; 29 NativeEmitter get nativeEmitter => task.nativeEmitter;
30 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry; 30 TypeTestRegistry get typeTestRegistry => task.typeTestRegistry;
31 31
32 // The full code that is written to each hunk part-file. 32 // The full code that is written to each hunk part-file.
33 Map<OutputUnit, CodeBuffer> outputBuffers = new Map<OutputUnit, CodeBuffer>(); 33 Map<OutputUnit, CodeBuffer> outputBuffers = new Map<OutputUnit, CodeBuffer>();
34 final CodeBuffer deferredConstants = new CodeBuffer(); 34 final CodeBuffer deferredConstants = new CodeBuffer();
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 jsAst.Expression constantReference(ConstantValue value) { 140 jsAst.Expression constantReference(ConstantValue value) {
141 return constantEmitter.reference(value); 141 return constantEmitter.reference(value);
142 } 142 }
143 143
144 jsAst.Expression constantInitializerExpression(ConstantValue value) { 144 jsAst.Expression constantInitializerExpression(ConstantValue value) {
145 return constantEmitter.initializationExpression(value); 145 return constantEmitter.initializationExpression(value);
146 } 146 }
147 147
148 String get name => 'CodeEmitter'; 148 String get name => 'CodeEmitter';
149 149
150 String get currentGenerateAccessorName
151 => '${namer.currentIsolate}.\$generateAccessor';
152 String get generateAccessorHolder
153 => '$isolatePropertiesName.\$generateAccessor';
154 String get finishClassesProperty
155 => r'$finishClasses';
156 String get finishClassesName
157 => '${namer.isolateName}.$finishClassesProperty';
150 String get finishIsolateConstructorName 158 String get finishIsolateConstructorName
151 => '${namer.isolateName}.\$finishIsolateConstructor'; 159 => '${namer.isolateName}.\$finishIsolateConstructor';
152 String get isolatePropertiesName 160 String get isolatePropertiesName
153 => '${namer.isolateName}.${namer.isolatePropertiesName}'; 161 => '${namer.isolateName}.${namer.isolatePropertiesName}';
154 String get lazyInitializerProperty 162 String get lazyInitializerProperty
155 => r'$lazy'; 163 => r'$lazy';
156 String get lazyInitializerName 164 String get lazyInitializerName
157 => '${namer.isolateName}.${lazyInitializerProperty}'; 165 => '${namer.isolateName}.${lazyInitializerProperty}';
158 String get initName => 'init'; 166 String get initName => 'init';
159 String get makeConstListProperty 167 String get makeConstListProperty
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
206 } 214 }
207 215
208 jsAst.PropertyAccess classAccess(Element element) { 216 jsAst.PropertyAccess classAccess(Element element) {
209 return globalPropertyAccess(element); 217 return globalPropertyAccess(element);
210 } 218 }
211 219
212 jsAst.PropertyAccess typedefAccess(Element element) { 220 jsAst.PropertyAccess typedefAccess(Element element) {
213 return globalPropertyAccess(element); 221 return globalPropertyAccess(element);
214 } 222 }
215 223
216 List<jsAst.Statement> buildTrivialNsmHandlers(){
217 return nsmEmitter.buildTrivialNsmHandlers();
218 }
219
220 jsAst.FunctionDeclaration get generateAccessorFunction { 224 jsAst.FunctionDeclaration get generateAccessorFunction {
221 const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1; 225 const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
222 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; 226 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
223 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); 227 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST);
224 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); 228 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
225 const RANGE3_ADJUST = 229 const RANGE3_ADJUST =
226 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); 230 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
227 231
228 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; 232 String receiverParamName = compiler.enableMinification ? "r" : "receiver";
229 String valueParamName = compiler.enableMinification ? "v" : "value"; 233 String valueParamName = compiler.enableMinification ? "v" : "value";
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 } 339 }
336 if (#hasIsolateSupport) { 340 if (#hasIsolateSupport) {
337 str += name + ".$fieldNamesProperty=[" + fieldNames + "];\\n"; 341 str += name + ".$fieldNamesProperty=[" + fieldNames + "];\\n";
338 } 342 }
339 str += accessors.join(""); 343 str += accessors.join("");
340 344
341 return str; 345 return str;
342 }''', { 'hasIsolateSupport': hasIsolateSupport }); 346 }''', { 'hasIsolateSupport': hasIsolateSupport });
343 347
344 // Declare a function called "generateAccessor". This is used in 348 // Declare a function called "generateAccessor". This is used in
345 // defineClassFunction. 349 // defineClassFunction (it's a local declaration in init()).
346 List result = <jsAst.Node>[ 350 List result = <jsAst.Node>[
347 generateAccessorFunction, 351 generateAccessorFunction,
352 js('$generateAccessorHolder = generateAccessor'),
348 new jsAst.FunctionDeclaration( 353 new jsAst.FunctionDeclaration(
349 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; 354 new jsAst.VariableDeclaration('defineClass'), defineClass) ];
350 355
351 if (compiler.hasIncrementalSupport) { 356 if (compiler.hasIncrementalSupport) {
352 result.add( 357 result.add(
353 js(r'#.defineClass = defineClass', [namer.accessIncrementalHelper])); 358 js(r'#.defineClass = defineClass', [namer.accessIncrementalHelper]));
354 } 359 }
355 360
356 if (hasIsolateSupport) { 361 if (hasIsolateSupport) {
357 jsAst.Expression classIdExtractorAccess = 362 jsAst.Expression classIdExtractorAccess =
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
431 }; 436 };
432 }() 437 }()
433 '''); 438 ''');
434 if (compiler.hasIncrementalSupport) { 439 if (compiler.hasIncrementalSupport) {
435 result = js( 440 result = js(
436 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]); 441 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]);
437 } 442 }
438 return js(r'var inheritFrom = #', [result]); 443 return js(r'var inheritFrom = #', [result]);
439 } 444 }
440 445
446 /// Code that needs to be run before first invocation of
447 /// [finishClassesFunction], but should only be run once.
448 jsAst.Expression get initFinishClasses {
449 jsAst.Expression allClassesAccess =
450 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
451 jsAst.Expression interceptorsByTagAccess =
452 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
453 jsAst.Expression leafTagsAccess =
454 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
455 jsAst.Expression finishedClassesAccess =
456 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
457
458 return js('''
459 (function(){
460 #allClasses = Object.create(null);
461 #interceptorsByTag = Object.create(null);
462 #leafTags = Object.create(null);
463 #finishedClasses = Object.create(null);
464 })()
465 ''', {'allClasses': allClassesAccess,
466 'interceptorsByTag': interceptorsByTagAccess,
467 'leafTags': leafTagsAccess,
468 'finishedClasses': finishedClassesAccess});
469 }
470
471 jsAst.Fun get finishClassesFunction {
472 // Class descriptions are collected in a JS object.
473 // 'finishClasses' takes all collected descriptions and sets up
474 // the prototype.
475 // Once set up, the constructors prototype field satisfy:
476 // - it contains all (local) members.
477 // - its internal prototype (__proto__) points to the superclass'
478 // prototype field.
479 // - the prototype's constructor field points to the JavaScript
480 // constructor.
481 // For engines where we have access to the '__proto__' we can manipulate
482 // the object literal directly. For other engines we have to create a new
483 // object and copy over the members.
484
485 String reflectableField = namer.reflectableField;
486 jsAst.Expression allClassesAccess =
487 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
488 jsAst.Expression metadataAccess =
489 generateEmbeddedGlobalAccess(embeddedNames.METADATA);
490 String signaturePropertyName = namer.operatorSignature;
491
492 return js('''
493 function(collectedClasses, isolateProperties, existingIsolateProperties) {
494 var pendingClasses = Object.create(null);
495 var allClasses = #allClasses;
496 var constructors;
497
498 if (#debugFastObjects)
499 print("Number of classes: " +
500 Object.getOwnPropertyNames(\$\$).length);
501
502 var hasOwnProperty = Object.prototype.hasOwnProperty;
503
504 if (#inCspMode) {
505 constructors = dart_precompiled(collectedClasses);
506 }
507
508 if (#notInCspMode) {
509 var combinedConstructorFunction =
510 "function \$reflectable(fn){fn.$reflectableField=1;return fn};\\n"+
511 "var \$desc;\\n";
512 var constructorsList = [];
513 }
514
515 for (var cls in collectedClasses) {
516 var desc = collectedClasses[cls];
517 if (desc instanceof Array) desc = desc[1];
518
519 /* The 'fields' are either a constructor function or a
520 * string encoding fields, constructor and superclass. Gets the
521 * superclass and fields in the format
522 * 'Super;field1,field2'
523 * from the CLASS_DESCRIPTOR_PROPERTY property on the descriptor.
524 */
525 var classData = desc["${namer.classDescriptorProperty}"],
526 supr, fields = classData;
527 if (#hasRetainedMetadata)
528 if (typeof classData == "object" &&
529 classData instanceof Array) {
530 classData = fields = classData[0];
531 }
532 // ${ClassBuilder.fieldEncodingDescription}.
533 var s = fields.split(";");
534 fields = s[1] == "" ? [] : s[1].split(",");
535 supr = s[0];
536 // ${ClassBuilder.functionTypeEncodingDescription}.
537 split = supr.split(":");
538 if (split.length == 2) {
539 supr = split[0];
540 var functionSignature = split[1];
541 if (functionSignature)
542 desc.$signaturePropertyName = (function(s) {
543 return function(){ return #metadata[s]; };
544 })(functionSignature);
545 }
546
547 if (#notInCspMode) {
548 combinedConstructorFunction += defineClass(cls, fields);
549 constructorsList.push(cls);
550 }
551 if (supr) pendingClasses[cls] = supr;
552 }
553
554 if (#notInCspMode) {
555 combinedConstructorFunction +=
556 "return [\\n " + constructorsList.join(",\\n ") + "\\n]";
557 var constructors =
558 new Function("\$collectedClasses", combinedConstructorFunction)
559 (collectedClasses);
560 combinedConstructorFunction = null;
561 }
562
563 for (var i = 0; i < constructors.length; i++) {
564 var constructor = constructors[i];
565 var cls = constructor.name;
566 var desc = collectedClasses[cls];
567 var globalObject = isolateProperties;
568 if (desc instanceof Array) {
569 globalObject = desc[0] || isolateProperties;
570 desc = desc[1];
571 }
572 if (#isTreeShakingDisabled)
573 constructor["${namer.metadataField}"] = desc;
574 allClasses[cls] = constructor;
575 globalObject[cls] = constructor;
576 }
577
578 constructors = null;
579
580 #finishClassFunction;
581
582 #trivialNsmHandlers;
583
584 for (var cls in pendingClasses) finishClass(cls);
585 }''', { 'allClasses': allClassesAccess,
586 'debugFastObjects': DEBUG_FAST_OBJECTS,
587 'hasRetainedMetadata': backend.hasRetainedMetadata,
588 'metadata': metadataAccess,
589 'isTreeShakingDisabled': backend.isTreeShakingDisabled,
590 'finishClassFunction': buildFinishClass(),
591 'trivialNsmHandlers': nsmEmitter.buildTrivialNsmHandlers(),
592 'inCspMode': compiler.useContentSecurityPolicy,
593 'notInCspMode': !compiler.useContentSecurityPolicy});
594 }
595
441 jsAst.Statement buildFinishClass() { 596 jsAst.Statement buildFinishClass() {
442 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" 597 String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
443 598
444 jsAst.Expression finishedClassesAccess = 599 jsAst.Expression finishedClassesAccess =
445 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES); 600 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
446 jsAst.Expression interceptorsByTagAccess = 601 jsAst.Expression interceptorsByTagAccess =
447 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG); 602 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
448 jsAst.Expression leafTagsAccess = 603 jsAst.Expression leafTagsAccess =
449 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS); 604 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
450 605
451 return js.statement(''' 606 return js.statement('''
452 { 607 {
453 var finishedClasses = #finishedClassesAccess; 608 var finishedClasses = #finishedClassesAccess;
454 609
455 function finishClass(cls) { 610 function finishClass(cls) {
456 611
457 if (finishedClasses[cls]) return; 612 if (finishedClasses[cls]) return;
458 finishedClasses[cls] = true; 613 finishedClasses[cls] = true;
459 614
460 var superclass = processedClasses.pending[cls]; 615 var superclass = pendingClasses[cls];
461 616
462 if (#needsMixinSupport) { 617 if (#needsMixinSupport) {
463 if (superclass && superclass.indexOf("+") > 0) { 618 if (superclass && superclass.indexOf("+") > 0) {
464 var s = superclass.split("+"); 619 var s = superclass.split("+");
465 superclass = s[0]; 620 superclass = s[0];
466 var mixinClass = s[1]; 621 var mixinClass = s[1];
467 finishClass(mixinClass); 622 finishClass(mixinClass);
468 var mixin = allClasses[mixinClass]; 623 var mixin = allClasses[mixinClass];
469 // TODO(21896): this test shouldn't be necessary. Without it 624 // TODO(21896): this test shouldn't be necessary. Without it
470 // we have a crash in language/mixin_only_for_rti and 625 // we have a crash in language/mixin_only_for_rti and
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
549 } 704 }
550 } 705 }
551 }''', {'finishedClassesAccess': finishedClassesAccess, 706 }''', {'finishedClassesAccess': finishedClassesAccess,
552 'needsMixinSupport': needsMixinSupport, 707 'needsMixinSupport': needsMixinSupport,
553 'hasNativeClasses': nativeClasses.isNotEmpty, 708 'hasNativeClasses': nativeClasses.isNotEmpty,
554 'interceptorsByTagAccess': interceptorsByTagAccess, 709 'interceptorsByTagAccess': interceptorsByTagAccess,
555 'leafTagsAccess': leafTagsAccess, 710 'leafTagsAccess': leafTagsAccess,
556 'allowNativesSubclassing': true}); 711 'allowNativesSubclassing': true});
557 } 712 }
558 713
714 jsAst.Fun get finishIsolateConstructorFunction {
715 // We replace the old Isolate function with a new one that initializes
716 // all its fields with the initial (and often final) value of all globals.
717 //
718 // We also copy over old values like the prototype, and the
719 // isolateProperties themselves.
720 return js(
721 """
722 function (oldIsolate) {
723 var isolateProperties = oldIsolate.#isolatePropertiesName;
724 function Isolate() {
725 var hasOwnProperty = Object.prototype.hasOwnProperty;
726 for (var staticName in isolateProperties)
727 if (hasOwnProperty.call(isolateProperties, staticName))
728 this[staticName] = isolateProperties[staticName];
729
730 // Reset lazy initializers to null.
731 // When forcing the object to fast mode (below) v8 will consider
732 // functions as part the object's map. Since we will change them
733 // (after the first call to the getter), we would have a map
734 // transition.
735 var lazies = init.lazies;
736 for (var lazyInit in lazies) {
737 this[lazies[lazyInit]] = null;
738 }
739
740 // Use the newly created object as prototype. In Chrome,
741 // this creates a hidden class for the object and makes
742 // sure it is fast to access.
743 function ForceEfficientMap() {}
744 ForceEfficientMap.prototype = this;
745 new ForceEfficientMap();
746
747 // Now, after being a fast map we can set the lazies again.
748 for (var lazyInit in lazies) {
749 var lazyInitName = lazies[lazyInit];
750 this[lazyInitName] = isolateProperties[lazyInitName];
751 }
752 }
753 Isolate.prototype = oldIsolate.prototype;
754 Isolate.prototype.constructor = Isolate;
755 Isolate.#isolatePropertiesName = isolateProperties;
756 if (#needsDefineClass)
757 Isolate.#finishClassesProperty = oldIsolate.#finishClassesProperty;
758 if (#outputContainsConstantList)
759 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty;
760 if (#hasIncrementalSupport)
761 Isolate.#lazyInitializerProperty =
762 oldIsolate.#lazyInitializerProperty;
763 return Isolate;
764 }
765 """,
766 { 'isolatePropertiesName': namer.isolatePropertiesName,
767 'needsDefineClass': needsDefineClass,
768 'finishClassesProperty': finishClassesProperty,
769 'outputContainsConstantList': task.outputContainsConstantList,
770 'makeConstListProperty': makeConstListProperty,
771 'hasIncrementalSupport': compiler.hasIncrementalSupport,
772 'lazyInitializerProperty': lazyInitializerProperty,
773 });
774 }
775
776 jsAst.Fun get lazyInitializerFunction {
777 String isolate = namer.currentIsolate;
778 jsAst.Expression cyclicThrow =
779 staticFunctionAccess(backend.getCyclicThrowHelper());
780 jsAst.Expression laziesAccess =
781 generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
782
783 return js('''
784 function (prototype, staticName, fieldName, getterName, lazyValue) {
785 if (!#lazies) #lazies = Object.create(null);
786 #lazies[fieldName] = getterName;
787
788 var sentinelUndefined = {};
789 var sentinelInProgress = {};
790 prototype[fieldName] = sentinelUndefined;
791
792 prototype[getterName] = function () {
793 var result = $isolate[fieldName];
794 try {
795 if (result === sentinelUndefined) {
796 $isolate[fieldName] = sentinelInProgress;
797
798 try {
799 result = $isolate[fieldName] = lazyValue();
800 } finally {
801 // Use try-finally, not try-catch/throw as it destroys the
802 // stack trace.
803 if (result === sentinelUndefined)
804 $isolate[fieldName] = null;
805 }
806 } else {
807 if (result === sentinelInProgress)
808 #cyclicThrow(staticName);
809 }
810
811 return result;
812 } finally {
813 $isolate[getterName] = function() { return this[fieldName]; };
814 }
815 }
816 }
817 ''', {'lazies': laziesAccess, 'cyclicThrow': cyclicThrow});
818 }
819
820 List buildDefineClassAndFinishClassFunctionsIfNecessary() {
821 if (!needsDefineClass) return [];
822 return defineClassFunction
823 ..add(buildInheritFrom())
824 ..add(js('$finishClassesName = #', finishClassesFunction))
825 ..add(initFinishClasses);
826 }
827
828 List buildLazyInitializerFunctionIfNecessary() {
829 if (!needsLazyInitializer) return [];
830
831 return [js('# = #', [js(lazyInitializerName), lazyInitializerFunction])];
832 }
833
834 List buildFinishIsolateConstructor() {
835 return [
836 js('$finishIsolateConstructorName = #', finishIsolateConstructorFunction)
837 ];
838 }
839
559 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 840 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
560 String isolate = namer.isolateName; 841 String isolate = namer.isolateName;
561 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N"); 842 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N");
562 } 843 }
563 844
564 /// In minified mode we want to keep the name for the most common core types. 845 /// In minified mode we want to keep the name for the most common core types.
565 bool _isNativeTypeNeedingReflectionName(Element element) { 846 bool _isNativeTypeNeedingReflectionName(Element element) {
566 if (!element.isClass) return false; 847 if (!element.isClass) return false;
567 return (element == compiler.intClass || 848 return (element == compiler.intClass ||
568 element == compiler.doubleClass || 849 element == compiler.doubleClass ||
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
723 invariant(classElement, builder.functionType == null); 1004 invariant(classElement, builder.functionType == null);
724 invariant(classElement, builder.fieldMetadata == null); 1005 invariant(classElement, builder.fieldMetadata == null);
725 properties.properties.addAll(builder.properties); 1006 properties.properties.addAll(builder.properties);
726 } else { 1007 } else {
727 classEmitter.generateClass( 1008 classEmitter.generateClass(
728 classElement, properties, additionalProperties[classElement]); 1009 classElement, properties, additionalProperties[classElement]);
729 } 1010 }
730 }); 1011 });
731 } 1012 }
732 1013
1014 void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
1015 if (needsDefineClass) {
1016 buffer.write('$finishClassesName($classesCollector,'
1017 '$_$isolateProperties,'
1018 '${_}null)$N');
1019
1020 // Reset the map.
1021 buffer.write("$classesCollector$_=${_}null$N$n");
1022 }
1023 }
1024
733 void emitStaticFunctions(List<Element> staticFunctions) { 1025 void emitStaticFunctions(List<Element> staticFunctions) {
734 for (Element element in staticFunctions) { 1026 for (Element element in staticFunctions) {
735 ClassBuilder builder = new ClassBuilder(element, namer); 1027 ClassBuilder builder = new ClassBuilder(element, namer);
736 containerBuilder.addMember(element, builder); 1028 containerBuilder.addMember(element, builder);
737 getElementDescriptor(element).properties.addAll(builder.properties); 1029 getElementDescriptor(element).properties.addAll(builder.properties);
738 } 1030 }
739 } 1031 }
740 1032
741 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer, 1033 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer,
742 OutputUnit outputUnit) { 1034 OutputUnit outputUnit) {
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
1038 'mainCallClosure': mainCallClosure}); 1330 'mainCallClosure': mainCallClosure});
1039 1331
1040 buffer.write(';'); 1332 buffer.write(';');
1041 buffer.write(jsAst.prettyPrint(invokeMain, 1333 buffer.write(jsAst.prettyPrint(invokeMain,
1042 compiler, monitor: compiler.dumpInfoTask)); 1334 compiler, monitor: compiler.dumpInfoTask));
1043 buffer.write(N); 1335 buffer.write(N);
1044 addComment('END invoke [main].', buffer); 1336 addComment('END invoke [main].', buffer);
1045 } 1337 }
1046 1338
1047 void emitInitFunction(CodeBuffer buffer) { 1339 void emitInitFunction(CodeBuffer buffer) {
1048 String isolate = namer.currentIsolate;
1049 jsAst.Expression allClassesAccess =
1050 generateEmbeddedGlobalAccess(embeddedNames.ALL_CLASSES);
1051 jsAst.Expression interceptorsByTagAccess =
1052 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
1053 jsAst.Expression leafTagsAccess =
1054 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
1055 jsAst.Expression finishedClassesAccess =
1056 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
1057 jsAst.Expression cyclicThrow =
1058 staticFunctionAccess(backend.getCyclicThrowHelper());
1059 jsAst.Expression laziesAccess =
1060 generateEmbeddedGlobalAccess(embeddedNames.LAZIES);
1061
1062 jsAst.FunctionDeclaration decl = js.statement(''' 1340 jsAst.FunctionDeclaration decl = js.statement('''
1063 function init() { 1341 function init() {
1064 $isolateProperties = Object.create(null); 1342 $isolateProperties = Object.create(null);
1065 (function(){ 1343 #; #; #;
1066 #allClasses = Object.create(null); 1344 }''', [
1067 #interceptorsByTag = Object.create(null); 1345 buildDefineClassAndFinishClassFunctionsIfNecessary(),
1068 #leafTags = Object.create(null); 1346 buildLazyInitializerFunctionIfNecessary(),
1069 #finishedClasses = Object.create(null); 1347 buildFinishIsolateConstructor()]);
1070 })();
1071
1072 if (#needsLazyInitializer) {
1073 $lazyInitializerName = function (prototype, staticName, fieldName,
1074 getterName, lazyValue) {
1075 if (!#lazies) #lazies = Object.create(null);
1076 #lazies[fieldName] = getterName;
1077
1078 var sentinelUndefined = {};
1079 var sentinelInProgress = {};
1080 prototype[fieldName] = sentinelUndefined;
1081
1082 prototype[getterName] = function () {
1083 var result = $isolate[fieldName];
1084 try {
1085 if (result === sentinelUndefined) {
1086 $isolate[fieldName] = sentinelInProgress;
1087
1088 try {
1089 result = $isolate[fieldName] = lazyValue();
1090 } finally {
1091 // Use try-finally, not try-catch/throw as it destroys the
1092 // stack trace.
1093 if (result === sentinelUndefined)
1094 $isolate[fieldName] = null;
1095 }
1096 } else {
1097 if (result === sentinelInProgress)
1098 #cyclicThrow(staticName);
1099 }
1100
1101 return result;
1102 } finally {
1103 $isolate[getterName] = function() { return this[fieldName]; };
1104 }
1105 }
1106 }
1107 }
1108
1109 // We replace the old Isolate function with a new one that initializes
1110 // all its fields with the initial (and often final) value of all
1111 // globals.
1112 //
1113 // We also copy over old values like the prototype, and the
1114 // isolateProperties themselves.
1115 $finishIsolateConstructorName = function (oldIsolate) {
1116 var isolateProperties = oldIsolate.#isolatePropertiesName;
1117 function Isolate() {
1118 var hasOwnProperty = Object.prototype.hasOwnProperty;
1119 for (var staticName in isolateProperties)
1120 if (hasOwnProperty.call(isolateProperties, staticName))
1121 this[staticName] = isolateProperties[staticName];
1122
1123 // Reset lazy initializers to null.
1124 // When forcing the object to fast mode (below) v8 will consider
1125 // functions as part the object's map. Since we will change them
1126 // (after the first call to the getter), we would have a map
1127 // transition.
1128 var lazies = init.lazies;
1129 for (var lazyInit in lazies) {
1130 this[lazies[lazyInit]] = null;
1131 }
1132
1133 // Use the newly created object as prototype. In Chrome,
1134 // this creates a hidden class for the object and makes
1135 // sure it is fast to access.
1136 function ForceEfficientMap() {}
1137 ForceEfficientMap.prototype = this;
1138 new ForceEfficientMap();
1139
1140 // Now, after being a fast map we can set the lazies again.
1141 for (var lazyInit in lazies) {
1142 var lazyInitName = lazies[lazyInit];
1143 this[lazyInitName] = isolateProperties[lazyInitName];
1144 }
1145 }
1146 Isolate.prototype = oldIsolate.prototype;
1147 Isolate.prototype.constructor = Isolate;
1148 Isolate.#isolatePropertiesName = isolateProperties;
1149 if (#outputContainsConstantList) {
1150 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty;
1151 }
1152 if (#hasIncrementalSupport) {
1153 Isolate.#lazyInitializerProperty =
1154 oldIsolate.#lazyInitializerProperty;
1155 }
1156 return Isolate;
1157 }
1158
1159 }''', {'allClasses': allClassesAccess,
1160 'interceptorsByTag': interceptorsByTagAccess,
1161 'leafTags': leafTagsAccess,
1162 'finishedClasses': finishedClassesAccess,
1163 'needsLazyInitializer': needsLazyInitializer,
1164 'lazies': laziesAccess, 'cyclicThrow': cyclicThrow,
1165 'isolatePropertiesName': namer.isolatePropertiesName,
1166 'outputContainsConstantList': task.outputContainsConstantList,
1167 'makeConstListProperty': makeConstListProperty,
1168 'hasIncrementalSupport': compiler.hasIncrementalSupport,
1169 'lazyInitializerProperty': lazyInitializerProperty,});
1170 1348
1171 buffer.write(jsAst.prettyPrint(decl, 1349 buffer.write(jsAst.prettyPrint(decl,
1172 compiler, monitor: compiler.dumpInfoTask).getText()); 1350 compiler, monitor: compiler.dumpInfoTask).getText());
1173 if (compiler.enableMinification) buffer.write('\n'); 1351 if (compiler.enableMinification) buffer.write('\n');
1174 } 1352 }
1175 1353
1176 void emitConvertToFastObjectFunction() { 1354 void emitConvertToFastObjectFunction() {
1177 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; 1355 List<jsAst.Statement> debugCode = <jsAst.Statement>[];
1178 if (DEBUG_FAST_OBJECTS) { 1356 if (DEBUG_FAST_OBJECTS) {
1179 debugCode.add(js.statement(r''' 1357 debugCode.add(js.statement(r'''
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1481 mainBuffer 1659 mainBuffer
1482 .write('${globalsHolder}.${namer.isolateName}$_=$_' 1660 .write('${globalsHolder}.${namer.isolateName}$_=$_'
1483 '${namer.isolateName}$N' 1661 '${namer.isolateName}$N'
1484 '${globalsHolder}.$initName$_=${_}$initName$N'); 1662 '${globalsHolder}.$initName$_=${_}$initName$N');
1485 } 1663 }
1486 mainBuffer.write('init()$N$n'); 1664 mainBuffer.write('init()$N$n');
1487 mainBuffer.write('$isolateProperties$_=$_$isolatePropertiesName$N'); 1665 mainBuffer.write('$isolateProperties$_=$_$isolatePropertiesName$N');
1488 1666
1489 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]); 1667 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]);
1490 1668
1669 // Only output the classesCollector if we actually have any classes.
1670 if (needsDefineClass ||
1671 !(nativeClasses.isEmpty &&
1672 compiler.codegenWorld.staticFunctionsNeedingGetter.isEmpty &&
1673 outputClassLists.values.every((classList) => classList.isEmpty) &&
1674 typedefsNeededForReflection.isEmpty)) {
1675 // Shorten the code by using "$$" as temporary.
1676 classesCollector = r"$$";
1677 mainBuffer.write('var $classesCollector$_=${_}Object.create(null)$N$n');
1678 }
1679
1491 List<ClassElement> classes = task.outputClassLists[mainOutputUnit]; 1680 List<ClassElement> classes = task.outputClassLists[mainOutputUnit];
1492 if (classes != null) { 1681 if (classes != null) {
1493 for (ClassElement element in classes) { 1682 for (ClassElement element in classes) {
1494 generateClass(element, getElementDescriptor(element)); 1683 generateClass(element, getElementDescriptor(element));
1495 } 1684 }
1496 } 1685 }
1497 1686
1498 if (compiler.enableMinification) { 1687 if (compiler.enableMinification) {
1499 mainBuffer.write(';'); 1688 mainBuffer.write(';');
1500 } 1689 }
(...skipping 11 matching lines...) Expand all
1512 CodeBuffer libraryBuffer = new CodeBuffer(); 1701 CodeBuffer libraryBuffer = new CodeBuffer();
1513 for (LibraryElement library in Elements.sortedByPosition(libraries)) { 1702 for (LibraryElement library in Elements.sortedByPosition(libraries)) {
1514 writeLibraryDescriptors(libraryBuffer, library); 1703 writeLibraryDescriptors(libraryBuffer, library);
1515 elementDescriptors.remove(library); 1704 elementDescriptors.remove(library);
1516 } 1705 }
1517 1706
1518 mainBuffer 1707 mainBuffer
1519 ..write('(') 1708 ..write('(')
1520 ..write( 1709 ..write(
1521 jsAst.prettyPrint( 1710 jsAst.prettyPrint(
1522 getReflectionDataParser(this, backend), 1711 getReflectionDataParser(classesCollector, backend),
1523 compiler)) 1712 compiler))
1524 ..write(')') 1713 ..write(')')
1525 ..write('([$n') 1714 ..write('([$n')
1526 ..write(libraryBuffer) 1715 ..write(libraryBuffer)
1527 ..write('])$N'); 1716 ..write('])$N');
1717
1718 emitFinishClassesInvocationIfNecessary(mainBuffer);
1528 } 1719 }
1529 1720
1530 interceptorEmitter.emitGetInterceptorMethods(mainBuffer); 1721 interceptorEmitter.emitGetInterceptorMethods(mainBuffer);
1531 interceptorEmitter.emitOneShotInterceptors(mainBuffer); 1722 interceptorEmitter.emitOneShotInterceptors(mainBuffer);
1532 1723
1533 if (task.outputContainsConstantList) { 1724 if (task.outputContainsConstantList) {
1534 emitMakeConstantList(mainBuffer); 1725 emitMakeConstantList(mainBuffer);
1535 } 1726 }
1536 1727
1537 // Constants in checked mode call into RTI code to set type information 1728 // Constants in checked mode call into RTI code to set type information
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
1810 nativeEmitter.finishGenerateNativeClasses(); 2001 nativeEmitter.finishGenerateNativeClasses();
1811 nativeEmitter.assembleCode(nativeBuffer); 2002 nativeEmitter.assembleCode(nativeBuffer);
1812 2003
1813 return nativeBuffer; 2004 return nativeBuffer;
1814 } 2005 }
1815 2006
1816 void emitProgram(Program program) { 2007 void emitProgram(Program program) {
1817 // Shorten the code by using [namer.currentIsolate] as temporary. 2008 // Shorten the code by using [namer.currentIsolate] as temporary.
1818 isolateProperties = namer.currentIsolate; 2009 isolateProperties = namer.currentIsolate;
1819 2010
2011 classesCollector = r"$$";
2012
1820 // Emit deferred units first, so we have their hashes. 2013 // Emit deferred units first, so we have their hashes.
1821 // Map from OutputUnit to a hash of its content. The hash uniquely 2014 // Map from OutputUnit to a hash of its content. The hash uniquely
1822 // identifies the code of the output-unit. It does not include 2015 // identifies the code of the output-unit. It does not include
1823 // boilerplate JS code, like the sourcemap directives or the hash 2016 // boilerplate JS code, like the sourcemap directives or the hash
1824 // itself. 2017 // itself.
1825 Map<OutputUnit, String> deferredLoadHashes = emitDeferredOutputUnits(); 2018 Map<OutputUnit, String> deferredLoadHashes = emitDeferredOutputUnits();
1826 CodeBuffer nativeBuffer = buildNativesBuffer(); 2019 CodeBuffer nativeBuffer = buildNativesBuffer();
1827 emitMainOutputUnit(deferredLoadHashes, nativeBuffer); 2020 emitMainOutputUnit(deferredLoadHashes, nativeBuffer);
1828 2021
1829 if (backend.requiresPreamble && 2022 if (backend.requiresPreamble &&
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1958 ..write('var init$_=$_${globalsHolder}.init$N') 2151 ..write('var init$_=$_${globalsHolder}.init$N')
1959 ..write('var ${namer.isolateName}$_=$_' 2152 ..write('var ${namer.isolateName}$_=$_'
1960 '${globalsHolder}.${namer.isolateName}$N'); 2153 '${globalsHolder}.${namer.isolateName}$N');
1961 if (libraryDescriptorBuffer != null) { 2154 if (libraryDescriptorBuffer != null) {
1962 // TODO(ahe): This defines a lot of properties on the 2155 // TODO(ahe): This defines a lot of properties on the
1963 // Isolate.prototype object. We know this will turn it into a 2156 // Isolate.prototype object. We know this will turn it into a
1964 // slow object in V8, so instead we should do something similar 2157 // slow object in V8, so instead we should do something similar
1965 // to Isolate.$finishIsolateConstructor. 2158 // to Isolate.$finishIsolateConstructor.
1966 outputBuffer 2159 outputBuffer
1967 ..write('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N') 2160 ..write('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N')
2161 // The classesCollector object ($$).
2162 ..write('$classesCollector$_=${_}Object.create(null);$n')
1968 ..write('(') 2163 ..write('(')
1969 ..write( 2164 ..write(
1970 jsAst.prettyPrint( 2165 jsAst.prettyPrint(
1971 getReflectionDataParser(this, backend), 2166 getReflectionDataParser(classesCollector, backend),
1972 compiler, monitor: compiler.dumpInfoTask)) 2167 compiler, monitor: compiler.dumpInfoTask))
1973 ..write(')') 2168 ..write(')')
1974 ..write('([$n') 2169 ..write('([$n')
1975 ..addBuffer(libraryDescriptorBuffer) 2170 ..addBuffer(libraryDescriptorBuffer)
1976 ..write('])$N'); 2171 ..write('])$N');
1977 2172
2173 if (outputClassLists.containsKey(outputUnit)) {
2174 outputBuffer.write(
2175 '$finishClassesName($classesCollector,$_${namer.currentIsolate},'
2176 '$_$isolatePropertiesName)$N');
2177 }
2178
1978 } 2179 }
1979 2180
1980 // Set the currentIsolate variable to the current isolate (which is 2181 // Set the currentIsolate variable to the current isolate (which is
1981 // provided as second argument). 2182 // provided as second argument).
1982 // We need to do this, because we use the same variable for setting up 2183 // We need to do this, because we use the same variable for setting up
1983 // the isolate-properties and for storing the current isolate. During 2184 // the isolate-properties and for storing the current isolate. During
1984 // the setup (the code above this lines) we must set the variable to 2185 // the setup (the code above this lines) we must set the variable to
1985 // the isolate-properties. 2186 // the isolate-properties.
1986 // After we have done the setup it must point to the current Isolate. 2187 // After we have done the setup (finishing with `finishClasses`) it must
1987 // Otherwise all methods/functions accessing isolate variables will 2188 // point to the current Isolate. Otherwise all methods/functions
1988 // access the wrong object. 2189 // accessing isolate variables will access the wrong object.
1989 outputBuffer.write("${namer.currentIsolate}$_=${_}arguments[1]$N"); 2190 outputBuffer.write("${namer.currentIsolate}$_=${_}arguments[1]$N");
1990 2191
1991 emitCompileTimeConstants(outputBuffer, outputUnit); 2192 emitCompileTimeConstants(outputBuffer, outputUnit);
1992 emitStaticNonFinalFieldInitializations(outputBuffer, outputUnit); 2193 emitStaticNonFinalFieldInitializations(outputBuffer, outputUnit);
1993 outputBuffer.write('}$N'); 2194 outputBuffer.write('}$N');
1994 2195
1995 if (compiler.useContentSecurityPolicy) { 2196 if (compiler.useContentSecurityPolicy) {
1996 jsAst.FunctionDeclaration precompiledFunctionAst = 2197 jsAst.FunctionDeclaration precompiledFunctionAst =
1997 buildCspPrecompiledFunctionFor(outputUnit); 2198 buildCspPrecompiledFunctionFor(outputUnit);
1998 2199
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
2075 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { 2276 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) {
2076 if (element.isInstanceMember) { 2277 if (element.isInstanceMember) {
2077 cachedClassBuilders.remove(element.enclosingClass); 2278 cachedClassBuilders.remove(element.enclosingClass);
2078 2279
2079 nativeEmitter.cachedBuilders.remove(element.enclosingClass); 2280 nativeEmitter.cachedBuilders.remove(element.enclosingClass);
2080 2281
2081 } 2282 }
2082 } 2283 }
2083 } 2284 }
2084 } 2285 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698