|
4 | 4 |
|
5 | 5 | library dart2js.js_emitter.program_builder;
|
6 | 6 |
|
| 7 | +import 'dart:io'; |
| 8 | +import 'dart:convert' show JSON; |
| 9 | + |
7 | 10 | import '../../closure.dart' show ClosureTask, ClosureFieldElement;
|
8 | 11 | import '../../common.dart';
|
9 | 12 | import '../../common/names.dart' show Names, Selectors;
|
@@ -75,6 +78,7 @@ part 'registry.dart';
|
75 | 78 | /// emitted more easily by the individual emitters.
|
76 | 79 | class ProgramBuilder {
|
77 | 80 | final CompilerOptions _options;
|
| 81 | + final DiagnosticReporter _reporter; |
78 | 82 | final ElementEnvironment _elementEnvironment;
|
79 | 83 | final CommonElements _commonElements;
|
80 | 84 | final DartTypes _types;
|
@@ -117,6 +121,7 @@ class ProgramBuilder {
|
117 | 121 |
|
118 | 122 | ProgramBuilder(
|
119 | 123 | this._options,
|
| 124 | + this._reporter, |
120 | 125 | this._elementEnvironment,
|
121 | 126 | this._commonElements,
|
122 | 127 | this._types,
|
@@ -184,8 +189,17 @@ class ProgramBuilder {
|
184 | 189 |
|
185 | 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 | 200 | Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
|
188 | 201 | collector.collect();
|
| 202 | + _initializeSoftDeferredMap(); |
189 | 203 |
|
190 | 204 | this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata;
|
191 | 205 | // Note: In rare cases (mostly tests) output units can be empty. This
|
@@ -266,13 +280,77 @@ class ProgramBuilder {
|
266 | 280 | _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers,
|
267 | 281 | needsNativeSupport: needsNativeSupport,
|
268 | 282 | outputContainsConstantList: collector.outputContainsConstantList,
|
269 |
| - hasIsolateSupport: _backendUsage.isIsolateInUse); |
| 283 | + hasIsolateSupport: _backendUsage.isIsolateInUse, |
| 284 | + hasSoftDeferredClasses: _notSoftDeferred != null); |
270 | 285 | }
|
271 | 286 |
|
272 | 287 | void _markEagerClasses() {
|
273 | 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 | 354 | /// Builds a map from loadId to outputs-to-load.
|
277 | 355 | Map<String, List<Fragment>> _buildLoadMap() {
|
278 | 356 | Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{};
|
@@ -582,6 +660,10 @@ class ProgramBuilder {
|
582 | 660 | library, uri, statics, classes, staticFieldsForReflection);
|
583 | 661 | }
|
584 | 662 |
|
| 663 | + bool _isSoftDeferred(ClassElement element) { |
| 664 | + return _notSoftDeferred != null && !_notSoftDeferred.contains(element); |
| 665 | + } |
| 666 | + |
585 | 667 | Class _buildClass(ClassElement element) {
|
586 | 668 | bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
|
587 | 669 | bool hasRtiField = _rtiNeed.classNeedsRtiField(element);
|
@@ -745,7 +827,8 @@ class ProgramBuilder {
|
745 | 827 | hasRtiField: hasRtiField,
|
746 | 828 | onlyForRti: onlyForRti,
|
747 | 829 | isNative: _nativeData.isNativeClass(element),
|
748 |
| - isClosureBaseClass: isClosureBaseClass); |
| 830 | + isClosureBaseClass: isClosureBaseClass, |
| 831 | + isSoftDeferred: _isSoftDeferred(element)); |
749 | 832 | }
|
750 | 833 | _classes[element] = result;
|
751 | 834 | return result;
|
|
0 commit comments