[dart2js] Release codegen shard buffers

Change-Id: Iebf3a85920f141cff1595529b55b7cbac240434a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/176601
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/compiler_new.dart b/pkg/compiler/lib/compiler_new.dart
index 918c627..77e4a0c 100644
--- a/pkg/compiler/lib/compiler_new.dart
+++ b/pkg/compiler/lib/compiler_new.dart
@@ -40,6 +40,10 @@
 
   /// The raw data read from [uri].
   T get data;
+
+  /// Release any resources held by the input. After releasing, a call to `get
+  /// data` will fail, and previously returned data may be invalid.
+  void release();
 }
 
 /// Interface for providing the compiler with input. That is, Dart source files,
diff --git a/pkg/compiler/lib/src/io/source_file.dart b/pkg/compiler/lib/src/io/source_file.dart
index 1b358bc..f091dee 100644
--- a/pkg/compiler/lib/src/io/source_file.dart
+++ b/pkg/compiler/lib/src/io/source_file.dart
@@ -225,6 +225,9 @@
   @override
   set length(int v) => lengthCache = v;
   int lengthCache = -1;
+
+  @override
+  void release() {}
 }
 
 class CachingUtf8BytesSourceFile extends Utf8BytesSourceFile {
@@ -242,6 +245,12 @@
     }
     return cachedText;
   }
+
+  @override
+  void release() {
+    cachedText = null;
+    super.release();
+  }
 }
 
 class StringSourceFile extends SourceFile<List<int>> {
@@ -277,17 +286,30 @@
 
   @override
   String slowSubstring(int start, int end) => text.substring(start, end);
+
+  @override
+  void release() {}
 }
 
 /// Binary input data.
 class Binary implements Input<List<int>> {
   @override
   final Uri uri;
-  @override
-  final List<int> data;
+  List<int> /*?*/ _data;
 
-  Binary(this.uri, this.data);
+  Binary(this.uri, List<int> data) : _data = data;
+
+  @override
+  List<int> get data {
+    if (_data != null) return _data;
+    throw StateError("'get data' after 'release()'");
+  }
 
   @override
   InputKind get inputKind => InputKind.binary;
+
+  @override
+  void release() {
+    _data = null;
+  }
 }
diff --git a/pkg/compiler/lib/src/serialization/task.dart b/pkg/compiler/lib/src/serialization/task.dart
index 28d3224..707def0 100644
--- a/pkg/compiler/lib/src/serialization/task.dart
+++ b/pkg/compiler/lib/src/serialization/task.dart
@@ -259,25 +259,38 @@
         _reporter.log('Reading data from ${uri}');
         api.Input<List<int>> dataInput =
             await _provider.readFromUri(uri, inputKind: api.InputKind.binary);
-        DataSource source = new BinarySourceImpl(dataInput.data);
-        backendStrategy.prepareCodegenReader(source);
-        Map<MemberEntity, CodegenResult> codegenResults =
-            source.readMemberMap((MemberEntity member) {
-          List<ModularName> modularNames = [];
-          List<ModularExpression> modularExpressions = [];
-          CodegenReader reader = new CodegenReaderImpl(
-              closedWorld, modularNames, modularExpressions);
-          source.registerCodegenReader(reader);
-          CodegenResult result = CodegenResult.readFromDataSource(
-              source, modularNames, modularExpressions);
-          source.deregisterCodegenReader(reader);
-          return result;
-        });
-        _reporter.log('Read ${codegenResults.length} members from ${uri}');
-        results.addAll(codegenResults);
+        // TODO(36983): This code is extracted because there appeared to be a
+        // memory leak for large buffer held by `source`.
+        _deserializeCodegenInput(
+            backendStrategy, closedWorld, uri, dataInput, results);
+        dataInput.release();
       });
     }
     return new DeserializedCodegenResults(
         globalTypeInferenceResults, codegenInputs, results);
   }
+
+  void _deserializeCodegenInput(
+      BackendStrategy backendStrategy,
+      JClosedWorld closedWorld,
+      Uri uri,
+      api.Input<List<int>> dataInput,
+      Map<MemberEntity, CodegenResult> results) {
+    DataSource source = new BinarySourceImpl(dataInput.data);
+    backendStrategy.prepareCodegenReader(source);
+    Map<MemberEntity, CodegenResult> codegenResults =
+        source.readMemberMap((MemberEntity member) {
+      List<ModularName> modularNames = [];
+      List<ModularExpression> modularExpressions = [];
+      CodegenReader reader =
+          new CodegenReaderImpl(closedWorld, modularNames, modularExpressions);
+      source.registerCodegenReader(reader);
+      CodegenResult result = CodegenResult.readFromDataSource(
+          source, modularNames, modularExpressions);
+      source.deregisterCodegenReader(reader);
+      return result;
+    });
+    _reporter.log('Read ${codegenResults.length} members from ${uri}');
+    results.addAll(codegenResults);
+  }
 }