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.program_builder; | 5 library dart2js.js_emitter.program_builder; |
6 | 6 |
| 7 import 'dart:io'; |
| 8 import 'dart:convert' show JSON; |
| 9 |
7 import '../../closure.dart' show ClosureTask, ClosureFieldElement; | 10 import '../../closure.dart' show ClosureTask, ClosureFieldElement; |
8 import '../../common.dart'; | 11 import '../../common.dart'; |
9 import '../../common/names.dart' show Names, Selectors; | 12 import '../../common/names.dart' show Names, Selectors; |
10 import '../../constants/values.dart' | 13 import '../../constants/values.dart' |
11 show ConstantValue, InterceptorConstantValue; | 14 show ConstantValue, InterceptorConstantValue; |
12 import '../../common_elements.dart' show CommonElements, ElementEnvironment; | 15 import '../../common_elements.dart' show CommonElements, ElementEnvironment; |
13 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit; | 16 import '../../deferred_load.dart' show DeferredLoadTask, OutputUnit; |
14 import '../../elements/elements.dart' | 17 import '../../elements/elements.dart' |
15 show | 18 show |
16 ClassElement, | 19 ClassElement, |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 import '../sorter.dart'; | 71 import '../sorter.dart'; |
69 | 72 |
70 part 'collector.dart'; | 73 part 'collector.dart'; |
71 part 'field_visitor.dart'; | 74 part 'field_visitor.dart'; |
72 part 'registry.dart'; | 75 part 'registry.dart'; |
73 | 76 |
74 /// Builds a self-contained representation of the program that can then be | 77 /// Builds a self-contained representation of the program that can then be |
75 /// emitted more easily by the individual emitters. | 78 /// emitted more easily by the individual emitters. |
76 class ProgramBuilder { | 79 class ProgramBuilder { |
77 final CompilerOptions _options; | 80 final CompilerOptions _options; |
| 81 final DiagnosticReporter _reporter; |
78 final ElementEnvironment _elementEnvironment; | 82 final ElementEnvironment _elementEnvironment; |
79 final CommonElements _commonElements; | 83 final CommonElements _commonElements; |
80 final DartTypes _types; | 84 final DartTypes _types; |
81 final DeferredLoadTask _deferredLoadTask; | 85 final DeferredLoadTask _deferredLoadTask; |
82 final ClosureTask _closureToClassMapper; | 86 final ClosureTask _closureToClassMapper; |
83 final CodegenWorldBuilder _worldBuilder; | 87 final CodegenWorldBuilder _worldBuilder; |
84 final NativeCodegenEnqueuer _nativeCodegenEnqueuer; | 88 final NativeCodegenEnqueuer _nativeCodegenEnqueuer; |
85 final BackendUsage _backendUsage; | 89 final BackendUsage _backendUsage; |
86 final JavaScriptConstantCompiler _constantHandler; | 90 final JavaScriptConstantCompiler _constantHandler; |
87 final NativeData _nativeData; | 91 final NativeData _nativeData; |
(...skipping 22 matching lines...) Expand all Loading... |
110 final Registry _registry; | 114 final Registry _registry; |
111 | 115 |
112 final FunctionEntity _mainFunction; | 116 final FunctionEntity _mainFunction; |
113 final bool _isMockCompilation; | 117 final bool _isMockCompilation; |
114 | 118 |
115 /// True if the program should store function types in the metadata. | 119 /// True if the program should store function types in the metadata. |
116 bool _storeFunctionTypesInMetadata = false; | 120 bool _storeFunctionTypesInMetadata = false; |
117 | 121 |
118 ProgramBuilder( | 122 ProgramBuilder( |
119 this._options, | 123 this._options, |
| 124 this._reporter, |
120 this._elementEnvironment, | 125 this._elementEnvironment, |
121 this._commonElements, | 126 this._commonElements, |
122 this._types, | 127 this._types, |
123 this._deferredLoadTask, | 128 this._deferredLoadTask, |
124 this._closureToClassMapper, | 129 this._closureToClassMapper, |
125 this._worldBuilder, | 130 this._worldBuilder, |
126 this._nativeCodegenEnqueuer, | 131 this._nativeCodegenEnqueuer, |
127 this._backendUsage, | 132 this._backendUsage, |
128 this._constantHandler, | 133 this._constantHandler, |
129 this._nativeData, | 134 this._nativeData, |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 | 182 |
178 /// Mapping from names to strings. | 183 /// Mapping from names to strings. |
179 /// | 184 /// |
180 /// This mapping is used to support `const Symbol` expressions. | 185 /// This mapping is used to support `const Symbol` expressions. |
181 /// | 186 /// |
182 /// This map is filled when building classes. | 187 /// This map is filled when building classes. |
183 final Map<js.Name, String> _symbolsMap = <js.Name, String>{}; | 188 final Map<js.Name, String> _symbolsMap = <js.Name, String>{}; |
184 | 189 |
185 Set<Class> _unneededNativeClasses; | 190 Set<Class> _unneededNativeClasses; |
186 | 191 |
| 192 /// Classes that have been allocated during a profile run. |
| 193 /// |
| 194 /// These classes should not be soft-deferred. |
| 195 /// |
| 196 /// Also contains classes that are not tracked by the profile run (like |
| 197 /// interceptors, ...). |
| 198 Set<ClassElement> _notSoftDeferred; |
| 199 |
187 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { | 200 Program buildProgram({bool storeFunctionTypesInMetadata: false}) { |
188 collector.collect(); | 201 collector.collect(); |
| 202 _initializeSoftDeferredMap(); |
189 | 203 |
190 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; | 204 this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata; |
191 // Note: In rare cases (mostly tests) output units can be empty. This | 205 // Note: In rare cases (mostly tests) output units can be empty. This |
192 // happens when the deferred code is dead-code eliminated but we still need | 206 // happens when the deferred code is dead-code eliminated but we still need |
193 // to check that the library has been loaded. | 207 // to check that the library has been loaded. |
194 _deferredLoadTask.allOutputUnits.forEach(_registry.registerOutputUnit); | 208 _deferredLoadTask.allOutputUnits.forEach(_registry.registerOutputUnit); |
195 collector.outputClassLists.forEach(_registry.registerClasses); | 209 collector.outputClassLists.forEach(_registry.registerClasses); |
196 collector.outputStaticLists.forEach(_registry.registerMembers); | 210 collector.outputStaticLists.forEach(_registry.registerMembers); |
197 collector.outputConstantLists.forEach(_registerConstants); | 211 collector.outputConstantLists.forEach(_registerConstants); |
198 collector.outputStaticNonFinalFieldLists.forEach(_registry.registerMembers); | 212 collector.outputStaticNonFinalFieldLists.forEach(_registry.registerMembers); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
259 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; | 273 List<js.TokenFinalizer> finalizers = [_task.metadataCollector]; |
260 if (_namer is js.TokenFinalizer) { | 274 if (_namer is js.TokenFinalizer) { |
261 var namingFinalizer = _namer; | 275 var namingFinalizer = _namer; |
262 finalizers.add(namingFinalizer as js.TokenFinalizer); | 276 finalizers.add(namingFinalizer as js.TokenFinalizer); |
263 } | 277 } |
264 | 278 |
265 return new Program(fragments, holders, _buildLoadMap(), _symbolsMap, | 279 return new Program(fragments, holders, _buildLoadMap(), _symbolsMap, |
266 _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers, | 280 _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers, |
267 needsNativeSupport: needsNativeSupport, | 281 needsNativeSupport: needsNativeSupport, |
268 outputContainsConstantList: collector.outputContainsConstantList, | 282 outputContainsConstantList: collector.outputContainsConstantList, |
269 hasIsolateSupport: _backendUsage.isIsolateInUse); | 283 hasIsolateSupport: _backendUsage.isIsolateInUse, |
| 284 hasSoftDeferredClasses: _notSoftDeferred != null); |
270 } | 285 } |
271 | 286 |
272 void _markEagerClasses() { | 287 void _markEagerClasses() { |
273 _markEagerInterceptorClasses(); | 288 _markEagerInterceptorClasses(); |
274 } | 289 } |
275 | 290 |
| 291 void _initializeSoftDeferredMap() { |
| 292 var allocatedClassesPath = _options.experimentalAllocationsPath; |
| 293 if (allocatedClassesPath != null) { |
| 294 // TODO(29574): the following blacklist is ad-hoc and potentially |
| 295 // incomplete. We need to mark all classes as black listed, that are |
| 296 // used without code going through the class' constructor. |
| 297 var blackList = [ |
| 298 'dart:_interceptors', |
| 299 'dart:html', |
| 300 'dart:typed_data_implementation', |
| 301 'dart:_native_typed_data' |
| 302 ].toSet(); |
| 303 |
| 304 // TODO(29574): the compiler should not just use dart:io to get the |
| 305 // contents of a file. |
| 306 File file = new File(allocatedClassesPath); |
| 307 |
| 308 // TODO(29574): are the following checks necessary? |
| 309 // To make compilation in build-systems easier, we ignore non-existing |
| 310 // or empty profiles. |
| 311 if (!file.existsSync()) { |
| 312 _reporter.log("Profile file does not exist: $allocatedClassesPath"); |
| 313 return; |
| 314 } |
| 315 if (file.lengthSync() == 0) { |
| 316 _reporter.log("Profile information (allocated classes) is empty."); |
| 317 return; |
| 318 } |
| 319 |
| 320 String data = new File(allocatedClassesPath).readAsStringSync(); |
| 321 Set<String> allocatedClassesKeys = JSON.decode(data).keys.toSet(); |
| 322 Set<ClassElement> allocatedClasses = new Set<ClassElement>(); |
| 323 |
| 324 // Collects all super and mixin classes of a class. |
| 325 void collect(ClassElement element) { |
| 326 allocatedClasses.add(element); |
| 327 if (element.isMixinApplication) { |
| 328 collect(computeMixinClass(element)); |
| 329 } |
| 330 if (element.superclass != null) { |
| 331 collect(element.superclass); |
| 332 } |
| 333 } |
| 334 |
| 335 // For every known class, see if it was allocated in the profile. If yes, |
| 336 // collect its dependencies (supers and mixins) and mark them as |
| 337 // not-soft-deferrable. |
| 338 collector.outputClassLists.forEach((_, List<ClassElement> elements) { |
| 339 for (ClassElement element in elements) { |
| 340 // TODO(29574): share the encoding of the element with the code |
| 341 // that emits the profile-run. |
| 342 var key = "${element.library.canonicalUri}:${element.name}"; |
| 343 if (allocatedClassesKeys.contains(key) || |
| 344 _nativeData.isJsInteropClass(element) || |
| 345 blackList.contains(element.library.canonicalUri.toString())) { |
| 346 collect(element); |
| 347 } |
| 348 } |
| 349 }); |
| 350 _notSoftDeferred = allocatedClasses; |
| 351 } |
| 352 } |
| 353 |
276 /// Builds a map from loadId to outputs-to-load. | 354 /// Builds a map from loadId to outputs-to-load. |
277 Map<String, List<Fragment>> _buildLoadMap() { | 355 Map<String, List<Fragment>> _buildLoadMap() { |
278 Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{}; | 356 Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{}; |
279 _deferredLoadTask.hunksToLoad | 357 _deferredLoadTask.hunksToLoad |
280 .forEach((String loadId, List<OutputUnit> outputUnits) { | 358 .forEach((String loadId, List<OutputUnit> outputUnits) { |
281 loadMap[loadId] = outputUnits | 359 loadMap[loadId] = outputUnits |
282 .map((OutputUnit unit) => _outputs[unit]) | 360 .map((OutputUnit unit) => _outputs[unit]) |
283 .toList(growable: false); | 361 .toList(growable: false); |
284 }); | 362 }); |
285 return loadMap; | 363 return loadMap; |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
577 .toList(growable: false); | 655 .toList(growable: false); |
578 | 656 |
579 bool visitStatics = true; | 657 bool visitStatics = true; |
580 List<Field> staticFieldsForReflection = | 658 List<Field> staticFieldsForReflection = |
581 _buildFields(library, visitStatics: visitStatics); | 659 _buildFields(library, visitStatics: visitStatics); |
582 | 660 |
583 return new Library( | 661 return new Library( |
584 library, uri, statics, classes, staticFieldsForReflection); | 662 library, uri, statics, classes, staticFieldsForReflection); |
585 } | 663 } |
586 | 664 |
| 665 bool _isSoftDeferred(ClassElement element) { |
| 666 return _notSoftDeferred != null && !_notSoftDeferred.contains(element); |
| 667 } |
| 668 |
587 Class _buildClass(ClassElement element) { | 669 Class _buildClass(ClassElement element) { |
588 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); | 670 bool onlyForRti = collector.classesOnlyNeededForRti.contains(element); |
589 bool hasRtiField = _rtiNeed.classNeedsRtiField(element); | 671 bool hasRtiField = _rtiNeed.classNeedsRtiField(element); |
590 if (_nativeData.isJsInteropClass(element)) { | 672 if (_nativeData.isJsInteropClass(element)) { |
591 // TODO(jacobr): check whether the class has any active static fields | 673 // TODO(jacobr): check whether the class has any active static fields |
592 // if it does not we can suppress it completely. | 674 // if it does not we can suppress it completely. |
593 onlyForRti = true; | 675 onlyForRti = true; |
594 } | 676 } |
595 bool isClosureBaseClass = element == _commonElements.closureClass; | 677 bool isClosureBaseClass = element == _commonElements.closureClass; |
596 | 678 |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
745 staticFieldsForReflection, | 827 staticFieldsForReflection, |
746 callStubs, | 828 callStubs, |
747 noSuchMethodStubs, | 829 noSuchMethodStubs, |
748 checkedSetters, | 830 checkedSetters, |
749 isChecks, | 831 isChecks, |
750 typeTests.functionTypeIndex, | 832 typeTests.functionTypeIndex, |
751 isDirectlyInstantiated: isInstantiated, | 833 isDirectlyInstantiated: isInstantiated, |
752 hasRtiField: hasRtiField, | 834 hasRtiField: hasRtiField, |
753 onlyForRti: onlyForRti, | 835 onlyForRti: onlyForRti, |
754 isNative: _nativeData.isNativeClass(element), | 836 isNative: _nativeData.isNativeClass(element), |
755 isClosureBaseClass: isClosureBaseClass); | 837 isClosureBaseClass: isClosureBaseClass, |
| 838 isSoftDeferred: _isSoftDeferred(element)); |
756 } | 839 } |
757 _classes[element] = result; | 840 _classes[element] = result; |
758 return result; | 841 return result; |
759 } | 842 } |
760 | 843 |
761 bool _methodNeedsStubs(FunctionElement method) { | 844 bool _methodNeedsStubs(FunctionElement method) { |
762 return !method.functionSignature.optionalParameters.isEmpty; | 845 return !method.functionSignature.optionalParameters.isEmpty; |
763 } | 846 } |
764 | 847 |
765 bool _methodCanBeReflected(MethodElement method) { | 848 bool _methodCanBeReflected(MethodElement method) { |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1102 Constant constant = new Constant(name, holder, constantValue); | 1185 Constant constant = new Constant(name, holder, constantValue); |
1103 _constants[constantValue] = constant; | 1186 _constants[constantValue] = constant; |
1104 } | 1187 } |
1105 } | 1188 } |
1106 | 1189 |
1107 Holder _registerStaticStateHolder() { | 1190 Holder _registerStaticStateHolder() { |
1108 return _registry.registerHolder(_namer.staticStateHolder, | 1191 return _registry.registerHolder(_namer.staticStateHolder, |
1109 isStaticStateHolder: true); | 1192 isStaticStateHolder: true); |
1110 } | 1193 } |
1111 } | 1194 } |
OLD | NEW |