| 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 |