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

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

Issue 819993003: dart2js OldEmitter: inline FinishClasses. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Small fixes. 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 needsDefineClass = false; 24 bool needsClassSupport = 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';
158 String get finishIsolateConstructorName 150 String get finishIsolateConstructorName
159 => '${namer.isolateName}.\$finishIsolateConstructor'; 151 => '${namer.isolateName}.\$finishIsolateConstructor';
160 String get isolatePropertiesName 152 String get isolatePropertiesName
161 => '${namer.isolateName}.${namer.isolatePropertiesName}'; 153 => '${namer.isolateName}.${namer.isolatePropertiesName}';
162 String get lazyInitializerProperty 154 String get lazyInitializerProperty
163 => r'$lazy'; 155 => r'$lazy';
164 String get lazyInitializerName 156 String get lazyInitializerName
165 => '${namer.isolateName}.${lazyInitializerProperty}'; 157 => '${namer.isolateName}.${lazyInitializerProperty}';
166 String get initName => 'init'; 158 String get initName => 'init';
167 String get makeConstListProperty 159 String get makeConstListProperty
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 } 206 }
215 207
216 jsAst.PropertyAccess classAccess(Element element) { 208 jsAst.PropertyAccess classAccess(Element element) {
217 return globalPropertyAccess(element); 209 return globalPropertyAccess(element);
218 } 210 }
219 211
220 jsAst.PropertyAccess typedefAccess(Element element) { 212 jsAst.PropertyAccess typedefAccess(Element element) {
221 return globalPropertyAccess(element); 213 return globalPropertyAccess(element);
222 } 214 }
223 215
216 List<jsAst.Statement> buildTrivialNsmHandlers(){
217 return nsmEmitter.buildTrivialNsmHandlers();
218 }
219
224 jsAst.FunctionDeclaration get generateAccessorFunction { 220 jsAst.FunctionDeclaration get generateAccessorFunction {
225 const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1; 221 const RANGE1_SIZE = RANGE1_LAST - RANGE1_FIRST + 1;
226 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1; 222 const RANGE2_SIZE = RANGE2_LAST - RANGE2_FIRST + 1;
227 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST); 223 const RANGE1_ADJUST = - (FIRST_FIELD_CODE - RANGE1_FIRST);
228 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST); 224 const RANGE2_ADJUST = - (FIRST_FIELD_CODE + RANGE1_SIZE - RANGE2_FIRST);
229 const RANGE3_ADJUST = 225 const RANGE3_ADJUST =
230 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST); 226 - (FIRST_FIELD_CODE + RANGE1_SIZE + RANGE2_SIZE - RANGE3_FIRST);
231 227
232 String receiverParamName = compiler.enableMinification ? "r" : "receiver"; 228 String receiverParamName = compiler.enableMinification ? "r" : "receiver";
233 String valueParamName = compiler.enableMinification ? "v" : "value"; 229 String valueParamName = compiler.enableMinification ? "v" : "value";
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 } 335 }
340 if (#hasIsolateSupport) { 336 if (#hasIsolateSupport) {
341 str += name + ".$fieldNamesProperty=[" + fieldNames + "];\\n"; 337 str += name + ".$fieldNamesProperty=[" + fieldNames + "];\\n";
342 } 338 }
343 str += accessors.join(""); 339 str += accessors.join("");
344 340
345 return str; 341 return str;
346 }''', { 'hasIsolateSupport': hasIsolateSupport }); 342 }''', { 'hasIsolateSupport': hasIsolateSupport });
347 343
348 // Declare a function called "generateAccessor". This is used in 344 // Declare a function called "generateAccessor". This is used in
349 // defineClassFunction (it's a local declaration in init()). 345 // defineClassFunction.
350 List result = <jsAst.Node>[ 346 List result = <jsAst.Node>[
351 generateAccessorFunction, 347 generateAccessorFunction,
352 js('$generateAccessorHolder = generateAccessor'),
353 new jsAst.FunctionDeclaration( 348 new jsAst.FunctionDeclaration(
354 new jsAst.VariableDeclaration('defineClass'), defineClass) ]; 349 new jsAst.VariableDeclaration('defineClass'), defineClass) ];
355 350
356 if (compiler.hasIncrementalSupport) { 351 if (compiler.hasIncrementalSupport) {
357 result.add( 352 result.add(
358 js(r'#.defineClass = defineClass', [namer.accessIncrementalHelper])); 353 js(r'#.defineClass = defineClass', [namer.accessIncrementalHelper]));
359 } 354 }
360 355
361 if (hasIsolateSupport) { 356 if (hasIsolateSupport) {
362 jsAst.Expression classIdExtractorAccess = 357 jsAst.Expression classIdExtractorAccess =
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 }; 431 };
437 }() 432 }()
438 '''); 433 ''');
439 if (compiler.hasIncrementalSupport) { 434 if (compiler.hasIncrementalSupport) {
440 result = js( 435 result = js(
441 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]); 436 r'#.inheritFrom = #', [namer.accessIncrementalHelper, result]);
442 } 437 }
443 return js(r'var inheritFrom = #', [result]); 438 return js(r'var inheritFrom = #', [result]);
444 } 439 }
445 440
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
596 jsAst.Statement buildFinishClass() { 441 jsAst.Statement buildFinishClass() {
597 String specProperty = '"${namer.nativeSpecProperty}"'; // "%" 442 String specProperty = '"${namer.nativeSpecProperty}"'; // "%"
598 443
599 jsAst.Expression finishedClassesAccess = 444 jsAst.Expression finishedClassesAccess =
600 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES); 445 generateEmbeddedGlobalAccess(embeddedNames.FINISHED_CLASSES);
601 jsAst.Expression interceptorsByTagAccess = 446 jsAst.Expression interceptorsByTagAccess =
602 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG); 447 generateEmbeddedGlobalAccess(embeddedNames.INTERCEPTORS_BY_TAG);
603 jsAst.Expression leafTagsAccess = 448 jsAst.Expression leafTagsAccess =
604 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS); 449 generateEmbeddedGlobalAccess(embeddedNames.LEAF_TAGS);
605 450
606 return js.statement(''' 451 return js.statement('''
607 { 452 {
608 var finishedClasses = #finishedClassesAccess; 453 var finishedClasses = #finishedClassesAccess;
609 454
610 function finishClass(cls) { 455 function finishClass(cls) {
611 456
612 if (finishedClasses[cls]) return; 457 if (finishedClasses[cls]) return;
613 finishedClasses[cls] = true; 458 finishedClasses[cls] = true;
614 459
615 var superclass = pendingClasses[cls]; 460 var superclass = processedClasses.pending[cls];
616 461
617 if (#needsMixinSupport) { 462 if (#needsMixinSupport) {
618 if (superclass && superclass.indexOf("+") > 0) { 463 if (superclass && superclass.indexOf("+") > 0) {
619 var s = superclass.split("+"); 464 var s = superclass.split("+");
620 superclass = s[0]; 465 superclass = s[0];
621 var mixinClass = s[1]; 466 var mixinClass = s[1];
622 finishClass(mixinClass); 467 finishClass(mixinClass);
623 var mixin = allClasses[mixinClass]; 468 var mixin = allClasses[mixinClass];
624 // TODO(21896): this test shouldn't be necessary. Without it 469 // TODO(21896): this test shouldn't be necessary. Without it
625 // we have a crash in language/mixin_only_for_rti and 470 // we have a crash in language/mixin_only_for_rti and
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
704 } 549 }
705 } 550 }
706 }''', {'finishedClassesAccess': finishedClassesAccess, 551 }''', {'finishedClassesAccess': finishedClassesAccess,
707 'needsMixinSupport': needsMixinSupport, 552 'needsMixinSupport': needsMixinSupport,
708 'hasNativeClasses': nativeClasses.isNotEmpty, 553 'hasNativeClasses': nativeClasses.isNotEmpty,
709 'interceptorsByTagAccess': interceptorsByTagAccess, 554 'interceptorsByTagAccess': interceptorsByTagAccess,
710 'leafTagsAccess': leafTagsAccess, 555 'leafTagsAccess': leafTagsAccess,
711 'allowNativesSubclassing': true}); 556 'allowNativesSubclassing': true});
712 } 557 }
713 558
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
840 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) { 559 void emitFinishIsolateConstructorInvocation(CodeBuffer buffer) {
841 String isolate = namer.isolateName; 560 String isolate = namer.isolateName;
842 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N"); 561 buffer.write("$isolate = $finishIsolateConstructorName($isolate)$N");
843 } 562 }
844 563
845 /// In minified mode we want to keep the name for the most common core types. 564 /// In minified mode we want to keep the name for the most common core types.
846 bool _isNativeTypeNeedingReflectionName(Element element) { 565 bool _isNativeTypeNeedingReflectionName(Element element) {
847 if (!element.isClass) return false; 566 if (!element.isClass) return false;
848 return (element == compiler.intClass || 567 return (element == compiler.intClass ||
849 element == compiler.doubleClass || 568 element == compiler.doubleClass ||
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
1004 invariant(classElement, builder.functionType == null); 723 invariant(classElement, builder.functionType == null);
1005 invariant(classElement, builder.fieldMetadata == null); 724 invariant(classElement, builder.fieldMetadata == null);
1006 properties.properties.addAll(builder.properties); 725 properties.properties.addAll(builder.properties);
1007 } else { 726 } else {
1008 classEmitter.generateClass( 727 classEmitter.generateClass(
1009 classElement, properties, additionalProperties[classElement]); 728 classElement, properties, additionalProperties[classElement]);
1010 } 729 }
1011 }); 730 });
1012 } 731 }
1013 732
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
1025 void emitStaticFunctions(List<Element> staticFunctions) { 733 void emitStaticFunctions(List<Element> staticFunctions) {
1026 for (Element element in staticFunctions) { 734 for (Element element in staticFunctions) {
1027 ClassBuilder builder = new ClassBuilder(element, namer); 735 ClassBuilder builder = new ClassBuilder(element, namer);
1028 containerBuilder.addMember(element, builder); 736 containerBuilder.addMember(element, builder);
1029 getElementDescriptor(element).properties.addAll(builder.properties); 737 getElementDescriptor(element).properties.addAll(builder.properties);
1030 } 738 }
1031 } 739 }
1032 740
1033 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer, 741 void emitStaticNonFinalFieldInitializations(CodeBuffer buffer,
1034 OutputUnit outputUnit) { 742 OutputUnit outputUnit) {
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after
1330 'mainCallClosure': mainCallClosure}); 1038 'mainCallClosure': mainCallClosure});
1331 1039
1332 buffer.write(';'); 1040 buffer.write(';');
1333 buffer.write(jsAst.prettyPrint(invokeMain, 1041 buffer.write(jsAst.prettyPrint(invokeMain,
1334 compiler, monitor: compiler.dumpInfoTask)); 1042 compiler, monitor: compiler.dumpInfoTask));
1335 buffer.write(N); 1043 buffer.write(N);
1336 addComment('END invoke [main].', buffer); 1044 addComment('END invoke [main].', buffer);
1337 } 1045 }
1338 1046
1339 void emitInitFunction(CodeBuffer buffer) { 1047 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
1340 jsAst.FunctionDeclaration decl = js.statement(''' 1062 jsAst.FunctionDeclaration decl = js.statement('''
1341 function init() { 1063 function init() {
1342 $isolateProperties = Object.create(null); 1064 $isolateProperties = Object.create(null);
1343 #; #; #; 1065 (function(){
1344 }''', [ 1066 #allClasses = Object.create(null);
1345 buildDefineClassAndFinishClassFunctionsIfNecessary(), 1067 #interceptorsByTag = Object.create(null);
1346 buildLazyInitializerFunctionIfNecessary(), 1068 #leafTags = Object.create(null);
1347 buildFinishIsolateConstructor()]); 1069 #finishedClasses = Object.create(null);
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,});
1348 1170
1349 buffer.write(jsAst.prettyPrint(decl, 1171 buffer.write(jsAst.prettyPrint(decl,
1350 compiler, monitor: compiler.dumpInfoTask).getText()); 1172 compiler, monitor: compiler.dumpInfoTask).getText());
1351 if (compiler.enableMinification) buffer.write('\n'); 1173 if (compiler.enableMinification) buffer.write('\n');
1352 } 1174 }
1353 1175
1354 void emitConvertToFastObjectFunction() { 1176 void emitConvertToFastObjectFunction() {
1355 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; 1177 List<jsAst.Statement> debugCode = <jsAst.Statement>[];
1356 if (DEBUG_FAST_OBJECTS) { 1178 if (DEBUG_FAST_OBJECTS) {
1357 debugCode.add(js.statement(r''' 1179 debugCode.add(js.statement(r'''
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
1659 mainBuffer 1481 mainBuffer
1660 .write('${globalsHolder}.${namer.isolateName}$_=$_' 1482 .write('${globalsHolder}.${namer.isolateName}$_=$_'
1661 '${namer.isolateName}$N' 1483 '${namer.isolateName}$N'
1662 '${globalsHolder}.$initName$_=${_}$initName$N'); 1484 '${globalsHolder}.$initName$_=${_}$initName$N');
1663 } 1485 }
1664 mainBuffer.write('init()$N$n'); 1486 mainBuffer.write('init()$N$n');
1665 mainBuffer.write('$isolateProperties$_=$_$isolatePropertiesName$N'); 1487 mainBuffer.write('$isolateProperties$_=$_$isolatePropertiesName$N');
1666 1488
1667 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]); 1489 emitStaticFunctions(task.outputStaticLists[mainOutputUnit]);
1668 1490
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
1680 List<ClassElement> classes = task.outputClassLists[mainOutputUnit]; 1491 List<ClassElement> classes = task.outputClassLists[mainOutputUnit];
1681 if (classes != null) { 1492 if (classes != null) {
1682 for (ClassElement element in classes) { 1493 for (ClassElement element in classes) {
1683 generateClass(element, getElementDescriptor(element)); 1494 generateClass(element, getElementDescriptor(element));
1684 } 1495 }
1685 } 1496 }
1686 1497
1687 if (compiler.enableMinification) { 1498 if (compiler.enableMinification) {
1688 mainBuffer.write(';'); 1499 mainBuffer.write(';');
1689 } 1500 }
(...skipping 11 matching lines...) Expand all
1701 CodeBuffer libraryBuffer = new CodeBuffer(); 1512 CodeBuffer libraryBuffer = new CodeBuffer();
1702 for (LibraryElement library in Elements.sortedByPosition(libraries)) { 1513 for (LibraryElement library in Elements.sortedByPosition(libraries)) {
1703 writeLibraryDescriptors(libraryBuffer, library); 1514 writeLibraryDescriptors(libraryBuffer, library);
1704 elementDescriptors.remove(library); 1515 elementDescriptors.remove(library);
1705 } 1516 }
1706 1517
1707 mainBuffer 1518 mainBuffer
1708 ..write('(') 1519 ..write('(')
1709 ..write( 1520 ..write(
1710 jsAst.prettyPrint( 1521 jsAst.prettyPrint(
1711 getReflectionDataParser(classesCollector, backend), 1522 getReflectionDataParser(this, backend),
1712 compiler)) 1523 compiler))
1713 ..write(')') 1524 ..write(')')
1714 ..write('([$n') 1525 ..write('([$n')
1715 ..write(libraryBuffer) 1526 ..write(libraryBuffer)
1716 ..write('])$N'); 1527 ..write('])$N');
1717
1718 emitFinishClassesInvocationIfNecessary(mainBuffer);
1719 } 1528 }
1720 1529
1721 interceptorEmitter.emitGetInterceptorMethods(mainBuffer); 1530 interceptorEmitter.emitGetInterceptorMethods(mainBuffer);
1722 interceptorEmitter.emitOneShotInterceptors(mainBuffer); 1531 interceptorEmitter.emitOneShotInterceptors(mainBuffer);
1723 1532
1724 if (task.outputContainsConstantList) { 1533 if (task.outputContainsConstantList) {
1725 emitMakeConstantList(mainBuffer); 1534 emitMakeConstantList(mainBuffer);
1726 } 1535 }
1727 1536
1728 // Constants in checked mode call into RTI code to set type information 1537 // Constants in checked mode call into RTI code to set type information
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after
2001 nativeEmitter.finishGenerateNativeClasses(); 1810 nativeEmitter.finishGenerateNativeClasses();
2002 nativeEmitter.assembleCode(nativeBuffer); 1811 nativeEmitter.assembleCode(nativeBuffer);
2003 1812
2004 return nativeBuffer; 1813 return nativeBuffer;
2005 } 1814 }
2006 1815
2007 void emitProgram(Program program) { 1816 void emitProgram(Program program) {
2008 // Shorten the code by using [namer.currentIsolate] as temporary. 1817 // Shorten the code by using [namer.currentIsolate] as temporary.
2009 isolateProperties = namer.currentIsolate; 1818 isolateProperties = namer.currentIsolate;
2010 1819
2011 classesCollector = r"$$";
2012
2013 // Emit deferred units first, so we have their hashes. 1820 // Emit deferred units first, so we have their hashes.
2014 // Map from OutputUnit to a hash of its content. The hash uniquely 1821 // Map from OutputUnit to a hash of its content. The hash uniquely
2015 // identifies the code of the output-unit. It does not include 1822 // identifies the code of the output-unit. It does not include
2016 // boilerplate JS code, like the sourcemap directives or the hash 1823 // boilerplate JS code, like the sourcemap directives or the hash
2017 // itself. 1824 // itself.
2018 Map<OutputUnit, String> deferredLoadHashes = emitDeferredOutputUnits(); 1825 Map<OutputUnit, String> deferredLoadHashes = emitDeferredOutputUnits();
2019 CodeBuffer nativeBuffer = buildNativesBuffer(); 1826 CodeBuffer nativeBuffer = buildNativesBuffer();
2020 emitMainOutputUnit(deferredLoadHashes, nativeBuffer); 1827 emitMainOutputUnit(deferredLoadHashes, nativeBuffer);
2021 1828
2022 if (backend.requiresPreamble && 1829 if (backend.requiresPreamble &&
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2150 outputBuffer 1957 outputBuffer
2151 ..write('var init$_=$_${globalsHolder}.init$N') 1958 ..write('var init$_=$_${globalsHolder}.init$N')
2152 ..write('var ${namer.isolateName}$_=$_' 1959 ..write('var ${namer.isolateName}$_=$_'
2153 '${globalsHolder}.${namer.isolateName}$N'); 1960 '${globalsHolder}.${namer.isolateName}$N');
2154 if (libraryDescriptorBuffer != null) { 1961 if (libraryDescriptorBuffer != null) {
2155 // TODO(ahe): This defines a lot of properties on the 1962 // TODO(ahe): This defines a lot of properties on the
2156 // Isolate.prototype object. We know this will turn it into a 1963 // Isolate.prototype object. We know this will turn it into a
2157 // slow object in V8, so instead we should do something similar 1964 // slow object in V8, so instead we should do something similar
2158 // to Isolate.$finishIsolateConstructor. 1965 // to Isolate.$finishIsolateConstructor.
2159 outputBuffer 1966 outputBuffer
2160 ..write('var ${namer.currentIsolate}$_=$_$isolatePropertiesName$N') 1967 ..write('var ${namer.currentIsolate}$_=$_$isolatePropertiesName;$n')
2161 // The classesCollector object ($$).
2162 ..write('$classesCollector$_=${_}Object.create(null);$n')
2163 ..write('(') 1968 ..write('(')
2164 ..write( 1969 ..write(
2165 jsAst.prettyPrint( 1970 jsAst.prettyPrint(
2166 getReflectionDataParser(classesCollector, backend), 1971 getReflectionDataParser(this, backend),
2167 compiler, monitor: compiler.dumpInfoTask)) 1972 compiler, monitor: compiler.dumpInfoTask))
2168 ..write(')') 1973 ..write(')')
2169 ..write('([$n') 1974 ..write('([$n')
2170 ..addBuffer(libraryDescriptorBuffer) 1975 ..addBuffer(libraryDescriptorBuffer)
2171 ..write('])$N'); 1976 ..write('])$N');
2172 1977
2173 if (outputClassLists.containsKey(outputUnit)) {
2174 outputBuffer.write(
2175 '$finishClassesName($classesCollector,$_${namer.currentIsolate},'
2176 '$_$isolatePropertiesName)$N');
2177 }
2178
2179 } 1978 }
2180 1979
2181 // Set the currentIsolate variable to the current isolate (which is 1980 // Set the currentIsolate variable to the current isolate (which is
2182 // provided as second argument). 1981 // provided as second argument).
2183 // We need to do this, because we use the same variable for setting up 1982 // We need to do this, because we use the same variable for setting up
2184 // the isolate-properties and for storing the current isolate. During 1983 // the isolate-properties and for storing the current isolate. During
2185 // the setup (the code above this lines) we must set the variable to 1984 // the setup (the code above this lines) we must set the variable to
2186 // the isolate-properties. 1985 // the isolate-properties.
2187 // After we have done the setup (finishing with `finishClasses`) it must 1986 // After we have done the setup it must point to the current Isolate.
2188 // point to the current Isolate. Otherwise all methods/functions 1987 // Otherwise all methods/functions accessing isolate variables will
2189 // accessing isolate variables will access the wrong object. 1988 // access the wrong object.
2190 outputBuffer.write("${namer.currentIsolate}$_=${_}arguments[1]$N"); 1989 outputBuffer.write("${namer.currentIsolate}$_=${_}arguments[1]$N");
2191 1990
2192 emitCompileTimeConstants(outputBuffer, outputUnit); 1991 emitCompileTimeConstants(outputBuffer, outputUnit);
2193 emitStaticNonFinalFieldInitializations(outputBuffer, outputUnit); 1992 emitStaticNonFinalFieldInitializations(outputBuffer, outputUnit);
2194 outputBuffer.write('}$N'); 1993 outputBuffer.write('}$N');
2195 1994
2196 if (compiler.useContentSecurityPolicy) { 1995 if (compiler.useContentSecurityPolicy) {
2197 jsAst.FunctionDeclaration precompiledFunctionAst = 1996 jsAst.FunctionDeclaration precompiledFunctionAst =
2198 buildCspPrecompiledFunctionFor(outputUnit); 1997 buildCspPrecompiledFunctionFor(outputUnit);
2199 1998
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
2276 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { 2075 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) {
2277 if (element.isInstanceMember) { 2076 if (element.isInstanceMember) {
2278 cachedClassBuilders.remove(element.enclosingClass); 2077 cachedClassBuilders.remove(element.enclosingClass);
2279 2078
2280 nativeEmitter.cachedBuilders.remove(element.enclosingClass); 2079 nativeEmitter.cachedBuilders.remove(element.enclosingClass);
2281 2080
2282 } 2081 }
2283 } 2082 }
2284 } 2083 }
2285 } 2084 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698