| Index: pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
|
| diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
|
| index d27eca3e384c64cd6d65620cdfc3a70fcd3d2bf7..9ecf99ae97c271b3acf1501a440b48670ebb8f1d 100644
|
| --- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
|
| +++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
|
| @@ -4,6 +4,9 @@
|
|
|
| library dart2js.js_emitter.program_builder;
|
|
|
| +import 'dart:io';
|
| +import 'dart:convert' show JSON;
|
| +
|
| import '../../closure.dart' show ClosureTask, ClosureFieldElement;
|
| import '../../common.dart';
|
| import '../../common/names.dart' show Names, Selectors;
|
| @@ -75,6 +78,7 @@ part 'registry.dart';
|
| /// emitted more easily by the individual emitters.
|
| class ProgramBuilder {
|
| final CompilerOptions _options;
|
| + final DiagnosticReporter _reporter;
|
| final ElementEnvironment _elementEnvironment;
|
| final CommonElements _commonElements;
|
| final DartTypes _types;
|
| @@ -117,6 +121,7 @@ class ProgramBuilder {
|
|
|
| ProgramBuilder(
|
| this._options,
|
| + this._reporter,
|
| this._elementEnvironment,
|
| this._commonElements,
|
| this._types,
|
| @@ -184,8 +189,17 @@ class ProgramBuilder {
|
|
|
| Set<Class> _unneededNativeClasses;
|
|
|
| + /// Classes that have been allocated during a profile run.
|
| + ///
|
| + /// These classes should not be soft-deferred.
|
| + ///
|
| + /// Also contains classes that are not tracked by the profile run (like
|
| + /// interceptors, ...).
|
| + Set<ClassElement> _notSoftDeferred;
|
| +
|
| Program buildProgram({bool storeFunctionTypesInMetadata: false}) {
|
| collector.collect();
|
| + _initializeSoftDeferredMap();
|
|
|
| this._storeFunctionTypesInMetadata = storeFunctionTypesInMetadata;
|
| // Note: In rare cases (mostly tests) output units can be empty. This
|
| @@ -266,13 +280,77 @@ class ProgramBuilder {
|
| _buildTypeToInterceptorMap(), _task.metadataCollector, finalizers,
|
| needsNativeSupport: needsNativeSupport,
|
| outputContainsConstantList: collector.outputContainsConstantList,
|
| - hasIsolateSupport: _backendUsage.isIsolateInUse);
|
| + hasIsolateSupport: _backendUsage.isIsolateInUse,
|
| + hasSoftDeferredClasses: _notSoftDeferred != null);
|
| }
|
|
|
| void _markEagerClasses() {
|
| _markEagerInterceptorClasses();
|
| }
|
|
|
| + void _initializeSoftDeferredMap() {
|
| + var allocatedClassesPath = _options.experimentalAllocationsPath;
|
| + if (allocatedClassesPath != null) {
|
| + // TODO(29574): the following blacklist is ad-hoc and potentially
|
| + // incomplete. We need to mark all classes as black listed, that are
|
| + // used without code going through the class' constructor.
|
| + var blackList = [
|
| + 'dart:_interceptors',
|
| + 'dart:html',
|
| + 'dart:typed_data_implementation',
|
| + 'dart:_native_typed_data'
|
| + ].toSet();
|
| +
|
| + // TODO(29574): the compiler should not just use dart:io to get the
|
| + // contents of a file.
|
| + File file = new File(allocatedClassesPath);
|
| +
|
| + // TODO(29574): are the following checks necessary?
|
| + // To make compilation in build-systems easier, we ignore non-existing
|
| + // or empty profiles.
|
| + if (!file.existsSync()) {
|
| + _reporter.log("Profile file does not exist: $allocatedClassesPath");
|
| + return;
|
| + }
|
| + if (file.lengthSync() == 0) {
|
| + _reporter.log("Profile information (allocated classes) is empty.");
|
| + return;
|
| + }
|
| +
|
| + String data = new File(allocatedClassesPath).readAsStringSync();
|
| + Set<String> allocatedClassesKeys = JSON.decode(data).keys.toSet();
|
| + Set<ClassElement> allocatedClasses = new Set<ClassElement>();
|
| +
|
| + // Collects all super and mixin classes of a class.
|
| + void collect(ClassElement element) {
|
| + allocatedClasses.add(element);
|
| + if (element.isMixinApplication) {
|
| + collect(computeMixinClass(element));
|
| + }
|
| + if (element.superclass != null) {
|
| + collect(element.superclass);
|
| + }
|
| + }
|
| +
|
| + // For every known class, see if it was allocated in the profile. If yes,
|
| + // collect its dependencies (supers and mixins) and mark them as
|
| + // not-soft-deferrable.
|
| + collector.outputClassLists.forEach((_, List<ClassElement> elements) {
|
| + for (ClassElement element in elements) {
|
| + // TODO(29574): share the encoding of the element with the code
|
| + // that emits the profile-run.
|
| + var key = "${element.library.canonicalUri}:${element.name}";
|
| + if (allocatedClassesKeys.contains(key) ||
|
| + _nativeData.isJsInteropClass(element) ||
|
| + blackList.contains(element.library.canonicalUri.toString())) {
|
| + collect(element);
|
| + }
|
| + }
|
| + });
|
| + _notSoftDeferred = allocatedClasses;
|
| + }
|
| + }
|
| +
|
| /// Builds a map from loadId to outputs-to-load.
|
| Map<String, List<Fragment>> _buildLoadMap() {
|
| Map<String, List<Fragment>> loadMap = <String, List<Fragment>>{};
|
| @@ -584,6 +662,10 @@ class ProgramBuilder {
|
| library, uri, statics, classes, staticFieldsForReflection);
|
| }
|
|
|
| + bool _isSoftDeferred(ClassElement element) {
|
| + return _notSoftDeferred != null && !_notSoftDeferred.contains(element);
|
| + }
|
| +
|
| Class _buildClass(ClassElement element) {
|
| bool onlyForRti = collector.classesOnlyNeededForRti.contains(element);
|
| bool hasRtiField = _rtiNeed.classNeedsRtiField(element);
|
| @@ -752,7 +834,8 @@ class ProgramBuilder {
|
| hasRtiField: hasRtiField,
|
| onlyForRti: onlyForRti,
|
| isNative: _nativeData.isNativeClass(element),
|
| - isClosureBaseClass: isClosureBaseClass);
|
| + isClosureBaseClass: isClosureBaseClass,
|
| + isSoftDeferred: _isSoftDeferred(element));
|
| }
|
| _classes[element] = result;
|
| return result;
|
|
|