Version 2.15.0-46.0.dev

Merge commit 'cccc9f93b259dfd6d8f437da30f2a893afa33f78' into 'dev'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 944c834..f6e9780 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,15 @@
 
   This brings the implementation behavior in line with the spec.
 
+### Tools
+
+#### Dart command line
+
+- **Breaking Change** [#46100][]: The standalone `dart2native` tool has been
+  removed as previously announced. Its replacements are the
+  `dart compile exe` and `dart compile aot-snapshot` commands, which offer the
+  same functionality.
+
 ## 2.14.0
 
 ### Language
diff --git a/DEPS b/DEPS
index 1e12e6a..3a092fd 100644
--- a/DEPS
+++ b/DEPS
@@ -105,7 +105,7 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
   "dart_style_rev": "14d9b6fd58cc4744676c12be3cc5eee2a779db82",
 
-  "dartdoc_rev" : "5f39ec674d81f5c199151d823fa4ecd01fc59eb2",
+  "dartdoc_rev" : "a4ca86f9bf732d7adc4506f7373e0ed63251b646",
   "devtools_rev" : "2b47d9ed486479153ca2fd038000950674ed1beb",
   "jsshell_tag": "version:88.0",
   "ffi_rev": "4dd32429880a57b64edaf54c9d5af8a9fa9a4ffb",
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c5d1271..e0ef0b5 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -317,7 +317,7 @@
   /// used to create correction producers. The generators are then used to build
   /// fixes for those diagnostics. The generators used for non-lint diagnostics
   /// are in the [nonLintProducerMap].
-  static const Map<String, List<ProducerGenerator>> lintProducerMap = {
+  static final Map<String, List<ProducerGenerator>> lintProducerMap = {
     LintNames.always_declare_return_types: [
       // TODO(brianwilkerson) Consider applying in bulk.
       AddReturnType.newInstance,
@@ -1331,6 +1331,12 @@
       }
     }
   }
+
+  /// Associate the given correction producer [generator] with the lint with the
+  /// given [lintName].
+  static void registerFixForLint(String lintName, ProducerGenerator generator) {
+    lintProducerMap.putIfAbsent(lintName, () => []).add(generator);
+  }
 }
 
 /// [_FixState] that is still empty.
diff --git a/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart b/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
index cde9037..6e27913 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/fix_processor_map_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analysis_server/src/services/correction/dart/abstract_producer.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -22,6 +23,17 @@
     _testMap(FixProcessor.nonLintProducerMap.values);
   }
 
+  void test_registerFixForLint() {
+    CorrectionProducer producer() => MockCorrectionProducer();
+
+    var lintName = 'not_a_lint';
+    expect(FixProcessor.lintProducerMap[lintName], null);
+    FixProcessor.registerFixForLint(lintName, producer);
+    expect(FixProcessor.lintProducerMap[lintName], contains(producer));
+    // Restore the map to it's original state so as to not impact other tests.
+    FixProcessor.lintProducerMap.remove(lintName);
+  }
+
   void _testGenerator(ProducerGenerator generator) {
     var producer = generator();
     var className = producer.runtimeType.toString();
@@ -40,3 +52,10 @@
     }
   }
 }
+
+class MockCorrectionProducer implements CorrectionProducer {
+  @override
+  dynamic noSuchMethod(Invocation invocation) {
+    return super.noSuchMethod(invocation);
+  }
+}
diff --git a/pkg/analysis_server/tool/code_completion/completion_metrics.dart b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
index 46638b1..49d514d 100644
--- a/pkg/analysis_server/tool/code_completion/completion_metrics.dart
+++ b/pkg/analysis_server/tool/code_completion/completion_metrics.dart
@@ -58,6 +58,32 @@
 import 'relevance_table_generator.dart';
 import 'visitors.dart';
 
