| OLD | NEW |
| 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 library dart2js.js_emitter.full_emitter; | 5 library dart2js.js_emitter.full_emitter; |
| 6 | 6 |
| 7 import 'dart:collection' show HashMap; | 7 import 'dart:collection' show HashMap; |
| 8 import 'dart:convert'; | 8 import 'dart:convert'; |
| 9 | 9 |
| 10 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; | 10 import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 103 Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists; | 103 Map<OutputUnit, List<VariableElement>> outputStaticNonFinalFieldLists; |
| 104 Map<OutputUnit, Set<LibraryElement>> outputLibraryLists; | 104 Map<OutputUnit, Set<LibraryElement>> outputLibraryLists; |
| 105 List<TypedefElement> typedefsNeededForReflection; | 105 List<TypedefElement> typedefsNeededForReflection; |
| 106 | 106 |
| 107 final ContainerBuilder containerBuilder = new ContainerBuilder(); | 107 final ContainerBuilder containerBuilder = new ContainerBuilder(); |
| 108 final ClassEmitter classEmitter; | 108 final ClassEmitter classEmitter; |
| 109 final NsmEmitter nsmEmitter; | 109 final NsmEmitter nsmEmitter; |
| 110 final InterceptorEmitter interceptorEmitter; | 110 final InterceptorEmitter interceptorEmitter; |
| 111 | 111 |
| 112 // TODO(johnniwinther): Wrap these fields in a caching strategy. | 112 // TODO(johnniwinther): Wrap these fields in a caching strategy. |
| 113 final Set<ConstantValue> cachedEmittedConstants; | |
| 114 final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[]; | 113 final List<jsAst.Statement> cachedEmittedConstantsAst = <jsAst.Statement>[]; |
| 115 final Map<Element, ClassBuilder> cachedClassBuilders; | |
| 116 final Set<Element> cachedElements; | |
| 117 | 114 |
| 118 bool needsClassSupport = false; | 115 bool needsClassSupport = false; |
| 119 bool needsMixinSupport = false; | 116 bool needsMixinSupport = false; |
| 120 bool needsLazyInitializer = false; | 117 bool needsLazyInitializer = false; |
| 121 | 118 |
| 122 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info", | 119 /// True if [ContainerBuilder.addMemberMethodFromInfo] used "structured info", |
| 123 /// that is, some function was needed for reflection, had stubs, or had a | 120 /// that is, some function was needed for reflection, had stubs, or had a |
| 124 /// super alias. | 121 /// super alias. |
| 125 bool needsStructuredMemberInfo = false; | 122 bool needsStructuredMemberInfo = false; |
| 126 | 123 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 // this map. | 170 // this map. |
| 174 final Map<Fragment, Map<Element, ClassBuilder>> elementDescriptors = | 171 final Map<Fragment, Map<Element, ClassBuilder>> elementDescriptors = |
| 175 new Map<Fragment, Map<Element, ClassBuilder>>(); | 172 new Map<Fragment, Map<Element, ClassBuilder>>(); |
| 176 | 173 |
| 177 final bool generateSourceMap; | 174 final bool generateSourceMap; |
| 178 | 175 |
| 179 Emitter(Compiler compiler, Namer namer, ClosedWorld closedWorld, | 176 Emitter(Compiler compiler, Namer namer, ClosedWorld closedWorld, |
| 180 this.generateSourceMap, this.task) | 177 this.generateSourceMap, this.task) |
| 181 : this.compiler = compiler, | 178 : this.compiler = compiler, |
| 182 this.namer = namer, | 179 this.namer = namer, |
| 183 cachedEmittedConstants = compiler.cacheStrategy.newSet(), | |
| 184 cachedClassBuilders = compiler.cacheStrategy.newMap(), | |
| 185 cachedElements = compiler.cacheStrategy.newSet(), | |
| 186 classEmitter = new ClassEmitter(closedWorld), | 180 classEmitter = new ClassEmitter(closedWorld), |
| 187 interceptorEmitter = new InterceptorEmitter(closedWorld), | 181 interceptorEmitter = new InterceptorEmitter(closedWorld), |
| 188 nsmEmitter = new NsmEmitter(closedWorld) { | 182 nsmEmitter = new NsmEmitter(closedWorld) { |
| 189 constantEmitter = new ConstantEmitter( | 183 constantEmitter = new ConstantEmitter( |
| 190 compiler, namer, this.constantReference, constantListGenerator); | 184 compiler, namer, this.constantReference, constantListGenerator); |
| 191 containerBuilder.emitter = this; | 185 containerBuilder.emitter = this; |
| 192 classEmitter.emitter = this; | 186 classEmitter.emitter = this; |
| 193 nsmEmitter.emitter = this; | 187 nsmEmitter.emitter = this; |
| 194 interceptorEmitter.emitter = this; | 188 interceptorEmitter.emitter = this; |
| 195 if (compiler.options.hasIncrementalSupport) { | |
| 196 // Much like a scout, an incremental compiler is always prepared. For | |
| 197 // mixins, classes, and lazy statics, at least. | |
| 198 needsClassSupport = true; | |
| 199 needsMixinSupport = true; | |
| 200 needsLazyInitializer = true; | |
| 201 needsStructuredMemberInfo = true; | |
| 202 } | |
| 203 } | 189 } |
| 204 | 190 |
| 205 DiagnosticReporter get reporter => compiler.reporter; | 191 DiagnosticReporter get reporter => compiler.reporter; |
| 206 | 192 |
| 207 List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) { | 193 List<jsAst.Node> cspPrecompiledFunctionFor(OutputUnit outputUnit) { |
| 208 return _cspPrecompiledFunctions.putIfAbsent( | 194 return _cspPrecompiledFunctions.putIfAbsent( |
| 209 outputUnit, () => new List<jsAst.Node>()); | 195 outputUnit, () => new List<jsAst.Node>()); |
| 210 } | 196 } |
| 211 | 197 |
| 212 List<jsAst.Expression> cspPrecompiledConstructorNamesFor( | 198 List<jsAst.Expression> cspPrecompiledConstructorNamesFor( |
| 213 OutputUnit outputUnit) { | 199 OutputUnit outputUnit) { |
| 214 return _cspPrecompiledConstructorNames.putIfAbsent( | 200 return _cspPrecompiledConstructorNames.putIfAbsent( |
| 215 outputUnit, () => new List<jsAst.Expression>()); | 201 outputUnit, () => new List<jsAst.Expression>()); |
| 216 } | 202 } |
| 217 | 203 |
| 218 /// Erases the precompiled information for csp mode for all output units. | |
| 219 /// Used by the incremental compiler. | |
| 220 void clearCspPrecompiledNodes() { | |
| 221 _cspPrecompiledFunctions.clear(); | |
| 222 _cspPrecompiledConstructorNames.clear(); | |
| 223 } | |
| 224 | |
| 225 @override | 204 @override |
| 226 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { | 205 bool isConstantInlinedOrAlreadyEmitted(ConstantValue constant) { |
| 227 if (constant.isFunction) return true; // Already emitted. | 206 if (constant.isFunction) return true; // Already emitted. |
| 228 if (constant.isPrimitive) return true; // Inlined. | 207 if (constant.isPrimitive) return true; // Inlined. |
| 229 if (constant.isDummy) return true; // Inlined. | 208 if (constant.isDummy) return true; // Inlined. |
| 230 // The name is null when the constant is already a JS constant. | 209 // The name is null when the constant is already a JS constant. |
| 231 // TODO(floitsch): every constant should be registered, so that we can | 210 // TODO(floitsch): every constant should be registered, so that we can |
| 232 // share the ones that take up too much space (like some strings). | 211 // share the ones that take up too much space (like some strings). |
| 233 if (namer.constantName(constant) == null) return true; | 212 if (namer.constantName(constant) == null) return true; |
| 234 return false; | 213 return false; |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 }); | 568 }); |
| 590 } else { | 569 } else { |
| 591 return js.comment("Constructors are generated at runtime."); | 570 return js.comment("Constructors are generated at runtime."); |
| 592 } | 571 } |
| 593 } | 572 } |
| 594 | 573 |
| 595 void assembleClass( | 574 void assembleClass( |
| 596 Class cls, ClassBuilder enclosingBuilder, Fragment fragment) { | 575 Class cls, ClassBuilder enclosingBuilder, Fragment fragment) { |
| 597 ClassElement classElement = cls.element; | 576 ClassElement classElement = cls.element; |
| 598 reporter.withCurrentElement(classElement, () { | 577 reporter.withCurrentElement(classElement, () { |
| 599 if (compiler.options.hasIncrementalSupport) { | 578 classEmitter.emitClass(cls, enclosingBuilder, fragment); |
| 600 ClassBuilder cachedBuilder = | |
| 601 cachedClassBuilders.putIfAbsent(classElement, () { | |
| 602 ClassBuilder builder = new ClassBuilder.forClass(classElement, namer); | |
| 603 classEmitter.emitClass(cls, builder, fragment); | |
| 604 return builder; | |
| 605 }); | |
| 606 invariant(classElement, cachedBuilder.fields.isEmpty); | |
| 607 invariant(classElement, cachedBuilder.superName == null); | |
| 608 invariant(classElement, cachedBuilder.functionType == null); | |
| 609 invariant(classElement, cachedBuilder.fieldMetadata == null); | |
| 610 enclosingBuilder.properties.addAll(cachedBuilder.properties); | |
| 611 } else { | |
| 612 classEmitter.emitClass(cls, enclosingBuilder, fragment); | |
| 613 } | |
| 614 }); | 579 }); |
| 615 } | 580 } |
| 616 | 581 |
| 617 void assembleStaticFunctions( | 582 void assembleStaticFunctions( |
| 618 Iterable<Method> staticFunctions, Fragment fragment) { | 583 Iterable<Method> staticFunctions, Fragment fragment) { |
| 619 if (staticFunctions == null) return; | 584 if (staticFunctions == null) return; |
| 620 | 585 |
| 621 for (Method method in staticFunctions) { | 586 for (Method method in staticFunctions) { |
| 622 MethodElement element = method.element; | 587 MethodElement element = method.element; |
| 623 // We need to filter out null-elements for the interceptors. | 588 // We need to filter out null-elements for the interceptors. |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 if (!compiler.options.enableMinification) { | 699 if (!compiler.options.enableMinification) { |
| 735 laziesInfo.add(js.quoteName(field.name)); | 700 laziesInfo.add(js.quoteName(field.name)); |
| 736 } | 701 } |
| 737 if (!isMainFragment) { | 702 if (!isMainFragment) { |
| 738 laziesInfo.add(js('#', field.holder.name)); | 703 laziesInfo.add(js('#', field.holder.name)); |
| 739 } | 704 } |
| 740 } | 705 } |
| 741 return laziesInfo; | 706 return laziesInfo; |
| 742 } | 707 } |
| 743 | 708 |
| 744 // TODO(sra): Remove this unused function. | |
| 745 jsAst.Expression buildLazilyInitializedStaticField(VariableElement element, | |
| 746 {String isolateProperties}) { | |
| 747 jsAst.Expression code = backend.generatedCode[element]; | |
| 748 // The code is null if we ended up not needing the lazily | |
| 749 // initialized field after all because of constant folding | |
| 750 // before code generation. | |
| 751 if (code == null) return null; | |
| 752 // The code only computes the initial value. We build the lazy-check | |
| 753 // here: | |
| 754 // lazyInitializer(fieldName, getterName, initial, name, prototype); | |
| 755 // The name is used for error reporting. The 'initial' must be a | |
| 756 // closure that constructs the initial value. | |
| 757 if (isolateProperties != null) { | |
| 758 // This is currently only used in incremental compilation to patch | |
| 759 // in new lazy values. | |
| 760 return js('#(#,#,#,#,#)', [ | |
| 761 js(lazyInitializerName), | |
| 762 js.quoteName(namer.globalPropertyName(element)), | |
| 763 js.quoteName(namer.lazyInitializerName(element)), | |
| 764 code, | |
| 765 js.string(element.name), | |
| 766 isolateProperties | |
| 767 ]); | |
| 768 } | |
| 769 | |
| 770 if (compiler.options.enableMinification) { | |
| 771 return js('#(#,#,#)', [ | |
| 772 js(lazyInitializerName), | |
| 773 js.quoteName(namer.globalPropertyName(element)), | |
| 774 js.quoteName(namer.lazyInitializerName(element)), | |
| 775 code | |
| 776 ]); | |
| 777 } else { | |
| 778 return js('#(#,#,#,#)', [ | |
| 779 js(lazyInitializerName), | |
| 780 js.quoteName(namer.globalPropertyName(element)), | |
| 781 js.quoteName(namer.lazyInitializerName(element)), | |
| 782 code, | |
| 783 js.string(element.name) | |
| 784 ]); | |
| 785 } | |
| 786 } | |
| 787 | |
| 788 jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) { | 709 jsAst.Statement buildMetadata(Program program, OutputUnit outputUnit) { |
| 789 List<jsAst.Statement> parts = <jsAst.Statement>[]; | 710 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 790 | 711 |
| 791 jsAst.Expression types = program.metadataTypesForOutputUnit(outputUnit); | 712 jsAst.Expression types = program.metadataTypesForOutputUnit(outputUnit); |
| 792 | 713 |
| 793 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) { | 714 if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) { |
| 794 jsAst.Expression metadataAccess = | 715 jsAst.Expression metadataAccess = |
| 795 generateEmbeddedGlobalAccess(embeddedNames.METADATA); | 716 generateEmbeddedGlobalAccess(embeddedNames.METADATA); |
| 796 jsAst.Expression typesAccess = | 717 jsAst.Expression typesAccess = |
| 797 generateEmbeddedGlobalAccess(embeddedNames.TYPES); | 718 generateEmbeddedGlobalAccess(embeddedNames.TYPES); |
| 798 | 719 |
| 799 parts | 720 parts |
| 800 ..add(js.statement('# = #;', [metadataAccess, program.metadata])) | 721 ..add(js.statement('# = #;', [metadataAccess, program.metadata])) |
| 801 ..add(js.statement('# = #;', [typesAccess, types])); | 722 ..add(js.statement('# = #;', [typesAccess, types])); |
| 802 } else if (types != null) { | 723 } else if (types != null) { |
| 803 parts.add(js.statement('var ${namer.deferredTypesName} = #;', types)); | 724 parts.add(js.statement('var ${namer.deferredTypesName} = #;', types)); |
| 804 } | 725 } |
| 805 return new jsAst.Block(parts); | 726 return new jsAst.Block(parts); |
| 806 } | 727 } |
| 807 | 728 |
| 808 jsAst.Statement buildCompileTimeConstants(List<Constant> constants, | 729 jsAst.Statement buildCompileTimeConstants(List<Constant> constants, |
| 809 {bool isMainFragment}) { | 730 {bool isMainFragment}) { |
| 810 assert(isMainFragment != null); | 731 assert(isMainFragment != null); |
| 811 | 732 |
| 812 if (constants.isEmpty) return js.comment("No constants in program."); | 733 if (constants.isEmpty) return js.comment("No constants in program."); |
| 813 List<jsAst.Statement> parts = <jsAst.Statement>[]; | 734 List<jsAst.Statement> parts = <jsAst.Statement>[]; |
| 814 if (compiler.options.hasIncrementalSupport && isMainFragment) { | |
| 815 parts = cachedEmittedConstantsAst; | |
| 816 } | |
| 817 for (Constant constant in constants) { | 735 for (Constant constant in constants) { |
| 818 ConstantValue constantValue = constant.value; | 736 ConstantValue constantValue = constant.value; |
| 819 if (compiler.options.hasIncrementalSupport && isMainFragment) { | |
| 820 if (cachedEmittedConstants.contains(constantValue)) continue; | |
| 821 cachedEmittedConstants.add(constantValue); | |
| 822 } | |
| 823 parts.add(buildConstantInitializer(constantValue)); | 737 parts.add(buildConstantInitializer(constantValue)); |
| 824 } | 738 } |
| 825 | 739 |
| 826 return new jsAst.Block(parts); | 740 return new jsAst.Block(parts); |
| 827 } | 741 } |
| 828 | 742 |
| 829 jsAst.Statement buildConstantInitializer(ConstantValue constant) { | 743 jsAst.Statement buildConstantInitializer(ConstantValue constant) { |
| 830 jsAst.Name name = namer.constantName(constant); | 744 jsAst.Name name = namer.constantName(constant); |
| 831 jsAst.Statement initializer = js.statement('#.# = #', [ | 745 jsAst.Statement initializer = js.statement('#.# = #', [ |
| 832 namer.globalObjectForConstant(constant), | 746 namer.globalObjectForConstant(constant), |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1010 } | 924 } |
| 1011 } | 925 } |
| 1012 Isolate.prototype = oldIsolate.prototype; | 926 Isolate.prototype = oldIsolate.prototype; |
| 1013 Isolate.prototype.constructor = Isolate; | 927 Isolate.prototype.constructor = Isolate; |
| 1014 Isolate.#isolatePropertiesName = isolateProperties; | 928 Isolate.#isolatePropertiesName = isolateProperties; |
| 1015 if (#outputContainsConstantList) { | 929 if (#outputContainsConstantList) { |
| 1016 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty; | 930 Isolate.#makeConstListProperty = oldIsolate.#makeConstListProperty; |
| 1017 } | 931 } |
| 1018 Isolate.#functionThatReturnsNullProperty = | 932 Isolate.#functionThatReturnsNullProperty = |
| 1019 oldIsolate.#functionThatReturnsNullProperty; | 933 oldIsolate.#functionThatReturnsNullProperty; |
| 1020 if (#hasIncrementalSupport) { | |
| 1021 Isolate.#lazyInitializerProperty = | |
| 1022 oldIsolate.#lazyInitializerProperty; | |
| 1023 } | |
| 1024 return Isolate; | 934 return Isolate; |
| 1025 } | 935 } |
| 1026 | 936 |
| 1027 }''', | 937 }''', |
| 1028 { | 938 { |
| 1029 'allClasses': allClassesAccess, | 939 'allClasses': allClassesAccess, |
| 1030 'getTypeFromName': getTypeFromNameAccess, | 940 'getTypeFromName': getTypeFromNameAccess, |
| 1031 'interceptorsByTag': interceptorsByTagAccess, | 941 'interceptorsByTag': interceptorsByTagAccess, |
| 1032 'leafTags': leafTagsAccess, | 942 'leafTags': leafTagsAccess, |
| 1033 'finishedClasses': finishedClassesAccess, | 943 'finishedClasses': finishedClassesAccess, |
| 1034 'needsLazyInitializer': needsLazyInitializer, | 944 'needsLazyInitializer': needsLazyInitializer, |
| 1035 'lazies': laziesAccess, | 945 'lazies': laziesAccess, |
| 1036 'cyclicThrow': cyclicThrow, | 946 'cyclicThrow': cyclicThrow, |
| 1037 'isolatePropertiesName': namer.isolatePropertiesName, | 947 'isolatePropertiesName': namer.isolatePropertiesName, |
| 1038 'outputContainsConstantList': outputContainsConstantList, | 948 'outputContainsConstantList': outputContainsConstantList, |
| 1039 'makeConstListProperty': makeConstListProperty, | 949 'makeConstListProperty': makeConstListProperty, |
| 1040 'functionThatReturnsNullProperty': | 950 'functionThatReturnsNullProperty': |
| 1041 backend.rtiEncoder.getFunctionThatReturnsNullName, | 951 backend.rtiEncoder.getFunctionThatReturnsNullName, |
| 1042 'hasIncrementalSupport': compiler.options.hasIncrementalSupport, | |
| 1043 'lazyInitializerProperty': lazyInitializerProperty, | |
| 1044 }); | 952 }); |
| 1045 } | 953 } |
| 1046 | 954 |
| 1047 jsAst.Statement buildConvertToFastObjectFunction() { | 955 jsAst.Statement buildConvertToFastObjectFunction() { |
| 1048 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; | 956 List<jsAst.Statement> debugCode = <jsAst.Statement>[]; |
| 1049 if (DEBUG_FAST_OBJECTS) { | 957 if (DEBUG_FAST_OBJECTS) { |
| 1050 debugCode.add(js.statement(r''' | 958 debugCode.add(js.statement(r''' |
| 1051 // The following only works on V8 when run with option | 959 // The following only works on V8 when run with option |
| 1052 // "--allow-natives-syntax". We use'new Function' because the | 960 // "--allow-natives-syntax". We use'new Function' because the |
| 1053 // miniparser does not understand V8 native syntax. | 961 // miniparser does not understand V8 native syntax. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1081 // mode. | 989 // mode. |
| 1082 properties.__MAGIC_SLOW_PROPERTY = 1; | 990 properties.__MAGIC_SLOW_PROPERTY = 1; |
| 1083 delete properties.__MAGIC_SLOW_PROPERTY; | 991 delete properties.__MAGIC_SLOW_PROPERTY; |
| 1084 return properties; | 992 return properties; |
| 1085 }'''); | 993 }'''); |
| 1086 } | 994 } |
| 1087 | 995 |
| 1088 jsAst.Statement buildSupportsDirectProtoAccess() { | 996 jsAst.Statement buildSupportsDirectProtoAccess() { |
| 1089 jsAst.Statement supportsDirectProtoAccess; | 997 jsAst.Statement supportsDirectProtoAccess; |
| 1090 | 998 |
| 1091 if (compiler.options.hasIncrementalSupport) { | 999 supportsDirectProtoAccess = js.statement(r''' |
| 1092 supportsDirectProtoAccess = js.statement(r''' | 1000 var supportsDirectProtoAccess = (function () { |
| 1093 var supportsDirectProtoAccess = false; | 1001 var cls = function () {}; |
| 1094 '''); | 1002 cls.prototype = {'p': {}}; |
| 1095 } else { | 1003 var object = new cls(); |
| 1096 supportsDirectProtoAccess = js.statement(r''' | 1004 if (!(object.__proto__ && object.__proto__.p === cls.prototype.p)) |
| 1097 var supportsDirectProtoAccess = (function () { | 1005 return false; |
| 1098 var cls = function () {}; | |
| 1099 cls.prototype = {'p': {}}; | |
| 1100 var object = new cls(); | |
| 1101 if (!(object.__proto__ && object.__proto__.p === cls.prototype.p)) | |
| 1102 return false; | |
| 1103 | |
| 1104 try { | |
| 1105 // Are we running on a platform where the performance is good? | |
| 1106 // (i.e. Chrome or d8). | |
| 1107 | 1006 |
| 1108 // Chrome userAgent? | 1007 try { |
| 1109 if (typeof navigator != "undefined" && | 1008 // Are we running on a platform where the performance is good? |
| 1110 typeof navigator.userAgent == "string" && | 1009 // (i.e. Chrome or d8). |
| 1111 navigator.userAgent.indexOf("Chrome/") >= 0) return true; | |
| 1112 | 1010 |
| 1113 // d8 version() looks like "N.N.N.N", jsshell version() like "N". | 1011 // Chrome userAgent? |
| 1114 if (typeof version == "function" && | 1012 if (typeof navigator != "undefined" && |
| 1115 version.length == 0) { | 1013 typeof navigator.userAgent == "string" && |
| 1116 var v = version(); | 1014 navigator.userAgent.indexOf("Chrome/") >= 0) return true; |
| 1117 if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true; | 1015 |
| 1118 } | 1016 // d8 version() looks like "N.N.N.N", jsshell version() like "N". |
| 1119 } catch(_) {} | 1017 if (typeof version == "function" && |
| 1120 | 1018 version.length == 0) { |
| 1121 return false; | 1019 var v = version(); |
| 1122 })(); | 1020 if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true; |
| 1123 '''); | 1021 } |
| 1124 } | 1022 } catch(_) {} |
| 1023 |
| 1024 return false; |
| 1025 })(); |
| 1026 '''); |
| 1125 | 1027 |
| 1126 return supportsDirectProtoAccess; | 1028 return supportsDirectProtoAccess; |
| 1127 } | 1029 } |
| 1128 | 1030 |
| 1129 jsAst.Expression generateLibraryDescriptor( | 1031 jsAst.Expression generateLibraryDescriptor( |
| 1130 LibraryElement library, Fragment fragment) { | 1032 LibraryElement library, Fragment fragment) { |
| 1131 var uri = ""; | 1033 var uri = ""; |
| 1132 if (!compiler.options.enableMinification || backend.mustPreserveUris) { | 1034 if (!compiler.options.enableMinification || backend.mustPreserveUris) { |
| 1133 uri = library.canonicalUri; | 1035 uri = library.canonicalUri; |
| 1134 if (uri.scheme == 'file' && compiler.options.outputUri != null) { | 1036 if (uri.scheme == 'file' && compiler.options.outputUri != null) { |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1372 jsAst.Expression mangledGlobalNamesAccess = | 1274 jsAst.Expression mangledGlobalNamesAccess = |
| 1373 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); | 1275 generateEmbeddedGlobalAccess(embeddedNames.MANGLED_GLOBAL_NAMES); |
| 1374 jsAst.ObjectInitializer map = new jsAst.ObjectInitializer(properties); | 1276 jsAst.ObjectInitializer map = new jsAst.ObjectInitializer(properties); |
| 1375 parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map])); | 1277 parts.add(js.statement('# = #', [mangledGlobalNamesAccess, map])); |
| 1376 } | 1278 } |
| 1377 | 1279 |
| 1378 return new jsAst.Block(parts); | 1280 return new jsAst.Block(parts); |
| 1379 } | 1281 } |
| 1380 | 1282 |
| 1381 void checkEverythingEmitted(Iterable<Element> elements) { | 1283 void checkEverythingEmitted(Iterable<Element> elements) { |
| 1382 List<Element> pendingStatics; | 1284 List<Element> pendingStatics = |
| 1383 if (!compiler.options.hasIncrementalSupport) { | 1285 Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); |
| 1384 pendingStatics = | |
| 1385 Elements.sortedByPosition(elements.where((e) => !e.isLibrary)); | |
| 1386 | 1286 |
| 1387 pendingStatics.forEach((element) => reporter.reportInfo( | 1287 pendingStatics.forEach((element) => reporter.reportInfo( |
| 1388 element, MessageKind.GENERIC, {'text': 'Pending statics.'})); | 1288 element, MessageKind.GENERIC, {'text': 'Pending statics.'})); |
| 1389 } | |
| 1390 | 1289 |
| 1391 if (pendingStatics != null && !pendingStatics.isEmpty) { | 1290 if (pendingStatics != null && !pendingStatics.isEmpty) { |
| 1392 reporter.internalError( | 1291 reporter.internalError( |
| 1393 pendingStatics.first, 'Pending statics (see above).'); | 1292 pendingStatics.first, 'Pending statics (see above).'); |
| 1394 } | 1293 } |
| 1395 } | 1294 } |
| 1396 | 1295 |
| 1397 void assembleLibrary(Library library, Fragment fragment) { | 1296 void assembleLibrary(Library library, Fragment fragment) { |
| 1398 LibraryElement libraryElement = library.element; | 1297 LibraryElement libraryElement = library.element; |
| 1399 | 1298 |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1458 } | 1357 } |
| 1459 | 1358 |
| 1460 if (descriptors.isNotEmpty) { | 1359 if (descriptors.isNotEmpty) { |
| 1461 List<Element> remainingLibraries = | 1360 List<Element> remainingLibraries = |
| 1462 descriptors.keys.where((Element e) => e is LibraryElement).toList(); | 1361 descriptors.keys.where((Element e) => e is LibraryElement).toList(); |
| 1463 | 1362 |
| 1464 // The remaining descriptors are only accessible through reflection. | 1363 // The remaining descriptors are only accessible through reflection. |
| 1465 // The program builder does not collect libraries that only | 1364 // The program builder does not collect libraries that only |
| 1466 // contain typedefs that are used for reflection. | 1365 // contain typedefs that are used for reflection. |
| 1467 for (LibraryElement element in remainingLibraries) { | 1366 for (LibraryElement element in remainingLibraries) { |
| 1468 assert(element is LibraryElement || | 1367 assert(element is LibraryElement); |
| 1469 compiler.options.hasIncrementalSupport); | |
| 1470 if (element is LibraryElement) { | 1368 if (element is LibraryElement) { |
| 1471 parts.add(generateLibraryDescriptor(element, mainFragment)); | 1369 parts.add(generateLibraryDescriptor(element, mainFragment)); |
| 1472 descriptors.remove(element); | 1370 descriptors.remove(element); |
| 1473 } | 1371 } |
| 1474 } | 1372 } |
| 1475 } | 1373 } |
| 1476 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts); | 1374 jsAst.ArrayInitializer descriptorsAst = new jsAst.ArrayInitializer(parts); |
| 1477 | 1375 |
| 1478 // Using a named function here produces easier to read stack traces in | 1376 // Using a named function here produces easier to read stack traces in |
| 1479 // Chrome/V8. | 1377 // Chrome/V8. |
| 1480 statements.add(js.statement( | 1378 statements.add(js.statement( |
| 1481 """ | 1379 """ |
| 1482 (function() { | 1380 (function() { |
| 1483 // No renaming in the top-level function to save the locals for the | 1381 // No renaming in the top-level function to save the locals for the |
| 1484 // nested context where they will be used more. We have to put the | 1382 // nested context where they will be used more. We have to put the |
| 1485 // comment into a hole as the parser strips out comments right away. | 1383 // comment into a hole as the parser strips out comments right away. |
| 1486 #disableVariableRenaming; | 1384 #disableVariableRenaming; |
| 1487 #supportsDirectProtoAccess; | 1385 #supportsDirectProtoAccess; |
| 1488 | 1386 |
| 1489 if (#hasIncrementalSupport) { | |
| 1490 #helper = #helper || Object.create(null); | |
| 1491 #helper.patch = function(a) { eval(a)}; | |
| 1492 #helper.schemaChange = #schemaChange; | |
| 1493 #helper.addMethod = #addMethod; | |
| 1494 #helper.extractStubs = | |
| 1495 function(array, name, isStatic, originalDescriptor) { | |
| 1496 var descriptor = Object.create(null); | |
| 1497 this.addStubs(descriptor, array, name, isStatic, []); | |
| 1498 return descriptor; | |
| 1499 }; | |
| 1500 } | |
| 1501 | |
| 1502 if (#isProgramSplit) { | 1387 if (#isProgramSplit) { |
| 1503 /// We collect all the global state, so it can be passed to the | 1388 /// We collect all the global state, so it can be passed to the |
| 1504 /// initializer of deferred files. | 1389 /// initializer of deferred files. |
| 1505 var #globalsHolder = Object.create(null) | 1390 var #globalsHolder = Object.create(null) |
| 1506 } | 1391 } |
| 1507 | 1392 |
| 1508 // [map] returns an object that V8 shouldn't try to optimize with a | 1393 // [map] returns an object that V8 shouldn't try to optimize with a |
| 1509 // hidden class. This prevents a potential performance problem where V8 | 1394 // hidden class. This prevents a potential performance problem where V8 |
| 1510 // tries to build a hidden class for an object used as a hashMap. | 1395 // tries to build a hidden class for an object used as a hashMap. |
| 1511 // It requires fewer characters to declare a variable as a parameter than | 1396 // It requires fewer characters to declare a variable as a parameter than |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1584 #convertGlobalObjectsToFastObjects; | 1469 #convertGlobalObjectsToFastObjects; |
| 1585 #debugFastObjects; | 1470 #debugFastObjects; |
| 1586 | 1471 |
| 1587 #init; | 1472 #init; |
| 1588 | 1473 |
| 1589 #main; | 1474 #main; |
| 1590 })(); | 1475 })(); |
| 1591 """, | 1476 """, |
| 1592 { | 1477 { |
| 1593 "disableVariableRenaming": js.comment("/* ::norenaming:: */"), | 1478 "disableVariableRenaming": js.comment("/* ::norenaming:: */"), |
| 1594 "hasIncrementalSupport": compiler.options.hasIncrementalSupport, | |
| 1595 "helper": js('this.#', [namer.incrementalHelperName]), | |
| 1596 "schemaChange": buildSchemaChangeFunction(), | |
| 1597 "addMethod": buildIncrementalAddMethod(), | |
| 1598 "isProgramSplit": isProgramSplit, | 1479 "isProgramSplit": isProgramSplit, |
| 1599 "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(), | 1480 "supportsDirectProtoAccess": buildSupportsDirectProtoAccess(), |
| 1600 "globalsHolder": globalsHolder, | 1481 "globalsHolder": globalsHolder, |
| 1601 "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit), | 1482 "globalObjectSetup": buildGlobalObjectSetup(isProgramSplit), |
| 1602 "isolateName": namer.isolateName, | 1483 "isolateName": namer.isolateName, |
| 1603 "isolatePropertiesName": js(isolatePropertiesName), | 1484 "isolatePropertiesName": js(isolatePropertiesName), |
| 1604 "initName": initName, | 1485 "initName": initName, |
| 1605 "functionThatReturnsNull": buildFunctionThatReturnsNull(), | 1486 "functionThatReturnsNull": buildFunctionThatReturnsNull(), |
| 1606 "mangledNames": buildMangledNames(), | 1487 "mangledNames": buildMangledNames(), |
| 1607 "setupProgram": | 1488 "setupProgram": |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1663 } | 1544 } |
| 1664 | 1545 |
| 1665 mainOutput.close(); | 1546 mainOutput.close(); |
| 1666 | 1547 |
| 1667 if (generateSourceMap) { | 1548 if (generateSourceMap) { |
| 1668 outputSourceMap(mainOutput, lineColumnCollector, '', | 1549 outputSourceMap(mainOutput, lineColumnCollector, '', |
| 1669 compiler.options.sourceMapUri, compiler.options.outputUri); | 1550 compiler.options.sourceMapUri, compiler.options.outputUri); |
| 1670 } | 1551 } |
| 1671 } | 1552 } |
| 1672 | 1553 |
| 1673 /// Used by incremental compilation to patch up the prototype of | |
| 1674 /// [oldConstructor] for use as prototype of [newConstructor]. | |
| 1675 jsAst.Fun buildSchemaChangeFunction() { | |
| 1676 if (!compiler.options.hasIncrementalSupport) return null; | |
| 1677 return js(''' | |
| 1678 function(newConstructor, oldConstructor, superclass) { | |
| 1679 // Invariant: newConstructor.prototype has no interesting properties besides | |
| 1680 // generated accessors. These are copied to oldPrototype which will be | |
| 1681 // updated by other incremental changes. | |
| 1682 if (superclass != null) { | |
| 1683 this.inheritFrom(newConstructor, superclass); | |
| 1684 } | |
| 1685 var oldPrototype = oldConstructor.prototype; | |
| 1686 var newPrototype = newConstructor.prototype; | |
| 1687 var hasOwnProperty = Object.prototype.hasOwnProperty; | |
| 1688 for (var property in newPrototype) { | |
| 1689 if (hasOwnProperty.call(newPrototype, property)) { | |
| 1690 // Copy generated accessors. | |
| 1691 oldPrototype[property] = newPrototype[property]; | |
| 1692 } | |
| 1693 } | |
| 1694 oldPrototype.__proto__ = newConstructor.prototype.__proto__; | |
| 1695 oldPrototype.constructor = newConstructor; | |
| 1696 newConstructor.prototype = oldPrototype; | |
| 1697 return newConstructor; | |
| 1698 }'''); | |
| 1699 } | |
| 1700 | |
| 1701 /// Used by incremental compilation to patch up an object ([holder]) with a | |
| 1702 /// new (or updated) method. [arrayOrFunction] is either the new method, or | |
| 1703 /// an array containing the method (see | |
| 1704 /// [ContainerBuilder.addMemberMethodFromInfo]). [name] is the name of the | |
| 1705 /// new method. [isStatic] tells if method is static (or | |
| 1706 /// top-level). [globalFunctionsAccess] is a reference to | |
| 1707 /// [embeddedNames.GLOBAL_FUNCTIONS]. | |
| 1708 jsAst.Fun buildIncrementalAddMethod() { | |
| 1709 if (!compiler.options.hasIncrementalSupport) return null; | |
| 1710 return js(r""" | |
| 1711 function(originalDescriptor, name, holder, isStatic, globalFunctionsAccess) { | |
| 1712 var arrayOrFunction = originalDescriptor[name]; | |
| 1713 var method; | |
| 1714 if (arrayOrFunction.constructor === Array) { | |
| 1715 var existing = holder[name]; | |
| 1716 var array = arrayOrFunction; | |
| 1717 | |
| 1718 // Each method may have a number of stubs associated. For example, if an | |
| 1719 // instance method supports multiple arguments, a stub for each matching | |
| 1720 // selector. There is also a getter stub for tear-off getters. For example, | |
| 1721 // an instance method foo([a]) may have the following stubs: foo$0, foo$1, | |
| 1722 // and get$foo (here exemplified using unminified names). | |
| 1723 // [extractStubs] returns a JavaScript object whose own properties | |
| 1724 // corresponds to the stubs. | |
| 1725 var descriptor = | |
| 1726 this.extractStubs(array, name, isStatic, originalDescriptor); | |
| 1727 method = descriptor[name]; | |
| 1728 | |
| 1729 // Iterate through the properties of descriptor and copy the stubs to the | |
| 1730 // existing holder (for instance methods, a prototype). | |
| 1731 for (var property in descriptor) { | |
| 1732 if (!Object.prototype.hasOwnProperty.call(descriptor, property)) continue; | |
| 1733 var stub = descriptor[property]; | |
| 1734 var existingStub = holder[property]; | |
| 1735 if (stub === method || !existingStub || !stub.$getterStub) { | |
| 1736 // Not replacing an existing getter stub. | |
| 1737 holder[property] = stub; | |
| 1738 continue; | |
| 1739 } | |
| 1740 if (!stub.$getterStub) { | |
| 1741 var error = new Error('Unexpected stub.'); | |
| 1742 error.stub = stub; | |
| 1743 throw error; | |
| 1744 } | |
| 1745 | |
| 1746 // Existing getter stubs need special treatment as they may already have | |
| 1747 // been called and produced a closure. | |
| 1748 this.pendingStubs = this.pendingStubs || []; | |
| 1749 // It isn't safe to invoke the stub yet. | |
| 1750 this.pendingStubs.push((function(holder, stub, existingStub, existing, | |
| 1751 method) { | |
| 1752 return function() { | |
| 1753 var receiver = isStatic ? holder : new holder.constructor(); | |
| 1754 // Invoke the existing stub to obtain the tear-off closure. | |
| 1755 existingStub = existingStub.call(receiver); | |
| 1756 // Invoke the new stub to create a tear-off closure we can use as a | |
| 1757 // prototype. | |
| 1758 stub = stub.call(receiver); | |
| 1759 | |
| 1760 // Copy the properties from the new tear-off's prototype to the | |
| 1761 // prototype of the existing tear-off. | |
| 1762 var newProto = stub.constructor.prototype; | |
| 1763 var existingProto = existingStub.constructor.prototype; | |
| 1764 for (var stubProperty in newProto) { | |
| 1765 if (!Object.prototype.hasOwnProperty.call(newProto, stubProperty)) | |
| 1766 continue; | |
| 1767 existingProto[stubProperty] = newProto[stubProperty]; | |
| 1768 } | |
| 1769 | |
| 1770 // Update all the existing stub's references to [existing] to | |
| 1771 // [method]. Instance tear-offs are call-by-name, so this isn't | |
| 1772 // necessary for those. | |
| 1773 if (!isStatic) return; | |
| 1774 for (var reference in existingStub) { | |
| 1775 if (existingStub[reference] === existing) { | |
| 1776 existingStub[reference] = method; | |
| 1777 } | |
| 1778 } | |
| 1779 } | |
| 1780 })(holder, stub, existingStub, existing, method)); | |
| 1781 } | |
| 1782 } else { | |
| 1783 method = arrayOrFunction; | |
| 1784 holder[name] = method; | |
| 1785 } | |
| 1786 if (isStatic) globalFunctionsAccess[name] = method; | |
| 1787 }"""); | |
| 1788 } | |
| 1789 | |
| 1790 Map<OutputUnit, jsAst.Expression> buildDescriptorsForOutputUnits( | 1554 Map<OutputUnit, jsAst.Expression> buildDescriptorsForOutputUnits( |
| 1791 Program program) { | 1555 Program program) { |
| 1792 Map<OutputUnit, jsAst.Expression> outputs = | 1556 Map<OutputUnit, jsAst.Expression> outputs = |
| 1793 new Map<OutputUnit, jsAst.Expression>(); | 1557 new Map<OutputUnit, jsAst.Expression>(); |
| 1794 | 1558 |
| 1795 for (Fragment fragment in program.deferredFragments) { | 1559 for (Fragment fragment in program.deferredFragments) { |
| 1796 OutputUnit outputUnit = fragment.outputUnit; | 1560 OutputUnit outputUnit = fragment.outputUnit; |
| 1797 | 1561 |
| 1798 Map<Element, ClassBuilder> descriptors = elementDescriptors[fragment]; | 1562 Map<Element, ClassBuilder> descriptors = elementDescriptors[fragment]; |
| 1799 | 1563 |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2171 // Json does not support comments, so we embed the explanation in the | 1935 // Json does not support comments, so we embed the explanation in the |
| 2172 // data. | 1936 // data. |
| 2173 mapping["_comment"] = "This mapping shows which compiled `.js` files are " | 1937 mapping["_comment"] = "This mapping shows which compiled `.js` files are " |
| 2174 "needed for a given deferred library import."; | 1938 "needed for a given deferred library import."; |
| 2175 mapping.addAll(compiler.deferredLoadTask.computeDeferredMap()); | 1939 mapping.addAll(compiler.deferredLoadTask.computeDeferredMap()); |
| 2176 compiler.outputProvider( | 1940 compiler.outputProvider( |
| 2177 compiler.options.deferredMapUri.path, 'deferred_map') | 1941 compiler.options.deferredMapUri.path, 'deferred_map') |
| 2178 ..add(const JsonEncoder.withIndent(" ").convert(mapping)) | 1942 ..add(const JsonEncoder.withIndent(" ").convert(mapping)) |
| 2179 ..close(); | 1943 ..close(); |
| 2180 } | 1944 } |
| 2181 | |
| 2182 void invalidateCaches() { | |
| 2183 if (!compiler.options.hasIncrementalSupport) return; | |
| 2184 if (cachedElements.isEmpty) return; | |
| 2185 for (Element element in backend.codegenEnqueuer.newlyEnqueuedElements) { | |
| 2186 if (element.isInstanceMember) { | |
| 2187 cachedClassBuilders.remove(element.enclosingClass); | |
| 2188 } | |
| 2189 } | |
| 2190 } | |
| 2191 } | 1945 } |
| OLD | NEW |