+/// Completion metrics are computed by taking a single package and iterating
+/// over the compilation units in the package. For each unit we visit the AST
+/// structure to find all of the places where completion suggestions should be
+/// offered (essentially, everywhere that there's a keyword or identifier). At
+/// each location we compute the completion suggestions using the same code path
+/// used by the analysis server. We then compare the suggestions against the
+/// token that was actually at that location in the file.
+///
+/// This approach has several drawbacks:
+///
+/// - The AST is always complete and correct, and that's rarely the case for
+///   real completion requests. Usually the tree is incomplete and often has a
+///   completely different structure because of the way recovery works. We
+///   currently have no way of measuring completions under realistic conditions.
+///
+/// - We can't measure completions for several keywords because the presence of
+///   the keyword in the AST causes it to not be suggested.
+///
+/// - The time it takes to compute the suggestions doesn't include the time
+///   required to finish analyzing the file if the analysis hasn't been
+///   completed before suggestions are requested. While the times are accurate
+///   (within the accuracy of the `Stopwatch` class) they are the minimum
+///   possible time. This doesn't give us a measure of how completion will
+///   perform in production, but does give us an optimistic approximation.
+///
+/// The first is arguably the worst of the limitations of our current approach.
 Future<void> main(List<String> args) async {
   var parser = createArgParser();
   var result = parser.parse(args);
@@ -1318,7 +1344,7 @@
       var filePath = result.path;
       // Use the ExpectedCompletionsVisitor to compute the set of expected
       // completions for this CompilationUnit.
-      final visitor = ExpectedCompletionsVisitor(filePath);
+      final visitor = ExpectedCompletionsVisitor(result);
       _resolvedUnitResult.unit.accept(visitor);
 
       for (var expectedCompletion in visitor.expectedCompletions) {
diff --git a/pkg/analysis_server/tool/code_completion/visitors.dart b/pkg/analysis_server/tool/code_completion/visitors.dart
index 5a17c5e..5783758 100644
--- a/pkg/analysis_server/tool/code_completion/visitors.dart
+++ b/pkg/analysis_server/tool/code_completion/visitors.dart
@@ -5,11 +5,13 @@
 import 'package:analysis_server/src/protocol/protocol_internal.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
+import 'package:analyzer/dart/analysis/results.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/syntactic_entity.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart' as element;
+import 'package:analyzer/source/line_info.dart';
 
 class ExpectedCompletion {
   final String _filePath;
@@ -122,11 +124,12 @@
 }
 
 class ExpectedCompletionsVisitor extends RecursiveAstVisitor<void> {
-  final List<ExpectedCompletion> expectedCompletions;
+  /// The result of resolving the file being visited.
+  final ResolvedUnitResult result;
 
-  final String filePath;
-
-  late CompilationUnit _enclosingCompilationUnit;
+  /// The completions that are expected to be produced in the file being
+  /// visited.
+  final List<ExpectedCompletion> expectedCompletions = [];
 
   /// This boolean is set to enable whether or not we should assert that some
   /// found keyword in Dart syntax should be in the completion set returned from
@@ -141,22 +144,22 @@
   /// comment don't yield an error like Dart syntax mistakes would yield.
   final bool _doExpectCommentRefs = false;
 
-  ExpectedCompletionsVisitor(this.filePath)
-      : expectedCompletions = <ExpectedCompletion>[];
+  ExpectedCompletionsVisitor(this.result);
+
+  /// Return the path of the file that is being visited.
+  String get filePath => result.path;
+
+  /// Return the line info for the file that is being visited.
+  LineInfo get lineInfo => result.lineInfo;
 
   void safelyRecordEntity(SyntacticEntity? entity,
       {protocol.CompletionSuggestionKind? kind,
       protocol.ElementKind? elementKind}) {
     // Only record if this entity is not null, has a length, etc.
-    if (entity != null && entity.offset > 0 && entity.length > 0) {
-      // Compute the line number at this offset
-      var lineNumber = _enclosingCompilationUnit.lineInfo!
-          .getLocation(entity.offset)
-          .lineNumber;
-
-      var columnNumber = _enclosingCompilationUnit.lineInfo!
-          .getLocation(entity.offset)
-          .columnNumber;
+    if (entity != null && entity.offset >= 0 && entity.length > 0) {
+      var location = lineInfo.getLocation(entity.offset);
+      var lineNumber = location.lineNumber;
+      var columnNumber = location.columnNumber;
 
       bool isKeyword() => kind == protocol.CompletionSuggestionKind.KEYWORD;
 
@@ -315,12 +318,6 @@
   }
 
   @override
-  void visitCompilationUnit(CompilationUnit node) {
-    _enclosingCompilationUnit = node;
-    super.visitCompilationUnit(node);
-  }
-
-  @override
   void visitConfiguration(Configuration node) {
     safelyRecordKeywordCompletion(node.ifKeyword);
     super.visitConfiguration(node);
diff --git a/pkg/analyzer/lib/dart/ast/ast_factory.dart b/pkg/analyzer/lib/dart/ast/ast_factory.dart
index 15022fc..d8469f2 100644
--- a/pkg/analyzer/lib/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/dart/ast/ast_factory.dart
@@ -323,9 +323,22 @@
   /// Returns a newly created function body consisting of an expression.
   /// The [keyword] can be `null` if the function body is not an async function
   /// body.
+  @Deprecated("Use expressionFunctionBody2, with new 'star' parameter")
   ExpressionFunctionBody expressionFunctionBody(Token? keyword,
       Token functionDefinition, Expression expression, Token? semicolon);
 
+  /// Returns a newly created function body consisting of an expression.
+  /// The [keyword] can be `null` if the function body is not an async function
+  /// body. The [star] can be `null` if there is no star following the keyword
+  /// (and must be `null` if there is no keyword).
+  ExpressionFunctionBody expressionFunctionBody2({
+    Token? keyword,
+    Token? star,
+    required Token functionDefinition,
+    required Expression expression,
+    Token? semicolon,
+  });
+
   /// Returns a newly created expression statement.
   ExpressionStatement expressionStatement(
       Expression expression, Token? semicolon);
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index a568624..b99b124 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -430,9 +430,8 @@
           unignorableCodes.contains(code.name.toUpperCase())) {
         return false;
       }
-
       int errorLine = lineInfo.getLocation(error.offset).lineNumber;
-      String name = code.name.toLowerCase();
+      String name = code.name;
       if (ignoreInfo.ignoredAt(name, errorLine)) {
         return true;
       }
@@ -441,8 +440,7 @@
       if (period >= 0) {
         uniqueName = uniqueName.substring(period + 1);
       }
-      return uniqueName != name &&
-          ignoreInfo.ignoredAt(uniqueName.toLowerCase(), errorLine);
+      return uniqueName != name && ignoreInfo.ignoredAt(uniqueName, errorLine);
     }
 
     return errors.where((AnalysisError e) => !isIgnored(e)).toList();
diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart
index 434b963..0ea9f43 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast.dart
@@ -3381,6 +3381,14 @@
   @override
   Token? keyword;
 
+  /// The star optionally following the 'async' or 'sync' keyword, or `null` if
+  /// there is wither no such keyword or no star.
+  ///
+  /// It is an error for an expression function body to feature the star, but
+  /// the parser will accept it.
+  @override
+  Token? star;
+
   /// The token introducing the expression that represents the body of the
   /// function.
   @override
@@ -3396,8 +3404,8 @@
   /// Initialize a newly created function body consisting of a block of
   /// statements. The [keyword] can be `null` if the function body is not an
   /// async function body.
-  ExpressionFunctionBodyImpl(
-      this.keyword, this.functionDefinition, this._expression, this.semicolon) {
+  ExpressionFunctionBodyImpl(this.keyword, this.star, this.functionDefinition,
+      this._expression, this.semicolon) {
     _becomeParentOf(_expression);
   }
 
@@ -3412,6 +3420,7 @@
   @override
   Iterable<SyntacticEntity> get childEntities => ChildEntities()
     ..add(keyword)
+    ..add(star)
     ..add(functionDefinition)
     ..add(_expression)
     ..add(semicolon);
@@ -3432,10 +3441,13 @@
   }
 
   @override
-  bool get isAsynchronous => keyword != null;
+  bool get isAsynchronous => keyword?.lexeme == Keyword.ASYNC.lexeme;
 
   @override
-  bool get isSynchronous => keyword == null;
+  bool get isGenerator => star != null;
+
+  @override
+  bool get isSynchronous => keyword?.lexeme != Keyword.ASYNC.lexeme;
 
   @override
   E? accept<E>(AstVisitor<E> visitor) =>
diff --git a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
index cc2e492..bc7287e 100644
--- a/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
+++ b/pkg/analyzer/lib/src/dart/ast/ast_factory.dart
@@ -413,8 +413,19 @@
   @override
   ExpressionFunctionBodyImpl expressionFunctionBody(Token? keyword,
           Token functionDefinition, Expression expression, Token? semicolon) =>
-      ExpressionFunctionBodyImpl(
-          keyword, functionDefinition, expression as ExpressionImpl, semicolon);
+      ExpressionFunctionBodyImpl(keyword, null, functionDefinition,
+          expression as ExpressionImpl, semicolon);
+
+  @override
+  ExpressionFunctionBodyImpl expressionFunctionBody2({
+    Token? keyword,
+    Token? star,
+    required Token functionDefinition,
+    required Expression expression,
+    Token? semicolon,
+  }) =>
+      ExpressionFunctionBodyImpl(keyword, star, functionDefinition,
+          expression as ExpressionImpl, semicolon);
 
   @override
   ExpressionStatementImpl expressionStatement(
diff --git a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
index d8eaf00..b5929ae 100644
--- a/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/ast/to_source_visitor.dart
@@ -333,6 +333,9 @@
     var keyword = node.keyword;
     if (keyword != null) {
       sink.write(keyword.lexeme);
+      if (node.star != null) {
+        sink.write('*');
+      }
       sink.write(' ');
     }
     sink.write('${node.functionDefinition.lexeme} ');
diff --git a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
index a723a79..70109d0 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_analyzer.dart
@@ -413,8 +413,7 @@
 
     bool isIgnored(AnalysisError error) {
       int errorLine = lineInfo.getLocation(error.offset).lineNumber;
-      String errorCode = error.errorCode.name.toLowerCase();
-      return ignoreInfo.ignoredAt(errorCode, errorLine);
+      return ignoreInfo.ignoredAt(error.errorCode.name, errorLine);
     }
 
     return errors.where((AnalysisError e) => !isIgnored(e)).toList();
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 873ca31..44ea8bb 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2665,11 +2665,16 @@
     debugEvent("ExpressionFunctionBody");
 
     var expression = pop() as Expression;
-    pop(); // star (*)
+    var star = pop() as Token?;
     var asyncKeyword = pop() as Token?;
     if (parseFunctionBodies) {
-      push(ast.expressionFunctionBody(
-          asyncKeyword, arrowToken, expression, semicolon));
+      push(ast.expressionFunctionBody2(
+        keyword: asyncKeyword,
+        star: star,
+        functionDefinition: arrowToken,
+        expression: expression,
+        semicolon: semicolon,
+      ));
     } else {
       push(ast.emptyFunctionBody(semicolon!));
     }
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 70d878c..71aab4d 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -93,11 +93,14 @@
 
   static ExpressionFunctionBodyImpl asyncExpressionFunctionBody(
           Expression expression) =>
-      astFactory.expressionFunctionBody(
-          TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "async"),
-          TokenFactory.tokenFromType(TokenType.FUNCTION),
-          expression,
-          TokenFactory.tokenFromType(TokenType.SEMICOLON));
+      astFactory.expressionFunctionBody2(
+        keyword:
+            TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "async"),
+        star: null,
+        functionDefinition: TokenFactory.tokenFromType(TokenType.FUNCTION),
+        expression: expression,
+        semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
+      );
 
   static BlockFunctionBodyImpl asyncGeneratorBlockFunctionBody(
           [List<Statement> statements = const []]) =>
@@ -106,6 +109,17 @@
           TokenFactory.tokenFromType(TokenType.STAR),
           block(statements));
 
+  static ExpressionFunctionBodyImpl asyncGeneratorExpressionFunctionBody(
+          Expression expression) =>
+      astFactory.expressionFunctionBody2(
+        keyword:
+            TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "async"),
+        star: TokenFactory.tokenFromType(TokenType.STAR),
+        functionDefinition: TokenFactory.tokenFromType(TokenType.FUNCTION),
+        expression: expression,
+        semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
+      );
+
   static AwaitExpressionImpl awaitExpression(Expression expression) =>
       astFactory.awaitExpression(
           TokenFactory.tokenFromTypeAndString(TokenType.IDENTIFIER, "await"),
@@ -485,11 +499,13 @@
 
   static ExpressionFunctionBodyImpl expressionFunctionBody(
           Expression expression) =>
-      astFactory.expressionFunctionBody(
-          null,
-          TokenFactory.tokenFromType(TokenType.FUNCTION),
-          expression,
-          TokenFactory.tokenFromType(TokenType.SEMICOLON));
+      astFactory.expressionFunctionBody2(
+        keyword: null,
+        star: null,
+        functionDefinition: TokenFactory.tokenFromType(TokenType.FUNCTION),
+        expression: expression,
+        semicolon: TokenFactory.tokenFromType(TokenType.SEMICOLON),
+      );
 
   static ExpressionStatementImpl expressionStatement(Expression expression) =>
       astFactory.expressionStatement(
diff --git a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
index 8f7b0b3..b2e5b12 100644
--- a/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
+++ b/pkg/analyzer/lib/src/ignore_comments/ignore_info.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/ast/token.dart';
 
 /// The name and location of a diagnostic name in an ignore comment.
@@ -26,27 +25,16 @@
 /// Information about analysis `//ignore:` and `//ignore_for_file` comments
 /// within a source file.
 class IgnoreInfo {
-  ///  Instance shared by all cases without matches.
-  // ignore: deprecated_member_use_from_same_package
-  static final IgnoreInfo _EMPTY_INFO = IgnoreInfo();
-
-  /// A regular expression for matching 'ignore' comments.  Produces matches
-  /// containing 2 groups.  For example:
-  ///
-  ///     * ['//ignore: error_code', 'error_code']
+  /// A regular expression for matching 'ignore' comments.
   ///
   /// Resulting codes may be in a list ('error_code_1,error_code2').
-  static final RegExp IGNORE_MATCHER =
-      RegExp(r'//+[ ]*ignore:(.*)$', multiLine: true);
+  static final RegExp IGNORE_MATCHER = RegExp(r'//+[ ]*ignore:');
 
-  /// A regular expression for matching 'ignore_for_file' comments.  Produces
-  /// matches containing 2 groups.  For example:
-  ///
-  ///     * ['//ignore_for_file: error_code', 'error_code']
+  /// A regular expression for matching 'ignore_for_file' comments.
   ///
   /// Resulting codes may be in a list ('error_code_1,error_code2').
   static final RegExp IGNORE_FOR_FILE_MATCHER =
-      RegExp(r'//[ ]*ignore_for_file:(.*)$', multiLine: true);
+      RegExp(r'//[ ]*ignore_for_file:');
 
   /// A table mapping line numbers to the diagnostics that are ignored on that
   /// line.
@@ -56,9 +44,6 @@
   /// file.
   final List<DiagnosticName> _ignoredForFile = [];
 
-  @Deprecated('Use the constructor IgnoreInfo.forDart')
-  IgnoreInfo();
-
   /// Initialize a newly created instance of this class to represent the ignore
   /// comments in the given compilation [unit].
   IgnoreInfo.forDart(CompilationUnit unit, String content) {
@@ -68,11 +53,9 @@
       if (lexeme.contains('ignore:')) {
         var location = lineInfo.getLocation(comment.offset);
         var lineNumber = location.lineNumber;
-        String beforeMatch = content.substring(
-            lineInfo.getOffsetOfLine(lineNumber - 1),
-            lineInfo.getOffsetOfLine(lineNumber - 1) +
-                location.columnNumber -
-                1);
+        var offsetOfLine = lineInfo.getOffsetOfLine(lineNumber - 1);
+        var beforeMatch = content.substring(
+            offsetOfLine, offsetOfLine + location.columnNumber - 1);
         if (beforeMatch.trim().isEmpty) {
           // The comment is on its own line, so it refers to the next line.
           lineNumber++;
@@ -104,78 +87,21 @@
     return ignoredOnLine;
   }
 
-  /// Return `true` if the [errorCode] is ignored at the given [line].
+  /// Return `true` if the [errorCode] (case-insensitive) is ignored at the
+  /// given [line].
   bool ignoredAt(String errorCode, int line) {
-    for (var name in _ignoredForFile) {
-      if (name.matches(errorCode)) {
-        return true;
-      }
+    var ignoredDiagnostics = _ignoredOnLine[line];
+    if (ignoredForFile.isEmpty && ignoredDiagnostics == null) {
+      return false;
     }
-    var ignoredOnLine = _ignoredOnLine[line];
-    if (ignoredOnLine != null) {
-      for (var name in ignoredOnLine) {
-        if (name.matches(errorCode)) {
-          return true;
-        }
-      }
+    errorCode = errorCode.toLowerCase();
+    if (ignoredForFile.any((name) => name.matches(errorCode))) {
+      return true;
     }
-    return false;
-  }
-
-  /// Ignore these [errorCodes] at [line].
-  void _addAll(int line, Iterable<DiagnosticName> errorCodes) {
-    _ignoredOnLine.putIfAbsent(line, () => []).addAll(errorCodes);
-  }
-
-  /// Ignore these [errorCodes] in the whole file.
-  void _addAllForFile(Iterable<DiagnosticName> errorCodes) {
-    _ignoredForFile.addAll(errorCodes);
-  }
-
-  /// Calculate ignores for the given [content] with line [info].
-  @Deprecated('Use the constructor IgnoreInfo.forDart')
-  static IgnoreInfo calculateIgnores(String content, LineInfo info) {
-    Iterable<Match> matches = IGNORE_MATCHER.allMatches(content);
-    Iterable<Match> fileMatches = IGNORE_FOR_FILE_MATCHER.allMatches(content);
-    if (matches.isEmpty && fileMatches.isEmpty) {
-      return _EMPTY_INFO;
+    if (ignoredDiagnostics == null) {
+      return false;
     }
-
-    IgnoreInfo ignoreInfo = IgnoreInfo();
-    for (Match match in matches) {
-      // See _IGNORE_MATCHER for format --- note the possibility of error lists.
-      // Note that the offsets are not being computed here. This shouldn't
-      // affect older clients of this class because none of the previous APIs
-      // depended on having offsets.
-      Iterable<DiagnosticName> codes = match
-          .group(1)!
-          .split(',')
-          .map((String code) => DiagnosticName(code.trim().toLowerCase(), -1));
-      var location = info.getLocation(match.start);
-      int lineNumber = location.lineNumber;
-      String beforeMatch = content.substring(
-          info.getOffsetOfLine(lineNumber - 1),
-          info.getOffsetOfLine(lineNumber - 1) + location.columnNumber - 1);
-
-      if (beforeMatch.trim().isEmpty) {
-        // The comment is on its own line, so it refers to the next line.
-        ignoreInfo._addAll(lineNumber + 1, codes);
-      } else {
-        // The comment sits next to code, so it refers to its own line.
-        ignoreInfo._addAll(lineNumber, codes);
-      }
-    }
-    // Note that the offsets are not being computed here. This shouldn't affect
-    // older clients of this class because none of the previous APIs depended on
-    // having offsets.
-    for (Match match in fileMatches) {
-      Iterable<DiagnosticName> codes = match
-          .group(1)!
-          .split(',')
-          .map((String code) => DiagnosticName(code.trim().toLowerCase(), -1));
-      ignoreInfo._addAllForFile(codes);
-    }
-    return ignoreInfo;
+    return ignoredDiagnostics.any((name) => name.matches(errorCode));
   }
 }
 
@@ -186,14 +112,10 @@
       var comment = currentToken.precedingComments;
       while (comment != null) {
         var lexeme = comment.lexeme;
-        var match = IgnoreInfo.IGNORE_MATCHER.matchAsPrefix(lexeme);
-        if (match != null) {
+        if (lexeme.startsWith(IgnoreInfo.IGNORE_MATCHER)) {
           yield comment;
-        } else {
-          match = IgnoreInfo.IGNORE_FOR_FILE_MATCHER.matchAsPrefix(lexeme);
-          if (match != null) {
-            yield comment;
-          }
+        } else if (lexeme.startsWith(IgnoreInfo.IGNORE_FOR_FILE_MATCHER)) {
+          yield comment;
         }
         comment = comment.next as CommentToken?;
       }
diff --git a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
index 6119dbf..88e81b9 100644
--- a/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/to_source_visitor_test.dart
@@ -826,6 +826,13 @@
             AstTestFactory.identifier3("a")));
   }
 
+  void test_visitExpressionFunctionBody_async_star() {
+    _assertSource(
+        "async* => a;",
+        AstTestFactory.asyncGeneratorExpressionFunctionBody(
+            AstTestFactory.identifier3("a")));
+  }
+
   void test_visitExpressionFunctionBody_simple() {
     _assertSource("=> a;",
         AstTestFactory.expressionFunctionBody(AstTestFactory.identifier3("a")));
diff --git a/pkg/analyzer/test/src/diagnostics/illegal_sync_generator_return_type_test.dart b/pkg/analyzer/test/src/diagnostics/illegal_sync_generator_return_type_test.dart
index 1656f94..d22ab61 100644
--- a/pkg/analyzer/test/src/diagnostics/illegal_sync_generator_return_type_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/illegal_sync_generator_return_type_test.dart
@@ -15,6 +15,14 @@
 
 @reflectiveTest
 class IllegalSyncGeneratorReturnTypeTest extends PubPackageResolutionTest {
+  test_arrowFunction_iterator() async {
+    await assertErrorsInCode('''
+Iterable<void> f() sync* => [];
+''', [
+      error(CompileTimeErrorCode.RETURN_IN_GENERATOR, 25, 2),
+    ]);
+  }
+
   test_function_iterator() async {
     await assertNoErrorsInCode('''
 Iterable<void> f() sync* {}
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
deleted file mode 100644
index f8e95ef..0000000
--- a/pkg/dart2native/bin/dart2native.dart
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env dart
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:io';
-
-import 'package:args/args.dart';
-import 'package:dart2native/generate.dart';
-import 'package:front_end/src/api_prototype/compiler_options.dart'
-    show Verbosity;
-
-void printUsage(final ArgParser parser) {
-  print('''
-Usage: dart2native <main-dart-file> [<options>]
-
-Generates an executable or an AOT snapshot from <main-dart-file>.
-''');
-  print(parser.usage);
-}
-
-Future<void> main(List<String> args) async {
-  // If we're outputting to a terminal, wrap usage text to that width.
-  int? outputLineWidth;
-  try {
-    outputLineWidth = stdout.terminalColumns;
-  } catch (_) {/* Ignore. */}
-
-  final ArgParser parser = ArgParser(usageLineLength: outputLineWidth)
-    ..addMultiOption('define', abbr: 'D', valueHelp: 'key=value', help: '''
-Define an environment declaration. To specify multiple declarations, use multiple options or use commas to separate key-value pairs.
-E.g.: dart2native -Da=1,b=2 main.dart''')
-    ..addFlag('enable-asserts',
-        negatable: false, help: 'Enable assert statements.')
-    ..addMultiOption(
-      'extra-gen-snapshot-options',
-      help: 'Pass additional options to gen_snapshot.',
-      hide: true,
-      valueHelp: 'opt1,opt2,...',
-    )
-    ..addFlag('help',
-        abbr: 'h', negatable: false, help: 'Display this help message.')
-    ..addOption(
-      'output-kind',
-      abbr: 'k',
-      allowed: ['aot', 'exe'],
-      allowedHelp: {
-        'aot': 'Generate an AOT snapshot.',
-        'exe': 'Generate a standalone executable.',
-      },
-      defaultsTo: 'exe',
-      valueHelp: 'aot|exe',
-    )
-    ..addOption('output', abbr: 'o', valueHelp: 'path', help: '''
-Set the output filename. <path> can be relative or absolute.
-E.g.: dart2native main.dart -o ../bin/my_app.exe
-''')
-    ..addOption('packages', abbr: 'p', valueHelp: 'path', help: '''
-Get package locations from the specified file instead of .packages. <path> can be relative or absolute.
-E.g.: dart2native --packages=/tmp/pkgs main.dart
-''')
-    ..addOption('save-debugging-info', abbr: 'S', valueHelp: 'path', help: '''
-Remove debugging information from the output and save it separately to the specified file. <path> can be relative or absolute.
-''')
-    ..addOption('enable-experiment',
-        defaultsTo: '', valueHelp: 'feature', hide: true, help: '''
-Comma separated list of experimental features.
-''')
-    ..addFlag('sound-null-safety',
-        help: 'Respect the nullability of types at runtime.', defaultsTo: null)
-    ..addFlag('verbose',
-        abbr: 'v', negatable: false, help: 'Show verbose output.')
-    ..addOption(
-      'verbosity',
-      defaultsTo: Verbosity.defaultValue,
-      help: '''
-Sets the verbosity level used for filtering messages during compilation.
-''',
-      allowed: Verbosity.allowedValues,
-      allowedHelp: Verbosity.allowedValuesHelp,
-    );
-
-  ArgResults parsedArgs;
-  try {
-    parsedArgs = parser.parse(args);
-  } on FormatException catch (e) {
-    stderr.writeln('Error: ${e.message}');
-    await stderr.flush();
-    printUsage(parser);
-    exit(1);
-  }
-
-  if (parsedArgs['help']) {
-    printUsage(parser);
-    exit(0);
-  }
-
-  if (parsedArgs.rest.length != 1) {
-    printUsage(parser);
-    exit(1);
-  }
-
-  final String sourceFile = parsedArgs.rest[0];
-  if (!FileSystemEntity.isFileSync(sourceFile)) {
-    stderr.writeln(
-        '"$sourceFile" is not a file. See \'--help\' for more information.');
-    await stderr.flush();
-    exit(1);
-  }
-
-  try {
-    await generateNative(
-        kind: parsedArgs['output-kind'],
-        sourceFile: sourceFile,
-        outputFile: parsedArgs['output'],
-        debugFile: parsedArgs['save-debugging-info'],
-        packages: parsedArgs['packages'],
-        defines: parsedArgs['define'],
-        enableExperiment: parsedArgs['enable-experiment'],
-        enableAsserts: parsedArgs['enable-asserts'],
-        soundNullSafety: parsedArgs['sound-null-safety'],
-        verbose: parsedArgs['verbose'],
-        verbosity: parsedArgs['verbosity'],
-        extraOptions: parsedArgs['extra-gen-snapshot-options']);
-  } catch (e) {
-    stderr.writeln('Failed to generate native files:');
-    stderr.writeln(e);
-    await stderr.flush();
-    exit(1);
-  }
-}
diff --git a/pkg/dart2native/pubspec.yaml b/pkg/dart2native/pubspec.yaml
index 439a0cb..6cd6814 100644
--- a/pkg/dart2native/pubspec.yaml
+++ b/pkg/dart2native/pubspec.yaml
@@ -10,9 +10,6 @@
   dart2native:
 
 dependencies:
-   args: ^1.4.0
-   front_end:
-     path: ../front_end
    path: any
 
 dev_dependencies:
diff --git a/pkg/dartdev/lib/src/commands/compile.dart b/pkg/dartdev/lib/src/commands/compile.dart
index 5027f18..2dc8b55 100644
--- a/pkg/dartdev/lib/src/commands/compile.dart
+++ b/pkg/dartdev/lib/src/commands/compile.dart
@@ -239,7 +239,13 @@
           defaultsTo: null)
       ..addOption('save-debugging-info', abbr: 'S', valueHelp: 'path', help: '''
 Remove debugging information from the output and save it separately to the specified file.
-<path> can be relative or absolute.''');
+<path> can be relative or absolute.''')
+      ..addMultiOption(
+        'extra-gen-snapshot-options',
+        help: 'Pass additional options to gen_snapshot.',
+        hide: true,
+        valueHelp: 'opt1,opt2,...',
+      );
 
     addExperimentalFlags(argParser, verbose);
   }
@@ -277,6 +283,7 @@
         debugFile: argResults['save-debugging-info'],
         verbose: verbose,
         verbosity: argResults['verbosity'],
+        extraOptions: argResults['extra-gen-snapshot-options'],
       );
       return 0;
     } catch (e) {
diff --git a/pkg/native_stack_traces/README.md b/pkg/native_stack_traces/README.md
index a052851..4e609d5 100644
--- a/pkg/native_stack_traces/README.md
+++ b/pkg/native_stack_traces/README.md
@@ -32,7 +32,7 @@
 
 ```dart
 @pragma('vm:prefer-inline')
-bar() => throw null;
+bar() => throw Null;
 
 @pragma('vm:never-inline')
 foo() => bar();
@@ -44,24 +44,18 @@
 
 ```bash
 # Make sure that we have the native_stack_traces package.
-$ pub get native_stack_traces
-$ pub global activate native_stack_traces
+$ dart pub global activate native_stack_traces
 
 # We compile the example program, removing the source location information
 # from the snapshot and saving the debugging information into throws.debug.
-$ dart2native -k aot -S throws.debug -o throws.aotsnapshot throws.dart
+$ dart compile exe -S throws.debug throws.dart
 
 # Run the program, saving the error output to throws.err.
-$ dartaotruntime throws.aotsnapshot 2>throws.err
+$ ./throws.exe 2>throws.err
 
 # Using the saved debugging information, we can translate the stack trace
 # contained in throws.err to its symbolic form.
-$ pub global run native_stack_traces:decode translate -d throws.debug -i throws.err
-
-# We can also just pipe the output of running the program directly into
-# the utility.
-$ dartaotruntime throws.aotsnapshot |& \
-    pub global run native_stack_traces:decode translate -d throws.debug
+$ dart pub global run native_stack_traces:decode translate -d throws.debug -i throws.err
 ```
 
 ## Features and bugs
diff --git a/pkg/vm_snapshot_analysis/test/utils.dart b/pkg/vm_snapshot_analysis/test/utils.dart
index 1163ae7..02e25bd 100644
--- a/pkg/vm_snapshot_analysis/test/utils.dart
+++ b/pkg/vm_snapshot_analysis/test/utils.dart
@@ -8,16 +8,15 @@
 import 'package:path/path.dart' as path;
 import 'package:test/test.dart';
 
-final dart2native = () {
+final dartCompile = () {
   final sdkBin = path.dirname(Platform.executable);
-  final dart2native =
-      path.join(sdkBin, Platform.isWindows ? 'dart2native.bat' : 'dart2native');
+  final dartCmd = path.join(sdkBin, Platform.isWindows ? 'dart.bat' : 'dart');
 
-  if (!File(dart2native).existsSync()) {
-    throw 'Failed to locate dart2native in the SDK';
+  if (!File(dartCmd).existsSync()) {
+    throw 'Failed to locate `dart` in the SDK';
   }
 
-  return path.canonicalize(dart2native);
+  return path.canonicalize(dartCmd);
 }();
 
 class AotSnapshot {
@@ -61,6 +60,8 @@
     ];
 
     final args = [
+      'compile',
+      'exe',
       '-o',
       snapshot.outputBinary,
       '--packages=$packages',
@@ -69,12 +70,12 @@
     ];
 
     // Compile input.dart to native and output instruction sizes.
-    final result = await Process.run(dart2native, args);
+    final result = await Process.run(dartCompile, args);
 
     expect(result.exitCode, equals(0), reason: '''
 Compilation completed with exit code ${result.exitCode}.
 
-Command line: $dart2native ${args.join(' ')}
+Command line: $dartCompile ${args.join(' ')}
 
 stdout: ${result.stdout}
 stderr: ${result.stderr}
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 9f60f2a..61bef4b 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -931,6 +931,16 @@
   return cobject;
 }
 
+Dart_CObject* CObject::NewNativePointer(intptr_t ptr,
+                                        intptr_t size,
+                                        Dart_HandleFinalizer callback) {
+  Dart_CObject* cobject = New(Dart_CObject_kNativePointer);
+  cobject->value.as_native_pointer.ptr = ptr;
+  cobject->value.as_native_pointer.size = size;
+  cobject->value.as_native_pointer.callback = callback;
+  return cobject;
+}
+
 Dart_CObject* CObject::NewIOBuffer(int64_t length) {
   // Make sure that we do not have an integer overflow here. Actual check
   // against max elements will be done at the time of writing, as the constant
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 7ff1580..4eadf084 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -351,6 +351,9 @@
                                              uint8_t* data,
                                              void* peer,
                                              Dart_HandleFinalizer callback);
+  static Dart_CObject* NewNativePointer(intptr_t ptr,
+                                        intptr_t size,
+                                        Dart_HandleFinalizer callback);
 
   static Dart_CObject* NewIOBuffer(int64_t length);
   static void ShrinkIOBuffer(Dart_CObject* cobject, int64_t new_length);
@@ -579,6 +582,20 @@
   DISALLOW_COPY_AND_ASSIGN(CObjectExternalUint8Array);
 };
 
+class CObjectNativePointer : public CObject {
+ public:
+  DECLARE_COBJECT_CONSTRUCTORS(NativePointer)
+
+  intptr_t Ptr() const { return cobject_->value.as_native_pointer.ptr; }
+  intptr_t Size() const { return cobject_->value.as_native_pointer.size; }
+  Dart_HandleFinalizer Callback() const {
+    return cobject_->value.as_native_pointer.callback;
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CObjectNativePointer);
+};
+
 class ScopedBlockingCall {
  public:
   ScopedBlockingCall() { Dart_ThreadDisableProfiling(); }
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index 8e377a1..fad12cf 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -923,8 +923,8 @@
   if (file == NULL) {
     return CObject::NewOSError();
   }
-  return new CObjectIntptr(
-      CObject::NewIntptr(reinterpret_cast<intptr_t>(file)));
+  return new CObjectNativePointer(CObject::NewNativePointer(
+      reinterpret_cast<intptr_t>(file), sizeof(*file), ReleaseFile));
 }
 
 CObject* File::DeleteRequest(const CObjectArray& request) {
diff --git a/runtime/include/dart_native_api.h b/runtime/include/dart_native_api.h
index ac183b8..f99fff1 100644
--- a/runtime/include/dart_native_api.h
+++ b/runtime/include/dart_native_api.h
@@ -45,6 +45,7 @@
   Dart_CObject_kExternalTypedData,
   Dart_CObject_kSendPort,
   Dart_CObject_kCapability,
+  Dart_CObject_kNativePointer,
   Dart_CObject_kUnsupported,
   Dart_CObject_kNumberOfTypes
 } Dart_CObject_Type;
@@ -80,6 +81,11 @@
       void* peer;
       Dart_HandleFinalizer callback;
     } as_external_typed_data;
+    struct {
+      intptr_t ptr;
+      intptr_t size;
+      Dart_HandleFinalizer callback;
+    } as_native_pointer;
   } value;
 } Dart_CObject;
 // This struct is versioned by DART_API_DL_MAJOR_VERSION, bump the version when
diff --git a/runtime/tests/vm/dart/regress_46796_test.dart b/runtime/tests/vm/dart/regress_46796_test.dart
new file mode 100644
index 0000000..f28f740
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_46796_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=
+// VMOptions=--use_slow_path
+
+class RawSocketEvent {}
+
+class Stream<T> {}
+
+class _RawSocket extends Stream<RawSocketEvent> {
+  int field1 = 512;
+  int field2 = -512;
+
+  _RawSocket() {
+    blackhole(_onSubscriptionStateChange);
+  }
+
+  void _onSubscriptionStateChange<T>() {
+    print("blah");
+  }
+}
+
+@pragma("vm:never-inline")
+blackhole(x) {}
+
+main() {
+  for (var i = 0; i < 10000000; i++) {
+    blackhole(new _RawSocket());
+  }
+}
diff --git a/runtime/tests/vm/dart_2/regress_46796_test.dart b/runtime/tests/vm/dart_2/regress_46796_test.dart
new file mode 100644
index 0000000..5c11b5b
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_46796_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=
+// VMOptions=--use_slow_path
+
+// @dart = 2.9
+
+class RawSocketEvent {}
+
+class Stream<T> {}
+
+class _RawSocket extends Stream<RawSocketEvent> {
+  int field1 = 512;
+  int field2 = -512;
+
+  _RawSocket() {
+    blackhole(_onSubscriptionStateChange);
+  }
+
+  void _onSubscriptionStateChange<T>() {
+    print("blah");
+  }
+}
+
+@pragma("vm:never-inline")
+blackhole(x) {}
+
+main() {
+  for (var i = 0; i < 10000000; i++) {
+    blackhole(new _RawSocket());
+  }
+}
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 5ca709a..e7f7cbc 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -203,6 +203,10 @@
   // Illegal class id.
   kIllegalCid = 0,
 
+  // Pseudo class id for native pointers, the heap should never see an
+  // object with this class id.
+  kNativePointer,
+
   // The following entries describes classes for pseudo-objects in the heap
   // that should never be reachable from live objects. Free list elements
   // maintain the free list for old space, and forwarding corpses are used to
@@ -281,10 +285,11 @@
 // and should not be exposed directly to user code.
 inline bool IsInternalOnlyClassId(intptr_t index) {
   // Fix the condition below if these become non-contiguous.
-  COMPILE_ASSERT(kIllegalCid + 1 == kFreeListElement &&
-                 kIllegalCid + 2 == kForwardingCorpse &&
-                 kIllegalCid + 3 == kObjectCid &&
-                 kIllegalCid + 4 == kFirstInternalOnlyCid);
+  COMPILE_ASSERT(kIllegalCid + 1 == kNativePointer &&
+                 kIllegalCid + 2 == kFreeListElement &&
+                 kIllegalCid + 3 == kForwardingCorpse &&
+                 kIllegalCid + 4 == kObjectCid &&
+                 kIllegalCid + 5 == kFirstInternalOnlyCid);
   return index <= kLastInternalOnlyCid;
 }
 
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 7a139c4..11775fc 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -243,16 +243,18 @@
   // Allocate context.
   {
     Label done, slow_path;
-    __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
-                        &slow_path,
-                        R0,  // instance
-                        R1,  // end address
-                        R2, R3);
-    __ ldr(R1, Address(THR, target::Thread::object_null_offset()));
-    __ str(R1, FieldAddress(R0, target::Context::parent_offset()));
-    __ LoadImmediate(R1, 1);
-    __ str(R1, FieldAddress(R0, target::Context::num_variables_offset()));
-    __ b(&done);
+    if (!FLAG_use_slow_path && FLAG_inline_alloc) {
+      __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
+                          &slow_path,
+                          R0,  // instance
+                          R1,  // end address
+                          R2, R3);
+      __ ldr(R1, Address(THR, target::Thread::object_null_offset()));
+      __ str(R1, FieldAddress(R0, target::Context::parent_offset()));
+      __ LoadImmediate(R1, 1);
+      __ str(R1, FieldAddress(R0, target::Context::num_variables_offset()));
+      __ b(&done);
+    }
 
     __ Bind(&slow_path);
 
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index 2c1288d..916604b 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -472,7 +472,7 @@
   __ cmp(R4, Operand(0));
   __ b(&no_type_args, EQ);
   __ ldr(R0, Address(FP, kReceiverOffset * target::kWordSize));
-  __ ldr(R3, Address(R0, R4));
+  __ LoadCompressed(R3, Address(R0, R4));
   __ Bind(&no_type_args);
 
   // Push type arguments & extracted method.
@@ -482,16 +482,18 @@
   // Allocate context.
   {
     Label done, slow_path;
-    __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
-                        &slow_path,
-                        R0,  // instance
-                        R1,  // end address
-                        R2, R3);
-    __ ldr(R1, Address(THR, target::Thread::object_null_offset()));
-    __ str(R1, FieldAddress(R0, target::Context::parent_offset()));
-    __ LoadImmediate(R1, 1);
-    __ str(R1, FieldAddress(R0, target::Context::num_variables_offset()));
-    __ b(&done);
+    if (!FLAG_use_slow_path && FLAG_inline_alloc) {
+      __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
+                          &slow_path,
+                          R0,  // instance
+                          R1,  // end address
+                          R2, R3);
+      __ ldr(R1, Address(THR, target::Thread::object_null_offset()));
+      __ str(R1, FieldAddress(R0, target::Context::parent_offset()));
+      __ LoadImmediate(R1, 1);
+      __ str(R1, FieldAddress(R0, target::Context::num_variables_offset()));
+      __ b(&done);
+    }
 
     __ Bind(&slow_path);
 
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index 74405e0..74bab68 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -417,7 +417,7 @@
   __ cmpq(RDX, Immediate(0));
   __ j(EQUAL, &no_type_args, Assembler::kNearJump);
   __ movq(RAX, Address(RBP, target::kWordSize * kReceiverOffsetInWords));
-  __ movq(RCX, Address(RAX, RDX, TIMES_1, 0));
+  __ LoadCompressed(RCX, Address(RAX, RDX, TIMES_1, 0));
   __ Bind(&no_type_args);
   __ pushq(RCX);
 
@@ -427,16 +427,18 @@
   // Allocate context.
   {
     Label done, slow_path;
-    __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
-                        &slow_path, Assembler::kFarJump,
-                        RAX,  // instance
-                        RSI,  // end address
-                        RDI);
-    __ movq(RSI, Address(THR, target::Thread::object_null_offset()));
-    __ movq(FieldAddress(RAX, target::Context::parent_offset()), RSI);
-    __ movq(FieldAddress(RAX, target::Context::num_variables_offset()),
-            Immediate(1));
-    __ jmp(&done);
+    if (!FLAG_use_slow_path && FLAG_inline_alloc) {
+      __ TryAllocateArray(kContextCid, target::Context::InstanceSize(1),
+                          &slow_path, Assembler::kFarJump,
+                          RAX,  // instance
+                          RSI,  // end address
+                          RDI);
+      __ movq(RSI, Address(THR, target::Thread::object_null_offset()));
+      __ movq(FieldAddress(RAX, target::Context::parent_offset()), RSI);
+      __ movq(FieldAddress(RAX, target::Context::num_variables_offset()),
+              Immediate(1));
+      __ jmp(&done);
+    }
 
     __ Bind(&slow_path);
 
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index e65fc1c..ef3fba1 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -1818,6 +1818,67 @@
   const intptr_t cid_;
 };
 
+class NativePointerMessageSerializationCluster
+    : public MessageSerializationCluster {
+ public:
+  explicit NativePointerMessageSerializationCluster(Zone* zone)
+      : MessageSerializationCluster("NativePointer",
+                                    MessagePhase::kNonCanonicalInstances,
+                                    kNativePointer),
+        objects_(zone, 0) {}
+  ~NativePointerMessageSerializationCluster() {}
+
+  void Trace(MessageSerializer* s, Object* object) { UNREACHABLE(); }
+
+  void WriteNodes(MessageSerializer* s) { UNREACHABLE(); }
+
+  void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) {
+    objects_.Add(object);
+  }
+
+  void WriteNodesApi(ApiMessageSerializer* s) {
+    intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      Dart_CObject* data = objects_[i];
+      s->AssignRef(data);
+
+      intptr_t ptr = data->value.as_native_pointer.ptr;
+      s->WriteUnsigned(ptr);
+
+      s->finalizable_data()->Put(
+          data->value.as_native_pointer.size, nullptr,
+          reinterpret_cast<void*>(data->value.as_native_pointer.ptr),
+          data->value.as_native_pointer.callback);
+    }
+  }
+
+ private:
+  GrowableArray<Dart_CObject*> objects_;
+};
+
+class NativePointerMessageDeserializationCluster
+    : public MessageDeserializationCluster {
+ public:
+  NativePointerMessageDeserializationCluster()
+      : MessageDeserializationCluster("NativePointer"), cid_(kNativePointer) {}
+  ~NativePointerMessageDeserializationCluster() {}
+
+  void ReadNodes(MessageDeserializer* d) {
+    intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      intptr_t ptr = d->ReadUnsigned();
+      d->finalizable_data()->Take();
+      d->AssignRef(Integer::New(ptr));
+    }
+  }
+
+  void ReadNodesApi(ApiMessageDeserializer* d) { UNREACHABLE(); }
+
+ private:
+  const intptr_t cid_;
+};
+
 class TypedDataViewMessageSerializationCluster
     : public MessageSerializationCluster {
  public:
@@ -3189,6 +3250,9 @@
     case Dart_CObject_kCapability:
       cid = kCapabilityCid;
       break;
+    case Dart_CObject_kNativePointer:
+      cid = kNativePointer;
+      break;
     default:
       return Fail("invalid Dart_CObject type");
   }
@@ -3242,6 +3306,8 @@
   }
 
   switch (cid) {
+    case kNativePointer:
+      return new (Z) NativePointerMessageSerializationCluster(Z);
     case kClassCid:
       return new (Z) ClassMessageSerializationCluster();
     case kTypeArgumentsCid:
@@ -3326,6 +3392,9 @@
   }
 
   switch (cid) {
+    case kNativePointer:
+      ASSERT(!is_canonical);
+      return new (Z) NativePointerMessageDeserializationCluster();
     case kClassCid:
       ASSERT(!is_canonical);
       return new (Z) ClassMessageDeserializationCluster();
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 7067a89..654967a 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -37,7 +37,6 @@
 # ......dartaotruntime or dartaotruntime.exe (executable)
 # ......dartdoc
 # ......dartfmt
-# ......dart2native (if not on ia32)
 # ......dart2js
 # ......dartanalyzer
 # ......dartdevc
@@ -46,7 +45,6 @@
 # ......snapshots/
 # ........analysis_server.dart.snapshot
 # ........dart2js.dart.snapshot
-# ........dart2native.dart.snapshot (if not on ia32)
 # ........dartanalyzer.dart.snapshot
 # ........dartdev.dart.snapshot
 # ........dartdev.dill
@@ -147,12 +145,6 @@
     "../utils/pub",
   ],
 ]
-if (dart_target_arch != "ia32") {
-  _platform_sdk_snapshots += [ [
-        "dart2native",
-        "../utils/dart2native:generate_dart2native_snapshot",
-      ] ]
-}
 if (create_kernel_service_snapshot) {
   _platform_sdk_snapshots += [ [
         "kernel-service",
@@ -270,8 +262,8 @@
     {
       target = "copy_${library}_library"
       visibility = [
-        ":copy_platform_sdk_libraries",
         ":copy_full_sdk_libraries",
+        ":copy_platform_sdk_libraries",
       ]
       source = "lib/$library"
       dest = "$root_out_dir/$dart_sdk_output/lib/$library"
@@ -328,7 +320,7 @@
 }
 
 copy("copy_dartaotruntime") {
-  visibility = [ ":copy_dart2native" ]
+  visibility = [ ":group_dart2native" ]
   deps = [ "../runtime/bin:dart_precompiled_runtime_product" ]
   src_dir = get_label_info("../runtime/bin:dart_precompiled_runtime_product",
                            "root_out_dir")
@@ -341,7 +333,7 @@
 }
 
 copy("copy_gen_snapshot") {
-  visibility = [ ":copy_dart2native" ]
+  visibility = [ ":group_dart2native" ]
   deps = [ "../runtime/bin:gen_snapshot_product" ]
   src_dir =
       get_label_info("../runtime/bin:gen_snapshot_product", "root_out_dir")
@@ -352,7 +344,7 @@
 }
 
 copy("copy_vm_platform_strong_product") {
-  visibility = [ ":copy_dart2native" ]
+  visibility = [ ":group_dart2native" ]
   deps = [ "../runtime/vm:vm_platform_product" ]
   src_dir = get_label_info("../runtime/vm:vm_platform_product", "root_out_dir")
   sources = [ "$src_dir/vm_platform_strong_product.dill" ]
@@ -360,27 +352,21 @@
       [ "$root_out_dir/$dart_sdk_output/lib/_internal/{{source_file_part}}" ]
 }
 
-copy("copy_dart2native") {
+copy("copy_gen_kernel_snapshot") {
+  visibility = [ ":group_dart2native" ]
+  deps = [ "../utils/gen_kernel" ]
+  sources = [ "$root_gen_dir/gen_kernel.dart.snapshot" ]
+  outputs =
+      [ "$root_out_dir/$dart_sdk_output/bin/snapshots/{{source_file_part}}" ]
+}
+
+group("group_dart2native") {
   deps = [
     ":copy_dartaotruntime",
     ":copy_gen_kernel_snapshot",
     ":copy_gen_snapshot",
     ":copy_vm_platform_strong_product",
   ]
-  ext = ""
-  if (is_win) {
-    ext = ".bat"
-  }
-  sources = [ "bin/dart2native$ext" ]
-  outputs = [ "$root_out_dir/$dart_sdk_output/bin/{{source_file_part}}" ]
-}
-
-copy("copy_gen_kernel_snapshot") {
-  visibility = [ ":copy_dart2native" ]
-  deps = [ "../utils/gen_kernel" ]
-  sources = [ "$root_gen_dir/gen_kernel.dart.snapshot" ]
-  outputs =
-      [ "$root_out_dir/$dart_sdk_output/bin/snapshots/{{source_file_part}}" ]
 }
 
 # A template for copying the things in _platform_sdk_scripts and
@@ -394,8 +380,8 @@
   }
   copy(target_name) {
     visibility = [
-      ":copy_platform_sdk_scripts",
       ":copy_full_sdk_scripts",
+      ":copy_platform_sdk_scripts",
     ]
     sources = [ "bin/${name}_sdk$ext" ]
     outputs = [ "$root_out_dir/$dart_sdk_output/bin/$name$ext" ]
@@ -411,8 +397,8 @@
 foreach(script, _scripts) {
   copy("copy_${script}_script") {
     visibility = [
-      ":copy_platform_sdk_scripts",
       ":copy_full_sdk_scripts",
+      ":copy_platform_sdk_scripts",
     ]
     ext = ""
     if (is_win) {
@@ -458,8 +444,8 @@
   }
   copy("copy_${snapshot[0]}_snapshot") {
     visibility = [
-      ":copy_platform_sdk_snapshots",
       ":copy_full_sdk_snapshots",
+      ":copy_platform_sdk_snapshots",
     ]
     deps = [ snapshot[1] ]
     sources = [ "$root/${snapshot[0]}.dart.snapshot" ]
@@ -695,8 +681,8 @@
 # This is the main rule to copy libraries in _full_sdk_libraries to lib/
 group("copy_full_sdk_libraries") {
   visibility = [
-    ":create_full_sdk",
     ":copy_libraries",
+    ":create_full_sdk",
   ]
   public_deps = []
   foreach(library, _full_sdk_libraries) {
@@ -796,8 +782,8 @@
 # Parts common to both platform and full SDKs.
 group("create_common_sdk") {
   visibility = [
-    ":create_sdk",
     ":create_platform_sdk",
+    ":create_sdk",
   ]
   public_deps = [
     ":copy_analysis_summaries",
@@ -818,17 +804,17 @@
   ]
 
   # We do not support AOT on ia32 and should therefore not add the
-  # dart2native script (since there is no AOT compiler/runtime available)
+  # dart native compilation files (since there is no AOT compiler/runtime available)
   if (dart_target_arch != "ia32") {
-    public_deps += [ ":copy_dart2native" ]
+    public_deps += [ ":group_dart2native" ]
   }
 }
 
 # Parts specific to the platform SDK.
 group("_create_platform_sdk") {
   visibility = [
-    ":create_sdk",
     ":create_platform_sdk",
+    ":create_sdk",
   ]
   public_deps = [
     ":copy_platform_sdk_libraries",
diff --git a/sdk/bin/dart2native b/sdk/bin/dart2native
deleted file mode 100755
index 6f59f3f..0000000
--- a/sdk/bin/dart2native
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env bash
-# Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
-# for details. All rights reserved. Use of this source code is governed by a
-# BSD-style license that can be found in the LICENSE file.
-
-# Run dart2native.dart.snapshot on the Dart VM
-
-echo "Warning: 'dart2native' is deprecated. Please use 'dart compile exe'." 1>&2
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-SNAPSHOTS_DIR="${BIN_DIR}/snapshots"
-DART="$BIN_DIR/dart"
-
-exec "$DART" "${SNAPSHOTS_DIR}/dart2native.dart.snapshot" "$@"
diff --git a/sdk/bin/dart2native.bat b/sdk/bin/dart2native.bat
deleted file mode 100644
index ca4d8d7..0000000
--- a/sdk/bin/dart2native.bat
+++ /dev/null
@@ -1,45 +0,0 @@
-@echo off
-REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
-REM for details. All rights reserved. Use of this source code is governed by a
-REM BSD-style license that can be found in the LICENSE file.
-
-echo Warning: 'dart2native' is deprecated. Please use 'dart compile exe'. 1>&2
-
-setlocal
-rem Handle the case where dart-sdk/bin has been symlinked to.
-set DIR_NAME_WITH_SLASH=%~dp0
-set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
-call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
-rem Get rid of surrounding quotes.
-for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-
-set DART=%BIN_DIR%\dart
-
-"%DART%" "%BIN_DIR%\snapshots\dart2native.dart.snapshot" %*
-
-endlocal
-
-exit /b %errorlevel%
-
-rem Follow the symbolic links (junctions points) using `dir to determine the
-rem canonical path. Output with a link looks something like this
-rem
-rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
-rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
-rem
-rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
-rem surrounded by right angle bracket and left square bracket. Once we get
-rem the filename, which is name of the link, we recursively follow that.
-:follow_links
-setlocal
-for %%i in (%1) do set result=%%~fi
-set current=
-for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
-                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
-  set current=%%i
-)
-if not "%current%"=="" call :follow_links "%current%", result
-endlocal & set %~2=%result%
-goto :eof
-
-:end
diff --git a/tests/standalone/io/file_leak_test.dart b/tests/standalone/io/file_leak_test.dart
new file mode 100644
index 0000000..6c8ddf1
--- /dev/null
+++ b/tests/standalone/io/file_leak_test.dart
@@ -0,0 +1,139 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing file I/O.
+
+// OtherResources=fixed_length_file
+// OtherResources=read_as_text.dat
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:collection';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+class FileTest {
+  static Directory? tempDirectory;
+  static int numLiveAsyncTests = 0;
+
+  static void asyncTestStarted() {
+    asyncStart();
+    ++numLiveAsyncTests;
+  }
+
+  static void asyncTestDone(String name) {
+    asyncEnd();
+    --numLiveAsyncTests;
+    if (numLiveAsyncTests == 0) {
+      deleteTempDirectory();
+    }
+  }
+
+  static void createTempDirectory(Function doNext) {
+    Directory.systemTemp.createTemp('dart_file').then((temp) {
+      tempDirectory = temp;
+      doNext();
+    });
+  }
+
+  static void deleteTempDirectory() {
+    tempDirectory!.deleteSync(recursive: true);
+  }
+
+  static testReadInto() async {
+    asyncTestStarted();
+    File file = new File(tempDirectory!.path + "/out_read_into");
+
+    var openedFile = await file.open(mode: FileMode.write);
+    await openedFile.writeFrom(const [1, 2, 3]);
+
+    await openedFile.setPosition(0);
+    var list = <int>[1, 2, 3];
+    Expect.equals(3, await openedFile.readInto(list));
+    Expect.listEquals([1, 2, 3], list);
+
+    read(start, end, length, expected) async {
+      var list = <int>[1, 2, 3];
+      await openedFile.setPosition(0);
+      Expect.equals(length, await openedFile.readInto(list, start, end));
+      Expect.listEquals(expected, list);
+      return list;
+    }
+
+    await read(0, 3, 3, [1, 2, 3]);
+    await read(0, 2, 2, [1, 2, null]);
+    await read(1, 2, 1, [null, 1, null]);
+    await read(1, 3, 2, [null, 1, 2]);
+    await read(2, 3, 1, [null, null, 1]);
+    await read(0, 0, 0, [null, null, null]);
+
+    await openedFile.close();
+
+    asyncTestDone("testReadInto");
+  }
+
+  static void testReadAsText() {
+    asyncTestStarted();
+    var name = getFilename("fixed_length_file");
+    var f = new File(name);
+    f.readAsString(encoding: utf8).then((text) {
+      Expect.isTrue(text.endsWith("42 bytes."));
+      Expect.equals(42, text.length);
+      var name = getFilename("read_as_text.dat");
+      var f = new File(name);
+      f.readAsString(encoding: utf8).then((text) {
+        Expect.equals(6, text.length);
+        var expected = [955, 120, 46, 32, 120, 10];
+        Expect.listEquals(expected, text.codeUnits);
+        f.readAsString(encoding: latin1).then((text) {
+          Expect.equals(7, text.length);
+          var expected = [206, 187, 120, 46, 32, 120, 10];
+          Expect.listEquals(expected, text.codeUnits);
+          var readAsStringFuture = f.readAsString(encoding: ascii);
+          readAsStringFuture.then((text) {
+            Expect.fail("Non-ascii char should cause error");
+          }).catchError((e) {
+            asyncTestDone("testReadAsText");
+          });
+        });
+      });
+    });
+  }
+
+  static String getFilename(String path) {
+    return Platform.script.resolve(path).toFilePath();
+  }
+
+  // Main test entrypoint.
+  // This test results in an unhandled exception in the isolate while
+  // some async file IO operations are still pending. The unhandled
+  // exception results in the 'File' object being leaked, the error
+  // only shows up in the ASAN bots which detect the leak.
+  static testMain() {
+    asyncStart();
+    var outerZone = Zone.current;
+    var firstZone = Zone.current.fork(specification: ZoneSpecification(
+        handleUncaughtError: (self, parent, zone, error, stacktrace) {
+      asyncEnd();
+      print("unittest-suite-success"); // For the test harness.
+      exit(0);
+    }));
+    firstZone.run(() async {
+      Expect.identical(firstZone, Zone.current);
+      createTempDirectory(() {
+        testReadAsText();
+        testReadInto();
+        Expect.equals(1, 0); // Should not execute this.
+        asyncEnd();
+      });
+    });
+  }
+}
+
+main() {
+  FileTest.testMain();
+}
diff --git a/tests/standalone_2/io/file_leak_test.dart b/tests/standalone_2/io/file_leak_test.dart
new file mode 100644
index 0000000..9bac244
--- /dev/null
+++ b/tests/standalone_2/io/file_leak_test.dart
@@ -0,0 +1,141 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing file I/O.
+
+// @dart = 2.9
+
+// OtherResources=fixed_length_file
+// OtherResources=read_as_text.dat
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:collection';
+import 'dart:io';
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+import "package:path/path.dart";
+
+class FileTest {
+  static Directory tempDirectory;
+  static int numLiveAsyncTests = 0;
+
+  static void asyncTestStarted() {
+    asyncStart();
+    ++numLiveAsyncTests;
+  }
+
+  static void asyncTestDone(String name) {
+    asyncEnd();
+    --numLiveAsyncTests;
+    if (numLiveAsyncTests == 0) {
+      deleteTempDirectory();
+    }
+  }
+
+  static void createTempDirectory(Function doNext) {
+    Directory.systemTemp.createTemp('dart_file').then((temp) {
+      tempDirectory = temp;
+      doNext();
+    });
+  }
+
+  static void deleteTempDirectory() {
+    tempDirectory.deleteSync(recursive: true);
+  }
+
+  static testReadInto() async {
+    asyncTestStarted();
+    File file = new File(tempDirectory.path + "/out_read_into");
+
+    var openedFile = await file.open(mode: FileMode.write);
+    await openedFile.writeFrom(const [1, 2, 3]);
+
+    await openedFile.setPosition(0);
+    var list = [null, null, null];
+    Expect.equals(3, await openedFile.readInto(list));
+    Expect.listEquals([1, 2, 3], list);
+
+    read(start, end, length, expected) async {
+      var list = [null, null, null];
+      await openedFile.setPosition(0);
+      Expect.equals(length, await openedFile.readInto(list, start, end));
+      Expect.listEquals(expected, list);
+      return list;
+    }
+
+    await read(0, 3, 3, [1, 2, 3]);
+    await read(0, 2, 2, [1, 2, null]);
+    await read(1, 2, 1, [null, 1, null]);
+    await read(1, 3, 2, [null, 1, 2]);
+    await read(2, 3, 1, [null, null, 1]);
+    await read(0, 0, 0, [null, null, null]);
+
+    await openedFile.close();
+
+    asyncTestDone("testReadInto");
+  }
+
+  static void testReadAsText() {
+    asyncTestStarted();
+    var name = getFilename("fixed_length_file");
+    var f = new File(name);
+    f.readAsString(encoding: utf8).then((text) {
+      Expect.isTrue(text.endsWith("42 bytes."));
+      Expect.equals(42, text.length);
+      var name = getFilename("read_as_text.dat");
+      var f = new File(name);
+      f.readAsString(encoding: utf8).then((text) {
+        Expect.equals(6, text.length);
+        var expected = [955, 120, 46, 32, 120, 10];
+        Expect.listEquals(expected, text.codeUnits);
+        f.readAsString(encoding: latin1).then((text) {
+          Expect.equals(7, text.length);
+          var expected = [206, 187, 120, 46, 32, 120, 10];
+          Expect.listEquals(expected, text.codeUnits);
+          var readAsStringFuture = f.readAsString(encoding: ascii);
+          readAsStringFuture.then((text) {
+            Expect.fail("Non-ascii char should cause error");
+          }).catchError((e) {
+            asyncTestDone("testReadAsText");
+          });
+        });
+      });
+    });
+  }
+
+  static String getFilename(String path) {
+    return Platform.script.resolve(path).toFilePath();
+  }
+
+  // Main test entrypoint.
+  // This test results in an unhandled exception in the isolate while
+  // some async file IO operations are still pending. The unhandled
+  // exception results in the 'File' object being leaked, the error
+  // only shows up in the ASAN bots which detect the leak.
+  static testMain() {
+    asyncStart();
+    var outerZone = Zone.current;
+    var firstZone = Zone.current.fork(specification: ZoneSpecification(
+        handleUncaughtError: (self, parent, zone, error, stacktrace) {
+      asyncEnd();
+      print("unittest-suite-success"); // For the test harness.
+      exit(0);
+    }));
+    firstZone.run(() async {
+      Expect.identical(firstZone, Zone.current);
+      createTempDirectory(() {
+        testReadAsText();
+        testReadInto();
+        Expect.equals(1, 0); // Should not execute this.
+        asyncEnd();
+      });
+    });
+  }
+}
+
+main() {
+  FileTest.testMain();
+}
diff --git a/tools/VERSION b/tools/VERSION
index b6717ad..b711534 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 15
 PATCH 0
-PRERELEASE 45
+PRERELEASE 46
 PRERELEASE_PATCH 0
\ No newline at end of file