Version 2.14.0-272.0.dev

Merge commit '38c1d4aaf840900d85272f89af01f4ec8973c0df' into 'dev'
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 3aa4e18..f63580d 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -2121,8 +2121,6 @@
   
   
   
-  
-  
 <h3>Requests</h3><dl><dt class="request"><a name="request_edit.format">edit.format</a></dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "edit.format"
@@ -3084,8 +3082,6 @@
   
   
   
-  
-  
 <dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
     <p>
       A directive to begin overlaying the contents of a file. The supplied
@@ -5370,12 +5366,6 @@
           An "edit.sortMembers" request specified a Dart file that has
           scan or parse errors.
         </p>
-      </dd><dt class="value">UNKNOWN_FIX</dt><dd>
-        
-        <p>
-          A dartfix request was received containing the name of a fix
-          which does not match the name of any known fixes.
-        </p>
       </dd><dt class="value">UNKNOWN_REQUEST</dt><dd>
         
         <p>
diff --git a/pkg/analysis_server/lib/protocol/protocol_constants.dart b/pkg/analysis_server/lib/protocol/protocol_constants.dart
index c06dbe8..84b3a5c 100644
--- a/pkg/analysis_server/lib/protocol/protocol_constants.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_constants.dart
@@ -163,14 +163,6 @@
 const String EDIT_REQUEST_BULK_FIXES = 'edit.bulkFixes';
 const String EDIT_REQUEST_BULK_FIXES_INCLUDED = 'included';
 const String EDIT_REQUEST_BULK_FIXES_IN_TEST_MODE = 'inTestMode';
-const String EDIT_REQUEST_DARTFIX = 'edit.dartfix';
-const String EDIT_REQUEST_DARTFIX_EXCLUDED_FIXES = 'excludedFixes';
-const String EDIT_REQUEST_DARTFIX_INCLUDED = 'included';
-const String EDIT_REQUEST_DARTFIX_INCLUDED_FIXES = 'includedFixes';
-const String EDIT_REQUEST_DARTFIX_INCLUDE_PEDANTIC_FIXES =
-    'includePedanticFixes';
-const String EDIT_REQUEST_DARTFIX_OUTPUT_DIR = 'outputDir';
-const String EDIT_REQUEST_DARTFIX_PORT = 'port';
 const String EDIT_REQUEST_FORMAT = 'edit.format';
 const String EDIT_REQUEST_FORMAT_FILE = 'file';
 const String EDIT_REQUEST_FORMAT_LINE_LENGTH = 'lineLength';
@@ -185,7 +177,6 @@
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_FILE = 'file';
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_LENGTH = 'length';
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_OFFSET = 'offset';
-const String EDIT_REQUEST_GET_DARTFIX_INFO = 'edit.getDartfixInfo';
 const String EDIT_REQUEST_GET_FIXES = 'edit.getFixes';
 const String EDIT_REQUEST_GET_FIXES_FILE = 'file';
 const String EDIT_REQUEST_GET_FIXES_OFFSET = 'offset';
@@ -221,19 +212,11 @@
 const String EDIT_REQUEST_SORT_MEMBERS_FILE = 'file';
 const String EDIT_RESPONSE_BULK_FIXES_DETAILS = 'details';
 const String EDIT_RESPONSE_BULK_FIXES_EDITS = 'edits';
-const String EDIT_RESPONSE_DARTFIX_DETAILS = 'details';
-const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits';
-const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors';
-const String EDIT_RESPONSE_DARTFIX_OTHER_SUGGESTIONS = 'otherSuggestions';
-const String EDIT_RESPONSE_DARTFIX_PORT = 'port';
-const String EDIT_RESPONSE_DARTFIX_SUGGESTIONS = 'suggestions';
-const String EDIT_RESPONSE_DARTFIX_URLS = 'urls';
 const String EDIT_RESPONSE_FORMAT_EDITS = 'edits';
 const String EDIT_RESPONSE_FORMAT_SELECTION_LENGTH = 'selectionLength';
 const String EDIT_RESPONSE_FORMAT_SELECTION_OFFSET = 'selectionOffset';
 const String EDIT_RESPONSE_GET_ASSISTS_ASSISTS = 'assists';
 const String EDIT_RESPONSE_GET_AVAILABLE_REFACTORINGS_KINDS = 'kinds';
-const String EDIT_RESPONSE_GET_DARTFIX_INFO_FIXES = 'fixes';
 const String EDIT_RESPONSE_GET_FIXES_FIXES = 'fixes';
 const String EDIT_RESPONSE_GET_POSTFIX_COMPLETION_CHANGE = 'change';
 const String EDIT_RESPONSE_GET_REFACTORING_CHANGE = 'change';
diff --git a/pkg/analysis_server/lib/protocol/protocol_generated.dart b/pkg/analysis_server/lib/protocol/protocol_generated.dart
index b434a60..dcb4e02 100644
--- a/pkg/analysis_server/lib/protocol/protocol_generated.dart
+++ b/pkg/analysis_server/lib/protocol/protocol_generated.dart
@@ -5471,145 +5471,6 @@
   }
 }
 
-/// DartFix
-///
-/// {
-///   "name": String
-///   "description": optional String
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class DartFix implements HasToJson {
-  /// The name of the fix.
-  String name;
-
-  /// A human readable description of the fix.
-  String? description;
-
-  DartFix(this.name, {this.description});
-
-  factory DartFix.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      String name;
-      if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'name');
-      }
-      String? description;
-      if (json.containsKey('description')) {
-        description = jsonDecoder.decodeString(
-            jsonPath + '.description', json['description']);
-      }
-      return DartFix(name, description: description);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'DartFix', json);
-    }
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['name'] = name;
-    var description = this.description;
-    if (description != null) {
-      result['description'] = description;
-    }
-    return result;
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is DartFix) {
-      return name == other.name && description == other.description;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, name.hashCode);
-    hash = JenkinsSmiHash.combine(hash, description.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// DartFixSuggestion
-///
-/// {
-///   "description": String
-///   "location": optional Location
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class DartFixSuggestion implements HasToJson {
-  /// A human readable description of the suggested change.
-  String description;
-
-  /// The location of the suggested change.
-  Location? location;
-
-  DartFixSuggestion(this.description, {this.location});
-
-  factory DartFixSuggestion.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      String description;
-      if (json.containsKey('description')) {
-        description = jsonDecoder.decodeString(
-            jsonPath + '.description', json['description']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'description');
-      }
-      Location? location;
-      if (json.containsKey('location')) {
-        location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
-      }
-      return DartFixSuggestion(description, location: location);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'DartFixSuggestion', json);
-    }
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['description'] = description;
-    var location = this.location;
-    if (location != null) {
-      result['location'] = location.toJson();
-    }
-    return result;
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is DartFixSuggestion) {
-      return description == other.description && location == other.location;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, description.hashCode);
-    hash = JenkinsSmiHash.combine(hash, location.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// diagnostic.getDiagnostics params
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -5988,354 +5849,6 @@
   }
 }
 
-/// edit.dartfix params
-///
-/// {
-///   "included": List<FilePath>
-///   "includedFixes": optional List<String>
-///   "includePedanticFixes": optional bool
-///   "excludedFixes": optional List<String>
-///   "port": optional int
-///   "outputDir": optional FilePath
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditDartfixParams implements RequestParams {
-  /// A list of the files and directories for which edits should be suggested.
-  ///
-  /// If a request is made with a path that is invalid, e.g. is not absolute
-  /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be
-  /// generated. If a request is made for a file which does not exist, or which
-  /// is not currently subject to analysis (e.g. because it is not associated
-  /// with any analysis root specified to analysis.setAnalysisRoots), an error
-  /// of type FILE_NOT_ANALYZED will be generated.
-  List<String> included;
-
-  /// A list of names indicating which fixes should be applied.
-  ///
-  /// If a name is specified that does not match the name of a known fix, an
-  /// error of type UNKNOWN_FIX will be generated.
-  List<String>? includedFixes;
-
-  /// A flag indicating whether "pedantic" fixes should be applied.
-  bool? includePedanticFixes;
-
-  /// A list of names indicating which fixes should not be applied.
-  ///
-  /// If a name is specified that does not match the name of a known fix, an
-  /// error of type UNKNOWN_FIX will be generated.
-  List<String>? excludedFixes;
-
-  /// Deprecated: This field is now ignored by server.
-  int? port;
-
-  /// Deprecated: This field is now ignored by server.
-  String? outputDir;
-
-  EditDartfixParams(this.included,
-      {this.includedFixes,
-      this.includePedanticFixes,
-      this.excludedFixes,
-      this.port,
-      this.outputDir});
-
-  factory EditDartfixParams.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<String> included;
-      if (json.containsKey('included')) {
-        included = jsonDecoder.decodeList(
-            jsonPath + '.included', json['included'], jsonDecoder.decodeString);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'included');
-      }
-      List<String>? includedFixes;
-      if (json.containsKey('includedFixes')) {
-        includedFixes = jsonDecoder.decodeList(jsonPath + '.includedFixes',
-            json['includedFixes'], jsonDecoder.decodeString);
-      }
-      bool? includePedanticFixes;
-      if (json.containsKey('includePedanticFixes')) {
-        includePedanticFixes = jsonDecoder.decodeBool(
-            jsonPath + '.includePedanticFixes', json['includePedanticFixes']);
-      }
-      List<String>? excludedFixes;
-      if (json.containsKey('excludedFixes')) {
-        excludedFixes = jsonDecoder.decodeList(jsonPath + '.excludedFixes',
-            json['excludedFixes'], jsonDecoder.decodeString);
-      }
-      int? port;
-      if (json.containsKey('port')) {
-        port = jsonDecoder.decodeInt(jsonPath + '.port', json['port']);
-      }
-      String? outputDir;
-      if (json.containsKey('outputDir')) {
-        outputDir = jsonDecoder.decodeString(
-            jsonPath + '.outputDir', json['outputDir']);
-      }
-      return EditDartfixParams(included,
-          includedFixes: includedFixes,
-          includePedanticFixes: includePedanticFixes,
-          excludedFixes: excludedFixes,
-          port: port,
-          outputDir: outputDir);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.dartfix params', json);
-    }
-  }
-
-  factory EditDartfixParams.fromRequest(Request request) {
-    return EditDartfixParams.fromJson(
-        RequestDecoder(request), 'params', request.params);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['included'] = included;
-    var includedFixes = this.includedFixes;
-    if (includedFixes != null) {
-      result['includedFixes'] = includedFixes;
-    }
-    var includePedanticFixes = this.includePedanticFixes;
-    if (includePedanticFixes != null) {
-      result['includePedanticFixes'] = includePedanticFixes;
-    }
-    var excludedFixes = this.excludedFixes;
-    if (excludedFixes != null) {
-      result['excludedFixes'] = excludedFixes;
-    }
-    var port = this.port;
-    if (port != null) {
-      result['port'] = port;
-    }
-    var outputDir = this.outputDir;
-    if (outputDir != null) {
-      result['outputDir'] = outputDir;
-    }
-    return result;
-  }
-
-  @override
-  Request toRequest(String id) {
-    return Request(id, 'edit.dartfix', toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditDartfixParams) {
-      return listEqual(
-              included, other.included, (String a, String b) => a == b) &&
-          listEqual(includedFixes, other.includedFixes,
-              (String a, String b) => a == b) &&
-          includePedanticFixes == other.includePedanticFixes &&
-          listEqual(excludedFixes, other.excludedFixes,
-              (String a, String b) => a == b) &&
-          port == other.port &&
-          outputDir == other.outputDir;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, included.hashCode);
-    hash = JenkinsSmiHash.combine(hash, includedFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, includePedanticFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, excludedFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, port.hashCode);
-    hash = JenkinsSmiHash.combine(hash, outputDir.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// edit.dartfix result
-///
-/// {
-///   "suggestions": List<DartFixSuggestion>
-///   "otherSuggestions": List<DartFixSuggestion>
-///   "hasErrors": bool
-///   "edits": List<SourceFileEdit>
-///   "details": optional List<String>
-///   "port": optional int
-///   "urls": optional List<String>
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditDartfixResult implements ResponseResult {
-  /// A list of recommended changes that can be automatically made by applying
-  /// the 'edits' included in this response.
-  List<DartFixSuggestion> suggestions;
-
-  /// A list of recommended changes that could not be automatically made.
-  List<DartFixSuggestion> otherSuggestions;
-
-  /// True if the analyzed source contains errors that might impact the
-  /// correctness of the recommended changes that can be automatically applied.
-  bool hasErrors;
-
-  /// A list of source edits to apply the recommended changes.
-  List<SourceFileEdit> edits;
-
-  /// Messages that should be displayed to the user that describe details of
-  /// the fix generation. For example, the messages might (a) point out details
-  /// that users might want to explore before committing the changes or (b)
-  /// describe exceptions that were thrown but that did not stop the fixes from
-  /// being produced. The list will be omitted if it is empty.
-  List<String>? details;
-
-  /// The port on which the preview tool will respond to GET requests. The
-  /// field is omitted if a preview was not requested.
-  int? port;
-
-  /// The URLs that users can visit in a browser to see a preview of the
-  /// proposed changes. There is one URL for each of the included file paths.
-  /// The field is omitted if a preview was not requested.
-  List<String>? urls;
-
-  EditDartfixResult(
-      this.suggestions, this.otherSuggestions, this.hasErrors, this.edits,
-      {this.details, this.port, this.urls});
-
-  factory EditDartfixResult.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<DartFixSuggestion> suggestions;
-      if (json.containsKey('suggestions')) {
-        suggestions = jsonDecoder.decodeList(
-            jsonPath + '.suggestions',
-            json['suggestions'],
-            (String jsonPath, Object? json) =>
-                DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'suggestions');
-      }
-      List<DartFixSuggestion> otherSuggestions;
-      if (json.containsKey('otherSuggestions')) {
-        otherSuggestions = jsonDecoder.decodeList(
-            jsonPath + '.otherSuggestions',
-            json['otherSuggestions'],
-            (String jsonPath, Object? json) =>
-                DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'otherSuggestions');
-      }
-      bool hasErrors;
-      if (json.containsKey('hasErrors')) {
-        hasErrors =
-            jsonDecoder.decodeBool(jsonPath + '.hasErrors', json['hasErrors']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'hasErrors');
-      }
-      List<SourceFileEdit> edits;
-      if (json.containsKey('edits')) {
-        edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
-            json['edits'],
-            (String jsonPath, Object? json) =>
-                SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'edits');
-      }
-      List<String>? details;
-      if (json.containsKey('details')) {
-        details = jsonDecoder.decodeList(
-            jsonPath + '.details', json['details'], jsonDecoder.decodeString);
-      }
-      int? port;
-      if (json.containsKey('port')) {
-        port = jsonDecoder.decodeInt(jsonPath + '.port', json['port']);
-      }
-      List<String>? urls;
-      if (json.containsKey('urls')) {
-        urls = jsonDecoder.decodeList(
-            jsonPath + '.urls', json['urls'], jsonDecoder.decodeString);
-      }
-      return EditDartfixResult(suggestions, otherSuggestions, hasErrors, edits,
-          details: details, port: port, urls: urls);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.dartfix result', json);
-    }
-  }
-
-  factory EditDartfixResult.fromResponse(Response response) {
-    return EditDartfixResult.fromJson(
-        ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)),
-        'result',
-        response.result);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['suggestions'] =
-        suggestions.map((DartFixSuggestion value) => value.toJson()).toList();
-    result['otherSuggestions'] = otherSuggestions
-        .map((DartFixSuggestion value) => value.toJson())
-        .toList();
-    result['hasErrors'] = hasErrors;
-    result['edits'] =
-        edits.map((SourceFileEdit value) => value.toJson()).toList();
-    var details = this.details;
-    if (details != null) {
-      result['details'] = details;
-    }
-    var port = this.port;
-    if (port != null) {
-      result['port'] = port;
-    }
-    var urls = this.urls;
-    if (urls != null) {
-      result['urls'] = urls;
-    }
-    return result;
-  }
-
-  @override
-  Response toResponse(String id) {
-    return Response(id, result: toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditDartfixResult) {
-      return listEqual(suggestions, other.suggestions,
-              (DartFixSuggestion a, DartFixSuggestion b) => a == b) &&
-          listEqual(otherSuggestions, other.otherSuggestions,
-              (DartFixSuggestion a, DartFixSuggestion b) => a == b) &&
-          hasErrors == other.hasErrors &&
-          listEqual(edits, other.edits,
-              (SourceFileEdit a, SourceFileEdit b) => a == b) &&
-          listEqual(details, other.details, (String a, String b) => a == b) &&
-          port == other.port &&
-          listEqual(urls, other.urls, (String a, String b) => a == b);
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, suggestions.hashCode);
-    hash = JenkinsSmiHash.combine(hash, otherSuggestions.hashCode);
-    hash = JenkinsSmiHash.combine(hash, hasErrors.hashCode);
-    hash = JenkinsSmiHash.combine(hash, edits.hashCode);
-    hash = JenkinsSmiHash.combine(hash, details.hashCode);
-    hash = JenkinsSmiHash.combine(hash, port.hashCode);
-    hash = JenkinsSmiHash.combine(hash, urls.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// edit.format params
 ///
 /// {
@@ -6877,130 +6390,6 @@
   }
 }
 
-/// edit.getDartfixInfo params
-///
-/// {
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditGetDartfixInfoParams implements RequestParams {
-  EditGetDartfixInfoParams();
-
-  factory EditGetDartfixInfoParams.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      return EditGetDartfixInfoParams();
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.getDartfixInfo params', json);
-    }
-  }
-
-  factory EditGetDartfixInfoParams.fromRequest(Request request) {
-    return EditGetDartfixInfoParams.fromJson(
-        RequestDecoder(request), 'params', request.params);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    return result;
-  }
-
-  @override
-  Request toRequest(String id) {
-    return Request(id, 'edit.getDartfixInfo', toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditGetDartfixInfoParams) {
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// edit.getDartfixInfo result
-///
-/// {
-///   "fixes": List<DartFix>
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditGetDartfixInfoResult implements ResponseResult {
-  /// A list of fixes that can be specified in an edit.dartfix request.
-  List<DartFix> fixes;
-
-  EditGetDartfixInfoResult(this.fixes);
-
-  factory EditGetDartfixInfoResult.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<DartFix> fixes;
-      if (json.containsKey('fixes')) {
-        fixes = jsonDecoder.decodeList(
-            jsonPath + '.fixes',
-            json['fixes'],
-            (String jsonPath, Object? json) =>
-                DartFix.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'fixes');
-      }
-      return EditGetDartfixInfoResult(fixes);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.getDartfixInfo result', json);
-    }
-  }
-
-  factory EditGetDartfixInfoResult.fromResponse(Response response) {
-    return EditGetDartfixInfoResult.fromJson(
-        ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)),
-        'result',
-        response.result);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['fixes'] = fixes.map((DartFix value) => value.toJson()).toList();
-    return result;
-  }
-
-  @override
-  Response toResponse(String id) {
-    return Response(id, result: toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditGetDartfixInfoResult) {
-      return listEqual(fixes, other.fixes, (DartFix a, DartFix b) => a == b);
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, fixes.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// edit.getFixes params
 ///
 /// {
@@ -14269,7 +13658,6 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
-///   UNKNOWN_FIX
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -14436,10 +13824,6 @@
   static const RequestErrorCode SORT_MEMBERS_PARSE_ERRORS =
       RequestErrorCode._('SORT_MEMBERS_PARSE_ERRORS');
 
-  /// A dartfix request was received containing the name of a fix which does
-  /// not match the name of any known fixes.
-  static const RequestErrorCode UNKNOWN_FIX = RequestErrorCode._('UNKNOWN_FIX');
-
   /// A request was received which the analysis server does not recognize, or
   /// cannot handle in its current configuration.
   static const RequestErrorCode UNKNOWN_REQUEST =
@@ -14487,7 +13871,6 @@
     SERVER_ERROR,
     SORT_MEMBERS_INVALID_FILE,
     SORT_MEMBERS_PARSE_ERRORS,
-    UNKNOWN_FIX,
     UNKNOWN_REQUEST,
     UNSUPPORTED_FEATURE
   ];
@@ -14563,8 +13946,6 @@
         return SORT_MEMBERS_INVALID_FILE;
       case 'SORT_MEMBERS_PARSE_ERRORS':
         return SORT_MEMBERS_PARSE_ERRORS;
-      case 'UNKNOWN_FIX':
-        return UNKNOWN_FIX;
       case 'UNKNOWN_REQUEST':
         return UNKNOWN_REQUEST;
       case 'UNSUPPORTED_FEATURE':
diff --git a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart b/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
deleted file mode 100644
index 6289553..0000000
--- a/pkg/analysis_server/lib/src/edit/edit_dartfix.dart
+++ /dev/null
@@ -1,271 +0,0 @@
-// Copyright (c) 2018, 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 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_info.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_registrar.dart';
-import 'package:analysis_server/src/edit/fix/fix_code_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_error_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_lint_task.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/analysis/session.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
-import 'package:collection/collection.dart';
-
-class EditDartFix
-    with FixCodeProcessor, FixErrorProcessor, FixLintProcessor
-    implements DartFixRegistrar {
-  final AnalysisServer server;
-
-  final Request request;
-  final pkgFolders = <Folder>[];
-  final fixFolders = <Folder>[];
-  final fixFiles = <File>[];
-
-  DartFixListener listener;
-
-  EditDartFix(this.server, this.request) : listener = DartFixListener(server);
-
-  Future<Response> compute() async {
-    final params = EditDartfixParams.fromRequest(request);
-    // Determine the fixes to be applied
-    final fixInfo = <DartFixInfo>[];
-    if (params.includePedanticFixes == true) {
-      for (var fix in allFixes) {
-        if (fix.isPedantic && !fixInfo.contains(fix)) {
-          fixInfo.add(fix);
-        }
-      }
-    }
-    var includedFixes = params.includedFixes;
-    if (includedFixes != null) {
-      for (var key in includedFixes) {
-        var info = allFixes.firstWhereOrNull((i) => i.key == key);
-        if (info != null) {
-          fixInfo.add(info);
-        } else {
-          return Response.invalidParameter(
-              request, 'includedFixes', 'Unknown fix: $key');
-        }
-      }
-    }
-    var excludedFixes = params.excludedFixes;
-    if (excludedFixes != null) {
-      for (var key in excludedFixes) {
-        var info = allFixes.firstWhereOrNull((i) => i.key == key);
-        if (info != null) {
-          fixInfo.remove(info);
-        } else {
-          return Response.invalidParameter(
-              request, 'excludedFixes', 'Unknown fix: $key');
-        }
-      }
-    }
-    for (var info in fixInfo) {
-      info.setup(this, listener, params);
-    }
-
-    // Validate each included file and directory.
-    final resourceProvider = server.resourceProvider;
-    final contextManager = server.contextManager;
-
-    // Discard any existing analysis so that the linters set below will be
-    // used to generate errors that can then be fixed.
-    // TODO(danrubel): Rework to use a different approach if this command
-    // will be used from within the IDE.
-    contextManager.refresh();
-
-    for (var filePath in params.included) {
-      if (!server.isValidFilePath(filePath)) {
-        return Response.invalidFilePathFormat(request, filePath);
-      }
-
-      var analysisContext = contextManager.getContextFor(filePath);
-      if (analysisContext == null) {
-        return Response.fileNotAnalyzed(request, filePath);
-      }
-
-      var res = resourceProvider.getResource(filePath);
-      if (!res.exists) {
-        return Response.fileNotAnalyzed(request, filePath);
-      }
-
-      // Set the linters used during analysis. If this command is used from
-      // within an IDE, then this will cause the lint results to change.
-      // TODO(danrubel): Rework to use a different approach if this command
-      // will be used from within the IDE.
-      var driver = analysisContext.driver;
-      var analysisOptions = driver.analysisOptions as AnalysisOptionsImpl;
-      analysisOptions.lint = true;
-      analysisOptions.lintRules = linters;
-
-      var pkgFolder = analysisContext.contextRoot.root;
-      if (!pkgFolders.contains(pkgFolder)) {
-        pkgFolders.add(pkgFolder);
-      }
-
-      if (res is Folder) {
-        fixFolders.add(res);
-      } else {
-        fixFiles.add(res as File);
-      }
-    }
-
-    String? changedPath;
-    contextManager.driverMap.values.forEach((driver) {
-      // Setup a listener to remember the resource that changed during analysis
-      // so it can be reported if there is an InconsistentAnalysisException.
-      driver.onCurrentSessionAboutToBeDiscarded = (String? path) {
-        changedPath = path;
-      };
-    });
-
-    bool hasErrors;
-    try {
-      hasErrors = await runAllTasks();
-    } on InconsistentAnalysisException catch (_) {
-      // If a resource changed, report the problem without suggesting fixes
-      var changedMessage = changedPath != null
-          ? 'resource changed during analysis: $changedPath'
-          : 'multiple resources changed during analysis.';
-      return EditDartfixResult(
-        [DartFixSuggestion('Analysis canceled because $changedMessage')],
-        listener.otherSuggestions,
-        false, // We may have errors, but we do not know, and it doesn't matter.
-        listener.sourceChange.edits,
-        details: listener.details,
-      ).toResponse(request.id);
-    }
-
-    return EditDartfixResult(
-      listener.suggestions,
-      listener.otherSuggestions,
-      hasErrors,
-      listener.sourceChange.edits,
-      details: listener.details,
-    ).toResponse(request.id);
-  }
-
-  Folder? findPkgFolder(Folder start) {
-    for (var folder in start.withAncestors) {
-      if (folder.getChild('analysis_options.yaml').exists ||
-          folder.getChild('pubspec.yaml').exists) {
-        return folder;
-      }
-    }
-    return null;
-  }
-
-  Set<String> getPathsToProcess() {
-    final contextManager = server.contextManager;
-    final resourceProvider = server.resourceProvider;
-    final resources = <Resource>[];
-    for (var rootPath in contextManager.includedPaths) {
-      resources.add(resourceProvider.getResource(rootPath));
-    }
-
-    var pathsToProcess = <String>{};
-    while (resources.isNotEmpty) {
-      var res = resources.removeLast();
-      if (res is Folder) {
-        for (var child in res.getChildren()) {
-          if (!child.shortName.startsWith('.') &&
-              server.isAnalyzed(child.path)) {
-            resources.add(child);
-          }
-        }
-        continue;
-      }
-      if (!isIncluded(res.path)) {
-        continue;
-      }
-      pathsToProcess.add(res.path);
-    }
-    return pathsToProcess;
-  }
-
-  /// Return `true` if the path in within the set of `included` files
-  /// or is within an `included` directory.
-  bool isIncluded(String filePath) {
-    for (var file in fixFiles) {
-      if (file.path == filePath) {
-        return true;
-      }
-    }
-    for (var folder in fixFolders) {
-      if (folder.contains(filePath)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /// Call the supplied [process] function to process each compilation unit.
-  Future processResources(
-      Future<void> Function(ResolvedUnitResult result) process) async {
-    final pathsToProcess = getPathsToProcess();
-    var pathsProcessed = <String>{};
-    for (var path in pathsToProcess) {
-      if (pathsProcessed.contains(path)) continue;
-      var driver = server.getAnalysisDriver(path);
-      if (driver != null) {
-        var result = await driver.getResolvedLibrary2(path);
-        if (result is ResolvedLibraryResult) {
-          for (var unit in result.units!) {
-            if (pathsToProcess.contains(unit.path) &&
-                !pathsProcessed.contains(unit.path)) {
-              await process(unit);
-              pathsProcessed.add(unit.path!);
-            }
-          }
-          break;
-        }
-      }
-    }
-
-    for (var path in pathsToProcess.difference(pathsProcessed)) {
-      var result = await server.getResolvedUnit(path);
-      if (result == null || result.unit == null) {
-        continue;
-      }
-      await process(result);
-    }
-  }
-
-  Future<bool> runAllTasks() async {
-    // Process each package
-    for (var pkgFolder in pkgFolders) {
-      await processPackage(pkgFolder);
-    }
-
-    var hasErrors = false;
-
-    // Process each source file.
-    try {
-      await processResources((ResolvedUnitResult result) async {
-        if (await processErrors(result)) {
-          hasErrors = true;
-        }
-        if (numPhases > 0) {
-          await processCodeTasks(0, result);
-        }
-      });
-      for (var phase = 1; phase < numPhases; phase++) {
-        await processResources((ResolvedUnitResult result) async {
-          await processCodeTasks(phase, result);
-        });
-      }
-      await finishCodeTasks();
-    } finally {
-      server.contextManager.driverMap.values
-          .forEach((d) => d.onCurrentSessionAboutToBeDiscarded = null);
-    }
-
-    return hasErrors;
-  }
-}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index f4f16f9..e7456df 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -11,8 +11,6 @@
 import 'package:analysis_server/src/collections.dart';
 import 'package:analysis_server/src/computer/import_elements_computer.dart';
 import 'package:analysis_server/src/domain_abstract.dart';
-import 'package:analysis_server/src/edit/edit_dartfix.dart' show EditDartFix;
-import 'package:analysis_server/src/edit/fix/dartfix_info.dart' show allFixes;
 import 'package:analysis_server/src/plugin/plugin_manager.dart';
 import 'package:analysis_server/src/plugin/result_converter.dart';
 import 'package:analysis_server/src/protocol_server.dart'
@@ -119,23 +117,6 @@
     }
   }
 
-  Future dartfix(Request request) async {
-    // TODO(danrubel): Add support for dartfix plugins
-
-    //
-    // Compute fixes
-    //
-    try {
-      var dartFix = EditDartFix(server, request);
-      var response = await dartFix.compute();
-
-      server.sendResponse(response);
-    } catch (exception, stackTrace) {
-      server.sendServerErrorNotification('Exception while running dartfix',
-          CaughtException(exception, stackTrace), stackTrace);
-    }
-  }
-
   Response format(Request request) {
     server.options.analytics?.sendEvent('edit', 'format');
 
@@ -244,10 +225,6 @@
     server.sendResponse(EditGetAssistsResult(changes).toResponse(request.id));
   }
 
-  Response getDartfixInfo(Request request) =>
-      EditGetDartfixInfoResult(allFixes.map((i) => i.asDartFix()).toList())
-          .toResponse(request.id);
-
   Future<void> getFixes(Request request) async {
     var params = EditGetFixesParams.fromRequest(request);
     var file = params.file;
@@ -374,14 +351,9 @@
       } else if (requestName == EDIT_REQUEST_BULK_FIXES) {
         bulkFixes(request);
         return Response.DELAYED_RESPONSE;
-      } else if (requestName == EDIT_REQUEST_GET_DARTFIX_INFO) {
-        return getDartfixInfo(request);
       } else if (requestName == EDIT_REQUEST_GET_FIXES) {
         getFixes(request);
         return Response.DELAYED_RESPONSE;
-      } else if (requestName == EDIT_REQUEST_DARTFIX) {
-        dartfix(request);
-        return Response.DELAYED_RESPONSE;
       } else if (requestName == EDIT_REQUEST_GET_REFACTORING) {
         return _getRefactoring(request);
       } else if (requestName == EDIT_REQUEST_IMPORT_ELEMENTS) {
diff --git a/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart b/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart
deleted file mode 100644
index 0d4ac07..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/dartfix_info.dart
+++ /dev/null
@@ -1,562 +0,0 @@
-// 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 'package:analysis_server/protocol/protocol_generated.dart'
-    show DartFix, EditDartfixParams;
-import 'package:analysis_server/src/edit/edit_dartfix.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_registrar.dart';
-import 'package:analysis_server/src/edit/fix/fix_error_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_lint_task.dart';
-import 'package:analysis_server/src/edit/fix/prefer_mixin_fix.dart';
-import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analyzer/src/lint/registry.dart';
-import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
-
-final allFixes = <DartFixInfo>[
-  //
-  // Error and warning fixes.
-  //
-  DartFixInfo(
-    'wrong_number_of_type_arguments_constructor',
-    'Move named constructor type arguments from the name to the type.',
-    FixErrorTask.fixNamedConstructorTypeArgs,
-  ),
-  //
-  // Assist fixes.
-  //
-  DartFixInfo(
-    'convert_class_to_mixin',
-    'Convert classes used as a mixin to the new mixin syntax.',
-    PreferMixinFix.task,
-  ),
-  //
-  // Lint fixes.
-  //
-  // TODO(brianwilkerson) The commented out fixes below involve potentially
-  //  non-local changes, so they can't currently be applied together. I have an
-  //  idea for how to update FixProcessor to support these fixes.
-//  LintFixInfo.alwaysDeclareReturnTypes,
-//  LintFixInfo.alwaysRequireNonNullNamedParameters
-//  LintFixInfo.alwaysSpecifyTypes,
-  LintFixInfo.annotateOverrides,
-  LintFixInfo.avoidAnnotatingWithDynamic,
-  LintFixInfo.avoidEmptyElse,
-  LintFixInfo.avoidInitToNull,
-  LintFixInfo.avoidRedundantArgumentValues,
-  LintFixInfo.avoidRelativeLibImports,
-  LintFixInfo.avoidReturnTypesOnSetters,
-  LintFixInfo.avoidTypesOnClosureParameters,
-  LintFixInfo.awaitOnlyFutures,
-  LintFixInfo.curlyBracesInFlowControlStructures,
-  LintFixInfo.diagnosticDescribeAllProperties,
-  LintFixInfo.emptyCatches,
-  LintFixInfo.emptyConstructorBodies,
-  LintFixInfo.emptyStatements,
-  LintFixInfo.hashAndEquals,
-  LintFixInfo.noDuplicateCaseValues,
-  LintFixInfo.nonConstantIdentifierNames,
-  LintFixInfo.nullClosures,
-  LintFixInfo.omitLocalVariableTypes,
-  LintFixInfo.preferAdjacentStringConcatenation,
-  LintFixInfo.preferCollectionLiterals,
-  LintFixInfo.preferConditionalAssignment,
-  LintFixInfo.preferConstConstructors,
-  LintFixInfo.preferConstConstructorsInImmutables,
-  LintFixInfo.preferConstDeclarations,
-  LintFixInfo.preferContains,
-  LintFixInfo.preferEqualForDefaultValues,
-  LintFixInfo.preferFinalFields,
-  LintFixInfo.preferFinalLocals,
-  LintFixInfo.preferForElementsToMapFromIterable,
-  LintFixInfo.preferGenericFunctionTypeAliases,
-  LintFixInfo.preferIfElementsToConditionalExpressions,
-  LintFixInfo.preferIfNullOperators,
-  LintFixInfo.preferInlinedAdds,
-  LintFixInfo.preferIntLiterals,
-  LintFixInfo.preferIsEmpty,
-  LintFixInfo.preferIsNotEmpty,
-  LintFixInfo.preferIterableWhereType,
-  LintFixInfo.preferNullAwareOperators,
-  LintFixInfo.preferRelativeImports,
-  LintFixInfo.preferSingleQuotes,
-  LintFixInfo.preferSpreadCollections,
-  LintFixInfo.slashForDocComments,
-  LintFixInfo.sortChildPropertiesLast,
-//  LintFixInfo.typeAnnotatePublicApis,
-  LintFixInfo.typeInitFormals,
-  LintFixInfo.unawaitedFutures,
-  LintFixInfo.unnecessaryBraceInStringInterps,
-  LintFixInfo.unnecessaryConst,
-  LintFixInfo.unnecessaryLambdas,
-  LintFixInfo.unnecessaryNew,
-  LintFixInfo.unnecessaryOverrides,
-  LintFixInfo.unnecessaryThis,
-  LintFixInfo.useFunctionTypeSyntaxForParameters,
-  LintFixInfo.useRethrowWhenPossible,
-];
-
-/// [DartFixInfo] represents a fix that can be applied by [EditDartFix].
-class DartFixInfo {
-  /// The key provided on the command line via the `--fix` option to refer to
-  /// this fix.
-  final String key;
-
-  /// A description of the fix, printed by the `--help` option.
-  final String description;
-
-  /// A flag indicating whether this fix is related to the lints in the pedantic
-  /// lint set.
-  final bool isPedantic;
-
-  final void Function(DartFixRegistrar registrar, DartFixListener listener,
-      EditDartfixParams params) _setup;
-
-  const DartFixInfo(
-    this.key,
-    this.description,
-    this._setup, {
-    this.isPedantic = false,
-  });
-
-  /// Return a newly created fix generated from this fix info.
-  DartFix asDartFix() => DartFix(key, description: description);
-
-  /// Register this fix with the [registrar] and report progress to the
-  /// [listener].
-  void setup(DartFixRegistrar registrar, DartFixListener listener,
-      EditDartfixParams params) {
-    _setup(registrar, listener, params);
-  }
-}
-
-/// Information about a fix that applies to a lint.
-class LintFixInfo extends DartFixInfo {
-  // TODO(brianwilkerson) Add fixes in FixProcessor for the following pedantic
-  //  lints:
-  // avoid_null_checks_in_equality_operators
-  // avoid_shadowing_type_parameters
-  // avoid_types_as_parameter_names
-  // camel_case_extensions
-  // library_names
-  // prefer_contains
-  // recursive_getters
-  // unrelated_type_equality_checks
-  // valid_regexps
-
-  static final alwaysDeclareReturnTypes = LintFixInfo(
-    'always_declare_return_types',
-    DartFixKind.ADD_RETURN_TYPE,
-    'Add a return type where possible.',
-    isPedantic: true,
-  );
-
-  static final alwaysRequireNonNullNamedParameters = LintFixInfo(
-    'always_require_non_null_named_parameters',
-    DartFixKind.ADD_REQUIRED,
-    'Add an @required annotation.',
-    isPedantic: true,
-  );
-
-  static final alwaysSpecifyTypes = LintFixInfo(
-    'always_specify_types',
-    DartFixKind.ADD_TYPE_ANNOTATION,
-    'Add a type annotation.',
-  );
-
-  static final annotateOverrides = LintFixInfo(
-    'annotate_overrides',
-    DartFixKind.ADD_OVERRIDE,
-    'Add an @override annotation.',
-    isPedantic: true,
-  );
-
-  static final avoidAnnotatingWithDynamic = LintFixInfo(
-    'avoid_annotating_with_dynamic',
-    DartFixKind.REMOVE_TYPE_ANNOTATION,
-    'Remove the type annotation.',
-  );
-
-  static final avoidEmptyElse = LintFixInfo(
-    'avoid_empty_else',
-    DartFixKind.REMOVE_EMPTY_ELSE,
-    'Remove the empty else.',
-    isPedantic: true,
-  );
-
-  static final avoidInitToNull = LintFixInfo(
-    'avoid_init_to_null',
-    DartFixKind.REMOVE_INITIALIZER,
-    'Remove the initializer.',
-    isPedantic: true,
-  );
-
-  static final avoidRedundantArgumentValues = LintFixInfo(
-    'avoid_redundant_argument_values',
-    DartFixKind.REMOVE_ARGUMENT,
-    'Remove the redundant argument.',
-  );
-
-  static final avoidRelativeLibImports = LintFixInfo(
-    'avoid_relative_lib_imports',
-    DartFixKind.CONVERT_TO_PACKAGE_IMPORT,
-    'Convert the import to a package: import.',
-    isPedantic: true,
-  );
-
-  static final avoidReturnTypesOnSetters = LintFixInfo(
-    'avoid_return_types_on_setters',
-    DartFixKind.REMOVE_TYPE_ANNOTATION,
-    'Remove the return type.',
-    isPedantic: true,
-  );
-
-  static final avoidTypesOnClosureParameters = LintFixInfo(
-    'avoid_types_on_closure_parameters',
-    // Also sometimes fixed by DartFixKind.REPLACE_WITH_IDENTIFIER
-    DartFixKind.REMOVE_TYPE_ANNOTATION,
-    'Remove the type annotation.',
-  );
-
-  static final awaitOnlyFutures = LintFixInfo(
-    'await_only_futures',
-    DartFixKind.REMOVE_AWAIT,
-    "Remove the 'await'.",
-  );
-
-  static final curlyBracesInFlowControlStructures = LintFixInfo(
-    'curly_braces_in_flow_control_structures',
-    DartFixKind.ADD_CURLY_BRACES,
-    'Add curly braces.',
-    isPedantic: true,
-  );
-
-  static final diagnosticDescribeAllProperties = LintFixInfo(
-    'diagnostic_describe_all_properties',
-    DartFixKind.ADD_DIAGNOSTIC_PROPERTY_REFERENCE,
-    'Add a debug reference to this property.',
-  );
-
-  static final emptyCatches = LintFixInfo(
-    'empty_catches',
-    DartFixKind.REMOVE_EMPTY_CATCH,
-    'Remove the empty catch clause.',
-    isPedantic: true,
-  );
-
-  static final emptyConstructorBodies = LintFixInfo(
-    'empty_constructor_bodies',
-    DartFixKind.REMOVE_EMPTY_CONSTRUCTOR_BODY,
-    'Remove the empoty catch clause.',
-    isPedantic: true,
-  );
-
-  static final emptyStatements = LintFixInfo(
-    'empty_statements',
-    // Also sometimes fixed by DartFixKind.REPLACE_WITH_BRACKETS
-    DartFixKind.REMOVE_EMPTY_STATEMENT,
-    'Remove the empty statement.',
-  );
-
-  static final hashAndEquals = LintFixInfo(
-    'hash_and_equals',
-    DartFixKind.CREATE_METHOD,
-    'Create the missing method.',
-  );
-
-  static final noDuplicateCaseValues = LintFixInfo(
-    'no_duplicate_case_values',
-    DartFixKind.REMOVE_DUPLICATE_CASE,
-    'Remove the duplicate case clause.',
-    isPedantic: true,
-  );
-
-  static final nonConstantIdentifierNames = LintFixInfo(
-    'non_constant_identifier_names',
-    DartFixKind.RENAME_TO_CAMEL_CASE,
-    'Change the name to be camelCase.',
-  );
-
-  static final nullClosures = LintFixInfo(
-    'null_closures',
-    DartFixKind.REPLACE_NULL_WITH_CLOSURE,
-    'Convert nulls to closures that return null where expected.',
-    isPedantic: true,
-  );
-
-  static final omitLocalVariableTypes = LintFixInfo(
-    'omit_local_variable_types',
-    DartFixKind.REPLACE_WITH_VAR,
-    "Replace the type annotation with 'var'",
-    isPedantic: true,
-  );
-
-  static final preferAdjacentStringConcatenation = LintFixInfo(
-    'prefer_adjacent_string_concatenation',
-    DartFixKind.REMOVE_OPERATOR,
-    "Remove the '+' operator.",
-    isPedantic: true,
-  );
-
-  static final preferCollectionLiterals = LintFixInfo(
-    'prefer_collection_literals',
-    DartFixKind.CONVERT_TO_LIST_LITERAL,
-    'Replace with a collection literal.',
-    isPedantic: true,
-  );
-
-  static final preferConditionalAssignment = LintFixInfo(
-    'prefer_conditional_assignment',
-    DartFixKind.REPLACE_WITH_CONDITIONAL_ASSIGNMENT,
-    'Replace with a conditional assignment.',
-    isPedantic: true,
-  );
-
-  static final preferConstConstructors = LintFixInfo(
-    'prefer_const_constructors',
-    DartFixKind.ADD_CONST,
-    'Make the instantiation const.',
-  );
-
-  static final preferConstConstructorsInImmutables = LintFixInfo(
-    'prefer_const_constructors_in_immutables',
-    DartFixKind.ADD_CONST,
-    'Make the constructor const.',
-  );
-
-  static final preferConstDeclarations = LintFixInfo(
-    'prefer_const_declarations',
-    DartFixKind.REPLACE_FINAL_WITH_CONST,
-    'Make the declaration const.',
-  );
-
-  static final preferContains = LintFixInfo(
-    'prefer_contains',
-    DartFixKind.CONVERT_TO_CONTAINS,
-    "Convert to using 'contains'.",
-    isPedantic: true,
-  );
-
-  static final preferEqualForDefaultValues = LintFixInfo(
-    'prefer_equal_for_default_values',
-    DartFixKind.REPLACE_COLON_WITH_EQUALS,
-    'Convert declarations to use = to separate a named parameter from its default value.',
-    isPedantic: true,
-  );
-
-  static final preferFinalFields = LintFixInfo(
-    'prefer_final_fields',
-    DartFixKind.MAKE_FINAL,
-    'Make the field final.',
-    isPedantic: true,
-  );
-
-  static final preferFinalLocals = LintFixInfo(
-    'prefer_final_locals',
-    DartFixKind.MAKE_FINAL,
-    "Make the variable 'final'.",
-  );
-
-  static final preferForElementsToMapFromIterable = LintFixInfo(
-    'prefer_for_elements_to_map_fromIterable',
-    DartFixKind.CONVERT_TO_FOR_ELEMENT,
-    'Convert to a for element.',
-    isPedantic: true,
-  );
-
-  static final preferGenericFunctionTypeAliases = LintFixInfo(
-    'prefer_generic_function_type_aliases',
-    DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX,
-    "Convert into 'Function' syntax",
-    isPedantic: true,
-  );
-
-  static final preferIfElementsToConditionalExpressions = LintFixInfo(
-      'prefer_if_elements_to_conditional_expressions',
-      DartFixKind.CONVERT_TO_IF_ELEMENT,
-      "Convert to an 'if' element.");
-
-  static final preferIfNullOperators = LintFixInfo(
-    'prefer_if_null_operators',
-    DartFixKind.CONVERT_TO_IF_NULL,
-    "Convert to use '??'.",
-    isPedantic: true,
-  );
-
-  static final preferInlinedAdds = LintFixInfo(
-    'prefer_inlined_adds',
-    DartFixKind.INLINE_INVOCATION,
-    'Inline the invocation.',
-  );
-
-  static final preferIntLiterals = LintFixInfo(
-    'prefer_int_literals',
-    DartFixKind.CONVERT_TO_INT_LITERAL,
-    'Convert to an int literal',
-  );
-
-  static final preferIsEmpty = LintFixInfo(
-    'prefer_is_empty',
-    DartFixKind.REPLACE_WITH_IS_EMPTY,
-    "Convert to using 'isEmpty' when checking if a collection or iterable is empty.",
-    isPedantic: true,
-  );
-
-  static final preferIsNotEmpty = LintFixInfo(
-    'prefer_is_not_empty',
-    DartFixKind.REPLACE_WITH_IS_NOT_EMPTY,
-    "Convert to using 'isNotEmpty' when checking if a collection or iterable is not empty.",
-    isPedantic: true,
-  );
-
-  static final preferIterableWhereType = LintFixInfo(
-    'prefer_iterable_whereType',
-    DartFixKind.CONVERT_TO_WHERE_TYPE,
-    'Add a return type where possible.',
-    isPedantic: true,
-  );
-
-  static final preferNullAwareOperators = LintFixInfo(
-    'prefer_null_aware_operators',
-    DartFixKind.CONVERT_TO_NULL_AWARE,
-    "Convert to use '?.'.",
-  );
-
-  static final preferRelativeImports = LintFixInfo(
-    'prefer_relative_imports',
-    DartFixKind.CONVERT_TO_RELATIVE_IMPORT,
-    'Convert to a relative import.',
-  );
-
-  static final preferSingleQuotes = LintFixInfo(
-    'prefer_single_quotes',
-    DartFixKind.CONVERT_TO_SINGLE_QUOTED_STRING,
-    'Convert strings using a double quote to use a single quote.',
-    isPedantic: true,
-  );
-
-  static final preferSpreadCollections = LintFixInfo(
-    'prefer_spread_collections',
-    // TODO(brianwilkerson) There are two possible fixes here, but not under
-    //  user control.
-    DartFixKind.CONVERT_TO_SPREAD,
-    'Convert to a spread operator.',
-
-    isPedantic: true,
-  );
-
-  static final slashForDocComments = LintFixInfo(
-    'slash_for_doc_comments',
-    DartFixKind.CONVERT_TO_LINE_COMMENT,
-    'Convert to a line comment.',
-    isPedantic: true,
-  );
-
-  static final sortChildPropertiesLast = LintFixInfo(
-    'sort_child_properties_last',
-    DartFixKind.SORT_CHILD_PROPERTY_LAST,
-    "Move the 'child' argument to the end of the argument list.",
-  );
-
-  static final typeAnnotatePublicApis = LintFixInfo(
-    'type_annotate_public_apis',
-    DartFixKind.ADD_TYPE_ANNOTATION,
-    'Add a type annotation.',
-  );
-
-  static final typeInitFormals = LintFixInfo(
-    'type_init_formals',
-    DartFixKind.REMOVE_TYPE_ANNOTATION,
-    'Remove the type annotation.',
-    isPedantic: true,
-  );
-
-  static final unawaitedFutures = LintFixInfo(
-    'unawaited_futures',
-    DartFixKind.ADD_AWAIT,
-    'Add await.',
-    isPedantic: true,
-  );
-
-  static final unnecessaryBraceInStringInterps = LintFixInfo(
-    'unnecessary_brace_in_string_interps',
-    DartFixKind.REMOVE_INTERPOLATION_BRACES,
-    'Remove the unnecessary interpolation braces.',
-  );
-
-  static final unnecessaryConst = LintFixInfo(
-    'unnecessary_const',
-    DartFixKind.REMOVE_UNNECESSARY_CONST,
-    "Remove unnecessary 'const'' keywords.",
-    isPedantic: true,
-  );
-
-  static final unnecessaryLambdas = LintFixInfo(
-    'unnecessary_lambdas',
-    DartFixKind.REPLACE_WITH_TEAR_OFF,
-    'Replace the function literal with a tear-off.',
-  );
-
-  static final unnecessaryNew = LintFixInfo(
-    'unnecessary_new',
-    DartFixKind.REMOVE_UNNECESSARY_NEW,
-    "Remove unnecessary 'new' keywords.",
-    isPedantic: true,
-  );
-
-  static final unnecessaryNullInIfNullOperators = LintFixInfo(
-    'unnecessary_null_in_if_null_operators',
-    DartFixKind.REMOVE_IF_NULL_OPERATOR,
-    "Remove the '??' operator.",
-    isPedantic: true,
-  );
-
-  static final unnecessaryOverrides = LintFixInfo(
-    'unnecessary_overrides',
-    DartFixKind.REMOVE_METHOD_DECLARATION,
-    'Remove the unnecessary override.',
-  );
-
-  static final unnecessaryThis = LintFixInfo(
-    'unnecessary_this',
-    DartFixKind.REMOVE_THIS_EXPRESSION,
-    'Remove this.',
-    isPedantic: true,
-  );
-
-  static final useFunctionTypeSyntaxForParameters = LintFixInfo(
-    'use_function_type_syntax_for_parameters',
-    DartFixKind.CONVERT_TO_GENERIC_FUNCTION_SYNTAX,
-    "Convert into 'Function' syntax",
-    isPedantic: true,
-  );
-
-  static final useRethrowWhenPossible = LintFixInfo(
-    'use_rethrow_when_possible',
-    DartFixKind.USE_RETHROW,
-    'Replace with rethrow.',
-    isPedantic: true,
-  );
-
-  /// The name of the lint to be fixed.
-  final String lintName;
-
-  /// The kind of fix to be applied.
-  final FixKind fixKind;
-
-  /// Initialize a newly created set of fix information.
-  LintFixInfo(
-    this.lintName,
-    this.fixKind,
-    String description, {
-    bool isPedantic = false,
-  }) : super(lintName, description, (_, __, ___) {}, isPedantic: isPedantic);
-
-  @override
-  void setup(DartFixRegistrar registrar, DartFixListener listener,
-      EditDartfixParams params) {
-    registrar.registerLintTask(
-        Registry.ruleRegistry[lintName]!, FixLintTask(listener));
-  }
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart b/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart
deleted file mode 100644
index 42868cd..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/dartfix_listener.dart
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer_plugin/protocol/protocol_common.dart'
-    show Location, SourceChange, SourceEdit, SourceFileEdit;
-
-/// Tasks use this API to report results.
-class DartFixListener {
-  final AnalysisServer server;
-
-  final List<DartFixSuggestion> suggestions = <DartFixSuggestion>[];
-  final List<DartFixSuggestion> otherSuggestions = <DartFixSuggestion>[];
-
-  final SourceChange sourceChange = SourceChange('dartfix');
-
-  /// The details to be returned to the client.
-  List<String> details = [];
-
-  DartFixListener(this.server);
-
-  ResourceProvider get resourceProvider => server.resourceProvider;
-
-  /// Record an edit to be sent to the client.
-  ///
-  /// The associated suggestion should be separately added by calling
-  /// [addSuggestion].
-  void addEditWithoutSuggestion(Source source, SourceEdit edit) {
-    sourceChange.addEdit(source.fullName, -1, edit);
-  }
-
-  /// Record a recommendation to be sent to the client.
-  void addRecommendation(String description, [Location? location]) {
-    otherSuggestions.add(DartFixSuggestion(description, location: location));
-  }
-
-  /// Record a source change to be sent to the client.
-  void addSourceChange(
-      String description, Location location, SourceChange change) {
-    suggestions.add(DartFixSuggestion(description, location: location));
-    for (var fileEdit in change.edits) {
-      for (var sourceEdit in fileEdit.edits) {
-        sourceChange.addEdit(fileEdit.file, fileEdit.fileStamp, sourceEdit);
-      }
-    }
-  }
-
-  /// Record edits for a single source to be sent to the client.
-  void addSourceEdits(String description, Location location, Source source,
-      Iterable<SourceEdit> edits) {
-    suggestions.add(DartFixSuggestion(description, location: location));
-    for (var edit in edits) {
-      sourceChange.addEdit(source.fullName, -1, edit);
-    }
-  }
-
-  /// Record a source change to be sent to the client.
-  void addSourceFileEdit(
-      String description, Location location, SourceFileEdit fileEdit) {
-    suggestions.add(DartFixSuggestion(description, location: location));
-    for (var sourceEdit in fileEdit.edits) {
-      sourceChange.addEdit(fileEdit.file, fileEdit.fileStamp, sourceEdit);
-    }
-  }
-
-  /// Record a suggestion to be sent to the client.
-  ///
-  /// The associated edits should be separately added by calling
-  /// [addEditWithoutRecommendation].
-  void addSuggestion(String description, Location location) {
-    suggestions.add(DartFixSuggestion(description, location: location));
-  }
-
-  /// Return the [Location] representing the specified offset and length
-  /// in the given compilation unit.
-  Location locationFor(ResolvedUnitResult result, int offset, int length) {
-    var lineInfo = result.unit!.lineInfo!;
-    var startLocation = lineInfo.getLocation(offset);
-    var endLocation = lineInfo.getLocation(offset + length);
-    return Location(
-        result.path!,
-        offset,
-        length,
-        startLocation.lineNumber,
-        startLocation.columnNumber,
-        endLocation.lineNumber,
-        endLocation.columnNumber);
-  }
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/dartfix_registrar.dart b/pkg/analysis_server/lib/src/edit/fix/dartfix_registrar.dart
deleted file mode 100644
index 07652c0..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/dartfix_registrar.dart
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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 'package:analysis_server/src/edit/fix/dartfix_info.dart';
-import 'package:analysis_server/src/edit/fix/fix_code_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_error_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_lint_task.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/src/lint/linter.dart';
-
-/// Fixes use this API to register tasks. See [DartFixInfo.setup].
-abstract class DartFixRegistrar {
-  /// Register the specified task to analyze and fix problems.
-  void registerCodeTask(FixCodeTask task);
-
-  /// Register the specified task to fix the given error condition.
-  void registerErrorTask(ErrorCode errorCode, FixErrorTask task);
-
-  /// Register the specified task to fix the given lint.
-  void registerLintTask(LintRule ruleRegistry, FixLintTask task);
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/fix_code_task.dart b/pkg/analysis_server/lib/src/edit/fix/fix_code_task.dart
deleted file mode 100644
index a4243a9..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/fix_code_task.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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:math' show max;
-
-import 'package:analysis_server/src/edit/edit_dartfix.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/file_system/file_system.dart';
-
-/// A processor used by [EditDartFix] to manage [FixCodeTask]s.
-mixin FixCodeProcessor {
-  final _codeTasks = <FixCodeTask>[];
-
-  int _numPhases = 0;
-
-  int get numPhases => _numPhases;
-
-  Future<void> finishCodeTasks() async {
-    for (var task in _codeTasks) {
-      await task.finish();
-    }
-  }
-
-  Future<void> processCodeTasks(int phase, ResolvedUnitResult result) async {
-    for (var task in _codeTasks) {
-      await task.processUnit(phase, result);
-    }
-  }
-
-  Future<void> processPackage(Folder pkgFolder) async {
-    for (var task in _codeTasks) {
-      await task.processPackage(pkgFolder);
-    }
-  }
-
-  void registerCodeTask(FixCodeTask task) {
-    _codeTasks.add(task);
-    _numPhases = max(_numPhases, task.numPhases);
-  }
-}
-
-/// A general task for performing a fix.
-abstract class FixCodeTask {
-  /// Number of times [processUnit] should be called for each compilation unit.
-  int get numPhases;
-
-  /// [finish] is called after [processUnit] has been called for each
-  /// phase and compilation unit.
-  Future<void> finish();
-
-  /// [processPackage] is called once for each package
-  /// before [processUnit] is called for any compilation unit in any package.
-  Future<void> processPackage(Folder pkgFolder);
-
-  /// [processUnit] is called for each phase and compilation unit.
-  ///
-  /// First [processUnit] will be called once for each compilation unit with
-  /// [phase] set to 0; then it will be called for each compilation unit with
-  /// [phase] set to 1; and so on through `numPhases-1`.
-  Future<void> processUnit(int phase, ResolvedUnitResult result);
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart b/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart
deleted file mode 100644
index 2896407..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/fix_error_task.dart
+++ /dev/null
@@ -1,73 +0,0 @@
-// 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 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/edit/edit_dartfix.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_registrar.dart';
-import 'package:analysis_server/src/services/correction/change_workspace.dart';
-import 'package:analysis_server/src/services/correction/fix.dart';
-import 'package:analysis_server/src/services/correction/fix_internal.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/instrumentation/service.dart';
-import 'package:analyzer/src/error/codes.dart';
-
-/// A processor used by [EditDartFix] to manage [FixErrorTask]s.
-mixin FixErrorProcessor {
-  /// A mapping from [ErrorCode] to the fix that should be applied.
-  final errorTaskMap = <ErrorCode, FixErrorTask>{};
-
-  Future<bool> processErrors(ResolvedUnitResult result) async {
-    var foundError = false;
-    for (var error in result.errors) {
-      final task = errorTaskMap[error.errorCode];
-      if (task != null) {
-        await task.fixError(result, error);
-      } else if (error.errorCode.type == ErrorType.SYNTACTIC_ERROR) {
-        foundError = true;
-      }
-    }
-    return foundError;
-  }
-
-  void registerErrorTask(ErrorCode errorCode, FixErrorTask task) {
-    errorTaskMap[errorCode] = task;
-  }
-}
-
-/// A task for fixing a particular error
-class FixErrorTask {
-  final DartFixListener listener;
-
-  FixErrorTask(this.listener);
-
-  Future<void> fixError(ResolvedUnitResult result, AnalysisError error) async {
-    final workspace = DartChangeWorkspace(listener.server.currentSessions);
-    final dartContext = DartFixContextImpl(
-      InstrumentationService.NULL_SERVICE,
-      workspace,
-      result,
-      error,
-      (name) => [],
-    );
-    final processor = FixProcessor(dartContext);
-    var fix = await processor.computeFix();
-    final location = listener.locationFor(result, error.offset, error.length);
-    if (fix != null) {
-      listener.addSourceChange(fix.change.message, location, fix.change);
-    } else {
-      // TODO(danrubel): Determine why the fix could not be applied
-      // and report that in the description.
-      listener.addRecommendation("Couldn't fix \"${error.message}\"", location);
-    }
-  }
-
-  static void fixNamedConstructorTypeArgs(DartFixRegistrar registrar,
-      DartFixListener listener, EditDartfixParams params) {
-    registrar.registerErrorTask(
-        CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
-        FixErrorTask(listener));
-  }
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/fix_lint_task.dart b/pkg/analysis_server/lib/src/edit/fix/fix_lint_task.dart
deleted file mode 100644
index 2aac75e..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/fix_lint_task.dart
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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 'package:analysis_server/src/edit/edit_dartfix.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
-import 'package:analysis_server/src/edit/fix/fix_error_task.dart';
-import 'package:analyzer/src/lint/linter.dart';
-import 'package:analyzer/src/services/lint.dart';
-
-/// A processor used by [EditDartFix] to manage [FixLintTask]s.
-mixin FixLintProcessor implements FixErrorProcessor {
-  final linters = <Linter>[];
-  final lintTasks = <FixLintTask>[];
-
-  void registerLintTask(LintRule lint, FixLintTask task) {
-    linters.add(lint);
-    lintTasks.add(task);
-    errorTaskMap[lint.lintCode] = task;
-  }
-}
-
-/// A task for fixing a particular lint.
-class FixLintTask extends FixErrorTask {
-  FixLintTask(DartFixListener listener) : super(listener);
-}
diff --git a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart b/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
deleted file mode 100644
index 10c0214..0000000
--- a/pkg/analysis_server/lib/src/edit/fix/prefer_mixin_fix.dart
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (c) 2018, 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 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
-import 'package:analysis_server/src/edit/fix/dartfix_registrar.dart';
-import 'package:analysis_server/src/edit/fix/fix_code_task.dart';
-import 'package:analysis_server/src/edit/fix/fix_lint_task.dart';
-import 'package:analysis_server/src/services/correction/assist.dart';
-import 'package:analysis_server/src/services/correction/assist_internal.dart';
-import 'package:analysis_server/src/services/correction/change_workspace.dart';
-import 'package:analyzer/dart/analysis/results.dart';
-import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/error/error.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/instrumentation/service.dart';
-import 'package:analyzer/src/dart/ast/utilities.dart';
-import 'package:analyzer/src/lint/registry.dart';
-
-class PreferMixinFix extends FixLintTask implements FixCodeTask {
-  final classesToConvert = <Element>{};
-
-  PreferMixinFix(DartFixListener listener) : super(listener);
-
-  @override
-  int get numPhases => 0;
-
-  Future<void> convertClassToMixin(Element elem) async {
-    var result = await listener.server.getResolvedUnit(elem.source!.fullName);
-    if (result == null) {
-      return;
-    }
-
-    for (var declaration in result.unit!.declarations) {
-      if (declaration is ClassOrMixinDeclaration &&
-          declaration.name.name == elem.name) {
-        var processor = AssistProcessor(
-          DartAssistContextImpl(
-              InstrumentationService.NULL_SERVICE,
-              DartChangeWorkspace(listener.server.currentSessions),
-              result,
-              declaration.name.offset,
-              0),
-        );
-        var assists = await processor
-            .computeAssist(DartAssistKind.CONVERT_CLASS_TO_MIXIN);
-        final location =
-            listener.locationFor(result, elem.nameOffset, elem.nameLength);
-        if (assists.isNotEmpty) {
-          for (var assist in assists) {
-            listener.addSourceChange('Convert ${elem.displayName} to a mixin',
-                location, assist.change);
-          }
-        } else {
-          // TODO(danrubel): If assists is empty, then determine why
-          // assist could not be performed and report that in the description.
-          listener.addRecommendation(
-              "Couldn't convert ${elem.displayName} to a mixin"
-              ' because the class contains a constructor',
-              location);
-        }
-      }
-    }
-  }
-
-  @override
-  Future<void> finish() async {
-    for (var elem in classesToConvert) {
-      await convertClassToMixin(elem);
-    }
-  }
-
-  @override
-  Future<void> fixError(ResolvedUnitResult result, AnalysisError error) async {
-    var node = NodeLocator(error.offset).searchWithin(result.unit);
-    if (node == null) {
-      return;
-    }
-    var type = node.thisOrAncestorOfType<TypeName>();
-    if (type != null) {
-      var element = type.name.staticElement;
-      if (element != null && element.source?.fullName != null) {
-        classesToConvert.add(element);
-      }
-    } else {
-      // TODO(danrubel): Report if lint does not point to a type name
-      final location = listener.locationFor(result, node.offset, node.length);
-      listener.addRecommendation(
-          'Cannot not convert $node to a mixin', location);
-    }
-  }
-
-  @override
-  Future<void> processPackage(Folder pkgFolder) async {}
-
-  @override
-  Future<void> processUnit(int phase, ResolvedUnitResult result) async {}
-
-  static void task(DartFixRegistrar registrar, DartFixListener listener,
-      EditDartfixParams params) {
-    var task = PreferMixinFix(listener);
-    registrar.registerLintTask(Registry.ruleRegistry['prefer_mixin']!, task);
-    registrar.registerCodeTask(task);
-  }
-}
diff --git a/pkg/analysis_server/test/domain_edit_dartfix_test.dart b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
deleted file mode 100644
index 5f889d9..0000000
--- a/pkg/analysis_server/test/domain_edit_dartfix_test.dart
+++ /dev/null
@@ -1,340 +0,0 @@
-// Copyright (c) 2018, 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 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/edit/edit_dartfix.dart';
-import 'package:analyzer_plugin/protocol/protocol_common.dart';
-import 'package:linter/src/rules.dart';
-import 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import 'analysis_abstract.dart';
-
-void main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(EditDartfixDomainHandlerTest);
-  });
-}
-
-@reflectiveTest
-class EditDartfixDomainHandlerTest extends AbstractAnalysisTest {
-  int requestId = 30;
-
-  String get nextRequestId => (++requestId).toString();
-
-  void expectEdits(List<SourceFileEdit> fileEdits, String expectedSource) {
-    expect(fileEdits, hasLength(1));
-    expect(fileEdits[0].file, testFile);
-    expectFileEdits(testCode, fileEdits[0], expectedSource);
-  }
-
-  void expectFileEdits(
-      String originalSource, SourceFileEdit fileEdit, String expectedSource) {
-    var source = SourceEdit.applySequence(originalSource, fileEdit.edits);
-    expect(source, expectedSource);
-  }
-
-  void expectSuggestion(DartFixSuggestion suggestion, String partialText,
-      [int? offset, int? length]) {
-    expect(suggestion.description, contains(partialText));
-    if (offset == null) {
-      expect(suggestion.location, isNull);
-    } else {
-      var location = suggestion.location!;
-      expect(location.offset, offset);
-      expect(location.length, length);
-    }
-  }
-
-  Future<EditDartfixResult> performFix(
-      {List<String>? includedFixes, bool? pedantic}) async {
-    var response =
-        await performFixRaw(includedFixes: includedFixes, pedantic: pedantic);
-    expect(response.error, isNull);
-    return EditDartfixResult.fromResponse(response);
-  }
-
-  Future<Response> performFixRaw(
-      {List<String>? includedFixes,
-      List<String>? excludedFixes,
-      bool? pedantic}) async {
-    final id = nextRequestId;
-    final params = EditDartfixParams([projectPath]);
-    params.includedFixes = includedFixes;
-    params.excludedFixes = excludedFixes;
-    params.includePedanticFixes = pedantic;
-    final request = Request(id, 'edit.dartfix', params.toJson());
-
-    var fix = EditDartFix(server, request);
-    final response = await fix.compute();
-    expect(response.id, id);
-    return response;
-  }
-
-  @override
-  void setUp() {
-    super.setUp();
-    registerLintRules();
-    testFile = resourceProvider.convertPath('/project/lib/fileToBeFixed.dart');
-  }
-
-  Future<void> test_collection_if_elements() async {
-    addTestFile('''
-f(bool b) {
-  return ['a', b ? 'c' : 'd', 'e'];
-}
-''');
-    createProject();
-    var result = await performFix(
-        includedFixes: ['prefer_if_elements_to_conditional_expressions']);
-    expect(result.suggestions.length, greaterThanOrEqualTo(1));
-    expect(result.hasErrors, isFalse);
-    expectEdits(result.edits, '''
-f(bool b) {
-  return ['a', if (b) 'c' else 'd', 'e'];
-}
-''');
-  }
-
-  Future<void> test_excludedFix_invalid() async {
-    addTestFile('''
-const double myDouble = 42.0;
-    ''');
-    createProject();
-
-    final result = await performFixRaw(excludedFixes: ['not_a_fix']);
-    expect(result.error, isNotNull);
-  }
-
-  Future<void> test_excludedSource() async {
-    // Add analysis options to exclude the lib directory then reanalyze
-    newAnalysisOptionsYamlFile('/project', content: '''
-analyzer:
-  exclude:
-    - lib/**
-''');
-
-    addTestFile('''
-const double myDouble = 42.0;
-    ''');
-    createProject();
-
-    // Assert no suggestions now that source has been excluded
-    final result = await performFix(includedFixes: ['prefer_int_literals']);
-    expect(result.suggestions, hasLength(0));
-    expect(result.edits, hasLength(0));
-  }
-
-  Future<void> test_fixNamedConstructorTypeArgs() async {
-    addTestFile('''
-class A<T> {
-  A.from(Object obj);
-}
-void f() {
-  print(A.from<String>([]));
-}
-    ''');
-    createProject();
-    var result = await performFix(
-        includedFixes: ['wrong_number_of_type_arguments_constructor']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], 'type arguments', 62, 8);
-    expectEdits(result.edits, '''
-class A<T> {
-  A.from(Object obj);
-}
-void f() {
-  print(A<String>.from([]));
-}
-    ''');
-  }
-
-  Future<void> test_includedFix_invalid() async {
-    addTestFile('''
-const double myDouble = 42.0;
-    ''');
-    createProject();
-
-    final result = await performFixRaw(includedFixes: ['not_a_fix']);
-    expect(result.error, isNotNull);
-  }
-
-  Future<void> test_partFile() async {
-    newFile('/project/lib/lib.dart', content: '''
-library lib2;
-part 'fileToBeFixed.dart';
-    ''');
-    addTestFile('''
-part of lib2;
-const double myDouble = 42.0;
-    ''');
-    createProject();
-
-    // Assert dartfix suggestions
-    var result = await performFix(includedFixes: ['prefer_int_literals']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], 'int literal', 38, 4);
-    expectEdits(result.edits, '''
-part of lib2;
-const double myDouble = 42;
-    ''');
-  }
-
-  Future<void> test_partFile_loose() async {
-    addTestFile('''
-part of lib2;
-const double myDouble = 42.0;
-    ''');
-    createProject();
-
-    // Assert dartfix suggestions
-    var result = await performFix(includedFixes: ['prefer_int_literals']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], 'int literal', 38, 4);
-    expectEdits(result.edits, '''
-part of lib2;
-const double myDouble = 42;
-    ''');
-  }
-
-  Future<void> test_pedantic() async {
-    addTestFile('void f(List args) { if (args.length == 0) { } }');
-    createProject();
-    var result = await performFix(pedantic: true);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], "Replace with 'isEmpty'", 24, 16);
-    expect(result.hasErrors, isFalse);
-    expectEdits(result.edits, 'void f(List args) { if (args.isEmpty) { } }');
-  }
-
-  Future<void> test_preferEqualForDefaultValues() async {
-    // Add analysis options to enable ui as code
-    addTestFile('f({a: 1}) { }');
-    createProject();
-    var result =
-        await performFix(includedFixes: ['prefer_equal_for_default_values']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], "Replace ':' with '='", 4, 1);
-    expect(result.hasErrors, isFalse);
-    expectEdits(result.edits, 'f({a = 1}) { }');
-  }
-
-  Future<void> test_preferForElementsToMapFromIterable() async {
-    addTestFile('''
-var m =
-  Map<int, int>.fromIterable([1, 2, 3], key: (i) => i, value: (i) => i * 2);
-    ''');
-    createProject();
-    var result = await performFix(
-        includedFixes: ['prefer_for_elements_to_map_fromIterable']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(
-        result.suggestions[0], "Convert to a 'for' element", 10, 73);
-    expectEdits(result.edits, '''
-var m =
-  { for (var i in [1, 2, 3]) i : i * 2 };
-    ''');
-  }
-
-  Future<void> test_preferIfElementsToConditionalExpressions() async {
-    addTestFile('''
-f(bool b) => ['a', b ? 'c' : 'd', 'e'];
-    ''');
-    createProject();
-    var result = await performFix(
-        includedFixes: ['prefer_if_elements_to_conditional_expressions']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(
-        result.suggestions[0], "Convert to an 'if' element", 19, 13);
-    expectEdits(result.edits, '''
-f(bool b) => ['a', if (b) 'c' else 'd', 'e'];
-    ''');
-  }
-
-  Future<void> test_preferIntLiterals() async {
-    addTestFile('''
-const double myDouble = 42.0;
-    ''');
-    createProject();
-    var result = await performFix(includedFixes: ['prefer_int_literals']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], 'int literal', 24, 4);
-    expectEdits(result.edits, '''
-const double myDouble = 42;
-    ''');
-  }
-
-  Future<void> test_preferIsEmpty() async {
-    addTestFile('void f(List<String> args) { if (args.length == 0) { } }');
-    createProject();
-    var result = await performFix(includedFixes: ['prefer_is_empty']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], "Replace with 'isEmpty'", 32, 16);
-    expect(result.hasErrors, isFalse);
-    expectEdits(
-        result.edits, 'void f(List<String> args) { if (args.isEmpty) { } }');
-  }
-
-  Future<void> test_preferMixin() async {
-    addTestFile('''
-class A {}
-class B extends A {}
-class C with B {}
-    ''');
-    createProject();
-    var result = await performFix(includedFixes: ['convert_class_to_mixin']);
-    expect(result.suggestions, hasLength(1));
-    expectSuggestion(result.suggestions[0], 'mixin', 17, 1);
-    expectEdits(result.edits, '''
-class A {}
-mixin B implements A {}
-class C with B {}
-    ''');
-  }
-
-  Future<void> test_preferSingleQuotes() async {
-    addTestFile('''
-var l = [
-  "abc",
-  'def',
-  "'g'",
-  """hij""",
-  \'''klm\''',
-];
-''');
-    createProject();
-    var result = await performFix(includedFixes: ['prefer_single_quotes']);
-    expect(result.suggestions, hasLength(2));
-    expectSuggestion(
-        result.suggestions[0], 'Convert to single quoted string', 12, 5);
-    expectSuggestion(
-        result.suggestions[1], 'Convert to single quoted string', 39, 9);
-    expect(result.hasErrors, isFalse);
-    expectEdits(result.edits, '''
-var l = [
-  'abc',
-  'def',
-  "'g'",
-  \'''hij\''',
-  \'''klm\''',
-];
-''');
-  }
-
-  Future<void> test_preferSpreadCollections() async {
-    addTestFile('''
-var l1 = ['b'];
-var l2 = ['a']..addAll(l1);
-''');
-    createProject();
-    var result = await performFix(includedFixes: ['prefer_spread_collections']);
-    expect(result.suggestions.length, greaterThanOrEqualTo(1));
-    expect(result.hasErrors, isFalse);
-    expectEdits(result.edits, '''
-var l1 = ['b'];
-var l2 = ['a', ...l1];
-''');
-  }
-}
diff --git a/pkg/analysis_server/test/integration/coverage.md b/pkg/analysis_server/test/integration/coverage.md
index 38705c6..58d0edf 100644
--- a/pkg/analysis_server/test/integration/coverage.md
+++ b/pkg/analysis_server/test/integration/coverage.md
@@ -44,11 +44,9 @@
 
 ## edit domain
 - [x] edit.bulkFixes
-- [x] edit.dartfix
 - [x] edit.format
 - [x] edit.getAssists
 - [x] edit.getAvailableRefactorings
-- [x] edit.getDartfixInfo
 - [x] edit.getFixes
 - [x] edit.getPostfixCompletion
 - [x] edit.getRefactoring
diff --git a/pkg/analysis_server/test/integration/edit/dartfix_test.dart b/pkg/analysis_server/test/integration/edit/dartfix_test.dart
deleted file mode 100644
index 7029973..0000000
--- a/pkg/analysis_server/test/integration/edit/dartfix_test.dart
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../support/integration_tests.dart';
-
-void main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(DartfixTest);
-  });
-}
-
-@reflectiveTest
-class DartfixTest extends AbstractAnalysisServerIntegrationTest {
-  void setupTarget() {
-    writeFile(sourcePath('test.dart'), '''
-class A {}
-class B extends A {}
-class C with B {}
-    ''');
-    standardAnalysisSetup();
-  }
-
-  Future<void> test_dartfix_exclude() async {
-    setupTarget();
-    var result = await sendEditDartfix([(sourceDirectory.path)],
-        excludedFixes: ['convert_class_to_mixin']);
-    expect(result.hasErrors, isFalse);
-    expect(result.suggestions.length, 0);
-    expect(result.edits.length, 0);
-  }
-
-  Future<void> test_dartfix_include() async {
-    setupTarget();
-    var result = await sendEditDartfix([(sourceDirectory.path)],
-        includedFixes: ['convert_class_to_mixin']);
-    expect(result.hasErrors, isFalse);
-    expect(result.suggestions.length, greaterThanOrEqualTo(1));
-    expect(result.edits.length, greaterThanOrEqualTo(1));
-  }
-
-  Future<void> test_dartfix_include_other() async {
-    setupTarget();
-    var result = await sendEditDartfix([(sourceDirectory.path)],
-        includedFixes: ['prefer_int_literals']);
-    expect(result.hasErrors, isFalse);
-    expect(result.suggestions.length, 0);
-    expect(result.edits.length, 0);
-  }
-}
diff --git a/pkg/analysis_server/test/integration/edit/get_dartfix_info_test.dart b/pkg/analysis_server/test/integration/edit/get_dartfix_info_test.dart
deleted file mode 100644
index 3d3bf9f..0000000
--- a/pkg/analysis_server/test/integration/edit/get_dartfix_info_test.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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 'package:test/test.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../support/integration_tests.dart';
-
-void main() {
-  defineReflectiveSuite(() {
-    defineReflectiveTests(GetDartfixInfoTest);
-  });
-}
-
-@reflectiveTest
-class GetDartfixInfoTest extends AbstractAnalysisServerIntegrationTest {
-  Future<void> test_getDartfixInfo() async {
-    standardAnalysisSetup();
-    var info = await sendEditGetDartfixInfo();
-    expect(info.fixes.length, greaterThanOrEqualTo(3));
-  }
-}
diff --git a/pkg/analysis_server/test/integration/edit/test_all.dart b/pkg/analysis_server/test/integration/edit/test_all.dart
index 5c3a653..f0e98d7 100644
--- a/pkg/analysis_server/test/integration/edit/test_all.dart
+++ b/pkg/analysis_server/test/integration/edit/test_all.dart
@@ -5,12 +5,10 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'bulk_fixes_test.dart' as bulk_fixes_test;
-import 'dartfix_test.dart' as dartfix_test;
 import 'format_test.dart' as format_test;
 import 'get_assists_test.dart' as get_assists_test;
 import 'get_available_refactorings_test.dart'
     as get_available_refactorings_test;
-import 'get_dartfix_info_test.dart' as get_dartfix_info_test;
 import 'get_fixes_test.dart' as get_fixes_test;
 import 'get_postfix_completion_test.dart' as get_postfix_completion_test;
 import 'get_refactoring_test.dart' as get_refactoring_test;
@@ -26,11 +24,9 @@
 void main() {
   defineReflectiveSuite(() {
     bulk_fixes_test.main();
-    dartfix_test.main();
     format_test.main();
     get_assists_test.main();
     get_available_refactorings_test.main();
-    get_dartfix_info_test.main();
     get_fixes_test.main();
     get_refactoring_test.main();
     get_postfix_completion_test.main();
diff --git a/pkg/analysis_server/test/integration/support/integration_test_methods.dart b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
index c424f42..5fd4d70 100644
--- a/pkg/analysis_server/test/integration/support/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/support/integration_test_methods.dart
@@ -1522,23 +1522,6 @@
         decoder, 'result', result);
   }
 
-  /// Request information about edit.dartfix such as the list of known fixes
-  /// that can be specified in an edit.dartfix request.
-  ///
-  /// Parameters
-  ///
-  /// Returns
-  ///
-  /// fixes: List<DartFix>
-  ///
-  ///   A list of fixes that can be specified in an edit.dartfix request.
-  Future<EditGetDartfixInfoResult> sendEditGetDartfixInfo() async {
-    var params = EditGetDartfixInfoParams().toJson();
-    var result = await server.send('edit.getDartfixInfo', params);
-    var decoder = ResponseDecoder(null);
-    return EditGetDartfixInfoResult.fromJson(decoder, 'result', result);
-  }
-
   /// Analyze the specified sources for fixes that can be applied in bulk and
   /// return a set of suggested edits for those sources. These edits may
   /// include changes to sources outside the set of specified sources if a
@@ -1586,117 +1569,6 @@
     return EditBulkFixesResult.fromJson(decoder, 'result', result);
   }
 
-  /// Analyze the specified sources for recommended changes and return a set of
-  /// suggested edits for those sources. These edits may include changes to
-  /// sources outside the set of specified sources if a change in a specified
-  /// source requires it.
-  ///
-  /// If includedFixes is specified, then those fixes will be applied. If
-  /// includePedanticFixes is specified, then fixes associated with the
-  /// pedantic rule set will be applied in addition to whatever fixes are
-  /// specified in includedFixes if any. If neither includedFixes nor
-  /// includePedanticFixes is specified, then no fixes will be applied. If
-  /// excludedFixes is specified, then those fixes will not be applied
-  /// regardless of whether they are specified in includedFixes.
-  ///
-  /// Parameters
-  ///
-  /// included: List<FilePath>
-  ///
-  ///   A list of the files and directories for which edits should be
-  ///   suggested.
-  ///
-  ///   If a request is made with a path that is invalid, e.g. is not absolute
-  ///   and normalized, an error of type INVALID_FILE_PATH_FORMAT will be
-  ///   generated. If a request is made for a file which does not exist, or
-  ///   which is not currently subject to analysis (e.g. because it is not
-  ///   associated with any analysis root specified to
-  ///   analysis.setAnalysisRoots), an error of type FILE_NOT_ANALYZED will be
-  ///   generated.
-  ///
-  /// includedFixes: List<String> (optional)
-  ///
-  ///   A list of names indicating which fixes should be applied.
-  ///
-  ///   If a name is specified that does not match the name of a known fix, an
-  ///   error of type UNKNOWN_FIX will be generated.
-  ///
-  /// includePedanticFixes: bool (optional)
-  ///
-  ///   A flag indicating whether "pedantic" fixes should be applied.
-  ///
-  /// excludedFixes: List<String> (optional)
-  ///
-  ///   A list of names indicating which fixes should not be applied.
-  ///
-  ///   If a name is specified that does not match the name of a known fix, an
-  ///   error of type UNKNOWN_FIX will be generated.
-  ///
-  /// port: int (optional)
-  ///
-  ///   Deprecated: This field is now ignored by server.
-  ///
-  /// outputDir: FilePath (optional)
-  ///
-  ///   Deprecated: This field is now ignored by server.
-  ///
-  /// Returns
-  ///
-  /// suggestions: List<DartFixSuggestion>
-  ///
-  ///   A list of recommended changes that can be automatically made by
-  ///   applying the 'edits' included in this response.
-  ///
-  /// otherSuggestions: List<DartFixSuggestion>
-  ///
-  ///   A list of recommended changes that could not be automatically made.
-  ///
-  /// hasErrors: bool
-  ///
-  ///   True if the analyzed source contains errors that might impact the
-  ///   correctness of the recommended changes that can be automatically
-  ///   applied.
-  ///
-  /// edits: List<SourceFileEdit>
-  ///
-  ///   A list of source edits to apply the recommended changes.
-  ///
-  /// details: List<String> (optional)
-  ///
-  ///   Messages that should be displayed to the user that describe details of
-  ///   the fix generation. For example, the messages might (a) point out
-  ///   details that users might want to explore before committing the changes
-  ///   or (b) describe exceptions that were thrown but that did not stop the
-  ///   fixes from being produced. The list will be omitted if it is empty.
-  ///
-  /// port: int (optional)
-  ///
-  ///   The port on which the preview tool will respond to GET requests. The
-  ///   field is omitted if a preview was not requested.
-  ///
-  /// urls: List<String> (optional)
-  ///
-  ///   The URLs that users can visit in a browser to see a preview of the
-  ///   proposed changes. There is one URL for each of the included file paths.
-  ///   The field is omitted if a preview was not requested.
-  Future<EditDartfixResult> sendEditDartfix(List<String> included,
-      {List<String>? includedFixes,
-      bool? includePedanticFixes,
-      List<String>? excludedFixes,
-      int? port,
-      String? outputDir}) async {
-    var params = EditDartfixParams(included,
-            includedFixes: includedFixes,
-            includePedanticFixes: includePedanticFixes,
-            excludedFixes: excludedFixes,
-            port: port,
-            outputDir: outputDir)
-        .toJson();
-    var result = await server.send('edit.dartfix', params);
-    var decoder = ResponseDecoder(null);
-    return EditDartfixResult.fromJson(decoder, 'result', result);
-  }
-
   /// Return the set of fixes that are available for the errors at a given
   /// offset in a given file.
   ///
diff --git a/pkg/analysis_server/test/integration/support/protocol_matchers.dart b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
index 4ad56ae..3c0e282 100644
--- a/pkg/analysis_server/test/integration/support/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/support/protocol_matchers.dart
@@ -344,26 +344,6 @@
           'cacheEntryExceptions': isListOf(isString)
         }));
 
-/// DartFix
-///
-/// {
-///   "name": String
-///   "description": optional String
-/// }
-final Matcher isDartFix = LazyMatcher(() => MatchesJsonObject(
-    'DartFix', {'name': isString},
-    optionalFields: {'description': isString}));
-
-/// DartFixSuggestion
-///
-/// {
-///   "description": String
-///   "location": optional Location
-/// }
-final Matcher isDartFixSuggestion = LazyMatcher(() => MatchesJsonObject(
-    'DartFixSuggestion', {'description': isString},
-    optionalFields: {'location': isLocation}));
-
 /// DiagnosticMessage
 ///
 /// {
@@ -1429,7 +1409,6 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
-///   UNKNOWN_FIX
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -1466,7 +1445,6 @@
   'SERVER_ERROR',
   'SORT_MEMBERS_INVALID_FILE',
   'SORT_MEMBERS_PARSE_ERRORS',
-  'UNKNOWN_FIX',
   'UNKNOWN_REQUEST',
   'UNSUPPORTED_FEATURE'
 ]);
@@ -2240,50 +2218,6 @@
     'edit.bulkFixes result',
     {'edits': isListOf(isSourceFileEdit), 'details': isListOf(isBulkFix)}));
 
-/// edit.dartfix params
-///
-/// {
-///   "included": List<FilePath>
-///   "includedFixes": optional List<String>
-///   "includePedanticFixes": optional bool
-///   "excludedFixes": optional List<String>
-///   "port": optional int
-///   "outputDir": optional FilePath
-/// }
-final Matcher isEditDartfixParams =
-    LazyMatcher(() => MatchesJsonObject('edit.dartfix params', {
-          'included': isListOf(isFilePath)
-        }, optionalFields: {
-          'includedFixes': isListOf(isString),
-          'includePedanticFixes': isBool,
-          'excludedFixes': isListOf(isString),
-          'port': isInt,
-          'outputDir': isFilePath
-        }));
-
-/// edit.dartfix result
-///
-/// {
-///   "suggestions": List<DartFixSuggestion>
-///   "otherSuggestions": List<DartFixSuggestion>
-///   "hasErrors": bool
-///   "edits": List<SourceFileEdit>
-///   "details": optional List<String>
-///   "port": optional int
-///   "urls": optional List<String>
-/// }
-final Matcher isEditDartfixResult =
-    LazyMatcher(() => MatchesJsonObject('edit.dartfix result', {
-          'suggestions': isListOf(isDartFixSuggestion),
-          'otherSuggestions': isListOf(isDartFixSuggestion),
-          'hasErrors': isBool,
-          'edits': isListOf(isSourceFileEdit)
-        }, optionalFields: {
-          'details': isListOf(isString),
-          'port': isInt,
-          'urls': isListOf(isString)
-        }));
-
 /// edit.format params
 ///
 /// {
@@ -2350,21 +2284,6 @@
     MatchesJsonObject('edit.getAvailableRefactorings result',
         {'kinds': isListOf(isRefactoringKind)}));
 
-/// edit.getDartfixInfo params
-///
-/// {
-/// }
-final Matcher isEditGetDartfixInfoParams =
-    LazyMatcher(() => MatchesJsonObject('edit.getDartfixInfo params', null));
-
-/// edit.getDartfixInfo result
-///
-/// {
-///   "fixes": List<DartFix>
-/// }
-final Matcher isEditGetDartfixInfoResult = LazyMatcher(() => MatchesJsonObject(
-    'edit.getDartfixInfo result', {'fixes': isListOf(isDartFix)}));
-
 /// edit.getFixes params
 ///
 /// {
diff --git a/pkg/analysis_server/test/test_all.dart b/pkg/analysis_server/test/test_all.dart
index eca22e0..4c5a33f 100644
--- a/pkg/analysis_server/test/test_all.dart
+++ b/pkg/analysis_server/test/test_all.dart
@@ -14,7 +14,6 @@
 import 'domain_analysis_test.dart' as domain_analysis;
 import 'domain_completion_test.dart' as domain_completion;
 import 'domain_diagnostic_test.dart' as domain_experimental;
-import 'domain_edit_dartfix_test.dart' as domain_edit_dartfix;
 import 'domain_execution_test.dart' as domain_execution;
 import 'domain_server_test.dart' as domain_server;
 import 'edit/test_all.dart' as edit;
@@ -40,7 +39,6 @@
     completion.main();
     domain_analysis.main();
     domain_completion.main();
-    domain_edit_dartfix.main();
     domain_execution.main();
     domain_experimental.main();
     domain_server.main();
diff --git a/pkg/analysis_server/tool/migration_runner.dart b/pkg/analysis_server/tool/migration_runner.dart
deleted file mode 100644
index ec9b6a2..0000000
--- a/pkg/analysis_server/tool/migration_runner.dart
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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.
-
-/// This executable provides the ability to run the migration tool in process
-/// on a single package.  It should be invoked with two command-line arguments:
-/// a path to a configuration file and the name of a package to migrate.
-///
-/// The configuration file format is a JSON map, with the following keys:
-/// - `sdk_root`: path to the SDK source code on the user's machine (this is the
-///   directory that contains `pkg`, `third_party`, `tests`, etc.
-/// - `output_root`: if present, path to the directory on the user's machine
-///   where output HTML files should go.  A subdirectory will be created for
-///   each package that is migrated.
-/// - `external_packages`: a map (name => path) of additional non-SDK packages
-///   that may need to be migrated.
-/// - `port`: if present, the port where a server should be spawned serving HTML
-///   pages.
-library migration_runner;
-
-import 'dart:convert';
-import 'dart:io' as io;
-
-import 'package:analysis_server/protocol/protocol.dart';
-import 'package:analysis_server/protocol/protocol_constants.dart';
-import 'package:analysis_server/protocol/protocol_generated.dart';
-import 'package:analysis_server/src/analysis_server.dart';
-import 'package:analysis_server/src/server/crash_reporting_attachments.dart';
-import 'package:analysis_server/src/utilities/mocks.dart';
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/physical_file_system.dart';
-import 'package:analyzer/instrumentation/instrumentation.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:cli_util/cli_util.dart';
-import 'package:path/path.dart' as path;
-import 'package:test/test.dart';
-
-Future<void> main(List<String> args) async {
-  if (args.length != 2) {
-    throw StateError(
-        'Exactly two arguments are required: the path to a JSON configuration '
-        'file, and the name of the package to migrate');
-  }
-  var testInfoJsonPath = args[0];
-  var testInfoJson = json.decode(io.File(testInfoJsonPath).readAsStringSync());
-  var packageName = args[1];
-  var testInfo = TestInfo(testInfoJson);
-  var packageRoot = testInfo.packageRoot(packageName);
-  var port = testInfo.port;
-  print('Preparing to migrate');
-  var migrationTest = MigrationTest();
-  migrationTest.setUp();
-  print('Migrating');
-  await migrationTest.run(packageRoot, port);
-  migrationTest.tearDown();
-  print('Done.  Please point your browser to localhost:$port/\$filePath');
-}
-
-class MigrationBase {
-  ResourceProvider resourceProvider = PhysicalResourceProvider.INSTANCE;
-  late MockServerChannel serverChannel;
-  late AnalysisServer server;
-
-  AnalysisServer createAnalysisServer() {
-    //
-    // Create server
-    //
-    var options = AnalysisServerOptions();
-    var sdkPath = getSdkPath();
-    return AnalysisServer(
-        serverChannel,
-        resourceProvider,
-        options,
-        DartSdkManager(sdkPath),
-        CrashReportingAttachmentsBuilder.empty,
-        InstrumentationService.NULL_SERVICE);
-  }
-
-  void processNotification(Notification notification) {
-    if (notification.event == SERVER_NOTIFICATION_ERROR) {
-      fail('${notification.toJson()}');
-    }
-  }
-
-  Future<Response> sendAnalysisSetAnalysisRoots(List<String> directories) {
-    var request =
-        AnalysisSetAnalysisRootsParams(directories, []).toRequest('0');
-    return waitResponse(request);
-  }
-
-  Future<Response> sendEditDartfix(List<String> directories, int port) {
-    var request = EditDartfixParams(directories,
-            includedFixes: ['non-nullable'], port: port)
-        .toRequest('1');
-    return waitResponse(request);
-  }
-
-  void setUp() {
-    serverChannel = MockServerChannel();
-    server = createAnalysisServer();
-    server.pluginManager = TestPluginManager();
-    // listen for notifications
-    var notificationStream = serverChannel.notificationController.stream;
-    notificationStream.listen((Notification notification) {
-      processNotification(notification);
-    });
-  }
-
-  void tearDown() {
-    server.done();
-  }
-
-  /// Returns a [Future] that completes when the server's analysis is complete.
-  Future waitForTasksFinished() {
-    return server.onAnalysisComplete;
-  }
-
-  /// Completes with a successful [Response] for the given [request].
-  Future<Response> waitResponse(Request request,
-      {bool throwOnError = true}) async {
-    return serverChannel.sendRequest(request, throwOnError: throwOnError);
-  }
-}
-
-class MigrationTest extends MigrationBase {
-  Future<void> run(String packageRoot, int port) async {
-    var packageRoots = <String>[packageRoot];
-    await sendAnalysisSetAnalysisRoots(packageRoots);
-    await sendEditDartfix(packageRoots, port);
-  }
-}
-
-class TestInfo {
-  static const Set<String> thirdPartyPackages = {
-    'charcode',
-    'collection',
-    'logging',
-    'meta',
-    'pedantic',
-    'typed_data'
-  };
-
-  static const Set<String> builtInPackages = {'meta', 'path'};
-
-  final Map<String, Object> testInfoJson;
-
-  TestInfo(this.testInfoJson);
-
-  Map<String, String> get externalPackages =>
-      ((testInfoJson['external_packages'] ?? {}) as Map).cast<String, String>();
-
-  String get outputRoot => testInfoJson['output_root'] as String;
-
-  int get port => testInfoJson['port'] as int;
-
-  String get sdkRoot => testInfoJson['sdk_root'] as String;
-
-  String packageRoot(String packageName) {
-    if (thirdPartyPackages.contains(packageName)) {
-      return path.join(sdkRoot, 'third_party', 'pkg', packageName);
-    } else if (builtInPackages.contains(packageName)) {
-      return path.join(sdkRoot, 'pkg', packageName);
-    } else if (externalPackages.containsKey(packageName)) {
-      return externalPackages[packageName] as String;
-    } else {
-      throw StateError('Unrecognized package $packageName');
-    }
-  }
-}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 5731163..03b9cbe 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -479,37 +479,6 @@
   public void edit_bulkFixes(List<String> included, boolean inTestMode, BulkFixesConsumer consumer);
 
   /**
-   * {@code edit.dartfix}
-   *
-   * Analyze the specified sources for recommended changes and return a set of suggested edits for
-   * those sources. These edits may include changes to sources outside the set of specified sources
-   * if a change in a specified source requires it.
-   *
-   * If includedFixes is specified, then those fixes will be applied. If includePedanticFixes is
-   * specified, then fixes associated with the pedantic rule set will be applied in addition to
-   * whatever fixes are specified in includedFixes if any. If neither includedFixes nor
-   * includePedanticFixes is specified, then no fixes will be applied. If excludedFixes is specified,
-   * then those fixes will not be applied regardless of whether they are specified in includedFixes.
-   *
-   * @param included A list of the files and directories for which edits should be suggested. If a
-   *         request is made with a path that is invalid, e.g. is not absolute and normalized, an
-   *         error of type INVALID_FILE_PATH_FORMAT will be generated. If a request is made for a
-   *         file which does not exist, or which is not currently subject to analysis (e.g. because
-   *         it is not associated with any analysis root specified to analysis.setAnalysisRoots), an
-   *         error of type FILE_NOT_ANALYZED will be generated.
-   * @param includedFixes A list of names indicating which fixes should be applied. If a name is
-   *         specified that does not match the name of a known fix, an error of type UNKNOWN_FIX will
-   *         be generated.
-   * @param includePedanticFixes A flag indicating whether "pedantic" fixes should be applied.
-   * @param excludedFixes A list of names indicating which fixes should not be applied. If a name is
-   *         specified that does not match the name of a known fix, an error of type UNKNOWN_FIX will
-   *         be generated.
-   * @param port Deprecated: This field is now ignored by server.
-   * @param outputDir Deprecated: This field is now ignored by server.
-   */
-  public void edit_dartfix(List<String> included, List<String> includedFixes, boolean includePedanticFixes, List<String> excludedFixes, int port, String outputDir, DartfixConsumer consumer);
-
-  /**
    * {@code edit.format}
    *
    * Format the contents of a single file. The currently selected region of text is passed in so that
@@ -556,14 +525,6 @@
   public void edit_getAvailableRefactorings(String file, int offset, int length, GetAvailableRefactoringsConsumer consumer);
 
   /**
-   * {@code edit.getDartfixInfo}
-   *
-   * Request information about edit.dartfix such as the list of known fixes that can be specified in
-   * an edit.dartfix request.
-   */
-  public void edit_getDartfixInfo(GetDartfixInfoConsumer consumer);
-
-  /**
    * {@code edit.getFixes}
    *
    * Return the set of fixes that are available for the errors at a given offset in a given file.
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/DartFix.java b/pkg/analysis_server/tool/spec/generated/java/types/DartFix.java
deleted file mode 100644
index 1d2dde1..0000000
--- a/pkg/analysis_server/tool/spec/generated/java/types/DartFix.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.
- *
- * This file has been automatically generated. Please do not edit it manually.
- * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
- */
-package org.dartlang.analysis.server.protocol;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import com.google.common.collect.Lists;
-import com.google.dart.server.utilities.general.JsonUtilities;
-import com.google.dart.server.utilities.general.ObjectUtilities;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import java.util.ArrayList;
-import java.util.Iterator;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * A "fix" that can be specified in an edit.dartfix request.
- *
- * @coverage dart.server.generated.types
- */
-@SuppressWarnings("unused")
-public class DartFix {
-
-  public static final DartFix[] EMPTY_ARRAY = new DartFix[0];
-
-  public static final List<DartFix> EMPTY_LIST = Lists.newArrayList();
-
-  /**
-   * The name of the fix.
-   */
-  private final String name;
-
-  /**
-   * A human readable description of the fix.
-   */
-  private final String description;
-
-  /**
-   * Constructor for {@link DartFix}.
-   */
-  public DartFix(String name, String description) {
-    this.name = name;
-    this.description = description;
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (obj instanceof DartFix) {
-      DartFix other = (DartFix) obj;
-      return
-        ObjectUtilities.equals(other.name, name) &&
-        ObjectUtilities.equals(other.description, description);
-    }
-    return false;
-  }
-
-  public static DartFix fromJson(JsonObject jsonObject) {
-    String name = jsonObject.get("name").getAsString();
-    String description = jsonObject.get("description") == null ? null : jsonObject.get("description").getAsString();
-    return new DartFix(name, description);
-  }
-
-  public static List<DartFix> fromJsonArray(JsonArray jsonArray) {
-    if (jsonArray == null) {
-      return EMPTY_LIST;
-    }
-    ArrayList<DartFix> list = new ArrayList<DartFix>(jsonArray.size());
-    Iterator<JsonElement> iterator = jsonArray.iterator();
-    while (iterator.hasNext()) {
-      list.add(fromJson(iterator.next().getAsJsonObject()));
-    }
-    return list;
-  }
-
-  /**
-   * A human readable description of the fix.
-   */
-  public String getDescription() {
-    return description;
-  }
-
-  /**
-   * The name of the fix.
-   */
-  public String getName() {
-    return name;
-  }
-
-  @Override
-  public int hashCode() {
-    HashCodeBuilder builder = new HashCodeBuilder();
-    builder.append(name);
-    builder.append(description);
-    return builder.toHashCode();
-  }
-
-  public JsonObject toJson() {
-    JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("name", name);
-    if (description != null) {
-      jsonObject.addProperty("description", description);
-    }
-    return jsonObject;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder builder = new StringBuilder();
-    builder.append("[");
-    builder.append("name=");
-    builder.append(name + ", ");
-    builder.append("description=");
-    builder.append(description);
-    builder.append("]");
-    return builder.toString();
-  }
-
-}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java b/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java
deleted file mode 100644
index b40cb10..0000000
--- a/pkg/analysis_server/tool/spec/generated/java/types/DartFixSuggestion.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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.
- *
- * This file has been automatically generated. Please do not edit it manually.
- * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
- */
-package org.dartlang.analysis.server.protocol;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import com.google.common.collect.Lists;
-import com.google.dart.server.utilities.general.JsonUtilities;
-import com.google.dart.server.utilities.general.ObjectUtilities;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import java.util.ArrayList;
-import java.util.Iterator;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * A suggestion from an edit.dartfix request.
- *
- * @coverage dart.server.generated.types
- */
-@SuppressWarnings("unused")
-public class DartFixSuggestion {
-
-  public static final DartFixSuggestion[] EMPTY_ARRAY = new DartFixSuggestion[0];
-
-  public static final List<DartFixSuggestion> EMPTY_LIST = Lists.newArrayList();
-
-  /**
-   * A human readable description of the suggested change.
-   */
-  private final String description;
-
-  /**
-   * The location of the suggested change.
-   */
-  private final Location location;
-
-  /**
-   * Constructor for {@link DartFixSuggestion}.
-   */
-  public DartFixSuggestion(String description, Location location) {
-    this.description = description;
-    this.location = location;
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (obj instanceof DartFixSuggestion) {
-      DartFixSuggestion other = (DartFixSuggestion) obj;
-      return
-        ObjectUtilities.equals(other.description, description) &&
-        ObjectUtilities.equals(other.location, location);
-    }
-    return false;
-  }
-
-  public static DartFixSuggestion fromJson(JsonObject jsonObject) {
-    String description = jsonObject.get("description").getAsString();
-    Location location = jsonObject.get("location") == null ? null : Location.fromJson(jsonObject.get("location").getAsJsonObject());
-    return new DartFixSuggestion(description, location);
-  }
-
-  public static List<DartFixSuggestion> fromJsonArray(JsonArray jsonArray) {
-    if (jsonArray == null) {
-      return EMPTY_LIST;
-    }
-    ArrayList<DartFixSuggestion> list = new ArrayList<DartFixSuggestion>(jsonArray.size());
-    Iterator<JsonElement> iterator = jsonArray.iterator();
-    while (iterator.hasNext()) {
-      list.add(fromJson(iterator.next().getAsJsonObject()));
-    }
-    return list;
-  }
-
-  /**
-   * A human readable description of the suggested change.
-   */
-  public String getDescription() {
-    return description;
-  }
-
-  /**
-   * The location of the suggested change.
-   */
-  public Location getLocation() {
-    return location;
-  }
-
-  @Override
-  public int hashCode() {
-    HashCodeBuilder builder = new HashCodeBuilder();
-    builder.append(description);
-    builder.append(location);
-    return builder.toHashCode();
-  }
-
-  public JsonObject toJson() {
-    JsonObject jsonObject = new JsonObject();
-    jsonObject.addProperty("description", description);
-    if (location != null) {
-      jsonObject.add("location", location.toJson());
-    }
-    return jsonObject;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder builder = new StringBuilder();
-    builder.append("[");
-    builder.append("description=");
-    builder.append(description + ", ");
-    builder.append("location=");
-    builder.append(location);
-    builder.append("]");
-    return builder.toString();
-  }
-
-}
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index 44da4d7..66c6210 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -198,12 +198,6 @@
   public static final String SORT_MEMBERS_PARSE_ERRORS = "SORT_MEMBERS_PARSE_ERRORS";
 
   /**
-   * A dartfix request was received containing the name of a fix which does not match the name of any
-   * known fixes.
-   */
-  public static final String UNKNOWN_FIX = "UNKNOWN_FIX";
-
-  /**
    * A request was received which the analysis server does not recognize, or cannot handle in its
    * current configuration.
    */
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 9168b9b..7bb2fe0 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -2154,26 +2154,6 @@
       </field>
     </result>
   </request>
-  <request method="getDartfixInfo" experimental="true">
-    <p>
-      Request information about edit.dartfix
-      such as the list of known fixes that can be specified
-      in an edit.dartfix request.
-    </p>
-    <params>
-    </params>
-    <result>
-      <field name="fixes">
-        <list>
-          <ref>DartFix</ref>
-        </list>
-        <p>
-          A list of fixes that can be specified
-          in an edit.dartfix request.
-        </p>
-      </field>
-    </result>
-  </request>
   <request method="bulkFixes" experimental="true">
     <p>
       Analyze the specified sources for fixes that can be applied in bulk
@@ -2233,148 +2213,6 @@
       </field>
     </result>
   </request>
-  <request method="dartfix" experimental="true">
-    <p>
-      Analyze the specified sources for recommended changes
-      and return a set of suggested edits for those sources.
-      These edits may include changes to sources outside the set
-      of specified sources if a change in a specified source requires it.
-    </p>
-    <p>
-      If includedFixes is specified, then those fixes will be applied. If
-      includePedanticFixes is specified, then fixes associated with the pedantic
-      rule set will be applied in addition to whatever fixes are specified in
-      includedFixes if any. If neither includedFixes nor includePedanticFixes is
-      specified, then no fixes will be applied. If excludedFixes is specified,
-      then those fixes will not be applied regardless of whether they are
-      specified in includedFixes.
-    </p>
-    <params>
-      <field name="included">
-        <list>
-          <ref>FilePath</ref>
-        </list>
-        <p>
-          A list of the files and directories for which edits should be
-          suggested.
-        </p>
-        <p>
-          If a request is made with a path that is invalid, e.g. is not absolute
-          and normalized, an error of type <tt>INVALID_FILE_PATH_FORMAT</tt>
-          will be generated. If a request is made for a file which does not
-          exist, or which is not currently subject to analysis (e.g. because it
-          is not associated with any analysis root specified to
-          analysis.setAnalysisRoots), an error of type
-          <tt>FILE_NOT_ANALYZED</tt> will be generated.
-        </p>
-      </field>
-      <field name="includedFixes" optional="true">
-        <list>
-          <ref>String</ref>
-        </list>
-        <p>
-          A list of names indicating which fixes should be applied.
-        </p>
-        <p>
-          If a name is specified that does not match the name of a known fix, an
-          error of type <tt>UNKNOWN_FIX</tt> will be generated.
-        </p>
-      </field>
-      <field name="includePedanticFixes" optional="true">
-        <ref>bool</ref>
-        <p>
-          A flag indicating whether "pedantic" fixes should be applied.
-        </p>
-      </field>
-      <field name="excludedFixes" optional="true">
-        <list>
-          <ref>String</ref>
-        </list>
-        <p>
-          A list of names indicating which fixes should not be applied.
-        </p>
-        <p>
-          If a name is specified that does not match the name of a known fix, an
-          error of type <tt>UNKNOWN_FIX</tt> will be generated.
-        </p>
-      </field>
-      <field name="port" optional="true" deprecated="true">
-        <ref>int</ref>
-        <p>
-          <b>Deprecated:</b> This field is now ignored by server.
-        </p>
-      </field>
-      <field name="outputDir" optional="true" deprecated="true">
-        <ref>FilePath</ref>
-        <p>
-          <b>Deprecated:</b> This field is now ignored by server.
-        </p>
-      </field>
-    </params>
-    <result>
-      <field name="suggestions">
-        <list>
-          <ref>DartFixSuggestion</ref>
-        </list>
-        <p>
-          A list of recommended changes that can be automatically made
-          by applying the 'edits' included in this response.
-        </p>
-      </field>
-      <field name="otherSuggestions">
-        <list>
-          <ref>DartFixSuggestion</ref>
-        </list>
-        <p>
-          A list of recommended changes that could not be automatically made.
-        </p>
-      </field>
-      <field name="hasErrors">
-        <ref>bool</ref>
-        <p>
-          True if the analyzed source contains errors that might impact the correctness
-          of the recommended changes that can be automatically applied.
-        </p>
-      </field>
-      <field name="edits">
-        <list>
-          <ref>SourceFileEdit</ref>
-        </list>
-        <p>
-          A list of source edits to apply the recommended changes.
-        </p>
-      </field>
-      <field name="details" optional="true">
-        <list>
-          <ref>String</ref>
-        </list>
-        <p>
-          Messages that should be displayed to the user that describe details of
-          the fix generation. For example, the messages might (a) point out
-          details that users might want to explore before committing the changes
-          or (b) describe exceptions that were thrown but that did not stop the
-          fixes from being produced. The list will be omitted if it is empty.
-        </p>
-      </field>
-      <field name="port" optional="true">
-        <ref>int</ref>
-        <p>
-          The port on which the preview tool will respond to GET requests. The
-          field is omitted if a preview was not requested.
-        </p>
-      </field>
-      <field name="urls" optional="true">
-        <list>
-          <ref>String</ref>
-        </list>
-        <p>
-          The URLs that users can visit in a browser to see a preview of the
-          proposed changes. There is one URL for each of the included file
-          paths. The field is omitted if a preview was not requested.
-        </p>
-      </field>
-    </result>
-  </request>
   <request method="getFixes">
     <p>
       Return the set of fixes that are available for the errors at
@@ -5206,13 +5044,6 @@
         </p>
       </value>
       <value>
-        <code>UNKNOWN_FIX</code>
-        <p>
-          A dartfix request was received containing the name of a fix
-          which does not match the name of any known fixes.
-        </p>
-      </value>
-      <value>
         <code>UNKNOWN_REQUEST</code>
         <p>
           A request was received which the analysis server does
@@ -5242,44 +5073,6 @@
       request.
     </p>
   </type>
-  <type name="DartFix" experimental="true">
-    <p>
-      A "fix" that can be specified in an edit.dartfix request.
-    </p>
-    <object>
-      <field name="name">
-        <ref>String</ref>
-        <p>
-          The name of the fix.
-        </p>
-      </field>
-      <field name="description" optional="true">
-        <ref>String</ref>
-        <p>
-          A human readable description of the fix.
-        </p>
-      </field>
-    </object>
-  </type>
-  <type name="DartFixSuggestion" experimental="true">
-    <p>
-      A suggestion from an edit.dartfix request.
-    </p>
-    <object>
-      <field name="description">
-        <ref>String</ref>
-        <p>
-          A human readable description of the suggested change.
-        </p>
-      </field>
-      <field name="location" optional="true">
-        <ref>Location</ref>
-        <p>
-          The location of the suggested change.
-        </p>
-      </field>
-    </object>
-  </type>
   <type name="SearchResult">
     <p>
       A single result from a search request.
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
index c06dbe8..84b3a5c 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_constants.dart
@@ -163,14 +163,6 @@
 const String EDIT_REQUEST_BULK_FIXES = 'edit.bulkFixes';
 const String EDIT_REQUEST_BULK_FIXES_INCLUDED = 'included';
 const String EDIT_REQUEST_BULK_FIXES_IN_TEST_MODE = 'inTestMode';
-const String EDIT_REQUEST_DARTFIX = 'edit.dartfix';
-const String EDIT_REQUEST_DARTFIX_EXCLUDED_FIXES = 'excludedFixes';
-const String EDIT_REQUEST_DARTFIX_INCLUDED = 'included';
-const String EDIT_REQUEST_DARTFIX_INCLUDED_FIXES = 'includedFixes';
-const String EDIT_REQUEST_DARTFIX_INCLUDE_PEDANTIC_FIXES =
-    'includePedanticFixes';
-const String EDIT_REQUEST_DARTFIX_OUTPUT_DIR = 'outputDir';
-const String EDIT_REQUEST_DARTFIX_PORT = 'port';
 const String EDIT_REQUEST_FORMAT = 'edit.format';
 const String EDIT_REQUEST_FORMAT_FILE = 'file';
 const String EDIT_REQUEST_FORMAT_LINE_LENGTH = 'lineLength';
@@ -185,7 +177,6 @@
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_FILE = 'file';
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_LENGTH = 'length';
 const String EDIT_REQUEST_GET_AVAILABLE_REFACTORINGS_OFFSET = 'offset';
-const String EDIT_REQUEST_GET_DARTFIX_INFO = 'edit.getDartfixInfo';
 const String EDIT_REQUEST_GET_FIXES = 'edit.getFixes';
 const String EDIT_REQUEST_GET_FIXES_FILE = 'file';
 const String EDIT_REQUEST_GET_FIXES_OFFSET = 'offset';
@@ -221,19 +212,11 @@
 const String EDIT_REQUEST_SORT_MEMBERS_FILE = 'file';
 const String EDIT_RESPONSE_BULK_FIXES_DETAILS = 'details';
 const String EDIT_RESPONSE_BULK_FIXES_EDITS = 'edits';
-const String EDIT_RESPONSE_DARTFIX_DETAILS = 'details';
-const String EDIT_RESPONSE_DARTFIX_EDITS = 'edits';
-const String EDIT_RESPONSE_DARTFIX_HAS_ERRORS = 'hasErrors';
-const String EDIT_RESPONSE_DARTFIX_OTHER_SUGGESTIONS = 'otherSuggestions';
-const String EDIT_RESPONSE_DARTFIX_PORT = 'port';
-const String EDIT_RESPONSE_DARTFIX_SUGGESTIONS = 'suggestions';
-const String EDIT_RESPONSE_DARTFIX_URLS = 'urls';
 const String EDIT_RESPONSE_FORMAT_EDITS = 'edits';
 const String EDIT_RESPONSE_FORMAT_SELECTION_LENGTH = 'selectionLength';
 const String EDIT_RESPONSE_FORMAT_SELECTION_OFFSET = 'selectionOffset';
 const String EDIT_RESPONSE_GET_ASSISTS_ASSISTS = 'assists';
 const String EDIT_RESPONSE_GET_AVAILABLE_REFACTORINGS_KINDS = 'kinds';
-const String EDIT_RESPONSE_GET_DARTFIX_INFO_FIXES = 'fixes';
 const String EDIT_RESPONSE_GET_FIXES_FIXES = 'fixes';
 const String EDIT_RESPONSE_GET_POSTFIX_COMPLETION_CHANGE = 'change';
 const String EDIT_RESPONSE_GET_REFACTORING_CHANGE = 'change';
diff --git a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
index 5a777f6..470f830 100644
--- a/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
+++ b/pkg/analysis_server_client/lib/src/protocol/protocol_generated.dart
@@ -5471,145 +5471,6 @@
   }
 }
 
-/// DartFix
-///
-/// {
-///   "name": String
-///   "description": optional String
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class DartFix implements HasToJson {
-  /// The name of the fix.
-  String name;
-
-  /// A human readable description of the fix.
-  String? description;
-
-  DartFix(this.name, {this.description});
-
-  factory DartFix.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      String name;
-      if (json.containsKey('name')) {
-        name = jsonDecoder.decodeString(jsonPath + '.name', json['name']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'name');
-      }
-      String? description;
-      if (json.containsKey('description')) {
-        description = jsonDecoder.decodeString(
-            jsonPath + '.description', json['description']);
-      }
-      return DartFix(name, description: description);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'DartFix', json);
-    }
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['name'] = name;
-    var description = this.description;
-    if (description != null) {
-      result['description'] = description;
-    }
-    return result;
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is DartFix) {
-      return name == other.name && description == other.description;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, name.hashCode);
-    hash = JenkinsSmiHash.combine(hash, description.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// DartFixSuggestion
-///
-/// {
-///   "description": String
-///   "location": optional Location
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class DartFixSuggestion implements HasToJson {
-  /// A human readable description of the suggested change.
-  String description;
-
-  /// The location of the suggested change.
-  Location? location;
-
-  DartFixSuggestion(this.description, {this.location});
-
-  factory DartFixSuggestion.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      String description;
-      if (json.containsKey('description')) {
-        description = jsonDecoder.decodeString(
-            jsonPath + '.description', json['description']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'description');
-      }
-      Location? location;
-      if (json.containsKey('location')) {
-        location = Location.fromJson(
-            jsonDecoder, jsonPath + '.location', json['location']);
-      }
-      return DartFixSuggestion(description, location: location);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'DartFixSuggestion', json);
-    }
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['description'] = description;
-    var location = this.location;
-    if (location != null) {
-      result['location'] = location.toJson();
-    }
-    return result;
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is DartFixSuggestion) {
-      return description == other.description && location == other.location;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, description.hashCode);
-    hash = JenkinsSmiHash.combine(hash, location.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// diagnostic.getDiagnostics params
 ///
 /// Clients may not extend, implement or mix-in this class.
@@ -5988,354 +5849,6 @@
   }
 }
 
-/// edit.dartfix params
-///
-/// {
-///   "included": List<FilePath>
-///   "includedFixes": optional List<String>
-///   "includePedanticFixes": optional bool
-///   "excludedFixes": optional List<String>
-///   "port": optional int
-///   "outputDir": optional FilePath
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditDartfixParams implements RequestParams {
-  /// A list of the files and directories for which edits should be suggested.
-  ///
-  /// If a request is made with a path that is invalid, e.g. is not absolute
-  /// and normalized, an error of type INVALID_FILE_PATH_FORMAT will be
-  /// generated. If a request is made for a file which does not exist, or which
-  /// is not currently subject to analysis (e.g. because it is not associated
-  /// with any analysis root specified to analysis.setAnalysisRoots), an error
-  /// of type FILE_NOT_ANALYZED will be generated.
-  List<String> included;
-
-  /// A list of names indicating which fixes should be applied.
-  ///
-  /// If a name is specified that does not match the name of a known fix, an
-  /// error of type UNKNOWN_FIX will be generated.
-  List<String>? includedFixes;
-
-  /// A flag indicating whether "pedantic" fixes should be applied.
-  bool? includePedanticFixes;
-
-  /// A list of names indicating which fixes should not be applied.
-  ///
-  /// If a name is specified that does not match the name of a known fix, an
-  /// error of type UNKNOWN_FIX will be generated.
-  List<String>? excludedFixes;
-
-  /// Deprecated: This field is now ignored by server.
-  int? port;
-
-  /// Deprecated: This field is now ignored by server.
-  String? outputDir;
-
-  EditDartfixParams(this.included,
-      {this.includedFixes,
-      this.includePedanticFixes,
-      this.excludedFixes,
-      this.port,
-      this.outputDir});
-
-  factory EditDartfixParams.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<String> included;
-      if (json.containsKey('included')) {
-        included = jsonDecoder.decodeList(
-            jsonPath + '.included', json['included'], jsonDecoder.decodeString);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'included');
-      }
-      List<String>? includedFixes;
-      if (json.containsKey('includedFixes')) {
-        includedFixes = jsonDecoder.decodeList(jsonPath + '.includedFixes',
-            json['includedFixes'], jsonDecoder.decodeString);
-      }
-      bool? includePedanticFixes;
-      if (json.containsKey('includePedanticFixes')) {
-        includePedanticFixes = jsonDecoder.decodeBool(
-            jsonPath + '.includePedanticFixes', json['includePedanticFixes']);
-      }
-      List<String>? excludedFixes;
-      if (json.containsKey('excludedFixes')) {
-        excludedFixes = jsonDecoder.decodeList(jsonPath + '.excludedFixes',
-            json['excludedFixes'], jsonDecoder.decodeString);
-      }
-      int? port;
-      if (json.containsKey('port')) {
-        port = jsonDecoder.decodeInt(jsonPath + '.port', json['port']);
-      }
-      String? outputDir;
-      if (json.containsKey('outputDir')) {
-        outputDir = jsonDecoder.decodeString(
-            jsonPath + '.outputDir', json['outputDir']);
-      }
-      return EditDartfixParams(included,
-          includedFixes: includedFixes,
-          includePedanticFixes: includePedanticFixes,
-          excludedFixes: excludedFixes,
-          port: port,
-          outputDir: outputDir);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.dartfix params', json);
-    }
-  }
-
-  factory EditDartfixParams.fromRequest(Request request) {
-    return EditDartfixParams.fromJson(
-        RequestDecoder(request), 'params', request.params);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['included'] = included;
-    var includedFixes = this.includedFixes;
-    if (includedFixes != null) {
-      result['includedFixes'] = includedFixes;
-    }
-    var includePedanticFixes = this.includePedanticFixes;
-    if (includePedanticFixes != null) {
-      result['includePedanticFixes'] = includePedanticFixes;
-    }
-    var excludedFixes = this.excludedFixes;
-    if (excludedFixes != null) {
-      result['excludedFixes'] = excludedFixes;
-    }
-    var port = this.port;
-    if (port != null) {
-      result['port'] = port;
-    }
-    var outputDir = this.outputDir;
-    if (outputDir != null) {
-      result['outputDir'] = outputDir;
-    }
-    return result;
-  }
-
-  @override
-  Request toRequest(String id) {
-    return Request(id, 'edit.dartfix', toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditDartfixParams) {
-      return listEqual(
-              included, other.included, (String a, String b) => a == b) &&
-          listEqual(includedFixes, other.includedFixes,
-              (String a, String b) => a == b) &&
-          includePedanticFixes == other.includePedanticFixes &&
-          listEqual(excludedFixes, other.excludedFixes,
-              (String a, String b) => a == b) &&
-          port == other.port &&
-          outputDir == other.outputDir;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, included.hashCode);
-    hash = JenkinsSmiHash.combine(hash, includedFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, includePedanticFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, excludedFixes.hashCode);
-    hash = JenkinsSmiHash.combine(hash, port.hashCode);
-    hash = JenkinsSmiHash.combine(hash, outputDir.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// edit.dartfix result
-///
-/// {
-///   "suggestions": List<DartFixSuggestion>
-///   "otherSuggestions": List<DartFixSuggestion>
-///   "hasErrors": bool
-///   "edits": List<SourceFileEdit>
-///   "details": optional List<String>
-///   "port": optional int
-///   "urls": optional List<String>
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditDartfixResult implements ResponseResult {
-  /// A list of recommended changes that can be automatically made by applying
-  /// the 'edits' included in this response.
-  List<DartFixSuggestion> suggestions;
-
-  /// A list of recommended changes that could not be automatically made.
-  List<DartFixSuggestion> otherSuggestions;
-
-  /// True if the analyzed source contains errors that might impact the
-  /// correctness of the recommended changes that can be automatically applied.
-  bool hasErrors;
-
-  /// A list of source edits to apply the recommended changes.
-  List<SourceFileEdit> edits;
-
-  /// Messages that should be displayed to the user that describe details of
-  /// the fix generation. For example, the messages might (a) point out details
-  /// that users might want to explore before committing the changes or (b)
-  /// describe exceptions that were thrown but that did not stop the fixes from
-  /// being produced. The list will be omitted if it is empty.
-  List<String>? details;
-
-  /// The port on which the preview tool will respond to GET requests. The
-  /// field is omitted if a preview was not requested.
-  int? port;
-
-  /// The URLs that users can visit in a browser to see a preview of the
-  /// proposed changes. There is one URL for each of the included file paths.
-  /// The field is omitted if a preview was not requested.
-  List<String>? urls;
-
-  EditDartfixResult(
-      this.suggestions, this.otherSuggestions, this.hasErrors, this.edits,
-      {this.details, this.port, this.urls});
-
-  factory EditDartfixResult.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<DartFixSuggestion> suggestions;
-      if (json.containsKey('suggestions')) {
-        suggestions = jsonDecoder.decodeList(
-            jsonPath + '.suggestions',
-            json['suggestions'],
-            (String jsonPath, Object? json) =>
-                DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'suggestions');
-      }
-      List<DartFixSuggestion> otherSuggestions;
-      if (json.containsKey('otherSuggestions')) {
-        otherSuggestions = jsonDecoder.decodeList(
-            jsonPath + '.otherSuggestions',
-            json['otherSuggestions'],
-            (String jsonPath, Object? json) =>
-                DartFixSuggestion.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'otherSuggestions');
-      }
-      bool hasErrors;
-      if (json.containsKey('hasErrors')) {
-        hasErrors =
-            jsonDecoder.decodeBool(jsonPath + '.hasErrors', json['hasErrors']);
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'hasErrors');
-      }
-      List<SourceFileEdit> edits;
-      if (json.containsKey('edits')) {
-        edits = jsonDecoder.decodeList(
-            jsonPath + '.edits',
-            json['edits'],
-            (String jsonPath, Object? json) =>
-                SourceFileEdit.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'edits');
-      }
-      List<String>? details;
-      if (json.containsKey('details')) {
-        details = jsonDecoder.decodeList(
-            jsonPath + '.details', json['details'], jsonDecoder.decodeString);
-      }
-      int? port;
-      if (json.containsKey('port')) {
-        port = jsonDecoder.decodeInt(jsonPath + '.port', json['port']);
-      }
-      List<String>? urls;
-      if (json.containsKey('urls')) {
-        urls = jsonDecoder.decodeList(
-            jsonPath + '.urls', json['urls'], jsonDecoder.decodeString);
-      }
-      return EditDartfixResult(suggestions, otherSuggestions, hasErrors, edits,
-          details: details, port: port, urls: urls);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.dartfix result', json);
-    }
-  }
-
-  factory EditDartfixResult.fromResponse(Response response) {
-    return EditDartfixResult.fromJson(
-        ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)),
-        'result',
-        response.result);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['suggestions'] =
-        suggestions.map((DartFixSuggestion value) => value.toJson()).toList();
-    result['otherSuggestions'] = otherSuggestions
-        .map((DartFixSuggestion value) => value.toJson())
-        .toList();
-    result['hasErrors'] = hasErrors;
-    result['edits'] =
-        edits.map((SourceFileEdit value) => value.toJson()).toList();
-    var details = this.details;
-    if (details != null) {
-      result['details'] = details;
-    }
-    var port = this.port;
-    if (port != null) {
-      result['port'] = port;
-    }
-    var urls = this.urls;
-    if (urls != null) {
-      result['urls'] = urls;
-    }
-    return result;
-  }
-
-  @override
-  Response toResponse(String id) {
-    return Response(id, result: toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditDartfixResult) {
-      return listEqual(suggestions, other.suggestions,
-              (DartFixSuggestion a, DartFixSuggestion b) => a == b) &&
-          listEqual(otherSuggestions, other.otherSuggestions,
-              (DartFixSuggestion a, DartFixSuggestion b) => a == b) &&
-          hasErrors == other.hasErrors &&
-          listEqual(edits, other.edits,
-              (SourceFileEdit a, SourceFileEdit b) => a == b) &&
-          listEqual(details, other.details, (String a, String b) => a == b) &&
-          port == other.port &&
-          listEqual(urls, other.urls, (String a, String b) => a == b);
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, suggestions.hashCode);
-    hash = JenkinsSmiHash.combine(hash, otherSuggestions.hashCode);
-    hash = JenkinsSmiHash.combine(hash, hasErrors.hashCode);
-    hash = JenkinsSmiHash.combine(hash, edits.hashCode);
-    hash = JenkinsSmiHash.combine(hash, details.hashCode);
-    hash = JenkinsSmiHash.combine(hash, port.hashCode);
-    hash = JenkinsSmiHash.combine(hash, urls.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// edit.format params
 ///
 /// {
@@ -6877,130 +6390,6 @@
   }
 }
 
-/// edit.getDartfixInfo params
-///
-/// {
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditGetDartfixInfoParams implements RequestParams {
-  EditGetDartfixInfoParams();
-
-  factory EditGetDartfixInfoParams.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      return EditGetDartfixInfoParams();
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.getDartfixInfo params', json);
-    }
-  }
-
-  factory EditGetDartfixInfoParams.fromRequest(Request request) {
-    return EditGetDartfixInfoParams.fromJson(
-        RequestDecoder(request), 'params', request.params);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    return result;
-  }
-
-  @override
-  Request toRequest(String id) {
-    return Request(id, 'edit.getDartfixInfo', toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditGetDartfixInfoParams) {
-      return true;
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
-/// edit.getDartfixInfo result
-///
-/// {
-///   "fixes": List<DartFix>
-/// }
-///
-/// Clients may not extend, implement or mix-in this class.
-class EditGetDartfixInfoResult implements ResponseResult {
-  /// A list of fixes that can be specified in an edit.dartfix request.
-  List<DartFix> fixes;
-
-  EditGetDartfixInfoResult(this.fixes);
-
-  factory EditGetDartfixInfoResult.fromJson(
-      JsonDecoder jsonDecoder, String jsonPath, Object? json) {
-    json ??= {};
-    if (json is Map) {
-      List<DartFix> fixes;
-      if (json.containsKey('fixes')) {
-        fixes = jsonDecoder.decodeList(
-            jsonPath + '.fixes',
-            json['fixes'],
-            (String jsonPath, Object? json) =>
-                DartFix.fromJson(jsonDecoder, jsonPath, json));
-      } else {
-        throw jsonDecoder.mismatch(jsonPath, 'fixes');
-      }
-      return EditGetDartfixInfoResult(fixes);
-    } else {
-      throw jsonDecoder.mismatch(jsonPath, 'edit.getDartfixInfo result', json);
-    }
-  }
-
-  factory EditGetDartfixInfoResult.fromResponse(Response response) {
-    return EditGetDartfixInfoResult.fromJson(
-        ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id)),
-        'result',
-        response.result);
-  }
-
-  @override
-  Map<String, Object> toJson() {
-    var result = <String, Object>{};
-    result['fixes'] = fixes.map((DartFix value) => value.toJson()).toList();
-    return result;
-  }
-
-  @override
-  Response toResponse(String id) {
-    return Response(id, result: toJson());
-  }
-
-  @override
-  String toString() => json.encode(toJson());
-
-  @override
-  bool operator ==(other) {
-    if (other is EditGetDartfixInfoResult) {
-      return listEqual(fixes, other.fixes, (DartFix a, DartFix b) => a == b);
-    }
-    return false;
-  }
-
-  @override
-  int get hashCode {
-    var hash = 0;
-    hash = JenkinsSmiHash.combine(hash, fixes.hashCode);
-    return JenkinsSmiHash.finish(hash);
-  }
-}
-
 /// edit.getFixes params
 ///
 /// {
@@ -14269,7 +13658,6 @@
 ///   SERVER_ERROR
 ///   SORT_MEMBERS_INVALID_FILE
 ///   SORT_MEMBERS_PARSE_ERRORS
-///   UNKNOWN_FIX
 ///   UNKNOWN_REQUEST
 ///   UNSUPPORTED_FEATURE
 /// }
@@ -14436,10 +13824,6 @@
   static const RequestErrorCode SORT_MEMBERS_PARSE_ERRORS =
       RequestErrorCode._('SORT_MEMBERS_PARSE_ERRORS');
 
-  /// A dartfix request was received containing the name of a fix which does
-  /// not match the name of any known fixes.
-  static const RequestErrorCode UNKNOWN_FIX = RequestErrorCode._('UNKNOWN_FIX');
-
   /// A request was received which the analysis server does not recognize, or
   /// cannot handle in its current configuration.
   static const RequestErrorCode UNKNOWN_REQUEST =
@@ -14487,7 +13871,6 @@
     SERVER_ERROR,
     SORT_MEMBERS_INVALID_FILE,
     SORT_MEMBERS_PARSE_ERRORS,
-    UNKNOWN_FIX,
     UNKNOWN_REQUEST,
     UNSUPPORTED_FEATURE
   ];
@@ -14563,8 +13946,6 @@
         return SORT_MEMBERS_INVALID_FILE;
       case 'SORT_MEMBERS_PARSE_ERRORS':
         return SORT_MEMBERS_PARSE_ERRORS;
-      case 'UNKNOWN_FIX':
-        return UNKNOWN_FIX;
       case 'UNKNOWN_REQUEST':
         return UNKNOWN_REQUEST;
       case 'UNSUPPORTED_FEATURE':
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 79fe467..d29f53d 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -9,6 +9,7 @@
 * `FieldElement.isFinal` is `true` only when the field is not synthetic.
 * Synthetic getters and setters now use `-1` as `nameOffset`.
 * Fixed bug that `defaultValueCode` is `null` for field formal parameters.
+* Updated `LibraryElement.name` so that it is non-nullable.
 
 ## 1.7.0
 * Require `meta: ^1.4.0`.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index 7b1db81..06d3348e 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1402,6 +1402,11 @@
   /// deferred import.
   FunctionElement get loadLibraryFunction;
 
+  /// Return the name of this library, possibly the empty string if this
+  /// library does not have an explicit name.
+  @override
+  String get name;
+
   /// Return a list containing all of the compilation units that are included in
   /// this library using a `part` directive. This does not include the defining
   /// compilation unit that contains the `part` directives.
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index e6eb121..8c8eb94 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -465,6 +465,7 @@
   CompileTimeErrorCode.YIELD_OF_INVALID_TYPE,
   FfiCode.ANNOTATION_ON_POINTER_FIELD,
   FfiCode.ARGUMENT_MUST_BE_A_CONSTANT,
+  FfiCode.CREATION_OF_STRUCT_OR_UNION,
   FfiCode.EMPTY_STRUCT,
   FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD,
   FfiCode.EXTRA_SIZE_ANNOTATION_CARRAY,
@@ -843,9 +844,20 @@
   ParserErrorCode.WITH_BEFORE_EXTENDS,
   ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
   ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP,
+  PubspecWarningCode.ASSET_DOES_NOT_EXIST,
+  PubspecWarningCode.ASSET_DIRECTORY_DOES_NOT_EXIST,
+  PubspecWarningCode.ASSET_FIELD_NOT_LIST,
+  PubspecWarningCode.ASSET_NOT_STRING,
+  PubspecWarningCode.DEPENDENCIES_FIELD_NOT_MAP,
+  PubspecWarningCode.DEPRECATED_FIELD,
+  PubspecWarningCode.FLUTTER_FIELD_NOT_MAP,
   PubspecWarningCode.INVALID_DEPENDENCY,
+  PubspecWarningCode.MISSING_NAME,
+  PubspecWarningCode.NAME_NOT_STRING,
   PubspecWarningCode.PATH_DOES_NOT_EXIST,
+  PubspecWarningCode.PATH_NOT_POSIX,
   PubspecWarningCode.PATH_PUBSPEC_DOES_NOT_EXIST,
+  PubspecWarningCode.UNNECESSARY_DEV_DEPENDENCY,
   ScannerErrorCode.EXPECTED_TOKEN,
   ScannerErrorCode.ILLEGAL_CHARACTER,
   ScannerErrorCode.MISSING_DIGIT,
diff --git a/pkg/analyzer/lib/file_system/overlay_file_system.dart b/pkg/analyzer/lib/file_system/overlay_file_system.dart
index 3c218f1..563954b 100644
--- a/pkg/analyzer/lib/file_system/overlay_file_system.dart
+++ b/pkg/analyzer/lib/file_system/overlay_file_system.dart
@@ -24,13 +24,8 @@
   /// do not have an overlay.
   final ResourceProvider baseProvider;
 
-  /// A map from the paths of files for which there is an overlay to the
-  /// contents of the files.
-  final Map<String, String> _overlayContent = <String, String>{};
-
-  /// A map from the paths of files for which there is an overlay to the
-  /// modification stamps of the files.
-  final Map<String, int> _overlayModificationStamps = <String, int>{};
+  /// A map from the paths of files for to the overlay data.
+  final Map<String, _OverlayFileData> _overlays = {};
 
   /// Initialize a newly created resource provider to represent an overlay on
   /// the given [baseProvider].
@@ -50,7 +45,7 @@
   Future<List<int>> getModificationTimes(List<Source> sources) async {
     return sources.map((source) {
       String path = source.fullName;
-      return _overlayModificationStamps[path] ??
+      return _overlays[path]?.modificationStamp ??
           baseProvider.getFile(path).modificationStamp;
     }).toList();
   }
@@ -73,15 +68,12 @@
 
   /// Return `true` if there is an overlay associated with the file at the given
   /// [path].
-  bool hasOverlay(String path) => _overlayContent.containsKey(path);
+  bool hasOverlay(String path) => _overlays.containsKey(path);
 
   /// Remove any overlay of the file at the given [path]. The state of the file
   /// in the base resource provider will not be affected.
   bool removeOverlay(String path) {
-    bool hadOverlay = _overlayContent.containsKey(path);
-    _overlayContent.remove(path);
-    _overlayModificationStamps.remove(path);
-    return hadOverlay;
+    return _overlays.remove(path) != null;
   }
 
   /// Overlay the content of the file at the given [path]. The file will appear
@@ -89,40 +81,47 @@
   /// modified in the base resource provider.
   void setOverlay(String path,
       {required String content, required int modificationStamp}) {
-    _overlayContent[path] = content;
-    _overlayModificationStamps[path] = modificationStamp;
+    _overlays[path] = _OverlayFileData(content, modificationStamp);
   }
 
   /// Copy any overlay for the file at the [oldPath] to be an overlay for the
   /// file with the [newPath].
   void _copyOverlay(String oldPath, String newPath) {
-    if (hasOverlay(oldPath)) {
-      _overlayContent[newPath] = _overlayContent[oldPath]!;
-      _overlayModificationStamps[newPath] =
-          _overlayModificationStamps[oldPath]!;
+    var data = _overlays[oldPath];
+    if (data != null) {
+      _overlays[newPath] = data;
     }
   }
 
   /// Return the content of the overlay of the file at the given [path], or
   /// `null` if there is no overlay for the specified file.
   String? _getOverlayContent(String path) {
-    return _overlayContent[path];
+    return _overlays[path]?.content;
   }
 
   /// Return the modification stamp of the overlay of the file at the given
   /// [path], or `null` if there is no overlay for the specified file.
   int? _getOverlayModificationStamp(String path) {
-    return _overlayModificationStamps[path];
+    return _overlays[path]?.modificationStamp;
   }
 
   /// Return `true` if there is an overlay associated with at least one file
   /// contained inside the folder with the given [folderPath].
-  bool _hasOverlayIn(String folderPath) => _overlayContent.keys
+  bool _hasOverlayIn(String folderPath) => _overlays.keys
       .any((filePath) => pathContext.isWithin(folderPath, filePath));
 
+  /// Move any overlay for the file at the [oldPath] to be an overlay for the
+  /// file with the [newPath].
+  void _moveOverlay(String oldPath, String newPath) {
+    var data = _overlays.remove(oldPath);
+    if (data != null) {
+      _overlays[newPath] = data;
+    }
+  }
+
   /// Return the paths of all of the overlaid files that are children of the
   /// given [folder], either directly or indirectly.
-  Iterable<String> _overlaysInFolder(String folderPath) => _overlayContent.keys
+  Iterable<String> _overlaysInFolder(String folderPath) => _overlays.keys
       .where((filePath) => pathContext.isWithin(folderPath, filePath));
 }
 
@@ -210,14 +209,7 @@
   @override
   File renameSync(String newPath) {
     File newFile = _file.renameSync(newPath);
-    if (provider.hasOverlay(path)) {
-      provider.setOverlay(
-        newPath,
-        content: provider._getOverlayContent(path)!,
-        modificationStamp: provider._getOverlayModificationStamp(path)!,
-      );
-      provider.removeOverlay(path);
-    }
+    provider._moveOverlay(path, newPath);
     return _OverlayFile(provider, newFile);
   }
 
@@ -235,6 +227,14 @@
   }
 }
 
+/// Overlay data for a file.
+class _OverlayFileData {
+  final String content;
+  final int modificationStamp;
+
+  _OverlayFileData(this.content, this.modificationStamp);
+}
+
 /// A folder from an [OverlayResourceProvider].
 class _OverlayFolder extends _OverlayResource implements Folder {
   /// Initialize a newly created folder to have the given [provider] and to
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index a7160e1..eed9bdc 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -82,7 +82,7 @@
 /// TODO(scheglov) Clean up the list of implicitly analyzed files.
 class AnalysisDriver implements AnalysisDriverGeneric {
   /// The version of data format, should be incremented on every format change.
-  static const int DATA_VERSION = 160;
+  static const int DATA_VERSION = 161;
 
   /// The number of exception contexts allowed to write. Once this field is
   /// zero, we stop writing any new exception contexts in this process.
diff --git a/pkg/analyzer/lib/src/dart/constant/compute.dart b/pkg/analyzer/lib/src/dart/constant/compute.dart
index b7a2d02..295c41c 100644
--- a/pkg/analyzer/lib/src/dart/constant/compute.dart
+++ b/pkg/analyzer/lib/src/dart/constant/compute.dart
@@ -78,7 +78,9 @@
 
   ConstantEvaluationEngine _getEvaluationEngine(_ConstantNode node) {
     return ConstantEvaluationEngine(
-        declaredVariables, experimentStatus.triple_shift);
+      declaredVariables: declaredVariables,
+      isNonNullableByDefault: experimentStatus.non_nullable,
+    );
   }
 
   _ConstantNode _getNode(ConstantEvaluationTarget constant) {
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 221872e..cab832a 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -67,8 +67,11 @@
     this._typeSystem,
     this._typeProvider,
     this.declaredVariables,
-  ) : _evaluationEngine = ConstantEvaluationEngine(declaredVariables,
-            _currentLibrary.featureSet.isEnabled(Feature.triple_shift));
+  ) : _evaluationEngine = ConstantEvaluationEngine(
+          declaredVariables: declaredVariables,
+          isNonNullableByDefault:
+              _currentLibrary.featureSet.isEnabled(Feature.non_nullable),
+        );
 
   bool get _isNonNullableByDefault => _currentLibrary.isNonNullableByDefault;
 
@@ -311,8 +314,8 @@
   ///        reference
   /// @param errorCode the error code to be used if the expression is or
   ///        consists of a reference to a deferred library
-  void _reportErrorIfFromDeferredLibrary(Expression expression,
-      ErrorCode errorCode,
+  void _reportErrorIfFromDeferredLibrary(
+      Expression expression, ErrorCode errorCode,
       [List<Object?>? arguments, List<DiagnosticMessage>? messages]) {
     DeferredLibraryReferenceDetector referenceDetector =
         DeferredLibraryReferenceDetector();
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 17fe297..b644c74 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -58,16 +58,18 @@
   /// The set of variables declared on the command line using '-D'.
   final DeclaredVariables _declaredVariables;
 
-  /// Whether the `triple_shift` experiment is enabled.
-  final bool _isTripleShiftExperimentEnabled;
+  /// Whether the `non-nullable` feature is enabled.
+  final bool _isNonNullableByDefault;
 
   /// Initialize a newly created [ConstantEvaluationEngine].
   ///
   /// [declaredVariables] is the set of variables declared on the command
   /// line using '-D'.
-  ConstantEvaluationEngine(
-      DeclaredVariables declaredVariables, this._isTripleShiftExperimentEnabled)
-      : _declaredVariables = declaredVariables;
+  ConstantEvaluationEngine({
+    required DeclaredVariables declaredVariables,
+    required bool isNonNullableByDefault,
+  })  : _declaredVariables = declaredVariables,
+        _isNonNullableByDefault = isNonNullableByDefault;
 
   /// Check that the arguments to a call to fromEnvironment() are correct. The
   /// [arguments] are the AST nodes of the arguments. The [argumentValues] are
@@ -134,11 +136,10 @@
     if (name == null) {
       return false;
     }
-    // TODO(srawlins): If the argument is '>>>' but triple-shift is not enabled,
-    // report a different error indicating that the triple-shift experiment
-    // should be enabled, or a minimum SDK version set, when one is declared.
-    return isValidPublicSymbol(name) ||
-        (_isTripleShiftExperimentEnabled && name == '>>>');
+    if (_isNonNullableByDefault) {
+      return true;
+    }
+    return isValidPublicSymbol(name);
   }
 
   /// Compute the constant value associated with the given [constant].
diff --git a/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart b/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart
index 022dc2b..d4321c6 100644
--- a/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart
+++ b/pkg/analyzer/lib/src/dart/constant/from_environment_evaluator.dart
@@ -43,11 +43,8 @@
       );
     }
 
-    if (namedValues.containsKey(_defaultValue)) {
-      return namedValues[_defaultValue]!;
-    }
-
-    return _defaultValueDefaultValue(constructor);
+    var defaultValue = namedValues[_defaultValue];
+    return defaultValue ?? _defaultValueDefaultValue(constructor);
   }
 
   /// Return the value of the variable with the given [name] interpreted as an
@@ -74,8 +71,9 @@
       }
     }
 
-    if (namedValues.containsKey(_defaultValue)) {
-      return namedValues[_defaultValue]!;
+    var defaultValue = namedValues[_defaultValue];
+    if (defaultValue != null) {
+      return defaultValue;
     }
 
     var defaultDefault = _defaultValueDefaultValue(constructor);
@@ -111,8 +109,9 @@
       );
     }
 
-    if (namedValues.containsKey(_defaultValue)) {
-      return namedValues[_defaultValue]!;
+    var defaultValue = namedValues[_defaultValue];
+    if (defaultValue != null) {
+      return defaultValue;
     }
 
     var defaultDefault = _defaultValueDefaultValue(constructor);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index a6a03a6..4f7c6a5 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -3014,7 +3014,7 @@
   }
 
   @override
-  String get identifier => exportedLibrary!.name ?? 'unknown';
+  String get identifier => exportedLibrary!.name;
 
   @override
   ElementKind get kind => ElementKind.EXPORT;
@@ -3912,6 +3912,9 @@
   }
 
   @override
+  String get name => super.name!;
+
+  @override
   List<CompilationUnitElement> get parts => _parts;
 
   /// Set the compilation units that are included in this library using a `part`
diff --git a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
index 41413ee..4f6246e 100644
--- a/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
+++ b/pkg/analyzer/lib/src/dart/element/inheritance_manager3.dart
@@ -187,16 +187,17 @@
   /// corresponding name will not be included.
   Map<Name, ExecutableElement> getInheritedMap2(ClassElement element) {
     var interface = getInterface(element);
-    if (interface._inheritedMap == null) {
-      interface._inheritedMap = {};
+    var inheritedMap = interface._inheritedMap;
+    if (inheritedMap == null) {
+      inheritedMap = interface._inheritedMap = {};
       _findMostSpecificFromNamedCandidates(
         element,
-        interface._inheritedMap!,
+        inheritedMap,
         interface._overridden,
         doTopMerge: false,
       );
     }
-    return interface._inheritedMap!;
+    return inheritedMap;
   }
 
   /// Return the interface of the given [element].  It might include
@@ -388,26 +389,6 @@
       Name name, List<ExecutableElement> candidates) {
     assert(candidates.length > 1);
 
-    bool allGetters = true;
-    bool allMethods = true;
-    bool allSetters = true;
-    for (var candidate in candidates) {
-      var kind = candidate.kind;
-      if (kind != ElementKind.GETTER) {
-        allGetters = false;
-      }
-      if (kind != ElementKind.METHOD) {
-        allMethods = false;
-      }
-      if (kind != ElementKind.SETTER) {
-        allSetters = false;
-      }
-    }
-
-    if (allGetters || allMethods || allSetters) {
-      return null;
-    }
-
     ExecutableElement? getter;
     ExecutableElement? method;
     for (var candidate in candidates) {
@@ -419,7 +400,10 @@
         method ??= candidate;
       }
     }
-    return GetterMethodConflict(name: name, getter: getter!, method: method!);
+
+    if (getter != null && method != null) {
+      return GetterMethodConflict(name: name, getter: getter, method: method);
+    }
   }
 
   /// The given [namedCandidates] maps names to candidates from direct
@@ -515,9 +499,10 @@
       // And there are individual override conflicts for each mixin.
       var candidatesFromSuperAndMixin = <Name, List<ExecutableElement>>{};
       var mixinConflicts = <Conflict>[];
-      for (var name in mixinInterface.map.keys) {
+      for (var entry in mixinInterface.map.entries) {
+        var name = entry.key;
         var candidate = ExecutableMember.from2(
-          mixinInterface.map[name]!,
+          entry.value,
           substitution,
         );
 
@@ -743,18 +728,11 @@
       return first;
     }
 
-    FunctionType? resultType;
-    for (var executable in validOverrides) {
-      var type = executable.type;
-      var normalizedType = typeSystem.normalize(type) as FunctionType;
-      if (resultType == null) {
-        resultType = normalizedType;
-      } else {
-        resultType =
-            typeSystem.topMerge(resultType, normalizedType) as FunctionType;
-      }
-    }
-    resultType!;
+    var resultType = validOverrides.map((e) {
+      return typeSystem.normalize(e.type) as FunctionType;
+    }).reduce((previous, next) {
+      return typeSystem.topMerge(previous, next) as FunctionType;
+    });
 
     for (var executable in validOverrides) {
       if (executable.type == resultType) {
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
index ef53b2c..83141a8 100644
--- a/pkg/analyzer/lib/src/dart/error/ffi_code.dart
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
@@ -31,6 +31,16 @@
       correction: "Try replacing the value with a literal or const.");
 
   /**
+   * No parameters.
+   */
+  static const FfiCode CREATION_OF_STRUCT_OR_UNION = FfiCode(
+    name: 'CREATION_OF_STRUCT_OR_UNION',
+    message: "Subclasses of 'Struct' and 'Union' are backed by native memory, "
+        "and can't be instantiated by a generative constructor.",
+    correction: "Try allocating it via allocation, or load from a 'Pointer'.",
+  );
+
+  /**
    * Parameters:
    * 0: the name of the struct class
    */
@@ -225,9 +235,9 @@
    * No parameters.
    */
   static const FfiCode NON_POSITIVE_ARRAY_DIMENSION = FfiCode(
-    name: 'NON_POSITIVE_INPUT_ON_ARRAY',
-    message: "Array dimensions must be positive numbers.",
-    correction: "Try changing the input to a positive number.");
+      name: 'NON_POSITIVE_INPUT_ON_ARRAY',
+      message: "Array dimensions must be positive numbers.",
+      correction: "Try changing the input to a positive number.");
 
   /**
    * Parameters:
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index fecdee1..f17f0d2 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -113,8 +113,9 @@
     );
     var result = expression.accept(ConstantVisitor(
         ConstantEvaluationEngine(
-          DeclaredVariables(),
-          _library.featureSet.isEnabled(Feature.triple_shift),
+          declaredVariables: DeclaredVariables(),
+          isNonNullableByDefault:
+              _library.featureSet.isEnabled(Feature.non_nullable),
         ),
         _library,
         errorReporter));
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
index d03a815..4dbed55 100644
--- a/pkg/analyzer/lib/src/generated/ffi_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -180,6 +180,20 @@
   }
 
   @override
+  void visitInstanceCreationExpression(InstanceCreationExpression node) {
+    var constructor = node.constructorName.staticElement;
+    var class_ = constructor?.enclosingElement;
+    if (class_.isStructSubclass || class_.isUnionSubclass) {
+      _errorReporter.reportErrorForNode(
+        FfiCode.CREATION_OF_STRUCT_OR_UNION,
+        node.constructorName,
+      );
+    }
+
+    super.visitInstanceCreationExpression(node);
+  }
+
+  @override
   void visitMethodInvocation(MethodInvocation node) {
     var element = node.methodName.staticElement;
     if (element is MethodElement) {
@@ -1041,6 +1055,34 @@
         element.isFfiClass;
   }
 
+  /// Return `true` if this represents the class `Struct`.
+  bool get isStruct {
+    final element = this;
+    return element is ClassElement &&
+        element.name == 'Struct' &&
+        element.isFfiClass;
+  }
+
+  /// Return `true` if this represents a subclass of the class `Struct`.
+  bool get isStructSubclass {
+    final element = this;
+    return element is ClassElement && element.supertype.isStruct;
+  }
+
+  /// Return `true` if this represents the class `Union`.
+  bool get isUnion {
+    final element = this;
+    return element is ClassElement &&
+        element.name == 'Union' &&
+        element.isFfiClass;
+  }
+
+  /// Return `true` if this represents a subclass of the class `Struct`.
+  bool get isUnionSubclass {
+    final element = this;
+    return element is ClassElement && element.supertype.isUnion;
+  }
+
   /// If this is a class element from `dart:ffi`, return it.
   ClassElement? get ffiClass {
     var element = this;
@@ -1095,6 +1137,18 @@
   }
 }
 
+extension on DartType? {
+  bool get isStruct {
+    final self = this;
+    return self is InterfaceType && self.element.isStruct;
+  }
+
+  bool get isUnion {
+    final self = this;
+    return self is InterfaceType && self.element.isUnion;
+  }
+}
+
 extension on DartType {
   /// Return `true` if this represents the class `Array`.
   bool get isArray {
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index 0fb77cf..2eaeac7 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -371,7 +371,9 @@
 
     var visitor = ConstantVisitor(
       ConstantEvaluationEngine(
-          declaredVariables, isEnabled(Feature.triple_shift)),
+        declaredVariables: declaredVariables,
+        isNonNullableByDefault: isEnabled(Feature.non_nullable),
+      ),
       libraryElement,
       errorReporter,
     );
diff --git a/pkg/analyzer/lib/src/summary2/bundle_writer.dart b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
index 9b3bb27..528b9d2 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_writer.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_writer.dart
@@ -99,7 +99,7 @@
     _classMembersLengths = <int>[];
 
     _sink.writeUInt30(_resolutionSink.offset);
-    _sink._writeStringReference(libraryElement.name!);
+    _sink._writeStringReference(libraryElement.name);
     _writeFeatureSet(libraryElement.featureSet);
     _writeLanguageVersion(libraryElement.languageVersion);
     _resolutionSink._writeAnnotationList(libraryElement.metadata);
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 430201e..40ba0f8 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -1232,8 +1232,9 @@
     DartObjectImpl? result = expression.accept(
       ConstantVisitor(
         ConstantEvaluationEngine(
-          DeclaredVariables.fromMap(declaredVariables),
-          unit.featureSet.isEnabled(Feature.triple_shift),
+          declaredVariables: DeclaredVariables.fromMap(declaredVariables),
+          isNonNullableByDefault:
+              unit.featureSet.isEnabled(Feature.non_nullable),
         ),
         this.result.libraryElement as LibraryElementImpl,
         errorReporter,
diff --git a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
index 926a7b6..077c88d 100644
--- a/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/const_eval_throws_exception_test.dart
@@ -337,14 +337,6 @@
     ]);
   }
 
-  test_symbolConstructor_badStringArgument() async {
-    await assertErrorsInCode(r'''
-var s1 = const Symbol('3');
-''', [
-      error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 9, 17),
-    ]);
-  }
-
   test_symbolConstructor_nonStringArgument() async {
     await assertErrorsInCode(r'''
 var s2 = const Symbol(3);
@@ -354,6 +346,24 @@
     ]);
   }
 
+  test_symbolConstructor_string_digit() async {
+    var expectedErrors = expectedErrorsByNullability(nullable: [], legacy: [
+      error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 8, 17),
+    ]);
+    await assertErrorsInCode(r'''
+var s = const Symbol('3');
+''', expectedErrors);
+  }
+
+  test_symbolConstructor_string_underscore() async {
+    var expectedErrors = expectedErrorsByNullability(nullable: [], legacy: [
+      error(CompileTimeErrorCode.CONST_EVAL_THROWS_EXCEPTION, 8, 17),
+    ]);
+    await assertErrorsInCode(r'''
+var s = const Symbol('_');
+''', expectedErrors);
+  }
+
   test_unaryBitNot_null() async {
     await assertErrorsInCode('''
 const dynamic D = null;
diff --git a/pkg/analyzer/test/src/diagnostics/creation_of_struct_or_union_test.dart b/pkg/analyzer/test/src/diagnostics/creation_of_struct_or_union_test.dart
new file mode 100644
index 0000000..94758d6
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/creation_of_struct_or_union_test.dart
@@ -0,0 +1,51 @@
+// 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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/context_collection_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(CreationOfStructOrUnionTest);
+  });
+}
+
+@reflectiveTest
+class CreationOfStructOrUnionTest extends PubPackageResolutionTest {
+  test_struct() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+
+class A extends Struct {
+  @Int32()
+  external int a;
+}
+
+void f() {
+  A();
+}
+''', [
+      error(FfiCode.CREATION_OF_STRUCT_OR_UNION, 90, 1),
+    ]);
+  }
+
+  test_union() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+
+class A extends Union {
+  @Int32()
+  external int a;
+}
+
+void f() {
+  A();
+}
+''', [
+      error(FfiCode.CREATION_OF_STRUCT_OR_UNION, 89, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 8af03ed..7ec87d4 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -110,6 +110,7 @@
 import 'const_with_undefined_constructor_test.dart'
     as const_with_undefined_constructor;
 import 'could_not_infer_test.dart' as could_not_infer;
+import 'creation_of_struct_or_union_test.dart' as creation_of_struct_or_union;
 import 'dead_code_test.dart' as dead_code;
 import 'dead_null_aware_expression_test.dart' as dead_null_aware_expression;
 import 'default_list_constructor_test.dart' as default_list_constructor;
@@ -783,6 +784,7 @@
     const_with_type_parameters.main();
     const_with_undefined_constructor.main();
     could_not_infer.main();
+    creation_of_struct_or_union.main();
     dead_code.main();
     dead_null_aware_expression.main();
     default_list_constructor.main();
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 4489693..4243b45 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -133,7 +133,7 @@
     _writelnWithIndent('library');
     _withIndent(() {
       var name = e.name;
-      if (name != null && name.isNotEmpty) {
+      if (name.isNotEmpty) {
         _writelnWithIndent('name: $name');
       }
 
diff --git a/pkg/analyzer/test/src/utilities/extensions/collection_test.dart b/pkg/analyzer/test/src/utilities/extensions/collection_test.dart
new file mode 100644
index 0000000..ea9231f
--- /dev/null
+++ b/pkg/analyzer/test/src/utilities/extensions/collection_test.dart
@@ -0,0 +1,28 @@
+// 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.
+
+import 'package:analyzer/src/utilities/extensions/collection.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ListExtensionTest);
+  });
+}
+
+@reflectiveTest
+class ListExtensionTest {
+  test_addIfNotNull_notNull() {
+    var elements = [0, 1];
+    elements.addIfNotNull(2);
+    expect(elements, [0, 1, 2]);
+  }
+
+  test_addIfNotNull_null() {
+    var elements = [0, 1];
+    elements.addIfNotNull(null);
+    expect(elements, [0, 1]);
+  }
+}
diff --git a/pkg/analyzer/test/src/utilities/extensions/test_all.dart b/pkg/analyzer/test/src/utilities/extensions/test_all.dart
index 8cb2105..e8928d7 100644
--- a/pkg/analyzer/test/src/utilities/extensions/test_all.dart
+++ b/pkg/analyzer/test/src/utilities/extensions/test_all.dart
@@ -4,10 +4,12 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'collection_test.dart' as collection;
 import 'string_test.dart' as string;
 
 main() {
   defineReflectiveSuite(() {
+    collection.main();
     string.main();
   }, name: 'extensions');
 }
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 3bd5de9..c11ced8 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -2396,7 +2396,9 @@
       var memberLibrary = member?.name?.library ??
           memberClass?.enclosingLibrary ??
           _currentLibrary;
-      // TODO(nshahan) Record the name for this member in memberNames.
+      // Wrap the name as a symbol here so it matches what you would find at
+      // runtime when you get all properties and symbols from an instance.
+      memberNames[member] = 'Symbol($name)';
       return getSymbol(emitPrivateNameSymbol(memberLibrary, name));
     }
 
diff --git a/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart b/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
index aacf754..ee907ce 100644
--- a/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
+++ b/pkg/dev_compiler/test/module_symbols/class_symbols_test.dart
@@ -265,7 +265,7 @@
           ${options.dartLangComment}
 
           class A {
-            String privateInstanceField = 'Cello';
+            String _privateInstanceField = 'Cello';
           }
           ''';
         setUpAll(() async {
@@ -279,7 +279,7 @@
           driver.cleanUp();
         });
         test('fieldId in classSymbol', () async {
-          expect(fieldId, endsWith('A|privateInstanceField'));
+          expect(fieldId, endsWith('A|Symbol(_privateInstanceField)'));
           expect(fieldId, fieldSymbol.id);
         });
         test('has class scopeId', () async {
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index fa2b398..4985f7d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -712,8 +712,7 @@
   TreeNode visitInstantiation(Instantiation node, TreeNode? removalSentinel) {
     Instantiation result =
         super.visitInstantiation(node, removalSentinel) as Instantiation;
-    if (enableConstructorTearOff &&
-        result.expression is ConstantExpression &&
+    if (result.expression is ConstantExpression &&
         result.typeArguments.every(isInstantiated)) {
       return evaluateAndTransformWithContext(node, result);
     }
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
index 955feff..f60235a 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart
@@ -2,15 +2,6 @@
 // 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=2.13
-
-// This test is similar to
-//
-//   constructor_tearoffs/identical_instantiated_function_tearoffs.dart
-//
-// but verifies that before the constructor-tearoffs experiment was enabled,
-// instantiations in non-constant context were not canonicalized.
-
 T id<T>(T t) => t;
 
 int Function(int) implicitInstantiation = id;
@@ -20,10 +11,10 @@
 
 main() {
   expect(true, identical(implicitInstantiation, implicitInstantiation));
-  expect(false, identical(implicitInstantiation, implicitConstInstantiation));
+  expect(true, identical(implicitInstantiation, implicitConstInstantiation));
   expect(false, identical(implicitInstantiation, create<int>()));
 
-  expect(false, identical(implicitConstInstantiation, implicitInstantiation));
+  expect(true, identical(implicitConstInstantiation, implicitInstantiation));
   expect(
       true, identical(implicitConstInstantiation, implicitConstInstantiation));
   expect(false, identical(implicitConstInstantiation, create<int>()));
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
index 90e26eb..42d4b37 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline.expect
@@ -1,4 +1,3 @@
-// @dart = 2.13
 T id<T>(T t) => t;
 int Function(int) implicitInstantiation = id;
 const int Function(int) implicitConstInstantiation = id;
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
index a0e9251..9a6b746 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.textual_outline_modelled.expect
@@ -1,4 +1,3 @@
-// @dart = 2.13
 T Function(T) create<T>() => id;
 T id<T>(T t) => t;
 const int Function(int) implicitConstInstantiation = id;
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
index daf6f36..2190c5f 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static field (core::int) → core::int implicitInstantiation = #C2;
 static const field (core::int) → core::int implicitConstInstantiation = #C2;
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
@@ -10,9 +10,9 @@
   return #C1<self::create::T%>;
 static method main() → dynamic {
   self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
-  self::expect(false, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
   self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
-  self::expect(false, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
   self::expect(true, core::identical(#C2, #C2));
   self::expect(false, core::identical(#C2, self::create<core::int>()));
 }
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
index 9e4506e..bf07e2b 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.outline.expect
@@ -15,5 +15,5 @@
 
 
 Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:17:54 -> InstantiationConstant(id<int*>)
+Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:8:54 -> InstantiationConstant(id<int*>)
 Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
index e0f574c..00ad1f6 100644
--- a/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/general/identical_instantiated_function_tearoffs.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
-static field (core::int) → core::int implicitInstantiation = #C1<core::int>;
+static field (core::int) → core::int implicitInstantiation = #C2;
 static const field (core::int) → core::int implicitConstInstantiation = #C2;
 static method id<T extends core::Object? = dynamic>(self::id::T% t) → self::id::T%
   return t;
@@ -10,9 +10,9 @@
   return #C1<self::create::T%>;
 static method main() → dynamic {
   self::expect(true, core::identical(self::implicitInstantiation, self::implicitInstantiation));
-  self::expect(false, core::identical(self::implicitInstantiation, #C2));
+  self::expect(true, core::identical(self::implicitInstantiation, #C2));
   self::expect(false, core::identical(self::implicitInstantiation, self::create<core::int>()));
-  self::expect(false, core::identical(#C2, self::implicitInstantiation));
+  self::expect(true, core::identical(#C2, self::implicitInstantiation));
   self::expect(true, core::identical(#C2, #C2));
   self::expect(false, core::identical(#C2, self::create<core::int>()));
 }
@@ -27,6 +27,5 @@
 }
 
 Extra constant evaluation status:
-Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:28:13 -> BoolConstant(true)
-Evaluated: Instantiation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:16:43 -> InstantiationConstant(id<int*>)
-Extra constant evaluation: evaluated: 30, effectively constant: 2
+Evaluated: StaticInvocation @ org-dartlang-testcase:///identical_instantiated_function_tearoffs.dart:19:13 -> BoolConstant(true)
+Extra constant evaluation: evaluated: 29, effectively constant: 1
diff --git a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
index 2c7b116..4c414f6 100644
--- a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.expect
@@ -104,42 +104,42 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method test() → dynamic {
-  self::takeIII(#C1<core::int*>);
-  self::takeDDD(#C1<core::double*>);
-  self::takeNNN(#C1<core::num*>);
-  self::takeIDN(#C1<core::num*>);
-  self::takeDIN(#C1<core::num*>);
-  self::takeIIN(#C1<core::int*>);
-  self::takeDDN(#C1<core::double*>);
-  self::takeIIO(#C1<core::int*>);
-  self::takeDDO(#C1<core::double*>);
-  self::takeOOI((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::int*);
+  self::takeIII(#C2);
+  self::takeDDD(#C3);
+  self::takeNNN(#C4);
+  self::takeIDN(#C4);
+  self::takeDIN(#C4);
+  self::takeIIN(#C2);
+  self::takeDDN(#C3);
+  self::takeIIO(#C2);
+  self::takeDDO(#C3);
+  self::takeOOI((#C5) as{TypeError} (core::Object*, core::Object*) →* core::int*);
   self::takeIDI(let final Never* #t1 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:28:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
-                                                                        ^" in (#C1<core::num*>) as{TypeError} (core::double*, core::int*) →* core::int*);
+                                                                        ^" in (#C4) as{TypeError} (core::double*, core::int*) →* core::int*);
   self::takeDID(let final Never* #t2 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:30:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'double Function(int, double)'.
       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
-                                                                        ^" in (#C1<core::num*>) as{TypeError} (core::int*, core::double*) →* core::double*);
-  self::takeOON((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeOOO((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeIII(#C2<core::int*>);
-  self::takeDDD(#C2<core::double*>);
-  self::takeNNN(#C2<core::num*>);
-  self::takeIDN(#C2<core::num*>);
-  self::takeDIN(#C2<core::num*>);
-  self::takeIIN(#C2<core::int*>);
-  self::takeDDN(#C2<core::double*>);
-  self::takeIIO(#C2<core::int*>);
-  self::takeDDO(#C2<core::double*>);
-  self::takeOOI((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::int*);
+                                                                        ^" in (#C4) as{TypeError} (core::int*, core::double*) →* core::double*);
+  self::takeOON((#C5) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeOOO((#C5) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeIII(#C7);
+  self::takeDDD(#C8);
+  self::takeNNN(#C9);
+  self::takeIDN(#C9);
+  self::takeDIN(#C9);
+  self::takeIIN(#C7);
+  self::takeDDN(#C8);
+  self::takeIIO(#C7);
+  self::takeDDO(#C8);
+  self::takeOOI((#C10) as{TypeError} (core::Object*, core::Object*) →* core::int*);
   self::takeIDI(let final Never* #t3 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:46:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
   takeIDI(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
-                                                                       ^" in (#C2<core::num*>) as{TypeError} (core::double*, core::int*) →* core::int*);
+                                                                       ^" in (#C9) as{TypeError} (core::double*, core::int*) →* core::int*);
   self::takeDID(let final Never* #t4 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:47:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'double Function(int, double)'.
   takeDID(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
-                                                                       ^" in (#C2<core::num*>) as{TypeError} (core::int*, core::double*) →* core::double*);
-  self::takeOON((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeOOO((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+                                                                       ^" in (#C9) as{TypeError} (core::int*, core::double*) →* core::double*);
+  self::takeOON((#C10) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeOOO((#C10) as{TypeError} (core::Object*, core::Object*) →* core::num*);
   self::takeIII(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::int*>);
   self::takeDDD(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::double*>);
   self::takeNNN(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::num*>);
@@ -177,5 +177,13 @@
 
 constants  {
   #C1 = tearoff math::max
-  #C2 = tearoff math::min
+  #C2 = partial-instantiation math::max <core::int*>
+  #C3 = partial-instantiation math::max <core::double*>
+  #C4 = partial-instantiation math::max <core::num*>
+  #C5 = partial-instantiation math::max <core::Object*>
+  #C6 = tearoff math::min
+  #C7 = partial-instantiation math::min <core::int*>
+  #C8 = partial-instantiation math::min <core::double*>
+  #C9 = partial-instantiation math::min <core::num*>
+  #C10 = partial-instantiation math::min <core::Object*>
 }
diff --git a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
index 9dc6b9b..4c414f6 100644
--- a/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart.weak.transformed.expect
@@ -104,42 +104,42 @@
   abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
 }
 static method test() → dynamic {
-  self::takeIII(#C1<core::int*>);
-  self::takeDDD(#C1<core::double*>);
-  self::takeNNN(#C1<core::num*>);
-  self::takeIDN(#C1<core::num*>);
-  self::takeDIN(#C1<core::num*>);
-  self::takeIIN(#C1<core::int*>);
-  self::takeDDN(#C1<core::double*>);
-  self::takeIIO(#C1<core::int*>);
-  self::takeDDO(#C1<core::double*>);
-  self::takeOOI((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::int*);
+  self::takeIII(#C2);
+  self::takeDDD(#C3);
+  self::takeNNN(#C4);
+  self::takeIDN(#C4);
+  self::takeDIN(#C4);
+  self::takeIIN(#C2);
+  self::takeDDN(#C3);
+  self::takeIIO(#C2);
+  self::takeDDO(#C3);
+  self::takeOOI((#C5) as{TypeError} (core::Object*, core::Object*) →* core::int*);
   self::takeIDI(let final Never* #t1 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:28:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
-                                                                        ^" in (#C1<core::num*>) as{TypeError} (core::double*, core::int*) →* core::int*);
+                                                                        ^" in (#C4) as{TypeError} (core::double*, core::int*) →* core::int*);
   self::takeDID(let final Never* #t2 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:30:73: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'double Function(int, double)'.
       /*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ math.max);
-                                                                        ^" in (#C1<core::num*>) as{TypeError} (core::int*, core::double*) →* core::double*);
-  self::takeOON((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeOOO((#C1<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeIII(#C2<core::int*>);
-  self::takeDDD(#C2<core::double*>);
-  self::takeNNN(#C2<core::num*>);
-  self::takeIDN(#C2<core::num*>);
-  self::takeDIN(#C2<core::num*>);
-  self::takeIIN(#C2<core::int*>);
-  self::takeDDN(#C2<core::double*>);
-  self::takeIIO(#C2<core::int*>);
-  self::takeDDO(#C2<core::double*>);
-  self::takeOOI((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::int*);
+                                                                        ^" in (#C4) as{TypeError} (core::int*, core::double*) →* core::double*);
+  self::takeOON((#C5) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeOOO((#C5) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeIII(#C7);
+  self::takeDDD(#C8);
+  self::takeNNN(#C9);
+  self::takeIDN(#C9);
+  self::takeDIN(#C9);
+  self::takeIIN(#C7);
+  self::takeDDN(#C8);
+  self::takeIIO(#C7);
+  self::takeDDO(#C8);
+  self::takeOOI((#C10) as{TypeError} (core::Object*, core::Object*) →* core::int*);
   self::takeIDI(let final Never* #t3 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:46:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'int Function(double, int)'.
   takeIDI(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
-                                                                       ^" in (#C2<core::num*>) as{TypeError} (core::double*, core::int*) →* core::int*);
+                                                                       ^" in (#C9) as{TypeError} (core::double*, core::int*) →* core::int*);
   self::takeDID(let final Never* #t4 = invalid-expression "pkg/front_end/testcases/inference/generic_methods_infer_generic_instantiation.dart:47:72: Error: The argument type 'num Function(num, num)' can't be assigned to the parameter type 'double Function(int, double)'.
   takeDID(/*error:COULD_NOT_INFER,error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/ min);
-                                                                       ^" in (#C2<core::num*>) as{TypeError} (core::int*, core::double*) →* core::double*);
-  self::takeOON((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
-  self::takeOOO((#C2<core::Object*>) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+                                                                       ^" in (#C9) as{TypeError} (core::int*, core::double*) →* core::double*);
+  self::takeOON((#C10) as{TypeError} (core::Object*, core::Object*) →* core::num*);
+  self::takeOOO((#C10) as{TypeError} (core::Object*, core::Object*) →* core::num*);
   self::takeIII(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::int*>);
   self::takeDDD(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::double*>);
   self::takeNNN(new self::C::•().{self::C::m}{<T extends core::num*>(T*, T*) →* T*}<core::num*>);
@@ -177,36 +177,13 @@
 
 constants  {
   #C1 = tearoff math::max
-  #C2 = tearoff math::min
+  #C2 = partial-instantiation math::max <core::int*>
+  #C3 = partial-instantiation math::max <core::double*>
+  #C4 = partial-instantiation math::max <core::num*>
+  #C5 = partial-instantiation math::max <core::Object*>
+  #C6 = tearoff math::min
+  #C7 = partial-instantiation math::min <core::int*>
+  #C8 = partial-instantiation math::min <core::double*>
+  #C9 = partial-instantiation math::min <core::num*>
+  #C10 = partial-instantiation math::min <core::Object*>
 }
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:16:16 -> InstantiationConstant(max<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:17:16 -> InstantiationConstant(max<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:18:16 -> InstantiationConstant(max<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:19:16 -> InstantiationConstant(max<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:20:16 -> InstantiationConstant(max<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:21:16 -> InstantiationConstant(max<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:22:16 -> InstantiationConstant(max<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:23:16 -> InstantiationConstant(max<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:24:16 -> InstantiationConstant(max<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:26:70 -> InstantiationConstant(max<Object*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:28:73 -> InstantiationConstant(max<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:30:73 -> InstantiationConstant(max<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:31:70 -> InstantiationConstant(max<Object*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:32:70 -> InstantiationConstant(max<Object*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:35:11 -> InstantiationConstant(min<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:36:11 -> InstantiationConstant(min<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:37:11 -> InstantiationConstant(min<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:38:11 -> InstantiationConstant(min<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:39:11 -> InstantiationConstant(min<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:40:11 -> InstantiationConstant(min<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:41:11 -> InstantiationConstant(min<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:42:11 -> InstantiationConstant(min<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:43:11 -> InstantiationConstant(min<double*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:45:65 -> InstantiationConstant(min<Object*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:46:72 -> InstantiationConstant(min<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:47:72 -> InstantiationConstant(min<num*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:48:65 -> InstantiationConstant(min<Object*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_infer_generic_instantiation.dart:49:65 -> InstantiationConstant(min<Object*>)
-Extra constant evaluation: evaluated: 133, effectively constant: 28
diff --git a/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.expect b/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.expect
index 34108a8..a4f335a 100644
--- a/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.expect
@@ -39,10 +39,11 @@
 static method main() → dynamic {
   core::List<self::Trace*>* traces = <self::Trace*>[];
   core::int* longest = traces.{core::Iterable::map}<core::int*>((self::Trace* trace) → core::int* {
-    return trace.{self::Trace::frames}{core::List<self::Frame*>*}.{core::Iterable::map}<core::int*>((self::Frame* frame) → core::int* => frame.{self::Frame::location}{core::String*}.{core::String::length}{core::int*}){((self::Frame*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C1<core::int*>){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
-  }){((self::Trace*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C1<core::int*>){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
+    return trace.{self::Trace::frames}{core::List<self::Frame*>*}.{core::Iterable::map}<core::int*>((self::Frame* frame) → core::int* => frame.{self::Frame::location}{core::String*}.{core::String::length}{core::int*}){((self::Frame*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C2){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
+  }){((self::Trace*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C2){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
 }
 
 constants  {
   #C1 = tearoff math::max
+  #C2 = partial-instantiation math::max <core::int*>
 }
diff --git a/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.transformed.expect
index 8af73b0..712cd8d 100644
--- a/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/generic_methods_nested_generic_instantiation.dart.weak.transformed.expect
@@ -39,15 +39,11 @@
 static method main() → dynamic {
   core::List<self::Trace*>* traces = core::_GrowableList::•<self::Trace*>(0);
   core::int* longest = traces.{core::Iterable::map}<core::int*>((self::Trace* trace) → core::int* {
-    return trace.{self::Trace::frames}{core::List<self::Frame*>*}.{core::Iterable::map}<core::int*>((self::Frame* frame) → core::int* => frame.{self::Frame::location}{core::String*}.{core::String::length}{core::int*}){((self::Frame*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C1<core::int*>){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
-  }){((self::Trace*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C1<core::int*>){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
+    return trace.{self::Trace::frames}{core::List<self::Frame*>*}.{core::Iterable::map}<core::int*>((self::Frame* frame) → core::int* => frame.{self::Frame::location}{core::String*}.{core::String::length}{core::int*}){((self::Frame*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C2){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
+  }){((self::Trace*) →* core::int*) →* core::Iterable<core::int*>*}.{core::Iterable::fold}<core::int*>(0, #C2){(core::int*, (core::int*, core::int*) →* core::int*) →* core::int*};
 }
 
 constants  {
   #C1 = tearoff math::max
+  #C2 = partial-instantiation math::max <core::int*>
 }
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_nested_generic_instantiation.dart:28:71 -> InstantiationConstant(max<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///generic_methods_nested_generic_instantiation.dart:29:67 -> InstantiationConstant(max<int*>)
-Extra constant evaluation: evaluated: 16, effectively constant: 2
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.expect b/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.expect
index 41e2e41..060082e 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.expect
@@ -36,14 +36,16 @@
   function h<T extends core::Object* = dynamic>(T* x) → T*
     return x;
   (core::int*) →* core::int* func;
-  func = #C1<core::int*>;
+  func = #C2;
   func = new self::C::•().{self::C::f}{<T extends core::Object* = dynamic>(T*) →* T*}<core::int*>;
-  func = #C2<core::int*>;
+  func = #C4;
   func = h<core::int*>;
 }
 static method main() → dynamic {}
 
 constants  {
   #C1 = tearoff self::f
-  #C2 = tearoff self::C::g
+  #C2 = partial-instantiation self::f <core::int*>
+  #C3 = tearoff self::C::g
+  #C4 = partial-instantiation self::C::g <core::int*>
 }
diff --git a/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.transformed.expect b/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.transformed.expect
index 4c5080b..060082e 100644
--- a/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/inference/instantiate_tearoff.dart.weak.transformed.expect
@@ -36,19 +36,16 @@
   function h<T extends core::Object* = dynamic>(T* x) → T*
     return x;
   (core::int*) →* core::int* func;
-  func = #C1<core::int*>;
+  func = #C2;
   func = new self::C::•().{self::C::f}{<T extends core::Object* = dynamic>(T*) →* T*}<core::int*>;
-  func = #C2<core::int*>;
+  func = #C4;
   func = h<core::int*>;
 }
 static method main() → dynamic {}
 
 constants  {
   #C1 = tearoff self::f
-  #C2 = tearoff self::C::g
+  #C2 = partial-instantiation self::f <core::int*>
+  #C3 = tearoff self::C::g
+  #C4 = partial-instantiation self::C::g <core::int*>
 }
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///instantiate_tearoff.dart:25:10 -> InstantiationConstant(f<int*>)
-Evaluated: Instantiation @ org-dartlang-testcase:///instantiate_tearoff.dart:27:12 -> InstantiationConstant(C.g<int*>)
-Extra constant evaluation: evaluated: 18, effectively constant: 2
diff --git a/pkg/front_end/testcases/nnbd/issue42433.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue42433.dart.strong.expect
index 2d7f2f7..ca3b3bf 100644
--- a/pkg/front_end/testcases/nnbd/issue42433.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/issue42433.dart.strong.expect
@@ -10,9 +10,10 @@
 }
 static method checkme<T extends self::X>(self::checkme::T? t) → dynamic {}
 static method main() → dynamic {
-  (self::X?) → dynamic t2 = #C1<self::X>;
+  (self::X?) → dynamic t2 = #C2;
 }
 
 constants  {
   #C1 = tearoff self::checkme
+  #C2 = partial-instantiation self::checkme <self::X>
 }
diff --git a/pkg/front_end/testcases/nnbd/issue42433.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue42433.dart.strong.transformed.expect
index 62a035b..ca3b3bf 100644
--- a/pkg/front_end/testcases/nnbd/issue42433.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue42433.dart.strong.transformed.expect
@@ -10,13 +10,10 @@
 }
 static method checkme<T extends self::X>(self::checkme::T? t) → dynamic {}
 static method main() → dynamic {
-  (self::X?) → dynamic t2 = #C1<self::X>;
+  (self::X?) → dynamic t2 = #C2;
 }
 
 constants  {
   #C1 = tearoff self::checkme
+  #C2 = partial-instantiation self::checkme <self::X>
 }
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///issue42433.dart:11:16 -> InstantiationConstant(checkme<X>)
-Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/pkg/front_end/testcases/nnbd/issue42433.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue42433.dart.weak.expect
index 2d7f2f7..d2dd558 100644
--- a/pkg/front_end/testcases/nnbd/issue42433.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/issue42433.dart.weak.expect
@@ -10,9 +10,10 @@
 }
 static method checkme<T extends self::X>(self::checkme::T? t) → dynamic {}
 static method main() → dynamic {
-  (self::X?) → dynamic t2 = #C1<self::X>;
+  (self::X?) → dynamic t2 = #C2;
 }
 
 constants  {
   #C1 = tearoff self::checkme
+  #C2 = partial-instantiation self::checkme <self::X*>
 }
diff --git a/pkg/front_end/testcases/nnbd/issue42433.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue42433.dart.weak.transformed.expect
index 0fd30a8..d2dd558 100644
--- a/pkg/front_end/testcases/nnbd/issue42433.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/issue42433.dart.weak.transformed.expect
@@ -10,13 +10,10 @@
 }
 static method checkme<T extends self::X>(self::checkme::T? t) → dynamic {}
 static method main() → dynamic {
-  (self::X?) → dynamic t2 = #C1<self::X>;
+  (self::X?) → dynamic t2 = #C2;
 }
 
 constants  {
   #C1 = tearoff self::checkme
+  #C2 = partial-instantiation self::checkme <self::X*>
 }
-
-Extra constant evaluation status:
-Evaluated: Instantiation @ org-dartlang-testcase:///issue42433.dart:11:16 -> InstantiationConstant(checkme<X*>)
-Extra constant evaluation: evaluated: 1, effectively constant: 1
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 6705857..c5043c4 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -96,7 +96,9 @@
 static InstancePtr CreateParameterMirrorList(const Function& func,
                                              const FunctionType& signature,
                                              const Instance& owner_mirror) {
-  HANDLESCOPE(Thread::Current());
+  Thread* const T = Thread::Current();
+  Zone* const Z = T->zone();
+  HANDLESCOPE(T);
   const intptr_t implicit_param_count = signature.num_implicit_parameters();
   const intptr_t non_implicit_param_count =
       signature.NumParameters() - implicit_param_count;
@@ -104,15 +106,15 @@
       non_implicit_param_count - signature.NumOptionalParameters();
   const intptr_t index_of_first_named_param =
       non_implicit_param_count - signature.NumOptionalNamedParameters();
-  const Array& results = Array::Handle(Array::New(non_implicit_param_count));
-  const Array& args = Array::Handle(Array::New(9));
+  const Array& results = Array::Handle(Z, Array::New(non_implicit_param_count));
+  const Array& args = Array::Handle(Z, Array::New(9));
 
-  Smi& pos = Smi::Handle();
-  String& name = String::Handle();
-  Instance& param = Instance::Handle();
-  Bool& is_final = Bool::Handle();
-  Object& default_value = Object::Handle();
-  Object& metadata = Object::Handle();
+  Smi& pos = Smi::Handle(Z);
+  String& name = String::Handle(Z);
+  Instance& param = Instance::Handle(Z);
+  Bool& is_final = Bool::Handle(Z);
+  Object& default_value = Object::Handle(Z);
+  Object& metadata = Object::Handle(Z);
 
   // We force compilation of constructors to ensure the types of initializing
   // formals have been corrected. We do not force the compilation of all types
@@ -156,10 +158,17 @@
 
   for (intptr_t i = 0; i < non_implicit_param_count; i++) {
     pos = Smi::New(i);
-    if (!func.IsNull()) {
+    if (i >= index_of_first_named_param) {
+      // Named parameters are stored in the signature.
+      name = signature.ParameterNameAt(implicit_param_count + i);
+    } else if (!func.IsNull()) {
+      // Positional parameters are stored in the function.
       name = func.ParameterNameAt(implicit_param_count + i);
     } else {
-      name = signature.ParameterNameAt(implicit_param_count + i);
+      // We were not given a function, only the type, so create placeholder
+      // names for the positional parameters.
+      const char* const placeholder = OS::SCreate(Z, ":param%" Pd "", i);
+      name = String::New(placeholder);
     }
     if (has_extra_parameter_info) {
       is_final ^= param_descriptor.At(i * Parser::kParameterEntrySize +
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 129caeb..14dacfb 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -308,6 +308,11 @@
   return Object::null();
 }
 
+DEFINE_NATIVE_ENTRY(Internal_deoptimizeFunctionsOnStack, 0, 0) {
+  DeoptimizeFunctionsOnStack();
+  return Object::null();
+}
+
 static bool ExtractInterfaceTypeArgs(Zone* zone,
                                      const Class& instance_cls,
                                      const TypeArguments& instance_type_args,
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 545a3d3..da73ef8 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -74,11 +74,6 @@
 }
 
 // Gets current stack trace for `thread`.
-// This functions itself handles the --causel-async-stacks case.
-// For --lazy-async-stacks see `CurrentSyncStackTraceLazy`.
-// For fallback see `CurrentSyncStackTrace`.
-// Extracts the causal async stack from the thread if any set, then prepends
-// the current sync. stack up until the current async function (if any).
 static StackTracePtr CurrentStackTrace(Thread* thread,
                                        bool for_async_function,
                                        intptr_t skip_frames = 1) {
diff --git a/runtime/platform/utils.cc b/runtime/platform/utils.cc
index 940e85a..1ba74f7 100644
--- a/runtime/platform/utils.cc
+++ b/runtime/platform/utils.cc
@@ -200,7 +200,7 @@
     (hash) ^= (part);                                                          \
   }
 
-uint32_t Utils::StringHash(const char* data, int length) {
+uint32_t Utils::StringHash(const void* data, int length) {
   int size = length;
   uint32_t hash = size;
 
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index a73d6d9..41054c4 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -190,39 +190,51 @@
                                               int64_t* magic,
                                               int64_t* shift);
 
-  // Computes a hash value for the given string.
-  static uint32_t StringHash(const char* data, int length);
+  // Computes a hash value for the given series of bytes.
+  static uint32_t StringHash(const void* data, int length);
 
   // Computes a hash value for the given word.
   static uint32_t WordHash(intptr_t key);
 
   // Check whether an N-bit two's-complement representation can hold value.
   template <typename T>
-  static inline bool IsInt(int N, T value) {
-    ASSERT((0 < N) &&
-           (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
-    T limit = static_cast<T>(1) << (N - 1);
+  static inline bool IsInt(intptr_t N, T value) {
+    ASSERT(N >= 1);
+    constexpr intptr_t value_size_in_bits = kBitsPerByte * sizeof(T);
+    if constexpr (std::is_signed<T>::value) {
+      if (N >= value_size_in_bits) return true;  // Trivially fits.
+    } else {
+      if (N > value_size_in_bits) return true;  // Trivially fits.
+      if (N == value_size_in_bits) {
+        return static_cast<typename std::make_signed<T>::type>(value) >= 0;
+      }
+    }
+    const T limit = static_cast<T>(1) << (N - 1);
     return (-limit <= value) && (value < limit);
   }
 
   template <typename T>
-  static inline bool IsUint(int N, T value) {
-    ASSERT((0 < N) &&
-           (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
-    const auto limit =
-        (static_cast<typename std::make_unsigned<T>::type>(1) << N) - 1;
-    return (0 <= value) &&
-           (static_cast<typename std::make_unsigned<T>::type>(value) <= limit);
+  static inline bool IsUint(intptr_t N, T value) {
+    ASSERT(N >= 1);
+    constexpr intptr_t value_size_in_bits = kBitsPerByte * sizeof(T);
+    if constexpr (std::is_signed<T>::value) {
+      if (value < 0) return false;  // Not an unsigned value.
+      if (N >= value_size_in_bits - 1) {
+        return true;  // N can fit the magnitude bits.
+      }
+    } else {
+      if (N >= value_size_in_bits) return true;  // Trivially fits.
+    }
+    const T limit = (static_cast<T>(1) << N) - 1;
+    return value <= limit;
   }
 
   // Check whether the magnitude of value fits in N bits, i.e., whether an
   // (N+1)-bit sign-magnitude representation can hold value.
   template <typename T>
-  static inline bool IsAbsoluteUint(int N, T value) {
-    ASSERT((0 < N) &&
-           (static_cast<unsigned int>(N) < (kBitsPerByte * sizeof(value))));
-    if (value < 0) value = -value;
-    return IsUint(N, value);
+  static inline bool IsAbsoluteUint(intptr_t N, T value) {
+    ASSERT(N >= 1);
+    return IsInt(N + 1, value);
   }
 
   static inline int32_t Low16Bits(int32_t value) {
diff --git a/runtime/tests/concurrency/generate_stress_test.dart b/runtime/tests/concurrency/generate_stress_test.dart
index 621329a..3870ef2 100644
--- a/runtime/tests/concurrency/generate_stress_test.dart
+++ b/runtime/tests/concurrency/generate_stress_test.dart
@@ -159,13 +159,19 @@
   final shard = int.fromEnvironment(
       'shard', defaultValue: 0);
 
+  final repeat = int.fromEnvironment(
+      'repeat', defaultValue: 1);
+
   final parallelism = int.fromEnvironment(
       'parallelism', defaultValue: 0);
 
   final filteredTests = <Test>[];
   for (int i = 0; i < tests.length; ++i) {
     if ((i % shards) == shard) {
-      filteredTests.add(tests[i]);
+      final test = tests[i];
+      for (int j = 0; j < repeat; ++j) {
+        filteredTests.add(test);
+      }
     }
   }
 
diff --git a/runtime/tests/concurrency/run_stress_test_shards.dart b/runtime/tests/concurrency/run_stress_test_shards.dart
index 4ec29cf..5b3d001 100644
--- a/runtime/tests/concurrency/run_stress_test_shards.dart
+++ b/runtime/tests/concurrency/run_stress_test_shards.dart
@@ -94,6 +94,7 @@
   for (int i = 0; i < tsanShards; ++i)
     JitTestRunner('out/ReleaseTSANX64', [
       '--disable-dart-dev',
+      '-Drepeat=4',
       '-Dshard=$i',
       '-Dshards=$tsanShards',
       '--no-sound-null-safety',
diff --git a/runtime/tests/concurrency/stress_test_list.json b/runtime/tests/concurrency/stress_test_list.json
index 68a2c00..b8f2ae6 100644
--- a/runtime/tests/concurrency/stress_test_list.json
+++ b/runtime/tests/concurrency/stress_test_list.json
@@ -2799,8 +2799,8 @@
     "../../../tests/language/vm/bitnot_int_test.dart",
     "../../../tests/language/vm/bool_check_stack_traces_test.dart",
     "../../../tests/language/vm/canonicalization_preserves_deopt_test.dart",
-    "../../../tests/language/vm/causal_async_exception_stack2_test.dart",
-    "../../../tests/language/vm/causal_async_exception_stack_test.dart",
+    "../../../tests/language/vm/lazy_async_exception_stack2_test.dart",
+    "../../../tests/language/vm/lazy_async_exception_stack_test.dart",
     "../../../tests/language/vm/checked_smi_comparison_test.dart",
     "../../../tests/language/vm/checked_smi_op_test.dart",
     "../../../tests/language/vm/clamp_37868_test.dart",
@@ -3223,7 +3223,7 @@
     "../../../tests/standalone/assert_assignable_canon_test.dart",
     "../../../tests/standalone/byte_array_view_optimized_test.dart",
     "../../../tests/standalone/bytedata_test.dart",
-    "../../../tests/standalone/causal_async_stack_test.dart",
+    "../../../tests/standalone/lazy_async_stack_test.dart",
     "../../../tests/standalone/check_class_cha_test.dart",
     "../../../tests/standalone/check_null_cha_test.dart",
     "../../../tests/standalone/constant_left_shift_test.dart",
@@ -6149,8 +6149,8 @@
     "../../../tests/language_2/vm/await_synchronous_future_test.dart",
     "../../../tests/language_2/vm/bitnot_int_test.dart",
     "../../../tests/language_2/vm/canonicalization_preserves_deopt_test.dart",
-    "../../../tests/language_2/vm/causal_async_exception_stack2_test.dart",
-    "../../../tests/language_2/vm/causal_async_exception_stack_test.dart",
+    "../../../tests/language_2/vm/lazy_async_exception_stack2_test.dart",
+    "../../../tests/language_2/vm/lazy_async_exception_stack_test.dart",
     "../../../tests/language_2/vm/checked_smi_comparison_test.dart",
     "../../../tests/language_2/vm/checked_smi_op_test.dart",
     "../../../tests/language_2/vm/clamp_37868_test.dart",
@@ -6559,7 +6559,7 @@
     "../../../tests/standalone_2/assert_assignable_canon_test.dart",
     "../../../tests/standalone_2/byte_array_view_optimized_test.dart",
     "../../../tests/standalone_2/bytedata_test.dart",
-    "../../../tests/standalone_2/causal_async_stack_test.dart",
+    "../../../tests/standalone_2/lazy_async_stack_test.dart",
     "../../../tests/standalone_2/check_class_cha_test.dart",
     "../../../tests/standalone_2/check_null_cha_test.dart",
     "../../../tests/standalone_2/constant_left_shift_test.dart",
diff --git a/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart b/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart
index e2bcd2f..7015fe0 100644
--- a/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart
+++ b/runtime/tests/vm/dart/causal_stacks/sync_async_start_pkg_test_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
-// when causal async stacks are enabled by dropping frames below a synchronous
+// when lazy async stacks are enabled by dropping frames below a synchronous
 // start to an async function.
 
 import "package:test/test.dart";
diff --git a/runtime/tests/vm/dart/isolates/regress_46539_test.dart b/runtime/tests/vm/dart/isolates/regress_46539_test.dart
new file mode 100644
index 0000000..b07d133
--- /dev/null
+++ b/runtime/tests/vm/dart/isolates/regress_46539_test.dart
@@ -0,0 +1,83 @@
+// 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=--optimization-filter=foo --enable-isolate-groups --experimental-enable-isolate-groups-jit --no-use-osr --optimization-counter-threshold=1 --deterministic
+
+// Important: This is a regression test for a concurrency issue, if this test
+// is flaky it is essentially failing!
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:_internal' show VMInternalsForTesting;
+
+import 'package:expect/expect.dart';
+
+const int isolateCount = 3;
+const int deoptIsolateId = 0;
+const int polyIsolateId = 1;
+
+final bool isAOT = Platform.executable.contains('dart_precompiled_runtime');
+
+main() async {
+  // This test will cause deoptimizations (via helper in `dart:_internal`) and
+  // does therefore not run in AOT.
+  if (isAOT) return;
+
+  final onExit = ReceivePort();
+  final onError = ReceivePort()
+    ..listen((error) {
+      print('Error: $error');
+      exitCode = 250;
+    });
+  for (int i = 0; i < isolateCount; ++i) {
+    await Isolate.spawn(isolate, i,
+        onExit: onExit.sendPort, onError: onError.sendPort);
+  }
+  final onExits = StreamIterator(onExit);
+  for (int i = 0; i < isolateCount; ++i) {
+    Expect.isTrue(await onExits.moveNext());
+  }
+  onExits.cancel();
+  onError.close();
+}
+
+final globalA = A();
+final globalB = B();
+
+isolate(int isolateId) {
+  final A a = isolateId == polyIsolateId ? globalB : globalA;
+  if (isolateId == polyIsolateId) {
+    // We start deopting after 1 second.
+    sleep(500000);
+  }
+
+  // This runs in unoptimized mode and will therefore do switchable calls.
+  final sw = Stopwatch()..start();
+  while (sw.elapsedMicroseconds < 2000000) {
+    a.foo(isolateId);
+    a.foo(isolateId);
+    a.foo(isolateId);
+    a.foo(isolateId);
+  }
+}
+
+class A {
+  @pragma('vm:never-inline')
+  foo(int isolateId) {
+    if (isolateId == deoptIsolateId) {
+      VMInternalsForTesting.deoptimizeFunctionsOnStack();
+    }
+  }
+}
+
+class B implements A {
+  @pragma('vm:never-inline')
+  foo(int isolateId) {}
+}
+
+void sleep(int us) {
+  final sw = Stopwatch()..start();
+  while (sw.elapsedMicroseconds < us);
+}
diff --git a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
index 052ddda..d8cb33f 100644
--- a/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart
@@ -117,6 +117,11 @@
     // Check that build IDs match for traces.
     Expect.isNotNull(dwarf.buildId);
     print('Dwarf build ID: "${dwarf.buildId!}"');
+    // We should never generate an all-zero build ID.
+    Expect.notEquals(dwarf.buildId, "00000000000000000000000000000000");
+    // This is a common failure case as well, when HashBitsContainer ends up
+    // hashing over seemingly empty sections.
+    Expect.notEquals(dwarf.buildId, "01000000010000000100000001000000");
     final buildId1 = buildId(dwarfTrace1);
     Expect.isFalse(buildId1.isEmpty);
     print('Trace 1 build ID: "${buildId1}"');
diff --git a/runtime/tests/vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart b/runtime/tests/vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart
index e2bcd2f..7015fe0 100644
--- a/runtime/tests/vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart
+++ b/runtime/tests/vm/dart_2/causal_stacks/sync_async_start_pkg_test_test.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // This test ensures that "pkg:stack_trace" (used by "pkg:test") doesn't break
-// when causal async stacks are enabled by dropping frames below a synchronous
+// when lazy async stacks are enabled by dropping frames below a synchronous
 // start to an async function.
 
 import "package:test/test.dart";
diff --git a/runtime/tests/vm/dart_2/isolates/regress_46539_test.dart b/runtime/tests/vm/dart_2/isolates/regress_46539_test.dart
new file mode 100644
index 0000000..b07d133
--- /dev/null
+++ b/runtime/tests/vm/dart_2/isolates/regress_46539_test.dart
@@ -0,0 +1,83 @@
+// 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=--optimization-filter=foo --enable-isolate-groups --experimental-enable-isolate-groups-jit --no-use-osr --optimization-counter-threshold=1 --deterministic
+
+// Important: This is a regression test for a concurrency issue, if this test
+// is flaky it is essentially failing!
+
+import 'dart:async';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:_internal' show VMInternalsForTesting;
+
+import 'package:expect/expect.dart';
+
+const int isolateCount = 3;
+const int deoptIsolateId = 0;
+const int polyIsolateId = 1;
+
+final bool isAOT = Platform.executable.contains('dart_precompiled_runtime');
+
+main() async {
+  // This test will cause deoptimizations (via helper in `dart:_internal`) and
+  // does therefore not run in AOT.
+  if (isAOT) return;
+
+  final onExit = ReceivePort();
+  final onError = ReceivePort()
+    ..listen((error) {
+      print('Error: $error');
+      exitCode = 250;
+    });
+  for (int i = 0; i < isolateCount; ++i) {
+    await Isolate.spawn(isolate, i,
+        onExit: onExit.sendPort, onError: onError.sendPort);
+  }
+  final onExits = StreamIterator(onExit);
+  for (int i = 0; i < isolateCount; ++i) {
+    Expect.isTrue(await onExits.moveNext());
+  }
+  onExits.cancel();
+  onError.close();
+}
+
+final globalA = A();
+final globalB = B();
+
+isolate(int isolateId) {
+  final A a = isolateId == polyIsolateId ? globalB : globalA;
+  if (isolateId == polyIsolateId) {
+    // We start deopting after 1 second.
+    sleep(500000);
+  }
+
+  // This runs in unoptimized mode and will therefore do switchable calls.
+  final sw = Stopwatch()..start();
+  while (sw.elapsedMicroseconds < 2000000) {
+    a.foo(isolateId);
+    a.foo(isolateId);
+    a.foo(isolateId);
+    a.foo(isolateId);
+  }
+}
+
+class A {
+  @pragma('vm:never-inline')
+  foo(int isolateId) {
+    if (isolateId == deoptIsolateId) {
+      VMInternalsForTesting.deoptimizeFunctionsOnStack();
+    }
+  }
+}
+
+class B implements A {
+  @pragma('vm:never-inline')
+  foo(int isolateId) {}
+}
+
+void sleep(int us) {
+  final sw = Stopwatch()..start();
+  while (sw.elapsedMicroseconds < us);
+}
diff --git a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
index 967c027..b73ef75 100644
--- a/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
+++ b/runtime/tests/vm/dart_2/use_dwarf_stack_traces_flag_test.dart
@@ -118,6 +118,11 @@
     // Check that build IDs match for traces.
     Expect.isNotNull(dwarf.buildId);
     print('Dwarf build ID: "${dwarf.buildId}"');
+    // We should never generate an all-zero build ID.
+    Expect.notEquals(dwarf.buildId, "00000000000000000000000000000000");
+    // This is a common failure case as well, when HashBitsContainer ends up
+    // hashing over seemingly empty sections.
+    Expect.notEquals(dwarf.buildId, "01000000010000000100000001000000");
     final buildId1 = buildId(dwarfTrace1);
     Expect.isFalse(buildId1.isEmpty);
     print('Trace 1 build ID: "${buildId1}"');
diff --git a/runtime/vm/bitfield.h b/runtime/vm/bitfield.h
index b982d83..f96a34e 100644
--- a/runtime/vm/bitfield.h
+++ b/runtime/vm/bitfield.h
@@ -7,10 +7,121 @@
 
 #include <type_traits>
 
+#include "platform/atomic.h"
 #include "platform/globals.h"
+#include "platform/thread_sanitizer.h"
 
 namespace dart {
 
+class AtomicBitFieldContainerBase {
+ private:
+  AtomicBitFieldContainerBase() = delete;  // Only used for std::is_base_of.
+};
+
+template <typename T>
+class AtomicBitFieldContainer : AtomicBitFieldContainerBase {
+  static_assert(sizeof(std::atomic<T>) == sizeof(T),
+                "Size of type changes when made atomic");
+
+ public:
+  using ContainedType = T;
+
+  AtomicBitFieldContainer() : field_(0) {}
+
+  operator T() const { return field_.load(std::memory_order_relaxed); }
+  T operator=(T tags) {
+    field_.store(tags, std::memory_order_relaxed);
+    return tags;
+  }
+
+  T load(std::memory_order order) const { return field_.load(order); }
+  void store(T value, std::memory_order order) { field_.store(value, order); }
+
+  bool compare_exchange_weak(T old_tags, T new_tags, std::memory_order order) {
+    return field_.compare_exchange_weak(old_tags, new_tags, order);
+  }
+
+  template <class TargetBitField,
+            std::memory_order order = std::memory_order_relaxed>
+  typename TargetBitField::Type Read() const {
+    return TargetBitField::decode(field_.load(order));
+  }
+
+  template <class TargetBitField>
+  NO_SANITIZE_THREAD typename TargetBitField::Type ReadIgnoreRace() const {
+    return TargetBitField::decode(*reinterpret_cast<const T*>(&field_));
+  }
+
+  template <class TargetBitField,
+            std::memory_order order = std::memory_order_relaxed>
+  void UpdateBool(bool value) {
+    if (value) {
+      field_.fetch_or(TargetBitField::encode(true), order);
+    } else {
+      field_.fetch_and(~TargetBitField::encode(true), order);
+    }
+  }
+
+  template <class TargetBitField>
+  void FetchOr(typename TargetBitField::Type value) {
+    field_.fetch_or(TargetBitField::encode(value), std::memory_order_relaxed);
+  }
+
+  template <class TargetBitField>
+  void Update(typename TargetBitField::Type value) {
+    T old_field = field_.load(std::memory_order_relaxed);
+    T new_field;
+    do {
+      new_field = TargetBitField::update(value, old_field);
+    } while (!field_.compare_exchange_weak(old_field, new_field,
+                                           std::memory_order_relaxed));
+  }
+
+  template <class TargetBitField>
+  void UpdateUnsynchronized(typename TargetBitField::Type value) {
+    field_.store(
+        TargetBitField::update(value, field_.load(std::memory_order_relaxed)),
+        std::memory_order_relaxed);
+  }
+
+  template <class TargetBitField>
+  typename TargetBitField::Type UpdateConditional(
+      typename TargetBitField::Type value_to_be_set,
+      typename TargetBitField::Type conditional_old_value) {
+    T old_field = field_.load(std::memory_order_relaxed);
+    while (true) {
+      // This operation is only performed if the condition is met.
+      auto old_value = TargetBitField::decode(old_field);
+      if (old_value != conditional_old_value) {
+        return old_value;
+      }
+      T new_tags = TargetBitField::update(value_to_be_set, old_field);
+      if (field_.compare_exchange_weak(old_field, new_tags,
+                                       std::memory_order_relaxed)) {
+        return value_to_be_set;
+      }
+      // [old_tags] was updated to it's current value.
+    }
+  }
+
+  template <class TargetBitField>
+  bool TryAcquire() {
+    T mask = TargetBitField::encode(true);
+    T old_field = field_.fetch_or(mask, std::memory_order_relaxed);
+    return !TargetBitField::decode(old_field);
+  }
+
+  template <class TargetBitField>
+  bool TryClear() {
+    T mask = ~TargetBitField::encode(true);
+    T old_field = field_.fetch_and(mask, std::memory_order_relaxed);
+    return TargetBitField::decode(old_field);
+  }
+
+ private:
+  std::atomic<T> field_;
+};
+
 static const uword kUwordOne = 1U;
 
 // BitField is a template for encoding and decoding a value of type T
@@ -19,7 +130,8 @@
           typename T,
           int position,
           int size = (sizeof(S) * kBitsPerByte) - position,
-          bool sign_extend = false>
+          bool sign_extend = false,
+          typename Enable = void>
 class BitField {
  public:
   typedef T Type;
@@ -86,6 +198,50 @@
   }
 };
 
+// Partial instantiations to avoid having to change BitField declarations if
+// S is decltype(field_) and the type of field_ is changed to be wrapped in an
+// AtomicBitFieldContainer.
+template <typename S, typename T, int position, int size, bool sign_extend>
+class BitField<S,
+               T,
+               position,
+               size,
+               sign_extend,
+               typename std::enable_if<
+                   std::is_base_of<AtomicBitFieldContainerBase, S>::value,
+                   void>::type> : public BitField<typename S::ContainedType,
+                                                  T,
+                                                  position,
+                                                  size,
+                                                  sign_extend> {};
+
+template <typename S, typename T, int position, int size>
+class BitField<S,
+               T,
+               position,
+               size,
+               false,
+               typename std::enable_if<
+                   std::is_base_of<AtomicBitFieldContainerBase, S>::value,
+                   void>::type>
+    : public BitField<typename S::ContainedType, T, position, size, false> {};
+
+template <typename S, typename T, int position>
+class BitField<S,
+               T,
+               position,
+               (sizeof(S) * kBitsPerByte) - position,
+               false,
+               typename std::enable_if<
+                   std::is_base_of<AtomicBitFieldContainerBase, S>::value,
+                   void>::type>
+    : public BitField<typename S::ContainedType,
+                      T,
+                      position,
+                      (sizeof(typename S::ContainedType) * kBitsPerByte) -
+                          position,
+                      false> {};
+
 }  // namespace dart
 
 #endif  // RUNTIME_VM_BITFIELD_H_
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 7eb3452..e9710df6 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -344,6 +344,7 @@
   V(Internal_allocateTwoByteString, 1)                                         \
   V(Internal_writeIntoOneByteString, 3)                                        \
   V(Internal_writeIntoTwoByteString, 3)                                        \
+  V(Internal_deoptimizeFunctionsOnStack, 0)                                    \
   V(InvocationMirror_unpackTypeArguments, 2)                                   \
   V(NoSuchMethodError_existingMethodSignature, 3)                              \
   V(WeakProperty_getKey, 1)                                                    \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index a565e55..88ccfad 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -958,7 +958,7 @@
       // Remove this finalization code?
       signature = function.signature();
       signature ^= FinalizeType(signature);
-      function.set_signature(signature);
+      function.SetSignature(signature);
     }
   }
   // Finalize function signatures and check for conflicts in super classes and
@@ -969,7 +969,7 @@
     function ^= array.At(i);
     signature = function.signature();
     signature ^= FinalizeType(signature);
-    function.set_signature(signature);
+    function.SetSignature(signature);
     if (function.IsSetterFunction() || function.IsImplicitSetterFunction()) {
       continue;
     }
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 2cb3b2d..55d5b84 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -960,6 +960,9 @@
       s->Push(func->untag()->code());
       s->Push(func->untag()->ic_data_array());
     }
+    if (kind != Snapshot::kFullAOT) {
+      NOT_IN_PRECOMPILED(s->Push(func->untag()->positional_parameter_names()));
+    }
   }
 
   void WriteAlloc(Serializer* s) {
@@ -987,6 +990,8 @@
       }
 
       if (kind != Snapshot::kFullAOT) {
+        NOT_IN_PRECOMPILED(
+            WriteCompressedField(func, positional_parameter_names));
         s->WriteTokenPosition(func->untag()->token_pos_);
         s->WriteTokenPosition(func->untag()->end_token_pos_);
         s->Write<uint32_t>(func->untag()->kernel_offset_);
@@ -1061,6 +1066,8 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
       if (kind != Snapshot::kFullAOT) {
+        func->untag()->positional_parameter_names_ =
+            static_cast<ArrayPtr>(d->ReadRef());
         func->untag()->token_pos_ = d->ReadTokenPosition();
         func->untag()->end_token_pos_ = d->ReadTokenPosition();
         func->untag()->kernel_offset_ = d->Read<uint32_t>();
@@ -3971,7 +3978,8 @@
     ASSERT_EQUAL(type->untag()->type_state_, combined >> kNullabilityBitSize);
     ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
     s->Write<uint8_t>(combined);
-    s->Write<uint32_t>(type->untag()->packed_fields_);
+    s->Write<uint32_t>(type->untag()->packed_parameter_counts_);
+    s->Write<uint16_t>(type->untag()->packed_type_parameter_counts_);
   }
 };
 #endif  // !DART_PRECOMPILED_RUNTIME
@@ -4001,7 +4009,8 @@
       const uint8_t combined = d->Read<uint8_t>();
       type->untag()->type_state_ = combined >> kNullabilityBitSize;
       type->untag()->nullability_ = combined & kNullabilityBitMask;
-      type->untag()->packed_fields_ = d->Read<uint32_t>();
+      type->untag()->packed_parameter_counts_ = d->Read<uint32_t>();
+      type->untag()->packed_type_parameter_counts_ = d->Read<uint16_t>();
     }
   }
 
@@ -6255,6 +6264,10 @@
       name = String::ToCString(thread(), lib->untag()->url());
       break;
     }
+    case kFunctionTypeCid: {
+      type = "FunctionType";
+      break;
+    };
     default:
       FATAL("Request to create artificial node for object with cid %d", cid);
   }
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 568e8fd..99d4c22 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -151,6 +151,22 @@
   static constexpr const char* kEntryPointPragma = "entry point pragma";
   // The function is a target of FFI callback.
   static constexpr const char* kFfiCallbackTarget = "ffi callback target";
+  // The signature is used in a closure function.
+  static constexpr const char* kClosureSignature = "closure signature";
+  // The signature is used in an FFI trampoline.
+  static constexpr const char* kFfiTrampolineSignature =
+      "FFI trampoline signature";
+  // The signature is used in a native function.
+  static constexpr const char* kNativeSignature = "native function signature";
+  // The signature has required named parameters.
+  static constexpr const char* kRequiredNamedParameters =
+      "signature has required named parameters";
+  // The signature is used in a function that has dynamic calls.
+  static constexpr const char* kDynamicallyCalledSignature =
+      "signature of dynamically called function";
+  // The signature is used in a function with an entry point pragma.
+  static constexpr const char* kEntryPointPragmaSignature =
+      "signature of entry point function";
 };
 
 class RetainedReasonsWriter : public ValueObject {
@@ -267,6 +283,9 @@
       if (key->IsClass()) {
         return Utils::WordHash(Class::Cast(*key).id());
       }
+      if (key->IsAbstractType()) {
+        return AbstractType::Cast(*key).Hash();
+      }
       return Utils::WordHash(key->GetClassId());
     }
 
@@ -286,6 +305,11 @@
       writer_.PrintProperty("kind",
                             UntaggedFunction::KindToCString(function.kind()));
       return;
+    } else if (obj.IsFunctionType()) {
+      writer_.PrintProperty("type", "FunctionType");
+      const auto& sig = FunctionType::Cast(obj);
+      writer_.PrintProperty("name", sig.ToCString());
+      return;
     }
     FATAL("Unexpected object %s", obj.ToCString());
   }
@@ -375,6 +399,8 @@
       sent_selectors_(),
       functions_called_dynamically_(
           HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
+      functions_with_entry_point_pragmas_(
+          HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
       seen_functions_(HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
       possibly_retained_functions_(
           HashTables::New<FunctionSet>(/*initial_capacity=*/1024)),
@@ -401,6 +427,7 @@
 Precompiler::~Precompiler() {
   // We have to call Release() in DEBUG mode.
   functions_called_dynamically_.Release();
+  functions_with_entry_point_pragmas_.Release();
   seen_functions_.Release();
   possibly_retained_functions_.Release();
   functions_to_retain_.Release();
@@ -1501,6 +1528,7 @@
 
           if (type == EntryPointPragma::kAlways ||
               type == EntryPointPragma::kCallOnly) {
+            functions_with_entry_point_pragmas_.Insert(function);
             AddFunction(function, RetainReasons::kEntryPointPragma);
           }
 
@@ -1509,6 +1537,7 @@
               function.kind() != UntaggedFunction::kConstructor &&
               !function.IsSetterFunction()) {
             function2 = function.ImplicitClosureFunction();
+            functions_with_entry_point_pragmas_.Insert(function2);
             AddFunction(function2, RetainReasons::kEntryPointPragma);
           }
 
@@ -1521,6 +1550,7 @@
           for (intptr_t i = 0; i < implicit_getters.Length(); ++i) {
             field ^= implicit_getters.At(i);
             if (function.accessor_field() == field.ptr()) {
+              functions_with_entry_point_pragmas_.Insert(function);
               AddFunction(function, RetainReasons::kImplicitGetter);
             }
           }
@@ -1530,6 +1560,7 @@
           for (intptr_t i = 0; i < implicit_setters.Length(); ++i) {
             field ^= implicit_setters.At(i);
             if (function.accessor_field() == field.ptr()) {
+              functions_with_entry_point_pragmas_.Insert(function);
               AddFunction(function, RetainReasons::kImplicitSetter);
             }
           }
@@ -1539,6 +1570,7 @@
           for (intptr_t i = 0; i < implicit_static_getters.Length(); ++i) {
             field ^= implicit_static_getters.At(i);
             if (function.accessor_field() == field.ptr()) {
+              functions_with_entry_point_pragmas_.Insert(function);
               AddFunction(function, RetainReasons::kImplicitStaticGetter);
             }
           }
@@ -2051,6 +2083,51 @@
   Code& code = Code::Handle(Z);
   Object& owner = Object::Handle(Z);
   GrowableObjectArray& retained_functions = GrowableObjectArray::Handle(Z);
+  auto& sig = FunctionType::Handle(Z);
+  auto& ref = Object::Handle(Z);
+
+  auto trim_function = [&](const Function& function) {
+    sig = function.signature();
+    // In the AOT runtime, most calls are direct or through the dispatch table,
+    // not resolved via dynamic lookup. Thus, we only need to retain the
+    // function signature in the following cases:
+    if (function.IsClosureFunction()) {
+      // Dynamic calls to closures go through dynamic closure call dispatchers,
+      // which need the signature.
+      return AddRetainReason(sig, RetainReasons::kClosureSignature);
+    }
+    if (function.IsFfiTrampoline()) {
+      // FFI trampolines may be dynamically called.
+      return AddRetainReason(sig, RetainReasons::kFfiTrampolineSignature);
+    }
+    if (function.is_native()) {
+      return AddRetainReason(sig, RetainReasons::kNativeSignature);
+    }
+    if (function.HasRequiredNamedParameters()) {
+      // Required named parameters must be checked, so a NoSuchMethod exception
+      // can be thrown if they are not provided.
+      return AddRetainReason(sig, RetainReasons::kRequiredNamedParameters);
+    }
+    if (functions_called_dynamically_.ContainsKey(function)) {
+      // Dynamic resolution of these functions checks for valid arguments.
+      return AddRetainReason(sig, RetainReasons::kDynamicallyCalledSignature);
+    }
+    if (functions_with_entry_point_pragmas_.ContainsKey(function)) {
+      // Dynamic resolution of entry points also checks for valid arguments.
+      return AddRetainReason(sig, RetainReasons::kEntryPointPragmaSignature);
+    }
+    if (FLAG_trace_precompiler) {
+      THR_Print("Clearing signature for function %s\n",
+                function.ToLibNamePrefixedQualifiedCString());
+    }
+    // Other functions not listed here may end up in dynamic resolution via
+    // UnlinkedCalls. However, since it is not a dynamic invocation and has
+    // been type checked at compile time, we already know the arguments are
+    // valid. Thus, we can skip checking arguments for functions with dropped
+    // signatures in ResolveDynamicForReceiverClassWithCustomLookup.
+    ref = WeakSerializationReference::New(sig, Object::null_function_type());
+    function.set_signature(ref);
+  };
 
   auto drop_function = [&](const Function& function) {
     if (function.HasCode()) {
@@ -2088,6 +2165,7 @@
         function ^= functions.At(j);
         function.DropUncompiledImplicitClosureFunction();
         if (functions_to_retain_.ContainsKey(function)) {
+          trim_function(function);
           retained_functions.Add(function);
         } else {
           drop_function(function);
@@ -2113,6 +2191,7 @@
           if (functions_to_retain_.ContainsKey(function)) {
             retained_functions.Add(name);
             retained_functions.Add(desc);
+            trim_function(function);
             retained_functions.Add(function);
           } else {
             drop_function(function);
@@ -2135,6 +2214,7 @@
   retained_functions = GrowableObjectArray::New();
   ClosureFunctionsCache::ForAllClosureFunctions([&](const Function& function) {
     if (functions_to_retain_.ContainsKey(function)) {
+      trim_function(function);
       retained_functions.Add(function);
     } else {
       drop_function(function);
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 049a12a..303fbc4 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -376,6 +376,7 @@
   const GrowableObjectArray& pending_functions_;
   SymbolSet sent_selectors_;
   FunctionSet functions_called_dynamically_;
+  FunctionSet functions_with_entry_point_pragmas_;
   FunctionSet seen_functions_;
   FunctionSet possibly_retained_functions_;
   FieldSet fields_to_retain_;
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 3807b9a..76ab69a 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2801,7 +2801,7 @@
     case Slot::Kind::kClosure_instantiator_type_arguments:
     case Slot::Kind::kFunction_data:
     case Slot::Kind::kFunction_signature:
-    case Slot::Kind::kFunctionType_parameter_names:
+    case Slot::Kind::kFunctionType_named_parameter_names:
     case Slot::Kind::kFunctionType_parameter_types:
     case Slot::Kind::kFunctionType_type_parameters:
     case Slot::Kind::kPointerBase_data_field:
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index ece5752..f1821ce 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -226,7 +226,7 @@
     case Slot::Kind::kDartField:
     case Slot::Kind::kFunction_data:
     case Slot::Kind::kFunction_signature:
-    case Slot::Kind::kFunctionType_parameter_names:
+    case Slot::Kind::kFunctionType_named_parameter_names:
     case Slot::Kind::kFunctionType_parameter_types:
     case Slot::Kind::kFunctionType_type_parameters:
     case Slot::Kind::kPointerBase_data_field:
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index 43a27cc..2198ba7 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -59,9 +59,9 @@
     FINAL)                                                                     \
   V(Closure, UntaggedClosure, delayed_type_arguments, TypeArguments, FINAL)    \
   V(Closure, UntaggedClosure, function_type_arguments, TypeArguments, FINAL)   \
-  V(Type, UntaggedType, arguments, TypeArguments, FINAL)                       \
   V(FunctionType, UntaggedFunctionType, type_parameters, TypeParameters,       \
     FINAL)                                                                     \
+  V(Type, UntaggedType, arguments, TypeArguments, FINAL)                       \
   V(TypeParameters, UntaggedTypeParameters, flags, Array, FINAL)               \
   V(TypeParameters, UntaggedTypeParameters, bounds, TypeArguments, FINAL)      \
   V(TypeParameters, UntaggedTypeParameters, defaults, TypeArguments, FINAL)    \
@@ -87,7 +87,7 @@
   V(Closure, UntaggedClosure, context, Context, FINAL)                         \
   V(Closure, UntaggedClosure, hash, Context, VAR)                              \
   V(Function, UntaggedFunction, data, Dynamic, FINAL)                          \
-  V(FunctionType, UntaggedFunctionType, parameter_names, Array, FINAL)         \
+  V(FunctionType, UntaggedFunctionType, named_parameter_names, Array, FINAL)   \
   V(FunctionType, UntaggedFunctionType, parameter_types, Array, FINAL)         \
   V(GrowableObjectArray, UntaggedGrowableObjectArray, length, Smi, VAR)        \
   V(GrowableObjectArray, UntaggedGrowableObjectArray, data, Array, VAR)        \
@@ -145,7 +145,10 @@
   V(Function, UntaggedFunction, entry_point, Uword, FINAL)                     \
   V(Function, UntaggedFunction, kind_tag, Uint32, FINAL)                       \
   V(Function, UntaggedFunction, packed_fields, Uint32, FINAL)                  \
-  V(FunctionType, UntaggedFunctionType, packed_fields, Uint32, FINAL)          \
+  V(FunctionType, UntaggedFunctionType, packed_parameter_counts, Uint32,       \
+    FINAL)                                                                     \
+  V(FunctionType, UntaggedFunctionType, packed_type_parameter_counts, Uint16,  \
+    FINAL)                                                                     \
   V(Pointer, UntaggedPointer, data_field, FfiIntPtr, FINAL)                    \
   V(TypedDataBase, UntaggedTypedDataBase, data_field, IntPtr, VAR)             \
   V(TypeParameter, UntaggedTypeParameter, flags, Uint8, FINAL)
diff --git a/runtime/vm/compiler/ffi/call.cc b/runtime/vm/compiler/ffi/call.cc
index 990e257..d4cb983 100644
--- a/runtime/vm/compiler/ffi/call.cc
+++ b/runtime/vm/compiler/ffi/call.cc
@@ -32,28 +32,27 @@
                           /*is_native=*/false, owner_class,
                           TokenPosition::kMinSource));
   function.set_is_debuggable(false);
-  function.set_num_fixed_parameters(dart_signature.num_fixed_parameters());
+  // Trampolines have no optional arguments.
+  const intptr_t num_fixed = dart_signature.num_fixed_parameters();
+  signature.set_num_fixed_parameters(num_fixed);
   signature.set_result_type(
       AbstractType::Handle(zone, dart_signature.result_type()));
   signature.set_parameter_types(
       Array::Handle(zone, dart_signature.parameter_types()));
 
-  // The signature function won't have any names for the parameters. We need to
-  // assign unique names for scope building and error messages.
-  signature.CreateNameArrayIncludingFlags(Heap::kOld);
-  const intptr_t num_params = dart_signature.num_fixed_parameters();
-  for (intptr_t i = 0; i < num_params; ++i) {
-    if (i == 0) {
-      name = Symbols::ClosureParameter().ptr();
-    } else {
+  // Create unique names for the parameters, as they are used in scope building
+  // and error messages.
+  if (num_fixed > 0) {
+    function.CreateNameArray();
+    function.SetParameterNameAt(0, Symbols::ClosureParameter());
+    for (intptr_t i = 1; i < num_fixed; i++) {
       name = Symbols::NewFormatted(thread, ":ffi_param%" Pd, i);
+      function.SetParameterNameAt(i, name);
     }
-    signature.SetParameterNameAt(i, name);
   }
-  signature.FinalizeNameArrays(function);
   function.SetFfiCSignature(c_signature);
   signature ^= ClassFinalizer::FinalizeType(signature);
-  function.set_signature(signature);
+  function.SetSignature(signature);
 
   function.SetFfiIsLeaf(is_leaf);
 
diff --git a/runtime/vm/compiler/ffi/callback.cc b/runtime/vm/compiler/ffi/callback.cc
index c38f9d6..d1d9b67 100644
--- a/runtime/vm/compiler/ffi/callback.cc
+++ b/runtime/vm/compiler/ffi/callback.cc
@@ -28,15 +28,15 @@
                                 String::Handle(zone, dart_target.name())));
   const Library& lib = Library::Handle(zone, Library::FfiLibrary());
   const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
-  const Function& function =
-      Function::Handle(zone, Function::New(Object::null_function_type(), name,
-                                           UntaggedFunction::kFfiTrampoline,
-                                           /*is_static=*/true,
-                                           /*is_const=*/false,
-                                           /*is_abstract=*/false,
-                                           /*is_external=*/false,
-                                           /*is_native=*/false, owner_class,
-                                           TokenPosition::kNoSource));
+  auto& signature = FunctionType::Handle(zone, FunctionType::New());
+  const Function& function = Function::Handle(
+      zone, Function::New(signature, name, UntaggedFunction::kFfiTrampoline,
+                          /*is_static=*/true,
+                          /*is_const=*/false,
+                          /*is_abstract=*/false,
+                          /*is_external=*/false,
+                          /*is_native=*/false, owner_class,
+                          TokenPosition::kNoSource));
   function.set_is_debuggable(false);
 
   // Set callback-specific fields which the flow-graph builder needs to generate
@@ -60,6 +60,16 @@
     function.SetFfiCallbackExceptionalReturn(exceptional_return);
   }
 
+  // The dart type of the FfiCallback has no arguments or type arguments and
+  // has a result type of dynamic, as the callback is never invoked via Dart,
+  // only via native calls that do not use this information. Having no Dart
+  // arguments ensures the scope builder does not add inappropriate parameter
+  // variables.
+  signature.set_result_type(Object::dynamic_type());
+  // Finalize (and thus canonicalize) the signature.
+  signature ^= ClassFinalizer::FinalizeType(signature);
+  function.SetSignature(signature);
+
   return function.ptr();
 }
 
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index f27b185..7a07552 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -5320,11 +5320,9 @@
             break;
           case FunctionNodeHelper::kAsync:
             function.set_modifier(UntaggedFunction::kAsync);
-            function.set_is_inlinable(!FLAG_causal_async_stacks);
             break;
           case FunctionNodeHelper::kAsyncStar:
             function.set_modifier(UntaggedFunction::kAsyncGen);
-            function.set_is_inlinable(!FLAG_causal_async_stacks);
             break;
           default:
             // no special modifier
@@ -5343,8 +5341,7 @@
         }
         // Note: Is..() methods use the modifiers set above, so order matters.
         if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
-          function.set_is_inlinable(!FLAG_causal_async_stacks &&
-                                    !FLAG_lazy_async_stacks);
+          function.set_is_inlinable(!FLAG_lazy_async_stacks);
         }
 
         function.set_end_token_pos(function_node_helper.end_position_);
@@ -5365,7 +5362,7 @@
         // Finalize function type.
         FunctionType& signature = FunctionType::Handle(Z, function.signature());
         signature ^= ClassFinalizer::FinalizeType(signature);
-        function.set_signature(signature);
+        function.SetSignature(signature);
 
         ClosureFunctionsCache::AddClosureFunctionLocked(function);
         break;
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index c4a43ff..dc96c4e 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -2097,7 +2097,7 @@
   LocalVariable* num_opt_params = nullptr;
   LocalVariable* num_max_params = nullptr;
   LocalVariable* has_named_params = nullptr;
-  LocalVariable* parameter_names = nullptr;
+  LocalVariable* named_parameter_names = nullptr;
   LocalVariable* parameter_types = nullptr;
   LocalVariable* type_parameters = nullptr;
   LocalVariable* num_type_parameters = nullptr;
@@ -2136,30 +2136,23 @@
   if (!IG->use_strict_null_safety_checks()) return not_set;
 
   Fragment check_required;
-  // First, we convert the index to be in terms of the number of optional
-  // parameters, not total parameters (to calculate the flag index and shift).
+  // We calculate the index to dereference in the parameter names array.
   check_required += LoadLocal(info.vars->current_param_index);
-  check_required += LoadLocal(info.num_fixed_params);
-  check_required += SmiBinaryOp(Token::kSUB, /*is_truncating=*/true);
-  LocalVariable* opt_index = MakeTemporary("opt_index");  // Read-only.
-
-  // Next, we calculate the index to dereference in the parameter names array.
-  check_required += LoadLocal(opt_index);
   check_required +=
       IntConstant(compiler::target::kNumParameterFlagsPerElementLog2);
   check_required += SmiBinaryOp(Token::kSHR);
-  check_required += LoadLocal(info.num_max_params);
+  check_required += LoadLocal(info.num_opt_params);
   check_required += SmiBinaryOp(Token::kADD);
   LocalVariable* flags_index = MakeTemporary("flags_index");  // Read-only.
 
-  // Two read-only stack values (opt_index, flag_index) that must be dropped
+  // One read-only stack value (flag_index) that must be dropped
   // after we rejoin at after_check.
   JoinEntryInstr* after_check = BuildJoinEntry();
 
   // Now we check to see if the flags index is within the bounds of the
   // parameters names array. If not, it cannot be required.
   check_required += LoadLocal(flags_index);
-  check_required += LoadLocal(info.parameter_names);
+  check_required += LoadLocal(info.named_parameter_names);
   check_required += LoadNativeField(Slot::Array_length());
   check_required += SmiRelationalOp(Token::kLT);
   TargetEntryInstr* valid_index;
@@ -2174,11 +2167,11 @@
   // the flag slots are non-null, so after loading we can immediate check
   // the required flag bit for the given named parameter.
   check_required.current = valid_index;
-  check_required += LoadLocal(info.parameter_names);
+  check_required += LoadLocal(info.named_parameter_names);
   check_required += LoadLocal(flags_index);
   check_required += LoadIndexed(
       kArrayCid, /*index_scale*/ compiler::target::kCompressedWordSize);
-  check_required += LoadLocal(opt_index);
+  check_required += LoadLocal(info.vars->current_param_index);
   check_required +=
       IntConstant(compiler::target::kNumParameterFlagsPerElement - 1);
   check_required += SmiBinaryOp(Token::kBIT_AND);
@@ -2206,7 +2199,6 @@
   // After rejoining, drop the introduced temporaries.
   check_required.current = after_check;
   check_required += DropTemporary(&flags_index);
-  check_required += DropTemporary(&opt_index);
   return check_required;
 }
 
@@ -2328,8 +2320,8 @@
     // for named parameters. If this changes, we'll need to check each flag
     // entry appropriately for any set required bits.
     Fragment has_any;
-    has_any += LoadLocal(info.num_max_params);
-    has_any += LoadLocal(info.parameter_names);
+    has_any += LoadLocal(info.num_opt_params);
+    has_any += LoadLocal(info.named_parameter_names);
     has_any += LoadNativeField(Slot::Array_length());
     TargetEntryInstr* no_required;
     TargetEntryInstr* has_required;
@@ -2356,14 +2348,14 @@
   check_names += IntConstant(0);
   check_names += StoreLocal(info.vars->current_num_processed);
   check_names += Drop();
-  check_names += LoadLocal(info.num_fixed_params);
+  check_names += IntConstant(0);
   check_names += StoreLocal(info.vars->current_param_index);
   check_names += Drop();
   check_names += Goto(loop);
 
   Fragment loop_check(loop);
   loop_check += LoadLocal(info.vars->current_param_index);
-  loop_check += LoadLocal(info.num_max_params);
+  loop_check += LoadLocal(info.num_opt_params);
   loop_check += SmiRelationalOp(Token::kLT);
   TargetEntryInstr* no_more;
   TargetEntryInstr* more;
@@ -2373,7 +2365,7 @@
 
   Fragment loop_body(more);
   // First load the name we need to check against.
-  loop_body += LoadLocal(info.parameter_names);
+  loop_body += LoadLocal(info.named_parameter_names);
   loop_body += LoadLocal(info.vars->current_param_index);
   loop_body += LoadIndexed(
       kArrayCid, /*index_scale*/ compiler::target::kCompressedWordSize);
@@ -2398,6 +2390,8 @@
     // arguments. (No need to check the required bit for provided parameters.)
     Fragment matched(match);
     matched += LoadLocal(info.vars->current_param_index);
+    matched += LoadLocal(info.num_fixed_params);
+    matched += SmiBinaryOp(Token::kADD, /*is_truncating=*/true);
     matched += StoreLocal(info.vars->named_argument_parameter_indices.At(i));
     matched += Drop();
     matched += LoadLocal(info.vars->current_num_processed);
@@ -2460,9 +2454,10 @@
     TargetEntryInstr* not_null;
     check_type_args_length += BranchIfNull(&null, &not_null);
     check_type_args_length.current = not_null;  // Continue in non-error case.
-    check_type_args_length += LoadLocal(info.type_parameters);
-    check_type_args_length += LoadNativeField(Slot::TypeParameters_names());
-    check_type_args_length += LoadNativeField(Slot::Array_length());
+    check_type_args_length += LoadLocal(info.signature);
+    check_type_args_length += BuildExtractUnboxedSlotBitFieldIntoSmi<
+        UntaggedFunctionType::PackedNumTypeParameters>(
+        Slot::FunctionType_packed_type_parameter_counts());
     check_type_args_length += IntConstant(info.descriptor.TypeArgsLen());
     TargetEntryInstr* equal;
     TargetEntryInstr* not_equal;
@@ -2749,13 +2744,13 @@
   body += LoadLocal(info.signature);
   body += BuildExtractUnboxedSlotBitFieldIntoSmi<
       FunctionType::PackedNumFixedParameters>(
-      Slot::FunctionType_packed_fields());
+      Slot::FunctionType_packed_parameter_counts());
   info.num_fixed_params = MakeTemporary("num_fixed_params");
 
   body += LoadLocal(info.signature);
   body += BuildExtractUnboxedSlotBitFieldIntoSmi<
       FunctionType::PackedNumOptionalParameters>(
-      Slot::FunctionType_packed_fields());
+      Slot::FunctionType_packed_parameter_counts());
   info.num_opt_params = MakeTemporary("num_opt_params");
 
   body += LoadLocal(info.num_fixed_params);
@@ -2766,15 +2761,15 @@
   body += LoadLocal(info.signature);
   body += BuildExtractUnboxedSlotBitFieldIntoSmi<
       FunctionType::PackedHasNamedOptionalParameters>(
-      Slot::FunctionType_packed_fields());
+      Slot::FunctionType_packed_parameter_counts());
 
   body += IntConstant(0);
   body += StrictCompare(Token::kNE_STRICT);
   info.has_named_params = MakeTemporary("has_named_params");
 
   body += LoadLocal(info.signature);
-  body += LoadNativeField(Slot::FunctionType_parameter_names());
-  info.parameter_names = MakeTemporary("parameter_names");
+  body += LoadNativeField(Slot::FunctionType_named_parameter_names());
+  info.named_parameter_names = MakeTemporary("named_parameter_names");
 
   body += LoadLocal(info.signature);
   body += LoadNativeField(Slot::FunctionType_parameter_types());
@@ -2814,13 +2809,14 @@
   generic += LoadLocal(info.signature);
   generic += BuildExtractUnboxedSlotBitFieldIntoSmi<
       UntaggedFunctionType::PackedNumParentTypeArguments>(
-      Slot::FunctionType_packed_fields());
+      Slot::FunctionType_packed_type_parameter_counts());
   info.num_parent_type_args = MakeTemporary("num_parent_type_args");
 
   // Hoist number of type parameters.
-  generic += LoadLocal(info.type_parameters);
-  generic += LoadNativeField(Slot::TypeParameters_names());
-  generic += LoadNativeField(Slot::Array_length());
+  generic += LoadLocal(info.signature);
+  generic += BuildExtractUnboxedSlotBitFieldIntoSmi<
+      UntaggedFunctionType::PackedNumTypeParameters>(
+      Slot::FunctionType_packed_type_parameter_counts());
   info.num_type_parameters = MakeTemporary("num_type_parameters");
 
   // Hoist type parameter flags.
@@ -2877,7 +2873,7 @@
   body += DropTemporary(&info.instantiator_type_args);
   body += DropTemporary(&info.type_parameters);
   body += DropTemporary(&info.parameter_types);
-  body += DropTemporary(&info.parameter_names);
+  body += DropTemporary(&info.named_parameter_names);
   body += DropTemporary(&info.has_named_params);
   body += DropTemporary(&info.num_max_params);
   body += DropTemporary(&info.num_opt_params);
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 1b5a858..11b2fea 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -735,26 +735,25 @@
   intptr_t parameter_count = (is_method ? 1 : 0) + (is_setter ? 1 : 0);
 
   const FunctionType& signature = FunctionType::Handle(Z, function.signature());
-  function.SetNumOptionalParameters(0, false);
-  function.set_num_fixed_parameters(parameter_count);
+  signature.SetNumOptionalParameters(0, false);
+  signature.set_num_fixed_parameters(parameter_count);
   if (parameter_count > 0) {
     signature.set_parameter_types(
         Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
   }
-  signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  function.CreateNameArray();
 
   intptr_t pos = 0;
   if (is_method) {
     signature.SetParameterTypeAt(pos, GetDeclarationType(klass));
-    signature.SetParameterNameAt(pos, Symbols::This());
+    function.SetParameterNameAt(pos, Symbols::This());
     pos++;
   }
   if (is_setter) {
     signature.SetParameterTypeAt(pos, field_type);
-    signature.SetParameterNameAt(pos, Symbols::Value());
+    function.SetParameterNameAt(pos, Symbols::Value());
     pos++;
   }
-  signature.FinalizeNameArrays(function);
 }
 
 void TranslationHelper::ReportError(const char* format, ...) {
@@ -3182,16 +3181,14 @@
 
   signature.set_parameter_types(Array::Handle(
       Z, Array::New(kImplicitClosureParam + all_count, Heap::kOld)));
-  signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  signature.CreateNameArrayIncludingFlags();
 
   intptr_t pos = 0;
   signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-  signature.SetParameterNameAt(pos, H.DartSymbolPlain("_receiver_"));
   ++pos;
   for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
     BuildTypeInternal();  // read ith positional parameter.
     signature.SetParameterTypeAt(pos, result_);
-    signature.SetParameterNameAt(pos, H.DartSymbolPlain("noname"));
   }
 
   if (!simple) {
@@ -3209,7 +3206,7 @@
       }
     }
   }
-  signature.TruncateUnusedParameterFlags();
+  signature.FinalizeNameArray();
 
   if (!simple) {
     helper_->SkipOptionalDartType();  // read typedef type.
@@ -3415,10 +3412,7 @@
     parameterized_class.set_type_parameters(type_parameters);
   } else {
     ASSERT(parameterized_signature.type_parameters() == TypeParameters::null());
-    parameterized_signature.set_type_parameters(type_parameters);
-    if (!function.IsNull()) {
-      function.SetNumTypeParameters(type_parameter_count);
-    }
+    parameterized_signature.SetTypeParameters(type_parameters);
   }
 
   const Library& lib = Library::Handle(Z, active_class->klass->library());
@@ -3658,12 +3652,12 @@
   intptr_t named_parameter_count =
       total_parameter_count - positional_parameter_count;
 
-  function.set_num_fixed_parameters(extra_parameters +
-                                    required_parameter_count);
+  signature.set_num_fixed_parameters(extra_parameters +
+                                     required_parameter_count);
   if (named_parameter_count > 0) {
-    function.SetNumOptionalParameters(named_parameter_count, false);
+    signature.SetNumOptionalParameters(named_parameter_count, false);
   } else {
-    function.SetNumOptionalParameters(
+    signature.SetNumOptionalParameters(
         positional_parameter_count - required_parameter_count, true);
   }
   intptr_t parameter_count = extra_parameters + total_parameter_count;
@@ -3672,19 +3666,20 @@
   if (parameter_count > 0) {
     signature.set_parameter_types(
         Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
-    signature.CreateNameArrayIncludingFlags(Heap::kOld);
+    function.CreateNameArray();
+    signature.CreateNameArrayIncludingFlags();
     if (is_method) {
       ASSERT(!klass.IsNull());
       signature.SetParameterTypeAt(pos, H.GetDeclarationType(klass));
-      signature.SetParameterNameAt(pos, Symbols::This());
+      function.SetParameterNameAt(pos, Symbols::This());
       pos++;
     } else if (is_closure) {
       signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-      signature.SetParameterNameAt(pos, Symbols::ClosureParameter());
+      function.SetParameterNameAt(pos, Symbols::ClosureParameter());
       pos++;
     } else if (is_factory) {
       signature.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-      signature.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
+      function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
       pos++;
     }
   } else {
@@ -3705,8 +3700,7 @@
     }
 
     signature.SetParameterTypeAt(pos, type);
-    signature.SetParameterNameAt(pos,
-                                 H.DartIdentifier(lib, helper.name_index_));
+    function.SetParameterNameAt(pos, H.DartIdentifier(lib, helper.name_index_));
   }
 
   intptr_t named_parameter_count_check =
@@ -3729,7 +3723,7 @@
       signature.SetIsRequiredAt(pos);
     }
   }
-  signature.FinalizeNameArrays(function);
+  signature.FinalizeNameArray();
 
   function_node_helper->SetJustRead(FunctionNodeHelper::kNamedParameters);
 
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index 36fbbbb..b2a6031 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -418,7 +418,8 @@
             AbstractType::ZoneHandle(Z, function.IsFfiTrampoline()
                                             ? function.ParameterTypeAt(i)
                                             : Object::dynamic_type().ptr()));
-        scope_->InsertParameterAt(i, variable);
+        bool added = scope_->InsertParameterAt(i, variable);
+        ASSERT(added);
       }
       break;
     }
diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h
index ce683c3..9af2bbf 100644
--- a/runtime/vm/compiler/runtime_api.h
+++ b/runtime/vm/compiler/runtime_api.h
@@ -699,8 +699,9 @@
  public:
   static word hash_offset();
   static word type_state_offset();
-  static word packed_fields_offset();
-  static word parameter_names_offset();
+  static word packed_parameter_counts_offset();
+  static word packed_type_parameter_counts_offset();
+  static word named_parameter_names_offset();
   static word parameter_types_offset();
   static word type_parameters_offset();
   static word nullability_offset();
diff --git a/runtime/vm/compiler/runtime_offsets_extracted.h b/runtime/vm/compiler/runtime_offsets_extracted.h
index 99fcc93..ccb1925 100644
--- a/runtime/vm/compiler/runtime_offsets_extracted.h
+++ b/runtime/vm/compiler/runtime_offsets_extracted.h
@@ -19,7 +19,7 @@
 
 #if defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    76;
+    72;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 12;
@@ -159,14 +159,14 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 36;
-static constexpr dart::compiler::target::word Function_data_offset = 28;
+static constexpr dart::compiler::target::word Function_code_offset = 32;
+static constexpr dart::compiler::target::word Function_data_offset = 24;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    68;
-static constexpr dart::compiler::target::word Function_signature_offset = 24;
+    83;
+static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -419,11 +419,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 32;
+    FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 24;
+    FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -557,7 +559,7 @@
 
 #if defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    116;
+    112;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 24;
@@ -699,14 +701,14 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 72;
-static constexpr dart::compiler::target::word Function_data_offset = 56;
+static constexpr dart::compiler::target::word Function_code_offset = 64;
+static constexpr dart::compiler::target::word Function_data_offset = 48;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    108;
-static constexpr dart::compiler::target::word Function_signature_offset = 48;
+    123;
+static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -964,11 +966,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 64;
+    FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 48;
+    FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -1104,7 +1108,7 @@
 
 #if defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    76;
+    72;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 12;
@@ -1244,14 +1248,14 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 36;
-static constexpr dart::compiler::target::word Function_data_offset = 28;
+static constexpr dart::compiler::target::word Function_code_offset = 32;
+static constexpr dart::compiler::target::word Function_data_offset = 24;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    68;
-static constexpr dart::compiler::target::word Function_signature_offset = 24;
+    83;
+static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -1504,11 +1508,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 32;
+    FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 24;
+    FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -1639,7 +1645,7 @@
 
 #if defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    116;
+    112;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 24;
@@ -1781,14 +1787,14 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 72;
-static constexpr dart::compiler::target::word Function_data_offset = 56;
+static constexpr dart::compiler::target::word Function_code_offset = 64;
+static constexpr dart::compiler::target::word Function_data_offset = 48;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    108;
-static constexpr dart::compiler::target::word Function_signature_offset = 48;
+    123;
+static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2046,11 +2052,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 64;
+    FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 48;
+    FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -2187,7 +2195,7 @@
 
 #if defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    80;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 16;
@@ -2327,14 +2335,14 @@
     28;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 50;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 58;
-static constexpr dart::compiler::target::word Function_code_offset = 48;
-static constexpr dart::compiler::target::word Function_data_offset = 40;
+static constexpr dart::compiler::target::word Function_code_offset = 44;
+static constexpr dart::compiler::target::word Function_data_offset = 36;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
-static constexpr dart::compiler::target::word Function_signature_offset = 36;
+    91;
+static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -2592,11 +2600,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 40;
+    FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 32;
+    FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -2732,7 +2742,7 @@
 
 #if defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    80;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 16;
@@ -2872,14 +2882,14 @@
     28;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 50;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 58;
-static constexpr dart::compiler::target::word Function_code_offset = 48;
-static constexpr dart::compiler::target::word Function_data_offset = 40;
+static constexpr dart::compiler::target::word Function_code_offset = 44;
+static constexpr dart::compiler::target::word Function_data_offset = 36;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
-static constexpr dart::compiler::target::word Function_signature_offset = 36;
+    91;
+static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3137,11 +3147,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 40;
+    FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 32;
+    FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -3280,7 +3292,7 @@
 
 #if defined(TARGET_ARCH_ARM) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    76;
+    72;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 12;
@@ -3415,14 +3427,14 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 36;
-static constexpr dart::compiler::target::word Function_data_offset = 28;
+static constexpr dart::compiler::target::word Function_code_offset = 32;
+static constexpr dart::compiler::target::word Function_data_offset = 24;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    68;
-static constexpr dart::compiler::target::word Function_signature_offset = 24;
+    83;
+static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -3674,11 +3686,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 32;
+    FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 24;
+    FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -3812,7 +3826,7 @@
 
 #if defined(TARGET_ARCH_X64) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    116;
+    112;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 24;
@@ -3949,14 +3963,14 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 72;
-static constexpr dart::compiler::target::word Function_data_offset = 56;
+static constexpr dart::compiler::target::word Function_code_offset = 64;
+static constexpr dart::compiler::target::word Function_data_offset = 48;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    108;
-static constexpr dart::compiler::target::word Function_signature_offset = 48;
+    123;
+static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -4213,11 +4227,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 64;
+    FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 48;
+    FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -4353,7 +4369,7 @@
 
 #if defined(TARGET_ARCH_IA32) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    76;
+    72;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 16;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 12;
@@ -4488,14 +4504,14 @@
     24;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 54;
-static constexpr dart::compiler::target::word Function_code_offset = 36;
-static constexpr dart::compiler::target::word Function_data_offset = 28;
+static constexpr dart::compiler::target::word Function_code_offset = 32;
+static constexpr dart::compiler::target::word Function_data_offset = 24;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     4, 8};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 64;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    68;
-static constexpr dart::compiler::target::word Function_signature_offset = 24;
+    83;
+static constexpr dart::compiler::target::word Function_signature_offset = 20;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     4;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -4747,11 +4763,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 32;
+    FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 24;
+    FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -4882,7 +4900,7 @@
 
 #if defined(TARGET_ARCH_ARM64) && !defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    116;
+    112;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 24;
@@ -5019,14 +5037,14 @@
     48;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 82;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 90;
-static constexpr dart::compiler::target::word Function_code_offset = 72;
-static constexpr dart::compiler::target::word Function_data_offset = 56;
+static constexpr dart::compiler::target::word Function_code_offset = 64;
+static constexpr dart::compiler::target::word Function_data_offset = 48;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 104;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    108;
-static constexpr dart::compiler::target::word Function_signature_offset = 48;
+    123;
+static constexpr dart::compiler::target::word Function_signature_offset = 40;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -5283,11 +5301,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 64;
+    FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 48;
+    FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -5424,7 +5444,7 @@
 
 #if defined(TARGET_ARCH_X64) && defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    80;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 16;
@@ -5559,14 +5579,14 @@
     28;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 50;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 58;
-static constexpr dart::compiler::target::word Function_code_offset = 48;
-static constexpr dart::compiler::target::word Function_data_offset = 40;
+static constexpr dart::compiler::target::word Function_code_offset = 44;
+static constexpr dart::compiler::target::word Function_data_offset = 36;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
-static constexpr dart::compiler::target::word Function_signature_offset = 36;
+    91;
+static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -5823,11 +5843,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 40;
+    FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 32;
+    FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -5963,7 +5985,7 @@
 
 #if defined(TARGET_ARCH_ARM64) && defined(DART_COMPRESSED_POINTERS)
 static constexpr dart::compiler::target::word Function_usage_counter_offset =
-    84;
+    80;
 static constexpr dart::compiler::target::word
     ICData_receivers_static_type_offset = 32;
 static constexpr dart::compiler::target::word Array_elements_start_offset = 16;
@@ -6098,14 +6120,14 @@
     28;
 static constexpr dart::compiler::target::word Field_is_nullable_offset = 50;
 static constexpr dart::compiler::target::word Field_kind_bits_offset = 58;
-static constexpr dart::compiler::target::word Function_code_offset = 48;
-static constexpr dart::compiler::target::word Function_data_offset = 40;
+static constexpr dart::compiler::target::word Function_code_offset = 44;
+static constexpr dart::compiler::target::word Function_data_offset = 36;
 static constexpr dart::compiler::target::word Function_entry_point_offset[] = {
     8, 16};
 static constexpr dart::compiler::target::word Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word Function_packed_fields_offset =
-    76;
-static constexpr dart::compiler::target::word Function_signature_offset = 36;
+    91;
+static constexpr dart::compiler::target::word Function_signature_offset = 32;
 static constexpr dart::compiler::target::word FutureOr_type_arguments_offset =
     8;
 static constexpr dart::compiler::target::word GrowableObjectArray_data_offset =
@@ -6362,11 +6384,13 @@
 static constexpr dart::compiler::target::word Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    FunctionType_packed_fields_offset = 40;
+    FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    FunctionType_parameter_names_offset = 32;
+    FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -6656,15 +6680,15 @@
     AOT_Field_guarded_list_length_offset = 24;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 42;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 46;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 36;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 28;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 32;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 24;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 44;
+    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    24;
+    20;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
@@ -6948,11 +6972,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 32;
+    AOT_FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 24;
+    AOT_FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -7034,7 +7060,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -7261,15 +7287,15 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 64;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 84;
+    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    48;
+    40;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -7554,11 +7580,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 64;
+    AOT_FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 48;
+    AOT_FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -7642,7 +7670,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -7872,15 +7900,15 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 64;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 84;
+    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    48;
+    40;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -8165,11 +8193,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 64;
+    AOT_FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 48;
+    AOT_FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -8254,7 +8284,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -8480,15 +8510,15 @@
     AOT_Field_guarded_list_length_offset = 28;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 50;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 48;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 52;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 56;
+    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    36;
+    32;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -8773,11 +8803,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 40;
+    AOT_FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 32;
+    AOT_FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -8861,7 +8893,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     48;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -9087,15 +9119,15 @@
     AOT_Field_guarded_list_length_offset = 28;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 50;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 48;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 52;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 56;
+    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    36;
+    32;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -9380,11 +9412,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 40;
+    AOT_FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 32;
+    AOT_FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -9469,7 +9503,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     48;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -9692,15 +9726,15 @@
     AOT_Field_guarded_list_length_offset = 24;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 42;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 46;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 36;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 28;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 32;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 24;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {4, 8};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 44;
+    AOT_Function_packed_fields_offset = 40;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    24;
+    20;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 4;
 static constexpr dart::compiler::target::word
@@ -9982,11 +10016,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 25;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 32;
+    AOT_FunctionType_packed_parameter_counts_offset = 32;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 20;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 24;
+    AOT_FunctionType_named_parameter_names_offset = 24;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 12;
 static constexpr dart::compiler::target::word
@@ -10068,7 +10104,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 48;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 48;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 44;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     40;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 8;
@@ -10290,15 +10326,15 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 64;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 84;
+    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    48;
+    40;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -10581,11 +10617,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 64;
+    AOT_FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 48;
+    AOT_FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -10669,7 +10707,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -10894,15 +10932,15 @@
     AOT_Field_guarded_list_length_offset = 48;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 74;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 78;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 72;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 56;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 64;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 80;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 72;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 84;
+    AOT_Function_packed_fields_offset = 76;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    48;
+    40;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -11185,11 +11223,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 49;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 56;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 64;
+    AOT_FunctionType_packed_parameter_counts_offset = 64;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 68;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 40;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 48;
+    AOT_FunctionType_named_parameter_names_offset = 48;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 24;
 static constexpr dart::compiler::target::word
@@ -11274,7 +11314,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 88;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 80;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     72;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -11495,15 +11535,15 @@
     AOT_Field_guarded_list_length_offset = 28;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 50;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 48;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 52;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 56;
+    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    36;
+    32;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -11786,11 +11826,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 40;
+    AOT_FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 32;
+    AOT_FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -11874,7 +11916,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     48;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
@@ -12095,15 +12137,15 @@
     AOT_Field_guarded_list_length_offset = 28;
 static constexpr dart::compiler::target::word AOT_Field_is_nullable_offset = 46;
 static constexpr dart::compiler::target::word AOT_Field_kind_bits_offset = 50;
-static constexpr dart::compiler::target::word AOT_Function_code_offset = 48;
-static constexpr dart::compiler::target::word AOT_Function_data_offset = 40;
+static constexpr dart::compiler::target::word AOT_Function_code_offset = 44;
+static constexpr dart::compiler::target::word AOT_Function_data_offset = 36;
 static constexpr dart::compiler::target::word
     AOT_Function_entry_point_offset[] = {8, 16};
-static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 52;
+static constexpr dart::compiler::target::word AOT_Function_kind_tag_offset = 48;
 static constexpr dart::compiler::target::word
-    AOT_Function_packed_fields_offset = 56;
+    AOT_Function_packed_fields_offset = 52;
 static constexpr dart::compiler::target::word AOT_Function_signature_offset =
-    36;
+    32;
 static constexpr dart::compiler::target::word
     AOT_FutureOr_type_arguments_offset = 8;
 static constexpr dart::compiler::target::word
@@ -12386,11 +12428,13 @@
 static constexpr dart::compiler::target::word AOT_Type_nullability_offset = 33;
 static constexpr dart::compiler::target::word AOT_FunctionType_hash_offset = 36;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_packed_fields_offset = 40;
+    AOT_FunctionType_packed_parameter_counts_offset = 40;
+static constexpr dart::compiler::target::word
+    AOT_FunctionType_packed_type_parameter_counts_offset = 44;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_parameter_types_offset = 28;
 static constexpr dart::compiler::target::word
-    AOT_FunctionType_parameter_names_offset = 32;
+    AOT_FunctionType_named_parameter_names_offset = 32;
 static constexpr dart::compiler::target::word
     AOT_FunctionType_type_parameters_offset = 20;
 static constexpr dart::compiler::target::word
@@ -12475,7 +12519,7 @@
 static constexpr dart::compiler::target::word AOT_Field_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_Float32x4_InstanceSize = 24;
 static constexpr dart::compiler::target::word AOT_Float64x2_InstanceSize = 24;
-static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 64;
+static constexpr dart::compiler::target::word AOT_Function_InstanceSize = 56;
 static constexpr dart::compiler::target::word AOT_FunctionType_InstanceSize =
     48;
 static constexpr dart::compiler::target::word AOT_FutureOr_InstanceSize = 16;
diff --git a/runtime/vm/compiler/runtime_offsets_list.h b/runtime/vm/compiler/runtime_offsets_list.h
index 43df0cb..d943ed3 100644
--- a/runtime/vm/compiler/runtime_offsets_list.h
+++ b/runtime/vm/compiler/runtime_offsets_list.h
@@ -290,9 +290,10 @@
   FIELD(Type, type_state_offset)                                               \
   FIELD(Type, nullability_offset)                                              \
   FIELD(FunctionType, hash_offset)                                             \
-  FIELD(FunctionType, packed_fields_offset)                                    \
+  FIELD(FunctionType, packed_parameter_counts_offset)                          \
+  FIELD(FunctionType, packed_type_parameter_counts_offset)                     \
   FIELD(FunctionType, parameter_types_offset)                                  \
-  FIELD(FunctionType, parameter_names_offset)                                  \
+  FIELD(FunctionType, named_parameter_names_offset)                            \
   FIELD(FunctionType, type_parameters_offset)                                  \
   FIELD(TypeParameter, parameterized_class_id_offset)                          \
   FIELD(TypeParameter, index_offset)                                           \
diff --git a/runtime/vm/compiler/stub_code_compiler_arm.cc b/runtime/vm/compiler/stub_code_compiler_arm.cc
index 41d995d..ce2faf5 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm.cc
@@ -689,13 +689,13 @@
   // calling into the runtime.
   __ EnterStubFrame();
   __ LoadImmediate(R1, 0);
-  __ Push(R9);  // Preserve cache (guarded CID as Smi).
+  __ Push(R1);  // Result slot.
   __ Push(R0);  // Preserve receiver.
-  __ Push(R1);
-  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 0);
-  __ Pop(CODE_REG);
+  __ Push(R9);  // Preserve cache.
+  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 2);
+  __ Pop(R9);  // Restore cache.
   __ Pop(R0);  // Restore receiver.
-  __ Pop(R9);  // Restore cache (guarded CID as Smi).
+  __ Pop(CODE_REG);  // Get target Code object.
   // Remove the stub frame.
   __ LeaveStubFrame();
   // Jump to the dart function.
diff --git a/runtime/vm/compiler/stub_code_compiler_arm64.cc b/runtime/vm/compiler/stub_code_compiler_arm64.cc
index e3238dc..451a41f 100644
--- a/runtime/vm/compiler/stub_code_compiler_arm64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_arm64.cc
@@ -804,13 +804,13 @@
   // Create a stub frame as we are pushing some objects on the stack before
   // calling into the runtime.
   __ EnterStubFrame();
-  __ Push(R5);  // Preserve cache (guarded CID as Smi).
+  __ Push(ZR);  // Result slot.
   __ Push(R0);  // Preserve receiver.
-  __ Push(ZR);
-  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 0);
-  __ Pop(CODE_REG);
-  __ Pop(R0);  // Restore receiver.
-  __ Pop(R5);  // Restore cache (guarded CID as Smi).
+  __ Push(R5);  // Preserve cache (guarded CID as Smi).
+  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 2);
+  __ Pop(R5);        // Restore cache (guarded CID as Smi).
+  __ Pop(R0);        // Restore receiver.
+  __ Pop(CODE_REG);  // Get target Code object.
   // Remove the stub frame.
   __ LeaveStubFrame();
   // Jump to the dart function.
diff --git a/runtime/vm/compiler/stub_code_compiler_ia32.cc b/runtime/vm/compiler/stub_code_compiler_ia32.cc
index 16ef27a..03fd79d 100644
--- a/runtime/vm/compiler/stub_code_compiler_ia32.cc
+++ b/runtime/vm/compiler/stub_code_compiler_ia32.cc
@@ -515,13 +515,13 @@
   __ Bind(&monomorphic);
   // This was a switchable call.
   __ EnterStubFrame();
-  __ pushl(ECX);           // Preserve cache (guarded CID as Smi).
-  __ pushl(EBX);           // Preserve receiver.
   __ pushl(Immediate(0));  // Result slot.
-  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 0);
-  __ popl(CODE_REG);  // Get Code object.
-  __ popl(EBX);       // Restore receiver.
+  __ pushl(EBX);           // Preserve receiver.
+  __ pushl(ECX);           // Preserve cache (guarded CID as Smi).
+  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 2);
   __ popl(ECX);       // Restore cache (guarded CID as Smi).
+  __ popl(EBX);       // Restore receiver.
+  __ popl(CODE_REG);  // Get target Code object.
   __ movl(EAX, FieldAddress(CODE_REG, target::Code::entry_point_offset(
                                           CodeEntryKind::kMonomorphic)));
   __ LeaveFrame();
diff --git a/runtime/vm/compiler/stub_code_compiler_x64.cc b/runtime/vm/compiler/stub_code_compiler_x64.cc
index f72258a..a3c3821 100644
--- a/runtime/vm/compiler/stub_code_compiler_x64.cc
+++ b/runtime/vm/compiler/stub_code_compiler_x64.cc
@@ -721,13 +721,13 @@
   __ movq(CODE_REG,
           Address(THR, target::Thread::fix_callers_target_code_offset()));
   __ EnterStubFrame();
-  __ pushq(RBX);           // Preserve cache (guarded CID as Smi).
-  __ pushq(RDX);           // Preserve receiver.
   __ pushq(Immediate(0));  // Result slot.
-  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 0);
-  __ popq(CODE_REG);  // Get Code object.
+  __ pushq(RDX);           // Preserve receiver.
+  __ pushq(RBX);           // Preserve cache.
+  __ CallRuntime(kFixCallersTargetMonomorphicRuntimeEntry, 2);
+  __ popq(RBX);       // Restore cache.
   __ popq(RDX);       // Restore receiver.
-  __ popq(RBX);       // Restore cache (guarded CID as Smi).
+  __ popq(CODE_REG);  // Get target Code object.
   __ movq(RAX, FieldAddress(CODE_REG, target::Code::entry_point_offset(
                                           CodeEntryKind::kMonomorphic)));
   __ LeaveStubFrame();
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 4a634d4..b2601a5 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -221,14 +221,6 @@
       return error;
     }
   }
-  if (FLAG_causal_async_stacks && FLAG_lazy_async_stacks) {
-    return Utils::StrDup(
-        "To use --lazy-async-stacks, please disable --causal-async-stacks!");
-  }
-  // TODO(cskau): Remove once flag deprecation has been completed.
-  if (FLAG_causal_async_stacks) {
-    return Utils::StrDup("--causal-async-stacks is deprecated!");
-  }
 
   UntaggedFrame::Init();
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 8f0ed32..71d09e7 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -1903,10 +1903,7 @@
   if (FLAG_lazy_async_stacks) {
     return CollectAsyncLazy();
   }
-  if (!FLAG_causal_async_stacks) {
-    return nullptr;
-  }
-  UNREACHABLE();  //  FLAG_causal_async_stacks is deprecated.
+  return nullptr;
 }
 
 DebuggerStackTrace* DebuggerStackTrace::CollectAsyncLazy() {
@@ -1979,7 +1976,7 @@
 
 DebuggerStackTrace* DebuggerStackTrace::CollectAwaiterReturn() {
 #if defined(DART_PRECOMPILED_RUNTIME)
-  // Causal async stacks are not supported in the AOT runtime.
+  // AOT does not support debugging.
   ASSERT(!FLAG_async_debugger);
   return nullptr;
 #else
diff --git a/runtime/vm/dwarf.cc b/runtime/vm/dwarf.cc
index 8fe8ea3..53d6b39 100644
--- a/runtime/vm/dwarf.cc
+++ b/runtime/vm/dwarf.cc
@@ -28,13 +28,27 @@
  public:
   DwarfPosition(int32_t line, int32_t column) : line_(line), column_(column) {
     // Should only have no line information if also no column information.
-    ASSERT(line_ > 0 || column_ <= 0);
+    ASSERT(line_ > kNoLine || column_ <= kNoColumn);
   }
+  // CodeSourceMaps start the line and column registers at -1, not at 0, and
+  // the arguments passed to ChangePosition are retrieved from CodeSourceMaps.
   explicit DwarfPosition(int32_t line) : DwarfPosition(line, -1) {}
   constexpr DwarfPosition() : line_(-1), column_(-1) {}
 
-  int32_t line() const { return line_; }
-  int32_t column() const { return column_; }
+  // The DWARF standard uses 0 to denote missing line or column
+  // information.
+  static constexpr int32_t kNoLine = 0;
+  static constexpr int32_t kNoColumn = 0;
+
+  int32_t line() const { return line_ > kNoLine ? line_ : kNoLine; }
+  int32_t column() const { return column_ > kNoColumn ? column_ : kNoColumn; }
+
+  // Adjusts the contents given the arguments to a ChangePosition instruction
+  // from CodeSourceMaps.
+  void ChangePosition(int32_t line_delta, int32_t new_column) {
+    line_ = Utils::AddWithWrapAround(line_, line_delta);
+    column_ = new_column;
+  }
 
  private:
   int32_t line_;
@@ -289,57 +303,54 @@
   // 7.5.1.1 Compilation Unit Header
 
   // Unit length.
-  auto const cu_prefix = "cu";
-  intptr_t cu_start;
-  intptr_t cu_size_fixup = stream->ReserveSize(cu_prefix, &cu_start);
+  stream->WritePrefixedLength("cu", [&]() {
+    stream->u2(2);                            // DWARF version 2
+    stream->u4(0);                            // debug_abbrev_offset
+    stream->u1(compiler::target::kWordSize);  // address_size
 
-  stream->u2(2);                            // DWARF version 2
-  stream->u4(0);                            // debug_abbrev_offset
-  stream->u1(compiler::target::kWordSize);  // address_size
+    // Compilation Unit DIE. We describe the entire Dart program as a single
+    // compilation unit. Note we write attributes in the same order we declared
+    // them in our abbreviation above in WriteAbbreviations.
+    stream->uleb128(kCompilationUnit);
+    const Library& root_library = Library::Handle(
+        zone_, IsolateGroup::Current()->object_store()->root_library());
+    const String& root_uri = String::Handle(zone_, root_library.url());
+    stream->string(root_uri.ToCString());  // DW_AT_name
+    stream->string("Dart VM");             // DW_AT_producer
+    stream->string("");                    // DW_AT_comp_dir
 
-  // Compilation Unit DIE. We describe the entire Dart program as a single
-  // compilation unit. Note we write attributes in the same order we declared
-  // them in our abbreviation above in WriteAbbreviations.
-  stream->uleb128(kCompilationUnit);
-  const Library& root_library = Library::Handle(
-      zone_, IsolateGroup::Current()->object_store()->root_library());
-  const String& root_uri = String::Handle(zone_, root_library.url());
-  stream->string(root_uri.ToCString());  // DW_AT_name
-  stream->string("Dart VM");             // DW_AT_producer
-  stream->string("");                    // DW_AT_comp_dir
-
-  // DW_AT_low_pc
-  // The lowest instruction address in this object file that is part of our
-  // compilation unit. Dwarf consumers use this to quickly decide which
-  // compilation unit DIE to consult for a given pc.
-  stream->OffsetFromSymbol(kIsolateSnapshotInstructionsAsmSymbol, 0);
-
-  // DW_AT_high_pc
-  // The highest instruction address in this object file that is part of our
-  // compilation unit. Dwarf consumers use this to quickly decide which
-  // compilation unit DIE to consult for a given pc.
-  if (codes_.is_empty()) {
-    // No code objects in this program, so set high_pc to same as low_pc.
+    // DW_AT_low_pc
+    // The lowest instruction address in this object file that is part of our
+    // compilation unit. Dwarf consumers use this to quickly decide which
+    // compilation unit DIE to consult for a given pc.
     stream->OffsetFromSymbol(kIsolateSnapshotInstructionsAsmSymbol, 0);
-  } else {
-    const Code& last_code = *codes_.Last();
-    auto const last_code_name = code_to_name_.LookupValue(&last_code);
-    ASSERT(last_code_name != nullptr);
-    stream->OffsetFromSymbol(last_code_name, last_code.Size());
-  }
 
-  // DW_AT_stmt_list (offset into .debug_line)
-  // Indicates which line number program is associated with this compilation
-  // unit. We only emit a single line number program.
-  stream->u4(0);
+    // DW_AT_high_pc
+    // The highest instruction address in this object file that is part of our
+    // compilation unit. Dwarf consumers use this to quickly decide which
+    // compilation unit DIE to consult for a given pc.
+    if (codes_.is_empty()) {
+      // No code objects in this program, so set high_pc to same as low_pc.
+      stream->OffsetFromSymbol(kIsolateSnapshotInstructionsAsmSymbol, 0);
+    } else {
+      const Code& last_code = *codes_.Last();
+      auto const last_code_name = code_to_name_.LookupValue(&last_code);
+      ASSERT(last_code_name != nullptr);
+      stream->OffsetFromSymbol(last_code_name, last_code.Size());
+    }
 
-  WriteAbstractFunctions(stream);
-  WriteConcreteFunctions(stream);
+    // DW_AT_stmt_list (offset into .debug_line)
+    // Indicates which line number program is associated with this compilation
+    // unit. We only emit a single line number program.
+    stream->u4(0);
 
-  stream->uleb128(0);  // End of children.
+    WriteAbstractFunctions(stream);
+    WriteConcreteFunctions(stream);
 
-  stream->uleb128(0);  // End of entries.
-  stream->SetSize(cu_size_fixup, cu_prefix, cu_start);
+    stream->uleb128(0);  // End of children.
+
+    stream->uleb128(0);  // End of entries.
+  });
 }
 
 void Dwarf::WriteAbstractFunctions(DwarfWriteStream* stream) {
@@ -440,10 +451,8 @@
     const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg1, &arg2);
     switch (opcode) {
       case CodeSourceMapOps::kChangePosition: {
-        const DwarfPosition& old_pos =
-            token_positions[token_positions.length() - 1];
-        token_positions[token_positions.length() - 1] =
-            DwarfPosition(Utils::AddWithWrapAround(old_pos.line(), arg1), arg2);
+        DwarfPosition& pos = token_positions[token_positions.length() - 1];
+        pos.ChangePosition(arg1, arg2);
         break;
       }
       case CodeSourceMapOps::kAdvancePC: {
@@ -506,12 +515,10 @@
   // DW_AT_call_file
   stream->uleb128(file);
 
-  // The DWARF standard uses 0 to denote missing line or column information.
-
   // DW_AT_call_line
-  stream->uleb128(node->position.line() < 0 ? 0 : node->position.line());
+  stream->uleb128(node->position.line());
   // DW_at_call_column
-  stream->uleb128(node->position.column() < 0 ? 0 : node->position.column());
+  stream->uleb128(node->position.column());
 
   for (InliningNode* child = node->children_head; child != NULL;
        child = child->children_next) {
@@ -529,50 +536,98 @@
   explicit LineNumberProgramWriter(DwarfWriteStream* stream)
       : stream_(stream) {}
 
-  void SetFile(intptr_t file) {
+  void EmitRow(intptr_t file,
+               intptr_t line,
+               intptr_t column,
+               const char* asm_name,
+               intptr_t pc_offset) {
+    if (AddRow(file, line, column, asm_name, pc_offset)) {
+      // Address register must be updated from 0 before emitting an LNP row
+      // (dartbug.com/41756).
+      stream_->u1(Dwarf::DW_LNS_copy);
+    }
+  }
+
+  // Associates the given file, line, and column information for the instruction
+  // at the pc_offset into the instructions payload of the Code object with the
+  // symbol asm_name. Returns whether any changes were made to the stream.
+  bool AddRow(intptr_t file,
+              intptr_t line,
+              intptr_t column,
+              const char* asm_name,
+              intptr_t pc_offset) {
+    ASSERT_EQUAL(end_sequence_, false);
+    bool source_info_changed = false;
+    // Note that files are 1-indexed.
+    ASSERT(file >= 1);
     if (file != file_) {
       stream_->u1(Dwarf::DW_LNS_set_file);
       stream_->uleb128(file);
       file_ = file;
+      source_info_changed = true;
     }
-  }
-
-  void SetLine(intptr_t line) {
+    ASSERT(line >= DwarfPosition::kNoLine);
     if (line != line_) {
       stream_->u1(Dwarf::DW_LNS_advance_line);
       stream_->sleb128(line - line_);
       line_ = line;
+      source_info_changed = true;
     }
-  }
-
-  void SetColumn(intptr_t column) {
+    ASSERT(column >= DwarfPosition::kNoColumn);
     if (column != column_) {
       stream_->u1(Dwarf::DW_LNS_set_column);
       stream_->uleb128(column);
       column_ = column;
+      source_info_changed = true;
     }
+    // If the file, line, and column information match that for the previous
+    // AddRow call, no change is made to the stream. This is because all
+    // addresses between two line number program rows inherit the source
+    // information from the first.
+    if (source_info_changed) {
+      SetCurrentPosition(asm_name, pc_offset);
+    }
+    return source_info_changed;
   }
 
-  void SetPCOffset(const char* asm_name, intptr_t pc_offset) {
-    if (asm_name_ == nullptr) {
+  void MarkEnd() {
+    ASSERT_EQUAL(end_sequence_, false);
+    // End of contiguous machine code.
+    stream_->u1(0);  // This is an extended opcode
+    stream_->u1(1);  // that is 1 byte long
+    stream_->u1(Dwarf::DW_LNE_end_sequence);
+    end_sequence_ = true;
+  }
+
+  void MarkEnd(const char* asm_name, intptr_t pc_offset) {
+    ASSERT_EQUAL(end_sequence_, false);
+    SetCurrentPosition(asm_name, pc_offset);
+    MarkEnd();
+  }
+
+ private:
+  void SetCurrentPosition(const char* asm_name, intptr_t pc_offset) {
+    // Each LNP row is either in a different function from the previous row
+    // or is at an increasing PC offset into the same function.
+    ASSERT(asm_name != nullptr);
+    ASSERT(pc_offset >= 0);
+    ASSERT(asm_name_ != asm_name || pc_offset > pc_offset_);
+    if (asm_name_ != asm_name) {
+      // Set the address register to the given offset into the new code payload.
       auto const instr_size = 1 + compiler::target::kWordSize;
       stream_->u1(0);           // This is an extended opcode
       stream_->u1(instr_size);  // that is 5 or 9 bytes long
       stream_->u1(Dwarf::DW_LNE_set_address);
       stream_->OffsetFromSymbol(asm_name, pc_offset);
     } else {
-      // Emit LNP row if the address register has been updated to a
-      // non-zero value (dartbug.com/41756).
-      stream_->u1(Dwarf::DW_LNS_copy);
+      // Change the address register by the difference in the two offsets.
       stream_->u1(Dwarf::DW_LNS_advance_pc);
-      stream_->DistanceBetweenSymbolOffsets(asm_name, pc_offset, asm_name_,
-                                            pc_offset_);
+      stream_->uleb128(pc_offset - pc_offset_);
     }
     asm_name_ = asm_name;
     pc_offset_ = pc_offset;
   }
 
- private:
   DwarfWriteStream* const stream_;
   // The initial values for the line number program state machine registers
   // according to the DWARF standard.
@@ -580,6 +635,7 @@
   intptr_t file_ = 1;
   intptr_t line_ = 1;
   intptr_t column_ = 0;
+  intptr_t end_sequence_ = false;
 
   // Other info not stored in the state machine registers.
   const char* asm_name_ = nullptr;
@@ -607,9 +663,8 @@
     return;
   }
 
-  intptr_t current_line = 0;
-
-  writer->SetFile(comments_file_index);
+  // Lines in DWARF are 1-indexed.
+  intptr_t current_line = 1;
 
   for (intptr_t i = 0; i < codes_.length(); i++) {
     const Code& code = *(codes_[i]);
@@ -619,15 +674,14 @@
     auto& comments = code.comments();
     for (intptr_t i = 0, len = comments.Length(); i < len;) {
       intptr_t current_pc_offset = comments.PCOffsetAt(i);
-      writer->SetPCOffset(asm_name, current_pc_offset);
+      writer->AddRow(comments_file_index, current_line,
+                     DwarfPosition::kNoColumn, asm_name, current_pc_offset);
       while (i < len && current_pc_offset == comments.PCOffsetAt(i)) {
         comments_buffer.AddString(comments.CommentAt(i));
         comments_buffer.AddChar('\n');
         current_line++;
         i++;
       }
-
-      writer->SetLine(current_line);
     }
   }
 
@@ -673,33 +727,21 @@
           CodeSourceMapOps::Read(&code_map_stream, &arg1, &arg2);
       switch (opcode) {
         case CodeSourceMapOps::kChangePosition: {
-          const DwarfPosition& old_pos =
-              token_positions[token_positions.length() - 1];
-          token_positions[token_positions.length() - 1] = DwarfPosition(
-              Utils::AddWithWrapAround(old_pos.line(), arg1), arg2);
+          DwarfPosition& pos = token_positions[token_positions.length() - 1];
+          pos.ChangePosition(arg1, arg2);
           break;
         }
         case CodeSourceMapOps::kAdvancePC: {
-          current_pc_offset += arg1;
-
+          // Emit a row for the previous PC value if the source location
+          // changed since the last row was emitted.
           const Function& function = *(function_stack.Last());
           script = function.script();
-          intptr_t file = LookupScript(script);
+          const intptr_t file = LookupScript(script);
+          const intptr_t line = token_positions.Last().line();
+          const intptr_t column = token_positions.Last().column();
+          writer->EmitRow(file, line, column, asm_name, current_pc_offset);
 
-          // 1. Update LNP file.
-          writer->SetFile(file);
-
-          // 2. Update LNP line.
-          // The DWARF standard uses 0 to denote missing line or column
-          // information.
-          writer->SetLine(token_positions.Last().line() < 0
-                              ? 0
-                              : token_positions.Last().line());
-          writer->SetColumn(token_positions.Last().column() < 0
-                                ? 0
-                                : token_positions.Last().column());
-
-          writer->SetPCOffset(asm_name, current_pc_offset);
+          current_pc_offset += arg1;
           break;
         }
         case CodeSourceMapOps::kPushFunction: {
@@ -754,104 +796,96 @@
   // 6.2.4 The Line Number Program Header
 
   // 1. unit_length. This encoding implies 32-bit DWARF.
-  auto const line_prefix = "line";
-  intptr_t line_start;
-  intptr_t line_size_fixup = stream->ReserveSize(line_prefix, &line_start);
+  stream->WritePrefixedLength("line", [&]() {
+    stream->u2(2);  // 2. DWARF version 2
 
-  stream->u2(2);  // 2. DWARF version 2
+    // 3. header_length
+    stream->WritePrefixedLength("lineheader", [&]() {
+      stream->u1(1);   // 4. minimum_instruction_length
+      stream->u1(1);   // 5. default_is_stmt (true for dsymutil compatibility).
+      stream->u1(0);   // 6. line_base
+      stream->u1(1);   // 7. line_range
+      stream->u1(13);  // 8. opcode_base (12 standard opcodes in Dwarf 2)
 
-  // 3. header_length
-  auto const lineheader_prefix = "lineheader";
-  intptr_t lineheader_start;
-  intptr_t lineheader_size_fixup =
-      stream->ReserveSize(lineheader_prefix, &lineheader_start);
+      // 9. standard_opcode_lengths
+      stream->u1(0);  // DW_LNS_copy, 0 operands
+      stream->u1(1);  // DW_LNS_advance_pc, 1 operands
+      stream->u1(1);  // DW_LNS_advance_list, 1 operands
+      stream->u1(1);  // DW_LNS_set_file, 1 operands
+      stream->u1(1);  // DW_LNS_set_column, 1 operands
+      stream->u1(0);  // DW_LNS_negate_stmt, 0 operands
+      stream->u1(0);  // DW_LNS_set_basic_block, 0 operands
+      stream->u1(0);  // DW_LNS_const_add_pc, 0 operands
+      stream->u1(1);  // DW_LNS_fixed_advance_pc, 1 operands
+      stream->u1(0);  // DW_LNS_set_prolog_end, 0 operands
+      stream->u1(0);  // DW_LNS_set_epligoue_begin, 0 operands
+      stream->u1(1);  // DW_LNS_set_isa, 1 operands
 
-  stream->u1(1);   // 4. minimum_instruction_length
-  stream->u1(1);   // 5. default_is_stmt (true for compatibility with dsymutil).
-  stream->u1(0);   // 6. line_base
-  stream->u1(1);   // 7. line_range
-  stream->u1(13);  // 8. opcode_base (12 standard opcodes in Dwarf 2)
+      // 10. include_directories (sequence of path names)
+      // We don't emit any because we use full paths below.
+      stream->u1(0);
 
-  // 9. standard_opcode_lengths
-  stream->u1(0);  // DW_LNS_copy, 0 operands
-  stream->u1(1);  // DW_LNS_advance_pc, 1 operands
-  stream->u1(1);  // DW_LNS_advance_list, 1 operands
-  stream->u1(1);  // DW_LNS_set_file, 1 operands
-  stream->u1(1);  // DW_LNS_set_column, 1 operands
-  stream->u1(0);  // DW_LNS_negate_stmt, 0 operands
-  stream->u1(0);  // DW_LNS_set_basic_block, 0 operands
-  stream->u1(0);  // DW_LNS_const_add_pc, 0 operands
-  stream->u1(1);  // DW_LNS_fixed_advance_pc, 1 operands
-  stream->u1(0);  // DW_LNS_set_prolog_end, 0 operands
-  stream->u1(0);  // DW_LNS_set_epligoue_begin, 0 operands
-  stream->u1(1);  // DW_LNS_set_isa, 1 operands
+      // 11. file_names (sequence of file entries)
+      String& uri = String::Handle(zone_);
+      for (intptr_t i = 0; i < scripts_.length(); i++) {
+        const Script& script = *(scripts_[i]);
+        if (FLAG_resolve_dwarf_paths) {
+          uri = script.resolved_url();
+          // Strictly enforce this to catch unresolvable cases.
+          if (uri.IsNull()) {
+            FATAL("no resolved URI for Script %s available",
+                  script.ToCString());
+          }
+        } else {
+          uri = script.url();
+        }
+        ASSERT(!uri.IsNull());
+        auto uri_cstr = Deobfuscate(uri.ToCString());
+        if (FLAG_resolve_dwarf_paths) {
+          auto const converted_cstr = ConvertResolvedURI(uri_cstr);
+          // Strictly enforce this to catch inconvertable cases.
+          if (converted_cstr == nullptr) {
+            FATAL("cannot convert resolved URI %s", uri_cstr);
+          }
+          uri_cstr = converted_cstr;
+        }
+        RELEASE_ASSERT(strlen(uri_cstr) != 0);
 
-  // 10. include_directories (sequence of path names)
-  // We don't emit any because we use full paths below.
-  stream->u1(0);
-
-  // 11. file_names (sequence of file entries)
-  String& uri = String::Handle(zone_);
-  for (intptr_t i = 0; i < scripts_.length(); i++) {
-    const Script& script = *(scripts_[i]);
-    if (FLAG_resolve_dwarf_paths) {
-      uri = script.resolved_url();
-      // Strictly enforce this to catch unresolvable cases.
-      if (uri.IsNull()) {
-        FATAL("no resolved URI for Script %s available", script.ToCString());
+        stream->string(uri_cstr);  // NOLINT
+        stream->uleb128(0);        // Include directory index.
+        stream->uleb128(0);        // File modification time.
+        stream->uleb128(0);        // File length.
       }
+      if (FLAG_write_code_comments_as_synthetic_source_to != nullptr) {
+        stream->string(  // NOLINT
+            FLAG_write_code_comments_as_synthetic_source_to);
+        stream->uleb128(0);  // Include directory index.
+        stream->uleb128(0);  // File modification time.
+        stream->uleb128(0);  // File length.
+      }
+      stream->u1(0);  // End of file names.
+    });
+
+    // 6.2.5 The Line Number Program
+    LineNumberProgramWriter lnp_writer(stream);
+    if (FLAG_write_code_comments_as_synthetic_source_to != nullptr) {
+      WriteSyntheticLineNumberProgram(&lnp_writer);
     } else {
-      uri = script.url();
+      WriteLineNumberProgramFromCodeSourceMaps(&lnp_writer);
     }
-    ASSERT(!uri.IsNull());
-    auto uri_cstr = Deobfuscate(uri.ToCString());
-    if (FLAG_resolve_dwarf_paths) {
-      auto const converted_cstr = ConvertResolvedURI(uri_cstr);
-      // Strictly enforce this to catch inconvertable cases.
-      if (converted_cstr == nullptr) {
-        FATAL("cannot convert resolved URI %s", uri_cstr);
-      }
-      uri_cstr = converted_cstr;
+
+    // Advance pc to end of the compilation unit if not already there.
+    if (codes_.length() != 0) {
+      const intptr_t last_code_index = codes_.length() - 1;
+      const Code& last_code = *(codes_[last_code_index]);
+      const intptr_t last_pc_offset = last_code.Size();
+      const char* last_asm_name = code_to_name_.LookupValue(&last_code);
+      ASSERT(last_asm_name != nullptr);
+      lnp_writer.MarkEnd(last_asm_name, last_pc_offset);
+    } else {
+      lnp_writer.MarkEnd();
     }
-    RELEASE_ASSERT(strlen(uri_cstr) != 0);
-
-    stream->string(uri_cstr);  // NOLINT
-    stream->uleb128(0);        // Include directory index.
-    stream->uleb128(0);        // File modification time.
-    stream->uleb128(0);        // File length.
-  }
-  if (FLAG_write_code_comments_as_synthetic_source_to != nullptr) {
-    stream->string(FLAG_write_code_comments_as_synthetic_source_to);  // NOLINT
-    stream->uleb128(0);  // Include directory index.
-    stream->uleb128(0);  // File modification time.
-    stream->uleb128(0);  // File length.
-  }
-  stream->u1(0);  // End of file names.
-  stream->SetSize(lineheader_size_fixup, lineheader_prefix, lineheader_start);
-
-  // 6.2.5 The Line Number Program
-  LineNumberProgramWriter lnp_writer(stream);
-  if (FLAG_write_code_comments_as_synthetic_source_to != nullptr) {
-    WriteSyntheticLineNumberProgram(&lnp_writer);
-  } else {
-    WriteLineNumberProgramFromCodeSourceMaps(&lnp_writer);
-  }
-
-  // Advance pc to end of the compilation unit if not already there.
-  if (codes_.length() != 0) {
-    const intptr_t last_code_index = codes_.length() - 1;
-    const Code& last_code = *(codes_[last_code_index]);
-    const intptr_t last_pc_offset = last_code.Size();
-    const char* last_asm_name = code_to_name_.LookupValue(&last_code);
-    ASSERT(last_asm_name != nullptr);
-    lnp_writer.SetPCOffset(last_asm_name, last_pc_offset);
-  }
-
-  // End of contiguous machine code.
-  stream->u1(0);  // This is an extended opcode
-  stream->u1(1);  // that is 1 byte long
-  stream->u1(DW_LNE_end_sequence);
-  stream->SetSize(line_size_fixup, line_prefix, line_start);
+  });
 }
 
 const char* Dwarf::Deobfuscate(const char* cstr) {
diff --git a/runtime/vm/dwarf.h b/runtime/vm/dwarf.h
index ec214b6..3fd1255 100644
--- a/runtime/vm/dwarf.h
+++ b/runtime/vm/dwarf.h
@@ -211,19 +211,48 @@
   virtual void u8(uint64_t value) = 0;
   virtual void string(const char* cstr) = 0;  // NOLINT
 
-  // Returns the position (if any) to fix up in SetSize().
-  virtual intptr_t ReserveSize(const char* prefix, intptr_t* start) = 0;
-  virtual void SetSize(intptr_t position,
-                       const char* prefix,
-                       intptr_t start) = 0;
+  class EncodedPosition : public ValueObject {
+   public:
+    explicit EncodedPosition(intptr_t position)
+        : type_(Type::kPosition), position_(position) {}
+    explicit EncodedPosition(const char* symbol)
+        : type_(Type::kSymbol), symbol_(symbol) {}
+
+    enum class Type {
+      kPosition,
+      kSymbol,
+    };
+
+    bool IsPosition() const { return type_ == Type::kPosition; }
+    intptr_t position() const {
+      ASSERT(IsPosition());
+      return position_;
+    }
+    bool IsSymbol() const { return type_ == Type::kSymbol; }
+    const char* symbol() const {
+      ASSERT(IsSymbol());
+      return symbol_;
+    }
+
+   private:
+    const Type type_;
+    union {
+      intptr_t position_;
+      const char* symbol_;
+    };
+
+    DISALLOW_COPY_AND_ASSIGN(EncodedPosition);
+  };
+
+  // Prefixes the content added by body with its length. Returns an
+  // appropriately encoded representation of the start of the content added by
+  // the body (_not_ the start of the prefixed length).
+  //
+  // symbol_prefix is used when a local symbol is created for the length.
+  virtual EncodedPosition WritePrefixedLength(const char* symbol_prefix,
+                                              std::function<void()> body) = 0;
 
   virtual void OffsetFromSymbol(const char* symbol, intptr_t offset) = 0;
-  // Returns the difference between the relocated address at offset1 from
-  // symbol1 and the relocated address at offset2 from symbol2.
-  virtual void DistanceBetweenSymbolOffsets(const char* symbol1,
-                                            intptr_t offset1,
-                                            const char* symbol2,
-                                            intptr_t offset2) = 0;
 
   virtual void InitializeAbstractOrigins(intptr_t size) = 0;
   virtual void RegisterAbstractOrigin(intptr_t index) = 0;
@@ -297,6 +326,13 @@
   static const intptr_t DW_LNE_end_sequence = 0x01;
   static const intptr_t DW_LNE_set_address = 0x02;
 
+ public:
+  // Public because they're also used in constructing .eh_frame ELF sections.
+  static const intptr_t DW_CFA_offset = 0x80;
+  static const intptr_t DW_CFA_val_offset = 0x14;
+  static const intptr_t DW_CFA_def_cfa = 0x0c;
+
+ private:
   enum {
     kCompilationUnit = 1,
     kAbstractFunction,
diff --git a/runtime/vm/elf.cc b/runtime/vm/elf.cc
index 55b14e8..a073428 100644
--- a/runtime/vm/elf.cc
+++ b/runtime/vm/elf.cc
@@ -21,8 +21,12 @@
 // writing ELF files (e.g., using ELF definitions of data sizes).
 class ElfWriteStream : public ValueObject {
  public:
-  explicit ElfWriteStream(BaseWriteStream* stream)
-      : stream_(ASSERT_NOTNULL(stream)) {}
+  explicit ElfWriteStream(BaseWriteStream* stream, const Elf& elf)
+      : stream_(ASSERT_NOTNULL(stream)), elf_(elf) {}
+
+  // Subclasses of Section may need to query the Elf object during Write(),
+  // so we store it in the ElfWriteStream for easy access.
+  const Elf& elf() const { return elf_; }
 
   intptr_t Position() const { return stream_->Position(); }
   void Align(const intptr_t alignment) {
@@ -43,6 +47,7 @@
 
  private:
   BaseWriteStream* const stream_;
+  const Elf& elf_;
 };
 
 static constexpr intptr_t kLinearInitValue = -1;
@@ -98,6 +103,7 @@
   intptr_t link = elf::SHN_UNDEF;
   intptr_t info = 0;
   intptr_t entry_size = 0;
+  const char* symbol_name = nullptr;
 
 #define FOR_EACH_SECTION_LINEAR_FIELD(M)                                       \
   M(name)                                                                      \
@@ -128,17 +134,11 @@
   }
   bool IsWritable() const { return (flags & elf::SHF_WRITE) == elf::SHF_WRITE; }
 
-  // Returns whether new content can be added to a section.
+  // Returns whether the size of a section can change.
   bool HasBeenFinalized() const {
-    if (IsAllocated()) {
-      // The contents of a section that is allocated (part of a segment) must
-      // not change after the section is added.
-      return memory_offset_is_set();
-    } else {
-      // Unallocated sections can have new content added until we calculate
-      // file offsets.
-      return file_offset_is_set();
-    }
+    // Sections can grow or shrink up until Elf::ComputeOffsets has been run,
+    // which sets the file offset (and memory offset for allocated sections).
+    return file_offset_is_set();
   }
 
   virtual const BitsContainer* AsBitsContainer() const { return nullptr; }
@@ -216,18 +216,11 @@
     // Unlike sections, we don't have a reserved segment with the null type,
     // so we never should pass this value.
     ASSERT(segment_type != elf::ProgramHeaderType::PT_NULL);
-    // All segments should have at least one section. The first one is added
-    // during initialization. Unlike others added later, it should already have
-    // a memory offset since we use it to determine the segment memory offset.
+    // All segments should have at least one section.
     ASSERT(initial_section->IsAllocated());
-    ASSERT(initial_section->memory_offset_is_set());
-    // Make sure the memory offset chosen for the initial section is consistent
-    // with the alignment for the segment.
-    ASSERT(Utils::IsAligned(initial_section->memory_offset(), Alignment(type)));
     sections_.Add(initial_section);
     if (type == elf::ProgramHeaderType::PT_LOAD) {
       ASSERT(initial_section->load_segment == nullptr);
-      initial_section->load_segment = this;
     }
   }
 
@@ -270,68 +263,41 @@
 #endif
   }
 
-  // Adds the given section to this segment.
-  //
-  // Returns whether the Section could be added to the segment. If not, a
-  // new segment will need to be created for this section.
-  //
-  // Sets the memory offset of the section if added.
+  // Adds a given section to the end of this segment. Returns whether the
+  // section was successfully added.
   bool Add(Section* section) {
+    ASSERT(section != nullptr);
     // We only add additional sections to load segments.
     ASSERT(type == elf::ProgramHeaderType::PT_LOAD);
-    ASSERT(section != nullptr);
-    // Only sections with the allocate flag set should be added to segments,
-    // and sections with already-set memory offsets cannot be added.
-    ASSERT(section->IsAllocated());
-    ASSERT(!section->memory_offset_is_set());
+    // Don't use this to change a section's segment.
     ASSERT(section->load_segment == nullptr);
-    switch (sections_.Last()->type) {
-      // We only use SHT_NULL sections as pseudo sections that will not appear
-      // in the final ELF file. Don't pack sections into these segments, as we
-      // may remove/replace the segments during finalization.
-      case elf::SectionHeaderType::SHT_NULL:
-      // If the last section in the segments is NOBITS, then we don't add it,
-      // as otherwise we'll be guaranteed the file offset and memory offset
-      // won't be page aligned without padding.
-      case elf::SectionHeaderType::SHT_NOBITS:
-        return false;
-      default:
-        break;
-    }
-    // We don't add if the W or X bits don't match.
+    // We only add sections with the same executable and writable bits.
     if (IsExecutable() != section->IsExecutable() ||
         IsWritable() != section->IsWritable()) {
       return false;
     }
-    auto const start_address = Utils::RoundUp(MemoryEnd(), section->alignment);
-    section->set_memory_offset(start_address);
     sections_.Add(section);
     section->load_segment = this;
     return true;
   }
 
-  void Replace(Section* old_section, Section* new_section) {
-    ASSERT(old_section->load_segment == this);
-    // All these must be true for replacement to be safe.
-    ASSERT_EQUAL(static_cast<uint32_t>(old_section->type),
-                 static_cast<uint32_t>(new_section->type));
-    ASSERT_EQUAL(old_section->MemorySize(), new_section->MemorySize());
-    ASSERT_EQUAL(old_section->IsExecutable(), new_section->IsExecutable());
-    ASSERT_EQUAL(old_section->IsWritable(), new_section->IsWritable());
-    ASSERT(old_section->memory_offset_is_set());
-    ASSERT(!new_section->memory_offset_is_set());
-    for (intptr_t i = 0; i < sections_.length(); i++) {
-      auto const section = sections_[i];
-      if (section != old_section) {
-        continue;
-      }
-      new_section->set_memory_offset(old_section->memory_offset());
-      sections_[i] = new_section;
-      new_section->load_segment = this;
-      old_section->load_segment = nullptr;
-      return;
+  bool Merge(Segment* other) {
+    ASSERT(other != nullptr);
+    // We only add additional sections to load segments.
+    ASSERT(type == elf::ProgramHeaderType::PT_LOAD);
+    // We only merge segments with the same executable and writable bits.
+    if (IsExecutable() != other->IsExecutable() ||
+        IsWritable() != other->IsWritable()) {
+      return false;
     }
-    UNREACHABLE();
+    for (auto* section : other->sections_) {
+      // Don't merge segments where the memory offsets have already been
+      // calculated.
+      ASSERT(!section->memory_offset_is_set());
+      sections_.Add(section);
+      section->load_segment = this;
+    }
+    return true;
   }
 
   intptr_t FileOffset() const { return sections_[0]->file_offset(); }
@@ -368,7 +334,7 @@
   const intptr_t flags;
 
  private:
-  GrowableArray<const Section*> sections_;
+  GrowableArray<Section*> sections_;
 };
 
 // Represents the first entry in the section table, which should only contain
@@ -461,73 +427,6 @@
                 elf::ProgramHeaderType::PT_LOAD) {}
 };
 
-class BitsContainer : public Section {
- public:
-  // Fully specified BitsContainer information.
-  BitsContainer(elf::SectionHeaderType type,
-                bool allocate,
-                bool executable,
-                bool writable,
-                intptr_t size,
-                const uint8_t* bytes,
-                int alignment = kDefaultAlignment)
-      : Section(type, allocate, executable, writable, alignment),
-        file_size_(type == elf::SectionHeaderType::SHT_NOBITS ? 0 : size),
-        memory_size_(allocate ? size : 0),
-        bytes_(bytes) {
-    ASSERT(type == elf::SectionHeaderType::SHT_NOBITS || bytes != nullptr);
-  }
-
-  // For BitsContainers used only as sections.
-  BitsContainer(elf::SectionHeaderType type,
-                intptr_t size,
-                const uint8_t* bytes,
-                intptr_t alignment = kDefaultAlignment)
-      : BitsContainer(type,
-                      /*allocate=*/false,
-                      /*executable=*/false,
-                      /*writable=*/false,
-                      size,
-                      bytes,
-                      alignment) {}
-
-  // For BitsContainers used as segments whose type differ on the type of the
-  // ELF file. Creates an elf::SHT_PROGBITS section if type is Snapshot,
-  // otherwise creates an elf::SHT_NOBITS section.
-  BitsContainer(Elf::Type t,
-                bool executable,
-                bool writable,
-                intptr_t size,
-                const uint8_t* bytes,
-                intptr_t alignment = kDefaultAlignment)
-      : BitsContainer(t == Elf::Type::Snapshot
-                          ? elf::SectionHeaderType::SHT_PROGBITS
-                          : elf::SectionHeaderType::SHT_NOBITS,
-                      /*allocate=*/true,
-                      executable,
-                      writable,
-                      size,
-                      bytes,
-                      alignment) {}
-
-  const BitsContainer* AsBitsContainer() const { return this; }
-
-  void Write(ElfWriteStream* stream) {
-    if (type != elf::SectionHeaderType::SHT_NOBITS) {
-      stream->WriteBytes(bytes_, FileSize());
-    }
-  }
-
-  intptr_t FileSize() const { return file_size_; }
-  intptr_t MemorySize() const { return memory_size_; }
-  const uint8_t* bytes() const { return bytes_; }
-
- private:
-  const intptr_t file_size_;
-  const intptr_t memory_size_;
-  const uint8_t* const bytes_;
-};
-
 class StringTable : public Section {
  public:
   explicit StringTable(Zone* zone, bool allocate)
@@ -585,22 +484,33 @@
          intptr_t name,
          intptr_t binding,
          intptr_t type,
-         intptr_t section,
-         intptr_t offset,
+         intptr_t initial_section_index,
          intptr_t size)
       : name_index(name),
         binding(binding),
         type(type),
-        section_index(section),
-        offset(offset),
         size(size),
+        section_index(initial_section_index),
         cstr_(cstr) {}
 
+  void Finalize(intptr_t final_section_index, intptr_t offset) {
+    ASSERT(!HasBeenFinalized());  // No symbol should be re-finalized.
+    section_index = final_section_index;
+    offset_ = offset;
+  }
+  bool HasBeenFinalized() const { return offset_ != kNotFinalizedMarker; }
+  intptr_t offset() const {
+    ASSERT(HasBeenFinalized());
+    // Only the reserved initial symbol should have an offset of 0.
+    ASSERT_EQUAL(type == elf::STT_NOTYPE, offset_ == 0);
+    return offset_;
+  }
+
   void Write(ElfWriteStream* stream) const {
     const intptr_t start = stream->Position();
     stream->WriteWord(name_index);
 #if defined(TARGET_ARCH_IS_32_BIT)
-    stream->WriteAddr(offset);
+    stream->WriteAddr(offset());
     stream->WriteWord(size);
     stream->WriteByte(elf::SymbolInfo(binding, type));
     stream->WriteByte(0);
@@ -609,7 +519,7 @@
     stream->WriteByte(elf::SymbolInfo(binding, type));
     stream->WriteByte(0);
     stream->WriteHalf(section_index);
-    stream->WriteAddr(offset);
+    stream->WriteAddr(offset());
     stream->WriteXWord(size);
 #endif
     ASSERT_EQUAL(stream->Position() - start, sizeof(elf::Symbol));
@@ -618,14 +528,19 @@
   const intptr_t name_index;
   const intptr_t binding;
   const intptr_t type;
-  const intptr_t section_index;
-  const intptr_t offset;
   const intptr_t size;
+  // Is set twice: once in Elf::AddSection to the section's initial index into
+  // sections_, and then in Elf::FinalizeSymbols to the section's final index
+  // into sections_ after reordering.
+  intptr_t section_index;
 
  private:
-  friend class SymbolHashTable;  // For cstr_ access.
+  static const intptr_t kNotFinalizedMarker = -1;
 
   const char* const cstr_;
+  intptr_t offset_ = kNotFinalizedMarker;
+
+  friend class SymbolHashTable;  // For cstr_ access.
 };
 
 class SymbolTable : public Section {
@@ -644,8 +559,10 @@
     entry_size = sizeof(elf::Symbol);
     // The first symbol table entry is reserved and must be all zeros.
     // (String tables always have the empty string at the 0th index.)
-    AddSymbol("", elf::STB_LOCAL, elf::STT_NOTYPE, elf::SHN_UNDEF, /*offset=*/0,
+    const char* const kReservedName = "";
+    AddSymbol(kReservedName, elf::STB_LOCAL, elf::STT_NOTYPE, elf::SHN_UNDEF,
               /*size=*/0);
+    FinalizeSymbol(kReservedName, elf::SHN_UNDEF, /*offset=*/0);
   }
 
   intptr_t FileSize() const { return Length() * entry_size; }
@@ -664,13 +581,12 @@
                  intptr_t binding,
                  intptr_t type,
                  intptr_t section_index,
-                 intptr_t offset,
                  intptr_t size) {
     ASSERT(!table_->HasBeenFinalized());
     auto const name_index = table_->AddString(name);
     ASSERT(by_name_index_.Lookup(name_index) == nullptr);
     auto const symbol = new (zone_)
-        Symbol(name, name_index, binding, type, section_index, offset, size);
+        Symbol(name, name_index, binding, type, section_index, size);
     symbols_.Add(symbol);
     by_name_index_.Insert(name_index, symbol);
     // The info field on a symbol table section holds the index of the first
@@ -688,6 +604,17 @@
       info += 1;
     }
   }
+
+  void FinalizeSymbol(const char* name,
+                      intptr_t final_section_index,
+                      intptr_t offset) {
+    const intptr_t name_index = table_->Lookup(name);
+    ASSERT(name_index != StringTable::kNotIndexed);
+    Symbol* symbol = by_name_index_.Lookup(name_index);
+    ASSERT(symbol != nullptr);
+    symbol->Finalize(final_section_index, offset);
+  }
+
   intptr_t Length() const { return symbols_.length(); }
   const Symbol* At(intptr_t i) const { return symbols_[i]; }
 
@@ -701,8 +628,8 @@
   Zone* const zone_;
   StringTable* const table_;
   const bool dynamic_;
-  GrowableArray<const Symbol*> symbols_;
-  mutable IntMap<const Symbol*> by_name_index_;
+  GrowableArray<Symbol*> symbols_;
+  mutable IntMap<Symbol*> by_name_index_;
 };
 
 static uint32_t ElfHash(const unsigned char* name) {
@@ -723,7 +650,6 @@
                 /*allocate=*/true,
                 /*executable=*/false,
                 /*writable=*/false) {
-    link = symtab->index();
     entry_size = sizeof(int32_t);
 
     nchain_ = symtab->Length();
@@ -771,25 +697,24 @@
 
 class DynamicTable : public Section {
  public:
-  DynamicTable(Zone* zone,
-               StringTable* strtab,
-               SymbolTable* symtab,
-               SymbolHashTable* hash)
+  explicit DynamicTable(Zone* zone)
       : Section(elf::SectionHeaderType::SHT_DYNAMIC,
                 /*allocate=*/true,
                 /*executable=*/false,
                 /*writable=*/true) {
-    link = strtab->index();
     entry_size = sizeof(elf::DynamicEntry);
 
-    AddEntry(zone, elf::DynamicEntryType::DT_HASH, hash->memory_offset());
-    AddEntry(zone, elf::DynamicEntryType::DT_STRTAB, strtab->memory_offset());
-    AddEntry(zone, elf::DynamicEntryType::DT_STRSZ, strtab->MemorySize());
-    AddEntry(zone, elf::DynamicEntryType::DT_SYMTAB, symtab->memory_offset());
+    // Entries that are not constants are fixed during Elf::Finalize().
+    AddEntry(zone, elf::DynamicEntryType::DT_HASH, kInvalidEntry);
+    AddEntry(zone, elf::DynamicEntryType::DT_STRTAB, kInvalidEntry);
+    AddEntry(zone, elf::DynamicEntryType::DT_STRSZ, kInvalidEntry);
+    AddEntry(zone, elf::DynamicEntryType::DT_SYMTAB, kInvalidEntry);
     AddEntry(zone, elf::DynamicEntryType::DT_SYMENT, sizeof(elf::Symbol));
     AddEntry(zone, elf::DynamicEntryType::DT_NULL, 0);
   }
 
+  static constexpr intptr_t kInvalidEntry = -1;
+
   intptr_t FileSize() const { return entries_.length() * entry_size; }
   intptr_t MemorySize() const { return FileSize(); }
 
@@ -803,6 +728,7 @@
     Entry(elf::DynamicEntryType tag, intptr_t value) : tag(tag), value(value) {}
 
     void Write(ElfWriteStream* stream) {
+      ASSERT(value != kInvalidEntry);
       const intptr_t start = stream->Position();
 #if defined(TARGET_ARCH_IS_32_BIT)
       stream->WriteWord(static_cast<uint32_t>(tag));
@@ -823,6 +749,24 @@
     entries_.Add(entry);
   }
 
+  void FinalizeEntry(elf::DynamicEntryType tag, intptr_t value) {
+    for (auto* entry : entries_) {
+      if (entry->tag == tag) {
+        entry->value = value;
+        break;
+      }
+    }
+  }
+
+  void FinalizeEntries(StringTable* strtab,
+                       SymbolTable* symtab,
+                       SymbolHashTable* hash) {
+    FinalizeEntry(elf::DynamicEntryType::DT_HASH, hash->memory_offset());
+    FinalizeEntry(elf::DynamicEntryType::DT_STRTAB, strtab->memory_offset());
+    FinalizeEntry(elf::DynamicEntryType::DT_STRSZ, strtab->MemorySize());
+    FinalizeEntry(elf::DynamicEntryType::DT_SYMTAB, symtab->memory_offset());
+  }
+
  private:
   GrowableArray<Entry*> entries_;
 };
@@ -846,8 +790,205 @@
   }
 };
 
-// We assume that the final program table fits in a single page of memory.
-static constexpr intptr_t kProgramTableSegmentSize = Elf::kPageSize;
+class BitsContainer : public Section {
+ public:
+  // Fully specified BitsContainer information.
+  BitsContainer(elf::SectionHeaderType type,
+                bool allocate,
+                bool executable,
+                bool writable,
+                intptr_t size,
+                const uint8_t* bytes,
+                const ZoneGrowableArray<Elf::Relocation>* relocations,
+                const ZoneGrowableArray<Elf::SymbolData>* symbols,
+                int alignment = kDefaultAlignment)
+      : Section(type, allocate, executable, writable, alignment),
+        file_size_(type == elf::SectionHeaderType::SHT_NOBITS ? 0 : size),
+        memory_size_(allocate ? size : 0),
+        bytes_(bytes),
+        relocations_(relocations),
+        symbols_(symbols) {
+    ASSERT(type == elf::SectionHeaderType::SHT_NOBITS || bytes != nullptr);
+  }
+
+  // For BitsContainers used only as sections.
+  BitsContainer(elf::SectionHeaderType type,
+                intptr_t size,
+                const uint8_t* bytes,
+                const ZoneGrowableArray<Elf::Relocation>* relocations,
+                const ZoneGrowableArray<Elf::SymbolData>* symbols,
+                intptr_t alignment = kDefaultAlignment)
+      : BitsContainer(type,
+                      /*allocate=*/false,
+                      /*executable=*/false,
+                      /*writable=*/false,
+                      size,
+                      bytes,
+                      relocations,
+                      symbols,
+                      alignment) {}
+
+  // For BitsContainers used as segments whose type differ on the type of the
+  // ELF file. Creates an elf::SHT_PROGBITS section if type is Snapshot,
+  // otherwise creates an elf::SHT_NOBITS section.
+  BitsContainer(Elf::Type t,
+                bool executable,
+                bool writable,
+                intptr_t size,
+                const uint8_t* bytes,
+                const ZoneGrowableArray<Elf::Relocation>* relocations,
+                const ZoneGrowableArray<Elf::SymbolData>* symbols,
+                intptr_t alignment = kDefaultAlignment)
+      : BitsContainer(t == Elf::Type::Snapshot
+                          ? elf::SectionHeaderType::SHT_PROGBITS
+                          : elf::SectionHeaderType::SHT_NOBITS,
+                      /*allocate=*/true,
+                      executable,
+                      writable,
+                      size,
+                      bytes,
+                      relocations,
+                      symbols,
+                      alignment) {}
+
+  const BitsContainer* AsBitsContainer() const { return this; }
+  const ZoneGrowableArray<Elf::SymbolData>* symbols() const { return symbols_; }
+
+  void Write(ElfWriteStream* stream) {
+    if (type == elf::SectionHeaderType::SHT_NOBITS) return;
+    if (relocations_ == nullptr) {
+      return stream->WriteBytes(bytes(), FileSize());
+    }
+    const SymbolTable* symtab = ASSERT_NOTNULL(stream->elf().symtab());
+    // Resolve relocations as we write.
+    intptr_t current_pos = 0;
+    for (const auto& reloc : *relocations_) {
+      // We assume here that the relocations are sorted in increasing order,
+      // with unique section offsets.
+      ASSERT(current_pos <= reloc.section_offset);
+      if (current_pos < reloc.section_offset) {
+        stream->WriteBytes(bytes_ + current_pos,
+                           reloc.section_offset - current_pos);
+      }
+      intptr_t source_address = reloc.source_offset;
+      intptr_t target_address = reloc.target_offset;
+      // Null symbols denote that the corresponding offset should be treated
+      // as an absolute offset in the ELF memory space.
+      if (reloc.source_symbol != nullptr) {
+        const Symbol* const source_symbol = symtab->Find(reloc.source_symbol);
+        ASSERT(source_symbol != nullptr);
+        source_address += source_symbol->offset();
+      }
+      if (reloc.target_symbol != nullptr) {
+        const Symbol* const target_symbol = symtab->Find(reloc.target_symbol);
+        if (target_symbol == nullptr) {
+          ASSERT_EQUAL(strcmp(reloc.target_symbol, kSnapshotBuildIdAsmSymbol),
+                       0);
+          ASSERT_EQUAL(reloc.target_offset, 0);
+          ASSERT_EQUAL(reloc.source_offset, 0);
+          ASSERT_EQUAL(reloc.size_in_bytes, compiler::target::kWordSize);
+          // TODO(dartbug.com/43516): Special case for snapshots with deferred
+          // sections that handles the build ID relocation in an
+          // InstructionsSection when there is no build ID.
+          const word to_write = Image::kNoRelocatedAddress;
+          stream->WriteBytes(reinterpret_cast<const uint8_t*>(&to_write),
+                             reloc.size_in_bytes);
+          current_pos = reloc.section_offset + reloc.size_in_bytes;
+          continue;
+        }
+        target_address += target_symbol->offset();
+      }
+      ASSERT(reloc.size_in_bytes <= kWordSize);
+      const word to_write = target_address - source_address;
+      ASSERT(Utils::IsInt(reloc.size_in_bytes * kBitsPerByte, to_write));
+      stream->WriteBytes(reinterpret_cast<const uint8_t*>(&to_write),
+                         reloc.size_in_bytes);
+      current_pos = reloc.section_offset + reloc.size_in_bytes;
+    }
+    stream->WriteBytes(bytes_ + current_pos, FileSize() - current_pos);
+  }
+
+  uint32_t Hash() const {
+    ASSERT(bytes() != nullptr);
+    return Utils::StringHash(bytes(), MemorySize());
+  }
+
+  intptr_t FileSize() const { return file_size_; }
+  intptr_t MemorySize() const { return memory_size_; }
+  const uint8_t* bytes() const { return bytes_; }
+
+ private:
+  const intptr_t file_size_;
+  const intptr_t memory_size_;
+  const uint8_t* const bytes_;
+  const ZoneGrowableArray<Elf::Relocation>* const relocations_;
+  const ZoneGrowableArray<Elf::SymbolData>* const symbols_;
+};
+
+Elf::Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf)
+    : zone_(zone),
+      unwrapped_stream_(stream),
+      type_(type),
+      dwarf_(dwarf),
+      shstrtab_(new (zone) StringTable(zone, /*allocate=*/false)),
+      dynstrtab_(new (zone) StringTable(zone, /*allocate=*/true)),
+      dynsym_(new (zone) SymbolTable(zone, dynstrtab_, /*dynamic=*/true)),
+      strtab_(new (zone_) StringTable(zone_, /*allocate=*/false)),
+      symtab_(new (zone_) SymbolTable(zone, strtab_, /*dynamic=*/false)) {
+  // Separate debugging information should always have a Dwarf object.
+  ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
+  // Assumed by various offset logic in this file.
+  ASSERT_EQUAL(unwrapped_stream_->Position(), 0);
+}
+
+void Elf::AddSection(Section* section,
+                     const char* name,
+                     const char* symbol_name) {
+  ASSERT(section_table_file_size_ < 0);
+  ASSERT(!shstrtab_->HasBeenFinalized());
+  section->set_name(shstrtab_->AddString(name));
+  // We do not set the section index yet, that will be done during Finalize().
+  sections_.Add(section);
+  // We do set the initial section index in initialized symbols for quick lookup
+  // until reordering happens.
+  const intptr_t initial_section_index = sections_.length() - 1;
+  if (symbol_name != nullptr) {
+    ASSERT(section->IsAllocated());
+    section->symbol_name = symbol_name;
+    // While elf::STT_SECTION might seem more appropriate, section symbols are
+    // usually local and dlsym won't return them.
+    ASSERT(!dynsym_->HasBeenFinalized());
+    dynsym_->AddSymbol(symbol_name, elf::STB_GLOBAL, elf::STT_FUNC,
+                       initial_section_index, section->MemorySize());
+    // Some tools assume the static symbol table is a superset of the dynamic
+    // symbol table when it exists (see dartbug.com/41783).
+    ASSERT(!symtab_->HasBeenFinalized());
+    symtab_->AddSymbol(symbol_name, elf::STB_GLOBAL, elf::STT_FUNC,
+                       initial_section_index, section->FileSize());
+  }
+  if (auto const container = section->AsBitsContainer()) {
+    if (container->symbols() != nullptr) {
+      ASSERT(section->IsAllocated());
+      for (const auto& symbol_data : *container->symbols()) {
+        ASSERT(!symtab_->HasBeenFinalized());
+        symtab_->AddSymbol(symbol_data.name, elf::STB_LOCAL, symbol_data.type,
+                           initial_section_index, symbol_data.size);
+      }
+    }
+  }
+}
+
+void Elf::AddText(const char* name,
+                  const uint8_t* bytes,
+                  intptr_t size,
+                  const ZoneGrowableArray<Relocation>* relocations,
+                  const ZoneGrowableArray<SymbolData>* symbols) {
+  auto const image =
+      new (zone_) BitsContainer(type_, /*executable=*/true,
+                                /*writable=*/false, size, bytes, relocations,
+                                symbols, ImageWriter::kTextAlignment);
+  AddSection(image, ".text", name);
+}
 
 // Here, both VM and isolate will be compiled into a single snapshot.
 // In assembly generation, each serialized text section gets a separate
@@ -861,6 +1002,431 @@
     BSS::kIsolateEntryCount * compiler::target::kWordSize;
 static constexpr intptr_t kBssSize = kBssVmSize + kBssIsolateSize;
 
+void Elf::CreateBSS() {
+  uint8_t* bytes = nullptr;
+  if (type_ == Type::Snapshot) {
+    // Ideally the BSS segment would take no space in the object, but Android's
+    // "strip" utility truncates the memory-size of our segments to their
+    // file-size.
+    //
+    // Therefore we must insert zero-filled data for the BSS.
+    bytes = zone_->Alloc<uint8_t>(kBssSize);
+    memset(bytes, 0, kBssSize);
+  }
+  // For the BSS section, we add two local symbols to the static symbol table,
+  // one for each isolate. We use local symbols because these addresses are only
+  // used for relocation. (This matches the behavior in the assembly output,
+  // where these symbols are also local.)
+  auto* bss_symbols = new (zone_) ZoneGrowableArray<Elf::SymbolData>();
+  bss_symbols->Add({kVmSnapshotBssAsmSymbol, elf::STT_SECTION, 0, kBssVmSize});
+  bss_symbols->Add({kIsolateSnapshotBssAsmSymbol, elf::STT_SECTION, kBssVmSize,
+                    kBssIsolateSize});
+  bss_ = new (zone_) BitsContainer(
+      type_, /*executable=*/false, /*writable=*/true, kBssSize, bytes,
+      /*relocations=*/nullptr, bss_symbols, ImageWriter::kBssAlignment);
+  AddSection(bss_, ".bss");
+}
+
+void Elf::AddROData(const char* name,
+                    const uint8_t* bytes,
+                    intptr_t size,
+                    const ZoneGrowableArray<Relocation>* relocations,
+                    const ZoneGrowableArray<SymbolData>* symbols) {
+  auto const image =
+      new (zone_) BitsContainer(type_, /*executable=*/false,
+                                /*writable=*/false, size, bytes, relocations,
+                                symbols, ImageWriter::kRODataAlignment);
+  AddSection(image, ".rodata", name);
+}
+
+#if defined(DART_PRECOMPILER)
+class DwarfElfStream : public DwarfWriteStream {
+ public:
+  DwarfElfStream(Zone* zone, NonStreamingWriteStream* stream)
+      : zone_(ASSERT_NOTNULL(zone)),
+        stream_(ASSERT_NOTNULL(stream)),
+        relocations_(new (zone) ZoneGrowableArray<Elf::Relocation>()) {}
+
+  const uint8_t* buffer() const { return stream_->buffer(); }
+  intptr_t bytes_written() const { return stream_->bytes_written(); }
+
+  void sleb128(intptr_t value) { stream_->WriteSLEB128(value); }
+  void uleb128(uintptr_t value) { stream_->WriteLEB128(value); }
+  void u1(uint8_t value) { stream_->WriteByte(value); }
+  void u2(uint16_t value) { stream_->WriteFixed(value); }
+  void u4(uint32_t value) { stream_->WriteFixed(value); }
+  void u8(uint64_t value) { stream_->WriteFixed(value); }
+  void string(const char* cstr) {  // NOLINT
+    // Unlike stream_->WriteString(), we want the null terminator written.
+    stream_->WriteBytes(cstr, strlen(cstr) + 1);
+  }
+  // The prefix is ignored for DwarfElfStreams.
+  EncodedPosition WritePrefixedLength(const char* symbol_prefix,
+                                      std::function<void()> body) {
+    const intptr_t fixup = stream_->Position();
+    // We assume DWARF v2 currently, so all sizes are 32-bit.
+    u4(0);
+    // All sizes for DWARF sections measure the size of the section data _after_
+    // the size value.
+    const intptr_t start = stream_->Position();
+    body();
+    const intptr_t end = stream_->Position();
+    stream_->SetPosition(fixup);
+    u4(end - start);
+    stream_->SetPosition(end);
+    return EncodedPosition(start);
+  }
+  // Shorthand for when working directly with DwarfElfStreams.
+  intptr_t WritePrefixedLength(std::function<void()> body) {
+    const EncodedPosition& pos = WritePrefixedLength(nullptr, body);
+    return pos.position();
+  }
+
+  void OffsetFromSymbol(const char* symbol, intptr_t offset) {
+    relocations_->Add(
+        {kAddressSize, stream_->Position(), nullptr, 0, symbol, offset});
+    addr(0);  // Resolved later.
+  }
+  template <typename T>
+  void SizedOffsetFromSymbol(const char* symbol, intptr_t offset) {
+    relocations_->Add(
+        {sizeof(T), stream_->Position(), nullptr, 0, symbol, offset});
+    stream_->WriteFixed<T>(0);  // Resolved later.
+  }
+  void InitializeAbstractOrigins(intptr_t size) {
+    abstract_origins_size_ = size;
+    abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_);
+  }
+  void RegisterAbstractOrigin(intptr_t index) {
+    ASSERT(abstract_origins_ != nullptr);
+    ASSERT(index < abstract_origins_size_);
+    abstract_origins_[index] = stream_->Position();
+  }
+  void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
+
+  const ZoneGrowableArray<Elf::Relocation>* relocations() const {
+    return relocations_;
+  }
+
+ protected:
+#if defined(TARGET_ARCH_IS_32_BIT)
+  static constexpr intptr_t kAddressSize = kInt32Size;
+#else
+  static constexpr intptr_t kAddressSize = kInt64Size;
+#endif
+
+  void addr(uword value) {
+#if defined(TARGET_ARCH_IS_32_BIT)
+    u4(value);
+#else
+    u8(value);
+#endif
+  }
+
+  Zone* const zone_;
+  NonStreamingWriteStream* const stream_;
+  ZoneGrowableArray<Elf::Relocation>* relocations_ = nullptr;
+  uint32_t* abstract_origins_ = nullptr;
+  intptr_t abstract_origins_size_ = -1;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DwarfElfStream);
+};
+
+static constexpr intptr_t kInitialDwarfBufferSize = 64 * KB;
+#endif
+
+const Section* Elf::FindSectionBySymbolName(const char* name) const {
+  const Symbol* const symbol = symtab_->Find(name);
+  if (symbol == nullptr) return nullptr;
+  // Should not be run between OrderSectionsAndCreateSegments (when section
+  // indices may change) and FinalizeSymbols() (sets the final section index).
+  ASSERT(segments_.length() == 0 || symbol->HasBeenFinalized());
+  const Section* const section = sections_[symbol->section_index];
+  ASSERT_EQUAL(strcmp(section->symbol_name, name), 0);
+  return section;
+}
+
+void Elf::FinalizeSymbols() {
+  // Must be run after OrderSectionsAndCreateSegments and ComputeOffsets.
+  ASSERT(segments_.length() > 0);
+  ASSERT(section_table_file_offset_ > 0);
+  for (const auto& section : sections_) {
+    if (section->symbol_name != nullptr) {
+      dynsym_->FinalizeSymbol(section->symbol_name, section->index(),
+                              section->memory_offset());
+      symtab_->FinalizeSymbol(section->symbol_name, section->index(),
+                              section->memory_offset());
+    }
+    if (auto const container = section->AsBitsContainer()) {
+      if (container->symbols() != nullptr) {
+        for (const auto& symbol_data : *container->symbols()) {
+          symtab_->FinalizeSymbol(
+              symbol_data.name, section->index(),
+              section->memory_offset() + symbol_data.offset);
+        }
+      }
+    }
+  }
+}
+
+void Elf::FinalizeEhFrame() {
+#if defined(DART_PRECOMPILER) &&                                               \
+    (defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64))
+  // Multiplier which will be used to scale operands of DW_CFA_offset and
+  // DW_CFA_val_offset.
+  const intptr_t kDataAlignment = compiler::target::kWordSize;
+
+  static const uint8_t DW_EH_PE_pcrel = 0x10;
+  static const uint8_t DW_EH_PE_sdata4 = 0x0b;
+
+  ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
+  DwarfElfStream dwarf_stream(zone_, &stream);
+
+  // Emit CIE.
+
+  // Used to calculate offset to CIE in FDEs.
+  const intptr_t cie_start = dwarf_stream.WritePrefixedLength([&] {
+    dwarf_stream.u4(0);  // CIE
+    dwarf_stream.u1(1);  // Version (must be 1 or 3)
+    // Augmentation String
+    dwarf_stream.string("zR");             // NOLINT
+    dwarf_stream.uleb128(1);               // Code alignment (must be 1).
+    dwarf_stream.sleb128(kDataAlignment);  // Data alignment
+    dwarf_stream.u1(
+        ConcreteRegister(LINK_REGISTER));  // Return address register
+    dwarf_stream.uleb128(1);               // Augmentation size
+    dwarf_stream.u1(DW_EH_PE_pcrel | DW_EH_PE_sdata4);  // FDE encoding.
+    // CFA is FP+0
+    dwarf_stream.u1(Dwarf::DW_CFA_def_cfa);
+    dwarf_stream.uleb128(FP);
+    dwarf_stream.uleb128(0);
+  });
+
+  // Emit an FDE covering each .text section.
+  const auto text_name = shstrtab_->Lookup(".text");
+  ASSERT(text_name != StringTable::kNotIndexed);
+  for (auto section : sections_) {
+    if (section->name() != text_name) continue;
+    dwarf_stream.WritePrefixedLength([&]() {
+      // Offset to CIE. Note that unlike pcrel this offset is encoded
+      // backwards: it will be subtracted from the current position.
+      dwarf_stream.u4(stream.Position() - cie_start);
+      // Start address. 4 bytes because DW_EH_PE_sdata4 used in FDE encoding.
+      // Note: If (DW_EH_PE_pcrel | DW_EH_PE_absptr) can be used instead, we
+      // wouldn't need a special version of OffsetForSymbol just for this.
+      dwarf_stream.SizedOffsetFromSymbol<int32_t>(section->symbol_name, 0);
+      dwarf_stream.u4(section->MemorySize());  // Size.
+      dwarf_stream.u1(0);                      // Augmentation Data length.
+
+      // FP at FP+kSavedCallerPcSlotFromFp*kWordSize
+      COMPILE_ASSERT(kSavedCallerFpSlotFromFp >= 0);
+      dwarf_stream.u1(Dwarf::DW_CFA_offset | FP);
+      dwarf_stream.uleb128(kSavedCallerFpSlotFromFp);
+
+      // LR at FP+kSavedCallerPcSlotFromFp*kWordSize
+      COMPILE_ASSERT(kSavedCallerPcSlotFromFp >= 0);
+      dwarf_stream.u1(Dwarf::DW_CFA_offset | ConcreteRegister(LINK_REGISTER));
+      dwarf_stream.uleb128(kSavedCallerPcSlotFromFp);
+
+      // SP is FP+kCallerSpSlotFromFp*kWordSize
+      COMPILE_ASSERT(kCallerSpSlotFromFp >= 0);
+      dwarf_stream.u1(Dwarf::DW_CFA_val_offset);
+#if defined(TARGET_ARCH_ARM64)
+      dwarf_stream.uleb128(ConcreteRegister(CSP));
+#elif defined(TARGET_ARCH_ARM)
+      dwarf_stream.uleb128(SP);
+#else
+#error "Unsupported .eh_frame architecture"
+#endif
+      dwarf_stream.uleb128(kCallerSpSlotFromFp);
+    });
+  }
+
+  dwarf_stream.u4(0);  // end of section
+
+  auto const eh_frame = new (zone_)
+      BitsContainer(type_, /*writable=*/false, /*executable=*/false,
+                    dwarf_stream.bytes_written(), dwarf_stream.buffer(),
+                    dwarf_stream.relocations(), /*symbols=*/nullptr);
+  AddSection(eh_frame, ".eh_frame");
+#endif  // defined(DART_PRECOMPILER) && \
+        //   (defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64))
+}
+
+void Elf::FinalizeDwarfSections() {
+  if (dwarf_ == nullptr) return;
+#if defined(DART_PRECOMPILER)
+  auto add_debug = [&](const char* name, const DwarfElfStream& stream) {
+    auto const image = new (zone_) BitsContainer(
+        elf::SectionHeaderType::SHT_PROGBITS, stream.bytes_written(),
+        stream.buffer(), stream.relocations(), /*symbols=*/nullptr);
+    AddSection(image, name);
+  };
+  {
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
+    DwarfElfStream dwarf_stream(zone_, &stream);
+    dwarf_->WriteAbbreviations(&dwarf_stream);
+    add_debug(".debug_abbrev", dwarf_stream);
+  }
+
+  {
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
+    DwarfElfStream dwarf_stream(zone_, &stream);
+    dwarf_->WriteDebugInfo(&dwarf_stream);
+    add_debug(".debug_info", dwarf_stream);
+  }
+
+  {
+    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
+    DwarfElfStream dwarf_stream(zone_, &stream);
+    dwarf_->WriteLineNumberProgram(&dwarf_stream);
+    add_debug(".debug_line", dwarf_stream);
+  }
+#endif
+}
+
+void Elf::OrderSectionsAndCreateSegments() {
+  GrowableArray<Section*> reordered_sections;
+  // The first section in the section header table is always a reserved
+  // entry containing only 0 values.
+  reordered_sections.Add(new (zone_) ReservedSection());
+
+  Segment* current_segment = nullptr;
+  auto add_to_reordered_sections = [&](Section* section) {
+    section->set_index(reordered_sections.length());
+    reordered_sections.Add(section);
+    if (!section->IsAllocated()) return;
+    const bool was_added =
+        current_segment == nullptr ? false : current_segment->Add(section);
+    if (!was_added) {
+      // There is no current segment or it is incompatible for merging, so
+      // following compatible segments will be merged into this one if possible.
+      current_segment =
+          new (zone_) Segment(zone_, section, elf::ProgramHeaderType::PT_LOAD);
+      section->load_segment = current_segment;
+      segments_.Add(current_segment);
+    }
+  };
+
+  // Add writable, non-executable sections first, due to a bug in Jelly Bean's
+  // ELF loader when a writable segment is placed between two non-writable
+  // segments. See also Elf::WriteProgramTable(), which double-checks this.
+  for (auto* const section : sections_) {
+    if (section->IsAllocated() && section->IsWritable() &&
+        !section->IsExecutable()) {
+      add_to_reordered_sections(section);
+    }
+  }
+
+  // Now add the non-writable, non-executable allocated sections in a new
+  // segment, starting with the data sections.
+  for (auto* const section : sections_) {
+    if (section->IsAllocated() && !section->IsWritable() &&
+        !section->IsExecutable()) {
+      add_to_reordered_sections(section);
+    }
+  }
+
+  // Now add the non-writable, executable sections in a new segment.
+  for (auto* const section : sections_) {
+    if (section->IsAllocated() && !section->IsWritable() &&
+        section->IsExecutable()) {
+      add_to_reordered_sections(section);
+    }
+  }
+
+  // We put all unallocated sections last because otherwise, they would
+  // affect the file offset but not the memory offset of any following allocated
+  // sections. Doing it in this order makes it easier to keep file and memory
+  // offsets page-aligned with respect to each other, which is required for
+  // some loaders.
+  for (auto* const section : sections_) {
+    if (!section->IsAllocated()) {
+      add_to_reordered_sections(section);
+    }
+  }
+
+  // Now replace sections_.
+  sections_.Clear();
+  sections_.AddArray(reordered_sections);
+}
+
+void Elf::Finalize() {
+  ASSERT(program_table_file_size_ < 0);
+
+  // Generate the build ID now that we have all user-provided sections.
+  // Generating it at this point also means it'll be the first writable
+  // non-executable section added to sections_ and thus end up right after the
+  // program table after reordering. This limits how much of the ELF file needs
+  // to be read to get the build ID (header + program table + note segment).
+  GenerateBuildId();
+
+  // We add BSS in all cases, even to the separate debugging information ELF,
+  // to ensure that relocated addresses are consistent between ELF snapshots
+  // and ELF separate debugging information.
+  CreateBSS();
+
+  // Adding the dynamic symbol table and associated sections.
+  AddSection(dynstrtab_, ".dynstr");
+  AddSection(dynsym_, ".dynsym");
+
+  auto const hash = new (zone_) SymbolHashTable(zone_, dynstrtab_, dynsym_);
+  AddSection(hash, ".hash");
+
+  auto const dynamic = new (zone_) DynamicTable(zone_);
+  AddSection(dynamic, ".dynamic");
+
+  if (!IsStripped()) {
+    AddSection(strtab_, ".strtab");
+    AddSection(symtab_, ".symtab");
+  }
+  AddSection(shstrtab_, ".shstrtab");
+  FinalizeEhFrame();
+  FinalizeDwarfSections();
+
+  OrderSectionsAndCreateSegments();
+
+  // Now that the sections have indices, set up links between them as needed.
+  dynsym_->link = dynstrtab_->index();
+  hash->link = dynsym_->index();
+  dynamic->link = dynstrtab_->index();
+  if (!IsStripped()) {
+    symtab_->link = strtab_->index();
+  }
+
+  // Now add any special non-load segments.
+
+  if (build_id_ != nullptr) {
+    // Add a PT_NOTE segment for the build ID.
+    segments_.Add(new (zone_) NoteSegment(zone_, build_id_));
+  }
+
+  // Add a PT_DYNAMIC segment for the dynamic symbol table.
+  segments_.Add(new (zone_) DynamicSegment(zone_, dynamic));
+
+  // At this point, all sections have been added and ordered and all sections
+  // appropriately grouped into segments. Add the program table and then
+  // calculate file and memory offsets.
+  FinalizeProgramTable();
+  ComputeOffsets();
+
+  // Now that we have reordered the sections and set memory offsets, we can
+  // update the symbol tables to add index and address information. This must
+  // be done prior to writing the symbol tables and any sections with
+  // relocations.
+  FinalizeSymbols();
+  // Also update the entries in the dynamic table.
+  dynamic->FinalizeEntries(dynstrtab_, dynsym_, hash);
+
+  // Finally, write the ELF file contents.
+  ElfWriteStream wrapped(unwrapped_stream_, *this);
+  WriteHeader(&wrapped);
+  WriteProgramTable(&wrapped);
+  WriteSections(&wrapped);
+  WriteSectionTable(&wrapped);
+}
+
 // For the build ID, we generate a 128-bit hash, where each 32 bits is a hash of
 // the contents of the following segments in order:
 //
@@ -877,610 +1443,34 @@
 static constexpr intptr_t kBuildIdHeaderSize =
     sizeof(elf::Note) + sizeof(elf::ELF_NOTE_GNU);
 
-Elf::Elf(Zone* zone, BaseWriteStream* stream, Type type, Dwarf* dwarf)
-    : zone_(zone),
-      unwrapped_stream_(stream),
-      type_(type),
-      dwarf_(dwarf),
-      bss_(CreateBSS(zone, type, kBssSize)),
-      shstrtab_(new (zone) StringTable(zone, /*allocate=*/false)),
-      dynstrtab_(new (zone) StringTable(zone, /*allocate=*/true)),
-      dynsym_(new (zone) SymbolTable(zone, dynstrtab_, /*dynamic=*/true)) {
-  // Separate debugging information should always have a Dwarf object.
-  ASSERT(type_ == Type::Snapshot || dwarf_ != nullptr);
-  // Assumed by various offset logic in this file.
-  ASSERT_EQUAL(unwrapped_stream_->Position(), 0);
-  // The first section in the section header table is always a reserved
-  // entry containing only 0 values.
-  sections_.Add(new (zone_) ReservedSection());
-  if (!IsStripped()) {
-    // Not a stripped ELF file, so allocate static string and symbol tables.
-    strtab_ = new (zone_) StringTable(zone_, /* allocate= */ false);
-    symtab_ = new (zone_) SymbolTable(zone, strtab_, /*dynamic=*/false);
-  }
-  // We add an initial segment to represent reserved space for the program
-  // header, and so we can always assume there's at least one segment in the
-  // segments_ array. We later remove this and replace it with appropriately
-  // calculated segments in Elf::FinalizeProgramTable().
-  auto const start_segment =
-      new (zone_) ProgramTableLoadSegment(zone_, kProgramTableSegmentSize);
-  segments_.Add(start_segment);
-  // We allocate an initial build ID of all zeroes, since we need the build ID
-  // memory offset for the InstructionsSection (see BlobImageWriter::WriteText).
-  // We replace it with the real build ID during finalization. (We add this
-  // prior to BSS because we make the BuildID section writable also, so they are
-  // placed in the same segment before any non-writable ones, and if we add it
-  // after, then in separate debugging information, it'll go into a separate
-  // segment because the BSS section for debugging info is NOBITS.)
-  {
-    uint32_t zeroes[kBuildIdSegmentNamesLength] = {0};
-    build_id_ = CreateBuildIdNote(&zeroes, sizeof(zeroes));
-    AddSection(build_id_, kBuildIdNoteName, kSnapshotBuildIdAsmSymbol);
-  }
-  // Note that the BSS segment must be in the first user-defined segment because
-  // it cannot be placed in between any two non-writable segments, due to a bug
-  // in Jelly Bean's ELF loader. (For this reason, the program table segments
-  // generated during finalization are marked as writable.) See also
-  // Elf::WriteProgramTable().
-  //
-  // We add it in all cases, even to the separate debugging information ELF,
-  // to ensure that relocated addresses are consistent between ELF snapshots
-  // and ELF separate debugging information.
-  auto const bss_start = AddSection(bss_, ".bss");
-  // For the BSS section, we add two local symbols to the static symbol table,
-  // one for each isolate. We use local symbols because these addresses are only
-  // used for relocation. (This matches the behavior in the assembly output,
-  // where these symbols are also local.)
-  AddStaticSymbol(kVmSnapshotBssAsmSymbol, elf::STB_LOCAL, elf::STT_SECTION,
-                  bss_->index(), bss_start, kBssVmSize);
-  AddStaticSymbol(kIsolateSnapshotBssAsmSymbol, elf::STB_LOCAL,
-                  elf::STT_SECTION, bss_->index(), bss_start + kBssVmSize,
-                  kBssIsolateSize);
-}
-
-intptr_t Elf::NextMemoryOffset(intptr_t alignment) const {
-  // Without more information, we won't know whether we might create a new
-  // segment or put the section into the current one. Thus, for now, only allow
-  // the offset to be queried ahead of time if it matches the load segment
-  // alignment.
-  auto const type = elf::ProgramHeaderType::PT_LOAD;
-  ASSERT_EQUAL(alignment, Segment::Alignment(type));
-  return Utils::RoundUp(LastLoadSegment()->MemoryEnd(), alignment);
-}
-
-uword Elf::SymbolAddress(const char* name) const {
-  ASSERT(name != nullptr);
-  // Check the static symbol table first if it exists, since the dynamic
-  // table is a subset of it. Fall back on the dynamic otherwise.
-  if (symtab_ != nullptr) {
-    if (auto const symbol = symtab_->Find(name)) {
-      return symbol->offset;
-    }
-  } else if (auto const symbol = dynsym_->Find(name)) {
-    return symbol->offset;
-  }
-  // If stripping, then we won't have symbols for the BSS sections because
-  // they're only added to the static symbol table. Check for these special
-  // cases before returning kNoSectionStart.
-  if (strcmp(name, kVmSnapshotBssAsmSymbol) == 0) {
-    ASSERT(bss_ != nullptr);
-    ASSERT(bss_->memory_offset_is_set());
-    return bss_->memory_offset();
-  } else if (strcmp(name, kIsolateSnapshotBssAsmSymbol) == 0) {
-    ASSERT(bss_ != nullptr);
-    ASSERT(bss_->memory_offset_is_set());
-    return bss_->memory_offset() + kBssVmSize;
-  }
-  return kNoSectionStart;
-}
-
-intptr_t Elf::AddSection(Section* section,
-                         const char* name,
-                         const char* symbol_name) {
-  ASSERT(section_table_file_size_ < 0);
-  ASSERT(!shstrtab_->HasBeenFinalized());
-  section->set_name(shstrtab_->AddString(name));
-  section->set_index(sections_.length());
-  sections_.Add(section);
-
-  // No memory offset, so just return -1.
-  if (!section->IsAllocated()) return -1;
-
-  ASSERT(program_table_file_size_ < 0);
-  auto const last_load = LastLoadSegment();
-  if (!last_load->Add(section)) {
-    // We can't add this section to the last load segment, so create a new one.
-    // The new segment starts at the next aligned address.
-    auto const type = elf::ProgramHeaderType::PT_LOAD;
-    intptr_t alignment =
-        Utils::Maximum(section->alignment, Segment::Alignment(type));
-    auto const start_address =
-        Utils::RoundUp(last_load->MemoryEnd(), alignment);
-    section->set_memory_offset(start_address);
-    auto const segment = new (zone_) Segment(zone_, section, type);
-    segments_.Add(segment);
-  }
-  if (symbol_name != nullptr) {
-    // While elf::STT_SECTION might seem more appropriate, section symbols are
-    // usually local and dlsym won't return them.
-    AddDynamicSymbol(symbol_name, elf::STB_GLOBAL, elf::STT_FUNC,
-                     section->index(), section->memory_offset(),
-                     section->MemorySize());
-  }
-  return section->memory_offset();
-}
-
-void Elf::ReplaceSection(Section* old_section, Section* new_section) {
-  ASSERT(section_table_file_size_ < 0);
-  ASSERT(old_section->index_is_set());
-  ASSERT(!new_section->index_is_set());
-  ASSERT_EQUAL(new_section->IsAllocated(), old_section->IsAllocated());
-  new_section->set_name(old_section->name());
-  new_section->set_index(old_section->index());
-  sections_[old_section->index()] = new_section;
-
-  if (!old_section->IsAllocated()) {
-    return;
-  }
-
-  ASSERT(program_table_file_size_ < 0);
-  ASSERT(old_section->load_segment != nullptr);
-  old_section->load_segment->Replace(old_section, new_section);
-}
-
-intptr_t Elf::AddText(const char* name, const uint8_t* bytes, intptr_t size) {
-  auto const image = new (zone_) BitsContainer(type_, /*executable=*/true,
-                                               /*writable=*/false, size, bytes,
-                                               ImageWriter::kTextAlignment);
-  return AddSection(image, ".text", name);
-}
-
-Section* Elf::CreateBSS(Zone* zone, Type type, intptr_t size) {
-  uint8_t* bytes = nullptr;
-  if (type == Type::Snapshot) {
-    // Ideally the BSS segment would take no space in the object, but Android's
-    // "strip" utility truncates the memory-size of our segments to their
-    // file-size.
-    //
-    // Therefore we must insert zero-filled pages for the BSS.
-    bytes = zone->Alloc<uint8_t>(size);
-    memset(bytes, 0, size);
-  }
-  return new (zone) BitsContainer(type, /*executable=*/false, /*writable=*/true,
-                                  kBssSize, bytes, ImageWriter::kBssAlignment);
-}
-
-intptr_t Elf::AddROData(const char* name, const uint8_t* bytes, intptr_t size) {
-  auto const image = new (zone_) BitsContainer(type_, /*executable=*/false,
-                                               /*writable=*/false, size, bytes,
-                                               ImageWriter::kRODataAlignment);
-  return AddSection(image, ".rodata", name);
-}
-
-void Elf::AddDebug(const char* name, const uint8_t* bytes, intptr_t size) {
-  ASSERT(!IsStripped());
-  ASSERT(bytes != nullptr);
-  auto const image = new (zone_)
-      BitsContainer(elf::SectionHeaderType::SHT_PROGBITS, size, bytes);
-  AddSection(image, name);
-}
-
-void Elf::AddLocalSymbol(const char* name,
-                         intptr_t type,
-                         intptr_t offset,
-                         intptr_t size) {
-  const intptr_t section_index = sections_.length();
-  // Assume the next section will go into its own segment (currently true
-  // because we write writable sections, data vm (non-writable, non-executable),
-  // text vm (executable), data isolate (non-executable), text isolate
-  // (executable), and we only call this for data and text sections).
-  const intptr_t address =
-      NextMemoryOffset(ImageWriter::kTextAlignment) + offset;
-  AddStaticSymbol(name, elf::STB_LOCAL, type, section_index, address, size);
-}
-
-void Elf::AddDynamicSymbol(const char* name,
-                           intptr_t binding,
-                           intptr_t type,
-                           intptr_t section_index,
-                           intptr_t address,
-                           intptr_t size) {
-  ASSERT(!dynsym_->HasBeenFinalized());
-  dynsym_->AddSymbol(name, binding, type, section_index, address, size);
-
-  // Some tools assume the static symbol table is a superset of the dynamic
-  // symbol table when it exists (see dartbug.com/41783).
-  AddStaticSymbol(name, binding, type, section_index, address, size);
-}
-
-void Elf::AddStaticSymbol(const char* name,
-                          intptr_t binding,
-                          intptr_t type,
-                          intptr_t section_index,
-                          intptr_t address,
-                          intptr_t size) {
-  if (IsStripped()) return;  // No static info kept in stripped ELF files.
-  ASSERT(!symtab_->HasBeenFinalized());
-  symtab_->AddSymbol(name, binding, type, section_index, address, size);
-}
-
-#if defined(DART_PRECOMPILER)
-class DwarfElfStream : public DwarfWriteStream {
- public:
-  explicit DwarfElfStream(Zone* zone,
-                          NonStreamingWriteStream* stream,
-                          const SymbolTable* table)
-      : zone_(ASSERT_NOTNULL(zone)),
-        stream_(ASSERT_NOTNULL(stream)),
-        table_(table) {}
-
-  void sleb128(intptr_t value) { stream_->WriteSLEB128(value); }
-  void uleb128(uintptr_t value) { stream_->WriteLEB128(value); }
-  void u1(uint8_t value) { stream_->WriteByte(value); }
-  void u2(uint16_t value) { stream_->WriteFixed(value); }
-  void u4(uint32_t value) { stream_->WriteFixed(value); }
-  void u8(uint64_t value) { stream_->WriteFixed(value); }
-  void string(const char* cstr) {  // NOLINT
-    // Unlike stream_->WriteString(), we want the null terminator written.
-    stream_->WriteBytes(cstr, strlen(cstr) + 1);
-  }
-  intptr_t ReserveSize(const char* prefix, intptr_t* start) {
-    ASSERT(start != nullptr);
-    intptr_t fixup = stream_->Position();
-    // We assume DWARF v2, so all sizes are 32-bit.
-    u4(0);
-    // All sizes for DWARF sections measure the size of the section data _after_
-    // the size value.
-    *start = stream_->Position();
-    return fixup;
-  }
-  void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
-    const intptr_t old_position = stream_->Position();
-    stream_->SetPosition(fixup);
-    stream_->WriteFixed(static_cast<uint32_t>(old_position - start));
-    stream_->SetPosition(old_position);
-  }
-  void OffsetFromSymbol(const char* symbol, intptr_t offset) {
-    addr(RelocatedAddress(symbol, offset));
-  }
-  void DistanceBetweenSymbolOffsets(const char* symbol1,
-                                    intptr_t offset1,
-                                    const char* symbol2,
-                                    intptr_t offset2) {
-    auto const address1 = RelocatedAddress(symbol1, offset1);
-    auto const address2 = RelocatedAddress(symbol2, offset2);
-    RELEASE_ASSERT(address1 >= address2);
-    auto const delta = address1 - address2;
-    uleb128(delta);
-  }
-  void InitializeAbstractOrigins(intptr_t size) {
-    abstract_origins_size_ = size;
-    abstract_origins_ = zone_->Alloc<uint32_t>(abstract_origins_size_);
-  }
-  void RegisterAbstractOrigin(intptr_t index) {
-    ASSERT(abstract_origins_ != nullptr);
-    ASSERT(index < abstract_origins_size_);
-    abstract_origins_[index] = stream_->Position();
-  }
-  void AbstractOrigin(intptr_t index) { u4(abstract_origins_[index]); }
-
- private:
-  uword RelocatedAddress(const char* name, intptr_t offset) {
-    auto const symbol = table_->Find(name);
-    ASSERT(symbol != nullptr);
-    return symbol->offset + offset;
-  }
-
-  void addr(uword value) {
-#if defined(TARGET_ARCH_IS_32_BIT)
-    u4(value);
-#else
-    u8(value);
-#endif
-  }
-
-  Zone* const zone_;
-  NonStreamingWriteStream* const stream_;
-  const SymbolTable* table_;
-  uint32_t* abstract_origins_ = nullptr;
-  intptr_t abstract_origins_size_ = -1;
-
-  DISALLOW_COPY_AND_ASSIGN(DwarfElfStream);
-};
-
-static constexpr intptr_t kInitialDwarfBufferSize = 64 * KB;
-#endif
-
-Segment* Elf::LastLoadSegment() const {
-  for (intptr_t i = segments_.length() - 1; i >= 0; i--) {
-    auto const segment = segments_.At(i);
-    if (segment->type == elf::ProgramHeaderType::PT_LOAD) {
-      return segment;
-    }
-  }
-  // There should always be a load segment, since one is added in construction.
-  UNREACHABLE();
-}
-
-const Section* Elf::FindSectionForAddress(intptr_t address) const {
-  for (auto const section : sections_) {
-    if (!section->IsAllocated()) continue;
-    auto const start = section->memory_offset();
-    auto const end = start + section->MemorySize();
-    if (address >= start && address < end) {
-      return section;
-    }
-  }
-  return nullptr;
-}
-
-void Elf::FinalizeEhFrame() {
-#if defined(DART_PRECOMPILER) &&                                               \
-    (defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64))
-  // Multiplier which will be used to scale operands of DW_CFA_offset and
-  // DW_CFA_val_offset.
-  const intptr_t kDataAlignment = compiler::target::kWordSize;
-
-  const uint8_t DW_CFA_offset = 0x80;
-  const uint8_t DW_CFA_val_offset = 0x14;
-  const uint8_t DW_CFA_def_cfa = 0x0c;
-
-  // Relocation from .eh_frame into bytes within some previously emitted
-  // section.
-  struct Reloc {
-    intptr_t target_memory_offset;
-    intptr_t source_offset;
-  };
-
-  GrowableArray<Reloc> relocs(2);
-  ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
-  DwarfElfStream dwarf_stream(zone_, &stream, /*symtab=*/nullptr);
-
-  // Emits length prefixed CIE or FDE, returns starting offset.
-  auto emit_record = [&](auto&& body) -> intptr_t {
-    const intptr_t start = stream.Position();
-    stream.WriteFixed<uint32_t>(0);
-    body();
-    stream.Align(compiler::target::kWordSize);
-    const intptr_t end = stream.Position();
-    stream.SetPosition(start);
-    // Write length not counting the length field itself.
-    stream.WriteFixed(static_cast<uint32_t>(end - start - 4));
-    stream.SetPosition(end);
-    return start;
-  };
-
-  // Emit pcrel|sdata4 reference to the target memory offset.
-  auto add_pcrel_ref = [&](intptr_t target_memory_offset) {
-    relocs.Add({target_memory_offset, stream.Position()});
-    dwarf_stream.u4(0);
-  };
-
-  // Emit CIE.
-  const intptr_t cie_position = emit_record([&]() {
-    dwarf_stream.u4(0);  // CIE
-    dwarf_stream.u1(1);  // Version (must be 1 or 3)
-    // Augmentation String
-    dwarf_stream.string("zR");             // NOLINT
-    dwarf_stream.uleb128(1);               // Code alignment (must be 1).
-    dwarf_stream.sleb128(kDataAlignment);  // Data alignment
-    dwarf_stream.u1(
-        ConcreteRegister(LINK_REGISTER));  // Return address register
-    dwarf_stream.uleb128(1);               // Augmentation size
-    dwarf_stream.u1(0x1b);  // FDE encoding: DW_EH_PE_pcrel | DW_EH_PE_sdata4
-    // CFA is FP+0
-    dwarf_stream.u1(DW_CFA_def_cfa);
-    dwarf_stream.uleb128(FP);
-    dwarf_stream.uleb128(0);
-  });
-
-  // Emit an FDE covering each .text section.
-  const auto text_name = shstrtab_->Lookup(".text");
-  ASSERT(text_name != StringTable::kNotIndexed);
-  for (auto section : sections_) {
-    if (section->name() == text_name) {
-      RELEASE_ASSERT(section->memory_offset_is_set());
-      emit_record([&]() {
-        // Offset to CIE. Note that unlike pcrel this offset is encoded
-        // backwards: it will be subtracted from the current position.
-        dwarf_stream.u4(stream.Position() - cie_position);
-        add_pcrel_ref(section->memory_offset());  // Start address.
-        dwarf_stream.u4(section->MemorySize());   // Size.
-        dwarf_stream.u1(0);                       // Augmentation Data length.
-
-        // FP at FP+kSavedCallerPcSlotFromFp*kWordSize
-        COMPILE_ASSERT(kSavedCallerFpSlotFromFp >= 0);
-        dwarf_stream.u1(DW_CFA_offset | FP);
-        dwarf_stream.uleb128(kSavedCallerFpSlotFromFp);
-
-        // LR at FP+kSavedCallerPcSlotFromFp*kWordSize
-        COMPILE_ASSERT(kSavedCallerPcSlotFromFp >= 0);
-        dwarf_stream.u1(DW_CFA_offset | ConcreteRegister(LINK_REGISTER));
-        dwarf_stream.uleb128(kSavedCallerPcSlotFromFp);
-
-        // SP is FP+kCallerSpSlotFromFp*kWordSize
-        COMPILE_ASSERT(kCallerSpSlotFromFp >= 0);
-        dwarf_stream.u1(DW_CFA_val_offset);
-#if defined(TARGET_ARCH_ARM64)
-        dwarf_stream.uleb128(ConcreteRegister(CSP));
-#elif defined(TARGET_ARCH_ARM)
-        dwarf_stream.uleb128(SP);
-#else
-#error "Unsupported .eh_frame architecture"
-#endif
-        dwarf_stream.uleb128(kCallerSpSlotFromFp);
-      });
-    }
-  }
-
-  dwarf_stream.u4(0);  // end of section
-
-  // Add section and then relocate its contents.
-  auto const eh_frame = new (zone_) BitsContainer(
-      type_, false, false, stream.bytes_written(), stream.buffer());
-  AddSection(eh_frame, ".eh_frame");
-
-  // Relocate contents now that we have memory_offset assigned.
-  for (auto& reloc : relocs) {
-    const intptr_t pcrel_offset =
-        reloc.target_memory_offset -
-        (eh_frame->memory_offset() + reloc.source_offset);
-    // Note: IsInt<int32_t>(32, ...) does not work correctly.
-    RELEASE_ASSERT(kBitsPerWord == 32 || Utils::IsInt(32, pcrel_offset));
-    *reinterpret_cast<int32_t*>(stream.buffer() + reloc.source_offset) =
-        static_cast<int32_t>(pcrel_offset);
-  }
-#endif  // defined(DART_PRECOMPILER) && \
-        //   (defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_ARM64))
-}
-
-void Elf::FinalizeDwarfSections() {
-  if (dwarf_ == nullptr) return;
-#if defined(DART_PRECOMPILER)
-  {
-    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
-    // We can use symtab_ without checking because this is an unstripped
-    // snapshot or separate debugging information, both of which have static
-    // symbol tables, and the static symbol table is a superset of the dynamic.
-    DwarfElfStream dwarf_stream(zone_, &stream, symtab_);
-    dwarf_->WriteAbbreviations(&dwarf_stream);
-    AddDebug(".debug_abbrev", stream.buffer(), stream.bytes_written());
-  }
-
-  {
-    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
-    DwarfElfStream dwarf_stream(zone_, &stream, symtab_);
-    dwarf_->WriteDebugInfo(&dwarf_stream);
-    AddDebug(".debug_info", stream.buffer(), stream.bytes_written());
-  }
-
-  {
-    ZoneWriteStream stream(zone(), kInitialDwarfBufferSize);
-    DwarfElfStream dwarf_stream(zone_, &stream, symtab_);
-    dwarf_->WriteLineNumberProgram(&dwarf_stream);
-    AddDebug(".debug_line", stream.buffer(), stream.bytes_written());
-  }
-#endif
-}
-
-void Elf::Finalize() {
-  if (auto const new_build_id = GenerateFinalBuildId()) {
-    ReplaceSection(build_id_, new_build_id);
-
-    // Add a PT_NOTE segment for the build ID.
-    segments_.Add(new (zone_) NoteSegment(zone_, new_build_id));
-  }
-
-  // Adding the dynamic symbol table and associated sections.
-  AddSection(dynstrtab_, ".dynstr");
-  AddSection(dynsym_, ".dynsym");
-  dynsym_->link = dynstrtab_->index();
-
-  auto const hash = new (zone_) SymbolHashTable(zone_, dynstrtab_, dynsym_);
-  AddSection(hash, ".hash");
-
-  // Must come before .dynamic, because .dynamic is writable and
-  // .eh_frame is not. See restriction in Elf::WriteProgramTable.
-  FinalizeEhFrame();
-
-  auto const dynamic =
-      new (zone_) DynamicTable(zone_, dynstrtab_, dynsym_, hash);
-  AddSection(dynamic, ".dynamic");
-
-  // Add a PT_DYNAMIC segment for the dynamic symbol table.
-  segments_.Add(new (zone_) DynamicSegment(zone_, dynamic));
-
-  // Currently, we add all (non-reserved) unallocated sections after all
-  // allocated sections. If we put unallocated sections between allocated
-  // sections, they would affect the file offset but not the memory offset
-  // of the later allocated sections.
-  //
-  // However, memory offsets must be page-aligned to the file offset for the
-  // ELF file to be successfully loaded. This means we'd either have to add
-  // extra padding _or_ determine file offsets before memory offsets. The
-  // latter would require us to handle BSS relocations during ELF finalization,
-  // instead of while writing the .text section content.
-  if (!IsStripped()) {
-    AddSection(strtab_, ".strtab");
-    AddSection(symtab_, ".symtab");
-    symtab_->link = strtab_->index();
-  }
-  AddSection(shstrtab_, ".shstrtab");
-  FinalizeDwarfSections();
-
-  // At this point, all non-programmatically calculated sections and segments
-  // have been added. Add any programatically calculated sections and segments
-  // and then calculate file offsets.
-  FinalizeProgramTable();
-  ComputeFileOffsets();
-
-  // Finally, write the ELF file contents.
-  ElfWriteStream wrapped(unwrapped_stream_);
-  WriteHeader(&wrapped);
-  WriteProgramTable(&wrapped);
-  WriteSections(&wrapped);
-  WriteSectionTable(&wrapped);
-}
-
-static uint32_t HashBitsContainer(const BitsContainer* bits) {
-  uint32_t hash = 0;
-  auto const size = bits->MemorySize();
-  if (bits->bytes() == nullptr) {
-    // Just hash the size as a fallback if this section has no contents.
-    return FinalizeHash(size, 32);
-  }
-  auto const end = bits->bytes() + size;
-  auto const non_word_size = size % kWordSize;
-  auto const end_of_words =
-      reinterpret_cast<const uword*>(bits->bytes() + (size - non_word_size));
-  for (auto cursor = reinterpret_cast<const uword*>(bits->bytes());
-       cursor < end_of_words; cursor++) {
-    hash = CombineHashes(hash, *cursor);
-  }
-  for (auto cursor = reinterpret_cast<const uint8_t*>(end_of_words);
-       cursor < end; cursor++) {
-    hash = CombineHashes(hash, *cursor);
-  }
-  return FinalizeHash(hash, 32);
-}
-
-Section* Elf::GenerateFinalBuildId() {
+void Elf::GenerateBuildId() {
   uint32_t hashes[kBuildIdSegmentNamesLength];
   for (intptr_t i = 0; i < kBuildIdSegmentNamesLength; i++) {
     auto const name = kBuildIdSegmentNames[i];
-    auto const symbol = dynsym_->Find(name);
-    if (symbol == nullptr) {
-      // If we're missing a section, then we don't generate a final build ID.
-      return nullptr;
-    }
-    auto const bits = sections_[symbol->section_index]->AsBitsContainer();
+    auto const section = FindSectionBySymbolName(name);
+    // If we're missing a section, then we don't generate a final build ID.
+    if (section == nullptr) return;
+    auto const bits = section->AsBitsContainer();
     if (bits == nullptr) {
       FATAL1("Section for symbol %s is not a BitsContainer", name);
     }
-    if (bits->bytes() == nullptr) {
-      // For now, if we don't have section contents (because we're generating
-      // assembly), don't generate a final build ID, as we'll have different
-      // build IDs in the snapshot and the separate debugging information.
-      //
-      // TODO(dartbug.com/43274): Change once we generate consistent build IDs
-      // between assembly snapshots and their debugging information.
-      return nullptr;
-    }
-    ASSERT_EQUAL(bits->MemorySize(), symbol->size);
-    hashes[i] = HashBitsContainer(bits);
+    // For now, if we don't have section contents (because we're generating
+    // assembly), don't generate a final build ID, as we'll have different
+    // build IDs in the snapshot and the separate debugging information.
+    //
+    // TODO(dartbug.com/43274): Change once we generate consistent build IDs
+    // between assembly snapshots and their debugging information.
+    if (bits->bytes() == nullptr) return;
+    hashes[i] = bits->Hash();
   }
+  auto const description_bytes = reinterpret_cast<uint8_t*>(hashes);
+  const size_t description_length = sizeof(hashes);
   // To ensure we can quickly check for a final build ID, we ensure the first
   // byte contains a non-zero value.
-  auto const bytes = reinterpret_cast<uint8_t*>(hashes);
-  if (bytes[0] == 0) {
-    bytes[0] = 1;
+  if (description_bytes[0] == 0) {
+    description_bytes[0] = 1;
   }
-  return CreateBuildIdNote(&hashes, sizeof(hashes));
-}
-
-Section* Elf::CreateBuildIdNote(const void* description_bytes,
-                                intptr_t description_length) {
-  ASSERT(description_length == 0 || description_bytes != nullptr);
+  // Now that we have the description field contents, create the section.
   ZoneWriteStream stream(zone(), kBuildIdHeaderSize + description_length);
   stream.WriteFixed<decltype(elf::Note::name_size)>(sizeof(elf::ELF_NOTE_GNU));
   stream.WriteFixed<decltype(elf::Note::description_size)>(description_length);
@@ -1489,14 +1479,15 @@
   stream.WriteBytes(elf::ELF_NOTE_GNU, sizeof(elf::ELF_NOTE_GNU));
   ASSERT_EQUAL(stream.bytes_written(), kBuildIdHeaderSize);
   stream.WriteBytes(description_bytes, description_length);
-  // While the build ID section does not need to be writable, it and the
-  // BSS section are allocated segments at the same time. Having the same flags
-  // ensures they will be combined in the same segment and not unnecessarily
-  // aligned into a new page.
-  return new (zone_) BitsContainer(elf::SectionHeaderType::SHT_NOTE,
-                                   /*allocate=*/true, /*executable=*/false,
-                                   /*writable=*/true, stream.bytes_written(),
-                                   stream.buffer(), kNoteAlignment);
+  // While the build ID section does not need to be writable, the first segment
+  // in our ELF files is writable (see Elf::WriteProgramTable) and so this
+  // ensures we can put it right after the program table without padding.
+  build_id_ = new (zone_) BitsContainer(
+      elf::SectionHeaderType::SHT_NOTE,
+      /*allocate=*/true, /*executable=*/false,
+      /*writable=*/true, stream.bytes_written(), stream.buffer(),
+      /*relocations=*/nullptr, /*symbols=*/nullptr, kNoteAlignment);
+  AddSection(build_id_, kBuildIdNoteName, kSnapshotBuildIdAsmSymbol);
 }
 
 void Elf::FinalizeProgramTable() {
@@ -1504,68 +1495,76 @@
 
   program_table_file_offset_ = sizeof(elf::ElfHeader);
 
-  // There are two segments we need the size of the program table to create, so
-  // calculate it as if those two segments were already in place.
+  // There is one additional segment we need the size of the program table to
+  // create, so calculate it as if that segment were already in place.
   program_table_file_size_ =
-      (2 + segments_.length()) * sizeof(elf::ProgramHeader);
+      (1 + segments_.length()) * sizeof(elf::ProgramHeader);
 
-  // We pre-allocated the virtual memory space for the program table itself.
-  // Check that we didn't generate too many segments. Currently we generate a
-  // fixed num of segments based on the four pieces of a snapshot, but if we
-  // use more in the future we'll likely need to do something more compilated
-  // to generate DWARF without knowing a piece's virtual address in advance.
   auto const program_table_segment_size =
       program_table_file_offset_ + program_table_file_size_;
-  RELEASE_ASSERT(program_table_segment_size < kProgramTableSegmentSize);
 
-  // Remove the original stand-in segment we added in the constructor.
-  segments_.EraseAt(0);
+  // Segment for loading the initial part of the ELF file, including the
+  // program header table. Required by Android but not by Linux.
+  Segment* const initial_load =
+      new (zone_) ProgramTableLoadSegment(zone_, program_table_segment_size);
+  // Merge the initial writable segment into this one and replace it (so it
+  // doesn't change the number of segments).
+  const bool was_merged = initial_load->Merge(segments_[0]);
+  ASSERT(was_merged);
+  segments_[0] = initial_load;
 
   // Self-reference to program header table. Required by Android but not by
   // Linux. Must appear before any PT_LOAD entries.
   segments_.InsertAt(
       0, new (zone_) ProgramTableSelfSegment(zone_, program_table_file_offset_,
                                              program_table_file_size_));
-
-  // Segment for loading the initial part of the ELF file, including the
-  // program header table. Required by Android but not by Linux.
-  segments_.InsertAt(1, new (zone_) ProgramTableLoadSegment(
-                            zone_, program_table_segment_size));
 }
 
 static const intptr_t kElfSectionTableAlignment = compiler::target::kWordSize;
 
-void Elf::ComputeFileOffsets() {
+void Elf::ComputeOffsets() {
   // We calculate the size and offset of the program header table during
   // finalization.
   ASSERT(program_table_file_offset_ > 0 && program_table_file_size_ > 0);
   intptr_t file_offset = program_table_file_offset_ + program_table_file_size_;
-  // When calculating file offsets for sections, we'll need to know if we've
-  // changed segments. Start with the one for the program table.
+  // Program table memory size is same as file size.
+  intptr_t memory_offset = file_offset;
+
+  // When calculating memory and file offsets for sections, we'll need to know
+  // if we've changed segments. Start with the one for the program table.
+  ASSERT(segments_[0]->type != elf::ProgramHeaderType::PT_LOAD);
   const auto* current_segment = segments_[1];
+  ASSERT(current_segment->type == elf::ProgramHeaderType::PT_LOAD);
 
   // The non-reserved sections are output to the file in order after the program
   // header table. If we're entering a new segment, then we need to align
   // according to the PT_LOAD segment alignment as well to keep the file offsets
   // aligned with the memory addresses.
-  auto const load_align = Segment::Alignment(elf::ProgramHeaderType::PT_LOAD);
   for (intptr_t i = 1; i < sections_.length(); i++) {
     auto const section = sections_[i];
     file_offset = Utils::RoundUp(file_offset, section->alignment);
+    memory_offset = Utils::RoundUp(memory_offset, section->alignment);
     if (section->IsAllocated() && section->load_segment != current_segment) {
-      file_offset = Utils::RoundUp(file_offset, load_align);
       current_segment = section->load_segment;
+      ASSERT(current_segment->type == elf::ProgramHeaderType::PT_LOAD);
+      const intptr_t load_align = Segment::Alignment(current_segment->type);
+      file_offset = Utils::RoundUp(file_offset, load_align);
+      memory_offset = Utils::RoundUp(memory_offset, load_align);
     }
     section->set_file_offset(file_offset);
-#if defined(DEBUG)
     if (section->IsAllocated()) {
-      // For files that will be dynamically loaded, make sure the file offsets
-      // of allocated sections are page aligned to the memory offsets.
-      ASSERT_EQUAL(section->file_offset() % load_align,
-                   section->memory_offset() % load_align);
-    }
+      section->set_memory_offset(memory_offset);
+#if defined(DEBUG)
+      if (type_ == Type::Snapshot) {
+        // For files that will be dynamically loaded, make sure the file offsets
+        // of allocated sections are page aligned to the memory offsets.
+        ASSERT_EQUAL(section->file_offset() % Elf::kPageSize,
+                     section->memory_offset() % Elf::kPageSize);
+      }
 #endif
+    }
     file_offset += section->FileSize();
+    memory_offset += section->MemorySize();
   }
 
   file_offset = Utils::RoundUp(file_offset, kElfSectionTableAlignment);
@@ -1683,21 +1682,29 @@
 
 void Elf::WriteSections(ElfWriteStream* stream) {
   ASSERT(section_table_file_size_ >= 0);  // Check for finalization.
-
+  // Should be writing the first section immediately after the program table.
+  ASSERT_EQUAL(stream->Position(),
+               program_table_file_offset_ + program_table_file_size_);
   // Skip the reserved first section, as its alignment is 0 (which will cause
   // stream->Align() to fail) and it never contains file contents anyway.
   ASSERT_EQUAL(static_cast<uint32_t>(sections_[0]->type),
                static_cast<uint32_t>(elf::SectionHeaderType::SHT_NULL));
   ASSERT_EQUAL(sections_[0]->alignment, 0);
-  auto const load_align = Segment::Alignment(elf::ProgramHeaderType::PT_LOAD);
+  // The program table is considered part of the first load segment (the
+  // second segment in segments_), so other sections in the same segment should
+  // not have extra segment alignment added.
+  ASSERT(segments_[0]->type != elf::ProgramHeaderType::PT_LOAD);
   const Segment* current_segment = segments_[1];
+  ASSERT(current_segment->type == elf::ProgramHeaderType::PT_LOAD);
   for (intptr_t i = 1; i < sections_.length(); i++) {
     Section* section = sections_[i];
     stream->Align(section->alignment);
     if (section->IsAllocated() && section->load_segment != current_segment) {
       // Changing segments, so align accordingly.
-      stream->Align(load_align);
       current_segment = section->load_segment;
+      ASSERT(current_segment->type == elf::ProgramHeaderType::PT_LOAD);
+      const intptr_t load_align = Segment::Alignment(current_segment->type);
+      stream->Align(load_align);
     }
     ASSERT_EQUAL(stream->Position(), section->file_offset());
     section->Write(stream);
diff --git a/runtime/vm/elf.h b/runtime/vm/elf.h
index 91c8202b..035b487 100644
--- a/runtime/vm/elf.h
+++ b/runtime/vm/elf.h
@@ -39,75 +39,69 @@
 
   bool IsStripped() const { return dwarf_ == nullptr; }
 
-  Zone* zone() { return zone_; }
+  Zone* zone() const { return zone_; }
   const Dwarf* dwarf() const { return dwarf_; }
   Dwarf* dwarf() { return dwarf_; }
+  const SymbolTable* symtab() const { return symtab_; }
 
-  // Returns the relocated address for the symbol with the given name or
-  // kNoSectionStart if the symbol was not found.
-  uword SymbolAddress(const char* name) const;
+  // Stores the information needed to appropriately generate a
+  // relocation from the target to the source at the given section offset.
+  // If a given symbol is nullptr, then the offset is absolute (from 0).
+  struct Relocation {
+    size_t size_in_bytes;
+    intptr_t section_offset;
+    const char* source_symbol;
+    intptr_t source_offset;
+    const char* target_symbol;
+    intptr_t target_offset;
+  };
 
-  // What the next memory offset for an appropriately aligned section would be.
-  //
-  // Only used by AssemblyImageWriter and BlobImageWriter methods.
-  intptr_t NextMemoryOffset(intptr_t alignment) const;
-  intptr_t AddText(const char* name, const uint8_t* bytes, intptr_t size);
-  intptr_t AddROData(const char* name, const uint8_t* bytes, intptr_t size);
-  void AddDebug(const char* name, const uint8_t* bytes, intptr_t size);
+  // Stores the information needed to appropriately generate a symbol
+  // during finalization.
+  struct SymbolData {
+    const char* name;
+    intptr_t type;
+    intptr_t offset;
+    size_t size;
+  };
 
-  // Adds a local symbol for the given offset and size in the "current" section,
-  // that is, the section index for the symbol is for the next added section.
-  void AddLocalSymbol(const char* name,
-                      intptr_t type,
-                      intptr_t offset,
-                      intptr_t size);
+  void AddText(const char* name,
+               const uint8_t* bytes,
+               intptr_t size,
+               const ZoneGrowableArray<Relocation>* relocations,
+               const ZoneGrowableArray<SymbolData>* symbol);
+  void AddROData(const char* name,
+                 const uint8_t* bytes,
+                 intptr_t size,
+                 const ZoneGrowableArray<Relocation>* relocations,
+                 const ZoneGrowableArray<SymbolData>* symbols);
 
   void Finalize();
 
  private:
   static constexpr const char* kBuildIdNoteName = ".note.gnu.build-id";
 
-  static Section* CreateBSS(Zone* zone, Type type, intptr_t size);
-
   // Adds the section and also creates a PT_LOAD segment for the section if it
   // is an allocated section.
   //
-  // For allocated sections, if symbol_name is provided, a symbol for the
+  // For allocated sections, if a symbol_name is provided, a symbol for the
   // section will be added to the dynamic table (if allocated) and static
   // table (if not stripped) during finalization.
-  //
-  // Returns the memory offset if the section is allocated.
-  intptr_t AddSection(Section* section,
-                      const char* name,
-                      const char* symbol_name = nullptr);
-  // Replaces [old_section] with [new_section] in all appropriate places. If the
-  // section is allocated, the memory size of the section must be the same as
-  // the original to ensure any already-calculated memory offsets are unchanged.
-  void ReplaceSection(Section* old_section, Section* new_section);
+  void AddSection(Section* section,
+                  const char* name,
+                  const char* symbol_name = nullptr);
 
-  void AddStaticSymbol(const char* name,
-                       intptr_t binding,
-                       intptr_t type,
-                       intptr_t section_index,
-                       intptr_t address,
-                       intptr_t size);
-  void AddDynamicSymbol(const char* name,
-                        intptr_t binding,
-                        intptr_t type,
-                        intptr_t section_index,
-                        intptr_t address,
-                        intptr_t size);
+  const Section* FindSectionBySymbolName(const char* symbol_name) const;
 
-  Segment* LastLoadSegment() const;
-  const Section* FindSectionForAddress(intptr_t address) const;
-  Section* CreateBuildIdNote(const void* description_bytes,
-                             intptr_t description_length);
-  Section* GenerateFinalBuildId();
+  void CreateBSS();
+  void GenerateBuildId();
 
-  void AddSectionSymbols();
+  void OrderSectionsAndCreateSegments();
+
+  void FinalizeSymbols();
   void FinalizeDwarfSections();
   void FinalizeProgramTable();
-  void ComputeFileOffsets();
+  void ComputeOffsets();
 
   void FinalizeEhFrame();
 
@@ -124,28 +118,28 @@
   // the static symbol table (and its corresponding string table).
   Dwarf* const dwarf_;
 
-  // We always create a BSS section for all Elf files, though it may be NOBITS
-  // if this is separate debugging information.
-  Section* const bss_;
-
   // All our strings would fit in a single page. However, we use separate
   // .shstrtab and .dynstr to work around a bug in Android's strip utility.
   StringTable* const shstrtab_;
   StringTable* const dynstrtab_;
   SymbolTable* const dynsym_;
 
-  // The static tables are lazily created when static symbols are added.
-  StringTable* strtab_ = nullptr;
-  SymbolTable* symtab_ = nullptr;
+  // The static tables are always created for use in relocation calculations,
+  // even though they may not end up in the final ELF file.
+  StringTable* const strtab_;
+  SymbolTable* const symtab_;
 
-  // We always create a GNU build ID for all Elf files. In order to create
-  // the appropriate offset to it in an InstructionsSection object, we create an
-  // initial build ID section as a placeholder and then replace that section
-  // during finalization once we have the information to calculate the real one.
-  Section* build_id_;
+  // We always create a BSS section for all Elf files to keep memory offsets
+  // consistent, though it is NOBITS for separate debugging information.
+  Section* bss_ = nullptr;
+
+  // We currently create a GNU build ID for all ELF snapshots and associated
+  // debugging information.
+  Section* build_id_ = nullptr;
 
   GrowableArray<Section*> sections_;
   GrowableArray<Segment*> segments_;
+
   intptr_t memory_offset_;
   intptr_t section_table_file_offset_ = -1;
   intptr_t section_table_file_size_ = -1;
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index 86ede97..7e7a773 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -58,12 +58,10 @@
 //
 // The syntax used is the same as that for FLAG_LIST below, as these flags are
 // automatically included in FLAG_LIST.
-// TODO(cskau): Remove causal_async_stacks when deprecated.
 #define VM_GLOBAL_FLAG_LIST(P, R, C, D)                                        \
   P(code_comments, bool, false, "Include comments into code and disassembly.") \
   P(dwarf_stack_traces_mode, bool, false,                                      \
     "Use --[no-]dwarf-stack-traces instead.")                                  \
-  P(causal_async_stacks, bool, false, "DEPRECATED: Improved async stacks")     \
   P(lazy_async_stacks, bool, true, "Reconstruct async stacks from listeners")  \
   P(lazy_dispatchers, bool, true, "Generate dispatchers lazily")               \
   P(use_bare_instructions, bool, true, "Enable bare instructions mode.")       \
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 8318801..dd69383 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -185,16 +185,17 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 ImageWriter::ImageWriter(Thread* t)
-    : heap_(t->heap()),
+    : thread_(ASSERT_NOTNULL(t)),
+      zone_(t->zone()),
       next_data_offset_(0),
       next_text_offset_(0),
       objects_(),
       instructions_(),
-      image_type_(TagObjectTypeAsReadOnly(t->zone(), "Image")),
+      image_type_(TagObjectTypeAsReadOnly(zone_, "Image")),
       instructions_section_type_(
-          TagObjectTypeAsReadOnly(t->zone(), "InstructionsSection")),
-      instructions_type_(TagObjectTypeAsReadOnly(t->zone(), "Instructions")),
-      trampoline_type_(TagObjectTypeAsReadOnly(t->zone(), "Trampoline")) {
+          TagObjectTypeAsReadOnly(zone_, "InstructionsSection")),
+      instructions_type_(TagObjectTypeAsReadOnly(zone_, "Instructions")),
+      trampoline_type_(TagObjectTypeAsReadOnly(zone_, "Trampoline")) {
   ResetOffsets();
 }
 
@@ -206,13 +207,14 @@
       ASSERT((initial_offset + inst.expected_offset) == next_text_offset_);
       switch (inst.op) {
         case ImageWriterCommand::InsertInstructionOfCode: {
+          Heap* const heap = thread_->heap();
           CodePtr code = inst.insert_instruction_of_code.code;
           InstructionsPtr instructions = Code::InstructionsOf(code);
           const intptr_t offset = next_text_offset_;
           instructions_.Add(InstructionsData(instructions, code, offset));
           next_text_offset_ += SizeInSnapshot(instructions);
-          ASSERT(heap_->GetObjectId(instructions) == 0);
-          heap_->SetObjectId(instructions, offset);
+          ASSERT(heap->GetObjectId(instructions) == 0);
+          heap->SetObjectId(instructions, offset);
           break;
         }
         case ImageWriterCommand::InsertBytesOfTrampoline: {
@@ -233,13 +235,14 @@
 
 int32_t ImageWriter::GetTextOffsetFor(InstructionsPtr instructions,
                                       CodePtr code) {
-  intptr_t offset = heap_->GetObjectId(instructions);
+  Heap* const heap = thread_->heap();
+  intptr_t offset = heap->GetObjectId(instructions);
   if (offset != 0) {
     return offset;
   }
 
   offset = next_text_offset_;
-  heap_->SetObjectId(instructions, offset);
+  heap->SetObjectId(instructions, offset);
   next_text_offset_ += SizeInSnapshot(instructions);
   instructions_.Add(InstructionsData(instructions, code, offset));
 
@@ -317,15 +320,14 @@
 const char* ImageWriter::ObjectTypeForProfile(const Object& object) const {
   if (profile_writer_ == nullptr) return nullptr;
   ASSERT(IsROSpace());
-  Thread* thread = Thread::Current();
-  REUSABLE_CLASS_HANDLESCOPE(thread);
-  REUSABLE_STRING_HANDLESCOPE(thread);
-  Class& klass = thread->ClassHandle();
-  String& name = thread->StringHandle();
+  REUSABLE_CLASS_HANDLESCOPE(thread_);
+  REUSABLE_STRING_HANDLESCOPE(thread_);
+  Class& klass = thread_->ClassHandle();
+  String& name = thread_->StringHandle();
   klass = object.clazz();
   name = klass.UserVisibleName();
   auto const name_str = name.ToCString();
-  return TagObjectTypeAsReadOnly(thread->zone(), name_str);
+  return TagObjectTypeAsReadOnly(zone_, name_str);
 }
 
 const char* ImageWriter::TagObjectTypeAsReadOnly(Zone* zone, const char* type) {
@@ -348,14 +350,11 @@
 }
 
 void ImageWriter::DumpInstructionsSizes() {
-  auto thread = Thread::Current();
-  auto zone = thread->zone();
-
-  auto& cls = Class::Handle(zone);
-  auto& lib = Library::Handle(zone);
-  auto& owner = Object::Handle(zone);
-  auto& url = String::Handle(zone);
-  auto& name = String::Handle(zone);
+  auto& cls = Class::Handle(zone_);
+  auto& lib = Library::Handle(zone_);
+  auto& owner = Object::Handle(zone_);
+  auto& url = String::Handle(zone_);
+  auto& name = String::Handle(zone_);
   intptr_t trampolines_total_size = 0;
 
   JSONWriter js;
@@ -433,10 +432,8 @@
 #endif
 
 void ImageWriter::Write(NonStreamingWriteStream* clustered_stream, bool vm) {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
-  Heap* heap = thread->isolate_group()->heap();
-  TIMELINE_DURATION(thread, Isolate, "WriteInstructions");
+  Heap* heap = thread_->heap();
+  TIMELINE_DURATION(thread_, Isolate, "WriteInstructions");
 
   // Handlify collected raw pointers as building the names below
   // will allocate on the Dart heap.
@@ -445,9 +442,9 @@
     const bool is_trampoline = data.trampoline_bytes != nullptr;
     if (is_trampoline) continue;
 
-    data.insns_ = &Instructions::Handle(zone, data.raw_insns_);
+    data.insns_ = &Instructions::Handle(zone_, data.raw_insns_);
     ASSERT(data.raw_code_ != nullptr);
-    data.code_ = &Code::Handle(zone, data.raw_code_);
+    data.code_ = &Code::Handle(zone_, data.raw_code_);
 
     // Reset object id as an isolate snapshot after a VM snapshot will not use
     // the VM snapshot's text image.
@@ -455,7 +452,7 @@
   }
   for (intptr_t i = 0; i < objects_.length(); i++) {
     ObjectData& data = objects_[i];
-    data.obj_ = &Object::Handle(zone, data.raw_obj_);
+    data.obj_ = &Object::Handle(zone_, data.raw_obj_);
   }
 
   // Needs to happen before WriteText, as we add information about the
@@ -612,8 +609,6 @@
 }
 
 void ImageWriter::WriteText(bool vm) {
-  Zone* zone = Thread::Current()->zone();
-
   const bool bare_instruction_payloads =
       FLAG_precompiled_mode && FLAG_use_bare_instructions;
 
@@ -698,7 +693,7 @@
     // 2) The BSS offset from this section.
     text_offset += Relocation(text_offset, instructions_symbol, bss_symbol);
     // 3) The relocated address of the instructions.
-    text_offset += WriteTargetWord(RelocatedAddress(instructions_symbol));
+    text_offset += Relocation(text_offset, instructions_symbol);
     // 4) The GNU build ID note offset from this section.
     text_offset += Relocation(text_offset, instructions_symbol,
                               SectionSymbol(ProgramSection::BuildId, vm));
@@ -718,9 +713,9 @@
 
   FrameUnwindPrologue();
 
-  PcDescriptors& descriptors = PcDescriptors::Handle(zone);
 #if defined(DART_PRECOMPILER)
-  SnapshotTextObjectNamer namer(zone);
+  PcDescriptors& descriptors = PcDescriptors::Handle(zone_);
+  SnapshotTextObjectNamer namer(zone_);
 #endif
 
   ASSERT(offset_space_ != IdSpace::kSnapshot);
@@ -757,7 +752,6 @@
     }
 
     const intptr_t instr_start = text_offset;
-    const auto& code = *data.code_;
     const auto& insns = *data.insns_;
 
     // 1. Write from the object start to the payload start. This includes the
@@ -778,6 +772,7 @@
                  compiler::target::Instructions::HeaderSize());
 
 #if defined(DART_PRECOMPILER)
+    const auto& code = *data.code_;
     // 2. Add a symbol for the code at the entry point in precompiled snapshots.
     // Linux's perf uses these labels.
     AddCodeSymbol(code, object_name, text_offset);
@@ -795,33 +790,33 @@
       // target-sized words starting from that address.
       ASSERT(Utils::IsAligned(payload_start, compiler::target::kWordSize));
       const uword payload_size = insns.Size();
+      auto const payload_end = payload_start + payload_size;
+      auto cursor = payload_start;
+#if defined(DART_PRECOMPILER)
       descriptors = code.pc_descriptors();
       PcDescriptors::Iterator iterator(
           descriptors, /*kind_mask=*/UntaggedPcDescriptors::kBSSRelocation);
-
-      auto const payload_end = payload_start + payload_size;
-      auto cursor = payload_start;
       while (iterator.MoveNext()) {
+        // We only generate BSS relocations in the precompiler.
         ASSERT(FLAG_precompiled_mode);
         auto const next_reloc_offset = iterator.PcOffset();
         auto const next_reloc_address = payload_start + next_reloc_offset;
         // We only generate BSS relocations that are target word-sized and at
-        // target word-aligned offsets in the payload. Double-check this..
+        // target word-aligned offsets in the payload. Double-check this.
         ASSERT(
             Utils::IsAligned(next_reloc_address, compiler::target::kWordSize));
         text_offset += WriteBytes(cursor, next_reloc_address - cursor);
 
-#if defined(DART_PRECOMPILER)
-        // The instruction stream at the relocation position holds an offset
-        // into BSS corresponding to the symbol being resolved. This addend is
-        // factored into the relocation.
-        const auto addend = *reinterpret_cast<const compiler::target::word*>(
-            next_reloc_address);
+        // The instruction stream at the relocation position holds the target
+        // offset into the BSS section.
+        const auto target_offset =
+            *reinterpret_cast<const compiler::target::word*>(
+                next_reloc_address);
         text_offset += Relocation(text_offset, instructions_symbol, text_offset,
-                                  bss_symbol, /*target_offset=*/0, addend);
-#endif
+                                  bss_symbol, target_offset);
         cursor = next_reloc_address + compiler::target::kWordSize;
       }
+#endif
       text_offset += WriteBytes(cursor, payload_end - cursor);
     }
 
@@ -894,8 +889,8 @@
 
 class DwarfAssemblyStream : public DwarfWriteStream {
  public:
-  explicit DwarfAssemblyStream(BaseWriteStream* stream)
-      : stream_(ASSERT_NOTNULL(stream)) {}
+  explicit DwarfAssemblyStream(Zone* zone, BaseWriteStream* stream)
+      : zone_(ASSERT_NOTNULL(zone)), stream_(ASSERT_NOTNULL(stream)) {}
 
   void sleb128(intptr_t value) { stream_->Printf(".sleb128 %" Pd "\n", value); }
   void uleb128(uintptr_t value) {
@@ -916,19 +911,20 @@
   void string(const char* cstr) {               // NOLINT
     stream_->Printf(".string \"%s\"\n", cstr);  // NOLINT
   }
-  // Uses labels, so doesn't output to start or return a useful fixup position.
-  intptr_t ReserveSize(const char* prefix, intptr_t* start) {
+  EncodedPosition WritePrefixedLength(const char* prefix,
+                                      std::function<void()> body) {
+    ASSERT(prefix != nullptr);
+    const char* const start_symbol = OS::SCreate(zone_, ".L%s_start", prefix);
     // Assignment to temp works around buggy Mac assembler.
-    stream_->Printf("L%s_size = .L%s_end - .L%s_start\n", prefix, prefix,
-                    prefix);
+    stream_->Printf("L%s_size = .L%s_end - %s\n", prefix, prefix, start_symbol);
+    // We assume DWARF v2 currently, so all sizes are 32-bit.
     stream_->Printf("%s L%s_size\n", kSizeDirectives[kInt32SizeLog2], prefix);
-    stream_->Printf(".L%s_start:\n", prefix);
-    return -1;
-  }
-  // Just need to label the end so the assembler can calculate the size, so
-  // start and the fixup position is unused.
-  void SetSize(intptr_t fixup, const char* prefix, intptr_t start) {
+    // All sizes for DWARF sections measure the size of the section data _after_
+    // the size value.
+    stream_->Printf("%s:\n", start_symbol);
+    body();
     stream_->Printf(".L%s_end:\n", prefix);
+    return EncodedPosition(start_symbol);
   }
   void OffsetFromSymbol(const char* symbol, intptr_t offset) {
     if (offset == 0) {
@@ -937,13 +933,6 @@
       PrintNamedAddressWithOffset(symbol, offset);
     }
   }
-  void DistanceBetweenSymbolOffsets(const char* symbol1,
-                                    intptr_t offset1,
-                                    const char* symbol2,
-                                    intptr_t offset2) {
-    stream_->Printf(".uleb128 %s - %s + %" Pd "\n", symbol1, symbol2,
-                    offset1 - offset2);
-  }
 
   // No-op, we'll be using labels.
   void InitializeAbstractOrigins(intptr_t size) {}
@@ -1004,6 +993,7 @@
     stream_->Printf("%s %s + %" Pd "\n", kWordDirective, name, offset);
   }
 
+  Zone* const zone_;
   BaseWriteStream* const stream_;
   intptr_t temp_ = 0;
 
@@ -1028,12 +1018,12 @@
                                          Elf* debug_elf)
     : ImageWriter(thread),
       assembly_stream_(stream),
-      assembly_dwarf_(AddDwarfIfUnstripped(thread->zone(), strip, debug_elf)),
+      assembly_dwarf_(AddDwarfIfUnstripped(zone_, strip, debug_elf)),
       debug_elf_(debug_elf) {}
 
 void AssemblyImageWriter::Finalize() {
   if (assembly_dwarf_ != nullptr) {
-    DwarfAssemblyStream dwarf_stream(assembly_stream_);
+    DwarfAssemblyStream dwarf_stream(zone_, assembly_stream_);
     dwarf_stream.AbbreviationsPrologue();
     assembly_dwarf_->WriteAbbreviations(&dwarf_stream);
     dwarf_stream.DebugInfoPrologue();
@@ -1125,13 +1115,22 @@
                                        intptr_t alignment) {
   ASSERT(FLAG_precompiled_mode);
   ASSERT(current_section_symbol_ == nullptr);
+  ASSERT(current_symbols_ == nullptr);
   bool global_symbol = false;
   switch (section) {
     case ProgramSection::Text:
+      if (debug_elf_ != nullptr) {
+        current_symbols_ =
+            new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+      }
       assembly_stream_->WriteString(".text\n");
       global_symbol = true;
       break;
     case ProgramSection::Data:
+      if (debug_elf_ != nullptr) {
+        current_symbols_ =
+            new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+      }
 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) ||                  \
     defined(TARGET_OS_FUCHSIA)
       assembly_stream_->WriteString(".section .rodata\n");
@@ -1158,18 +1157,21 @@
   return true;
 }
 
-static void ElfAddSection(Elf* elf,
-                          ImageWriter::ProgramSection section,
-                          const char* symbol,
-                          const uint8_t* bytes,
-                          intptr_t size) {
+static void ElfAddSection(
+    Elf* elf,
+    ImageWriter::ProgramSection section,
+    const char* symbol,
+    uint8_t* bytes,
+    intptr_t size,
+    ZoneGrowableArray<Elf::SymbolData>* symbols,
+    ZoneGrowableArray<Elf::Relocation>* relocations = nullptr) {
   if (elf == nullptr) return;
   switch (section) {
     case ImageWriter::ProgramSection::Text:
-      elf->AddText(symbol, bytes, size);
+      elf->AddText(symbol, bytes, size, relocations, symbols);
       break;
     case ImageWriter::ProgramSection::Data:
-      elf->AddROData(symbol, bytes, size);
+      elf->AddROData(symbol, bytes, size, relocations, symbols);
       break;
     default:
       // Other sections are handled by the Elf object internally.
@@ -1199,8 +1201,9 @@
   // separate debugging information, we pass nullptr for the bytes, which
   // creates an appropriate NOBITS section instead of PROGBITS.
   ElfAddSection(debug_elf_, name, current_section_symbol_, /*bytes=*/nullptr,
-                size);
+                size, current_symbols_);
   current_section_symbol_ = nullptr;
+  current_symbols_ = nullptr;
 }
 
 intptr_t AssemblyImageWriter::WriteTargetWord(word value) {
@@ -1216,9 +1219,11 @@
                                          const char* source_symbol,
                                          intptr_t source_offset,
                                          const char* target_symbol,
-                                         intptr_t target_offset,
-                                         intptr_t target_addend) {
-  ASSERT(source_symbol != nullptr);
+                                         intptr_t target_offset) {
+  if (source_symbol == nullptr || target_symbol == nullptr) {
+    // We can't use absolute addresses in assembly relocations.
+    return WriteTargetWord(Image::kNoRelocatedAddress);
+  }
   ASSERT(target_symbol != nullptr);
 
   // TODO(dartbug.com/43274): Remove once we generate consistent build IDs
@@ -1240,9 +1245,6 @@
       assembly_stream_->Printf(" + %" Pd "", target_offset);
     }
   }
-  if (target_addend != 0) {
-    assembly_stream_->Printf(" + %" Pd "", target_addend);
-  }
   if (strcmp(source_symbol, current_section_symbol_) == 0 &&
       source_offset == section_offset) {
     assembly_stream_->WriteString(" - (.)");
@@ -1263,8 +1265,8 @@
     assembly_dwarf_->AddCode(code, symbol);
   }
   if (debug_elf_ != nullptr) {
+    current_symbols_->Add({symbol, elf::STT_FUNC, offset, code.Size()});
     debug_elf_->dwarf()->AddCode(code, symbol);
-    debug_elf_->AddLocalSymbol(symbol, elf::STT_FUNC, offset, code.Size());
   }
   assembly_stream_->Printf("%s:\n", symbol);
 }
@@ -1441,10 +1443,7 @@
 void BlobImageWriter::WriteBss(bool vm) {
 #if defined(DART_PRECOMPILER)
   // We don't actually write a BSS segment, it's created as part of the
-  // Elf constructor, but make sure it has an non-zero start.
-  ASSERT(elf_ == nullptr ||
-         elf_->SymbolAddress(vm ? kVmSnapshotBssAsmSymbol
-                                : kIsolateSnapshotBssAsmSymbol) != 0);
+  // Elf constructor.
 #endif
 }
 
@@ -1463,6 +1462,8 @@
                                    intptr_t alignment) {
 #if defined(DART_PRECOMPILER)
   ASSERT_EQUAL(elf_ != nullptr, FLAG_precompiled_mode);
+  ASSERT(current_relocations_ == nullptr);
+  ASSERT(current_symbols_ == nullptr);
 #endif
   // For now, we set current_section_stream_ in ::WriteData.
   ASSERT(section == ProgramSection::Data || current_section_stream_ == nullptr);
@@ -1471,8 +1472,20 @@
     case ProgramSection::Text:
       current_section_stream_ =
           ASSERT_NOTNULL(vm ? vm_instructions_ : isolate_instructions_);
+#if defined(DART_PRECOMPILER)
+      current_relocations_ =
+          new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0);
+      current_symbols_ =
+          new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+#endif
       break;
     case ProgramSection::Data:
+#if defined(DART_PRECOMPILER)
+      current_relocations_ =
+          new (zone_) ZoneGrowableArray<Elf::Relocation>(zone_, 0);
+      current_symbols_ =
+          new (zone_) ZoneGrowableArray<Elf::SymbolData>(zone_, 0);
+#endif
       break;
     case ProgramSection::Bss:
       // The BSS section is pre-made in the Elf object for precompiled snapshots
@@ -1494,11 +1507,15 @@
   ASSERT_EQUAL(strcmp(SectionSymbol(name, vm), current_section_symbol_), 0);
 #if defined(DART_PRECOMPILER)
   ElfAddSection(elf_, name, current_section_symbol_,
-                current_section_stream_->buffer(), size);
+                current_section_stream_->buffer(), size, current_symbols_,
+                current_relocations_);
   // We create the corresponding segment in the debugging information as well,
   // since it needs the contents to create the correct build ID.
   ElfAddSection(debug_elf_, name, current_section_symbol_,
-                current_section_stream_->buffer(), size);
+                current_section_stream_->buffer(), size, current_symbols_,
+                current_relocations_);
+  current_relocations_ = nullptr;
+  current_symbols_ = nullptr;
 #endif
   current_section_symbol_ = nullptr;
   current_section_stream_ = nullptr;
@@ -1521,38 +1538,25 @@
                                      const char* source_symbol,
                                      intptr_t source_offset,
                                      const char* target_symbol,
-                                     intptr_t target_offset,
-                                     intptr_t target_addend) {
+                                     intptr_t target_offset) {
   ASSERT(FLAG_precompiled_mode);
-  const uword source_address = RelocatedAddress(source_symbol) + source_offset;
-  const uword target_address = RelocatedAddress(target_symbol) + target_offset;
-  return WriteTargetWord(target_address + target_addend - source_address);
-}
-
-uword BlobImageWriter::RelocatedAddress(const char* symbol) {
-  ASSERT(FLAG_precompiled_mode);
-  ASSERT(symbol != nullptr);
-  if (strcmp(symbol, current_section_symbol_) == 0) {
-    // Cheating a bit here, assuming that the current section will go into its
-    // own load segment (and that the load segment alignment is the same as
-    // the text section alignment).
-    return elf_->NextMemoryOffset(ImageWriter::kTextAlignment);
-  }
-  const uword start = elf_->SymbolAddress(symbol);
-  ASSERT(start != Elf::kNoSectionStart);
-  return start;
+  current_relocations_->Add({compiler::target::kWordSize, section_offset,
+                             source_symbol, source_offset, target_symbol,
+                             target_offset});
+  // We write break instructions so it's easy to tell if a relocation doesn't
+  // get replaced appropriately.
+  return WriteTargetWord(kBreakInstructionFiller);
 }
 
 void BlobImageWriter::AddCodeSymbol(const Code& code,
                                     const char* symbol,
                                     intptr_t offset) {
+  current_symbols_->Add({symbol, elf::STT_FUNC, offset, code.Size()});
   if (elf_ != nullptr && elf_->dwarf() != nullptr) {
     elf_->dwarf()->AddCode(code, symbol);
-    elf_->AddLocalSymbol(symbol, elf::STT_FUNC, offset, code.Size());
   }
   if (debug_elf_ != nullptr) {
     debug_elf_->dwarf()->AddCode(code, symbol);
-    debug_elf_->AddLocalSymbol(symbol, elf::STT_FUNC, offset, code.Size());
   }
 }
 #endif  // defined(DART_PRECOMPILER)
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index df09407..3b2ed09 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -25,6 +25,7 @@
 namespace dart {
 
 // Forward declarations.
+class BitsContainer;
 class Code;
 class Dwarf;
 class Elf;
@@ -137,6 +138,7 @@
 
   // For access to private constants.
   friend class AssemblyImageWriter;
+  friend class BitsContainer;
   friend class BlobImageWriter;
   friend class ImageWriter;
 
@@ -402,15 +404,13 @@
   // relocated address of the target section and S is the final relocated
   // address of the source, the final value is:
   //   (T + target_offset + target_addend) - (S + source_offset)
+  // If either symbol is nullptr, then the corresponding is treated as an
+  // absolute address.
   virtual intptr_t Relocation(intptr_t section_offset,
                               const char* source_symbol,
                               intptr_t source_offset,
                               const char* target_symbol,
-                              intptr_t target_offset,
-                              intptr_t target_addend) = 0;
-  // Returns the final relocated address for the section represented by the
-  // symbol. May not be supported by some writers.
-  virtual uword RelocatedAddress(const char* symbol) = 0;
+                              intptr_t target_offset) = 0;
   // Creates a static symbol for the given Code object when appropriate.
   virtual void AddCodeSymbol(const Code& code,
                              const char* symbol,
@@ -423,7 +423,12 @@
   intptr_t Relocation(intptr_t section_offset,
                       const char* source_symbol,
                       const char* target_symbol) {
-    return Relocation(section_offset, source_symbol, 0, target_symbol, 0, 0);
+    return Relocation(section_offset, source_symbol, 0, target_symbol, 0);
+  }
+  // An overload of Relocation for outputting the relocated address of the
+  // target symbol at the given section offset.
+  intptr_t Relocation(intptr_t section_offset, const char* target_symbol) {
+    return Relocation(section_offset, nullptr, 0, target_symbol, 0);
   }
 #endif
   // Writes a fixed-sized value of type T to the section contents.
@@ -435,7 +440,8 @@
   // instruction for the target architecture is used.
   intptr_t AlignWithBreakInstructions(intptr_t alignment, intptr_t offset);
 
-  Heap* heap_;  // Used for mapping InstructionsPtr to object ids.
+  Thread* const thread_;
+  Zone* const zone_;
   intptr_t next_data_offset_;
   intptr_t next_text_offset_;
   GrowableArray<ObjectData> objects_;
@@ -549,13 +555,7 @@
                               const char* source_symbol,
                               intptr_t source_offset,
                               const char* target_symbol,
-                              intptr_t target_offset,
-                              intptr_t target_addend);
-  // We can't generate the relocated address in assembly, so it'll be
-  // retrieved and stored in the BSS during BSS initialization instead.
-  virtual uword RelocatedAddress(const char* symbol) {
-    return Image::kNoRelocatedAddress;
-  }
+                              intptr_t target_offset);
   virtual void FrameUnwindPrologue();
   virtual void FrameUnwindEpilogue();
   virtual void AddCodeSymbol(const Code& code,
@@ -569,6 +569,9 @@
   // Used in Relocation to output "(.)" for relocations involving the current
   // section position and creating local symbols in AddCodeSymbol.
   const char* current_section_symbol_ = nullptr;
+  // Used for creating local symbols for code objects in the debugging info,
+  // if separately written.
+  ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(AssemblyImageWriter);
 };
@@ -602,12 +605,18 @@
                               const char* source_symbol,
                               intptr_t source_offset,
                               const char* target_symbol,
-                              intptr_t target_offset,
-                              intptr_t target_addend);
-  virtual uword RelocatedAddress(const char* symbol);
+                              intptr_t target_offset);
   virtual void AddCodeSymbol(const Code& code,
                              const char* symbol,
                              intptr_t offset);
+
+  // Set on section entrance to a new array containing the relocations for the
+  // current section.
+  ZoneGrowableArray<Elf::Relocation>* current_relocations_ = nullptr;
+  // Set on section entrance to a new array containing the local symbol data
+  // for the current section.
+  ZoneGrowableArray<Elf::SymbolData>* current_symbols_ = nullptr;
+
 #endif
 
   NonStreamingWriteStream* const vm_instructions_;
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 7e59984..d6cbc64 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -801,7 +801,7 @@
     signature.SetParameterTypeAt(0, Object::dynamic_type());
   }
   signature ^= ClassFinalizer::FinalizeType(signature);
-  function.set_signature(signature);
+  function.SetSignature(signature);
 
   return function.ptr();
 }
@@ -1729,7 +1729,7 @@
       // must be finalized here, since finalization of member types will not be
       // called anymore.
       signature ^= ClassFinalizer::FinalizeType(signature);
-      function.set_signature(signature);
+      function.SetSignature(signature);
     }
     functions_.Add(&function);
 
@@ -2014,22 +2014,17 @@
   switch (function_node_helper.dart_async_marker_) {
     case FunctionNodeHelper::kSyncStar:
       function.set_modifier(UntaggedFunction::kSyncGen);
-      function.set_is_visible(!FLAG_causal_async_stacks &&
-                              !FLAG_lazy_async_stacks);
+      function.set_is_visible(!FLAG_lazy_async_stacks);
       break;
     case FunctionNodeHelper::kAsync:
       function.set_modifier(UntaggedFunction::kAsync);
-      function.set_is_inlinable(!FLAG_causal_async_stacks &&
-                                !FLAG_lazy_async_stacks);
-      function.set_is_visible(!FLAG_causal_async_stacks &&
-                              !FLAG_lazy_async_stacks);
+      function.set_is_inlinable(!FLAG_lazy_async_stacks);
+      function.set_is_visible(!FLAG_lazy_async_stacks);
       break;
     case FunctionNodeHelper::kAsyncStar:
       function.set_modifier(UntaggedFunction::kAsyncGen);
-      function.set_is_inlinable(!FLAG_causal_async_stacks &&
-                                !FLAG_lazy_async_stacks);
-      function.set_is_visible(!FLAG_causal_async_stacks &&
-                              !FLAG_lazy_async_stacks);
+      function.set_is_inlinable(!FLAG_lazy_async_stacks);
+      function.set_is_visible(!FLAG_lazy_async_stacks);
       break;
     default:
       // no special modifier
@@ -2404,14 +2399,13 @@
                     false,              // is_native
                     initializer_owner, TokenPosition::kNoSource));
   if (!field.is_static()) {
-    initializer_fun.set_num_fixed_parameters(1);
+    signature.set_num_fixed_parameters(1);
     signature.set_parameter_types(
         Array::Handle(zone, Array::New(1, Heap::kOld)));
-    signature.CreateNameArrayIncludingFlags(Heap::kOld);
     signature.SetParameterTypeAt(
         0, AbstractType::Handle(zone, field_owner.DeclarationType()));
-    signature.SetParameterNameAt(0, Symbols::This());
-    signature.FinalizeNameArrays(initializer_fun);
+    initializer_fun.CreateNameArray();
+    initializer_fun.SetParameterNameAt(0, Symbols::This());
   }
   signature.set_result_type(AbstractType::Handle(zone, field.type()));
   initializer_fun.set_is_reflectable(false);
@@ -2423,7 +2417,7 @@
   initializer_fun.set_is_extension_member(field.is_extension_member());
 
   signature ^= ClassFinalizer::FinalizeType(signature);
-  initializer_fun.set_signature(signature);
+  initializer_fun.SetSignature(signature);
 
   field.SetInitializerFunction(initializer_fun);
   return initializer_fun.ptr();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 56cdfac..06dcf56 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -205,6 +205,7 @@
 #endif
 
 PRECOMPILER_WSR_FIELD_DEFINITION(ClosureData, Function, parent_function)
+PRECOMPILER_WSR_FIELD_DEFINITION(Function, FunctionType, signature)
 
 #undef PRECOMPILER_WSR_FIELD_DEFINITION
 
@@ -3647,26 +3648,41 @@
                 false,  // Not native.
                 *this, TokenPosition::kMinSource));
   ArgumentsDescriptor desc(args_desc);
-  if (desc.TypeArgsLen() > 0) {
+  const intptr_t type_args_len = desc.TypeArgsLen();
+  if (type_args_len > 0) {
     // Make dispatcher function generic, since type arguments are passed.
-    invocation.SetNumTypeParameters(desc.TypeArgsLen());
+    const auto& type_parameters =
+        TypeParameters::Handle(zone, TypeParameters::New(type_args_len));
+    // Allow any type, as any type checking is compiled into the dispatcher.
+    auto& bound = Type::Handle(
+        zone, IsolateGroup::Current()->object_store()->nullable_object_type());
+    for (intptr_t i = 0; i < type_args_len; i++) {
+      // The name of the type parameter does not matter, as a type error using
+      // it should never be thrown.
+      type_parameters.SetNameAt(i, Symbols::OptimizedOut());
+      type_parameters.SetBoundAt(i, bound);
+      // Type arguments will always be provided, so the default is not used.
+      type_parameters.SetDefaultAt(i, Object::dynamic_type());
+    }
+    signature.SetTypeParameters(type_parameters);
   }
 
-  invocation.set_num_fixed_parameters(desc.PositionalCount());
-  invocation.SetNumOptionalParameters(desc.NamedCount(),
-                                      false);  // Not positional.
+  signature.set_num_fixed_parameters(desc.PositionalCount());
+  signature.SetNumOptionalParameters(desc.NamedCount(),
+                                     false);  // Not positional.
   signature.set_parameter_types(
       Array::Handle(zone, Array::New(desc.Count(), Heap::kOld)));
-  signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  invocation.CreateNameArray();
+  signature.CreateNameArrayIncludingFlags();
   // Receiver.
   signature.SetParameterTypeAt(0, Object::dynamic_type());
-  signature.SetParameterNameAt(0, Symbols::This());
+  invocation.SetParameterNameAt(0, Symbols::This());
   // Remaining positional parameters.
   for (intptr_t i = 1; i < desc.PositionalCount(); i++) {
     signature.SetParameterTypeAt(i, Object::dynamic_type());
     char name[64];
     Utils::SNPrint(name, 64, ":p%" Pd, i);
-    signature.SetParameterNameAt(
+    invocation.SetParameterNameAt(
         i, String::Handle(zone, Symbols::New(thread, name)));
   }
 
@@ -3677,7 +3693,7 @@
     signature.SetParameterTypeAt(param_index, Object::dynamic_type());
     signature.SetParameterNameAt(param_index, param_name);
   }
-  signature.FinalizeNameArrays(invocation);
+  signature.FinalizeNameArray();
   signature.set_result_type(Object::dynamic_type());
   invocation.set_is_debuggable(false);
   invocation.set_is_visible(false);
@@ -3685,7 +3701,7 @@
   invocation.set_saved_args_desc(args_desc);
 
   signature ^= ClassFinalizer::FinalizeType(signature);
-  invocation.set_signature(signature);
+  invocation.SetSignature(signature);
 
   return invocation.ptr();
 }
@@ -3718,11 +3734,12 @@
 
   // Initialize signature: receiver is a single fixed parameter.
   const intptr_t kNumParameters = 1;
-  extractor.set_num_fixed_parameters(kNumParameters);
-  extractor.SetNumOptionalParameters(0, false);
+  signature.set_num_fixed_parameters(kNumParameters);
+  signature.SetNumOptionalParameters(0, false);
   signature.set_parameter_types(Object::extractor_parameter_types());
-  signature.set_parameter_names(Object::extractor_parameter_names());
-  extractor.SetParameterNamesFrom(signature);
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  extractor.set_positional_parameter_names(Object::extractor_parameter_names());
+#endif
   signature.set_result_type(Object::dynamic_type());
 
   extractor.InheritKernelOffsetFrom(*this);
@@ -3732,7 +3749,7 @@
   extractor.set_is_visible(false);
 
   signature ^= ClassFinalizer::FinalizeType(signature);
-  extractor.set_signature(signature);
+  extractor.SetSignature(signature);
 
   owner.AddFunction(extractor);
 
@@ -7724,20 +7741,17 @@
   set_data(pair);
 }
 
-void Function::set_signature(const FunctionType& value) const {
-  // Signature may be reset to null in aot to save space.
-  untag()->set_signature(value.ptr());
-  if (!value.IsNull()) {
-    ASSERT(NumImplicitParameters() == value.num_implicit_parameters());
-    if (IsClosureFunction() && value.IsGeneric()) {
-      const TypeParameters& type_params =
-          TypeParameters::Handle(value.type_parameters());
-      const TypeArguments& defaults =
-          TypeArguments::Handle(type_params.defaults());
-      auto kind = DefaultTypeArgumentsKindFor(defaults);
-      ASSERT(kind != DefaultTypeArgumentsKind::kInvalid);
-      set_default_type_arguments_kind(kind);
-    }
+void Function::SetSignature(const FunctionType& value) const {
+  set_signature(value);
+  ASSERT(NumImplicitParameters() == value.num_implicit_parameters());
+  if (IsClosureFunction() && value.IsGeneric()) {
+    const TypeParameters& type_params =
+        TypeParameters::Handle(value.type_parameters());
+    const TypeArguments& defaults =
+        TypeArguments::Handle(type_params.defaults());
+    auto kind = DefaultTypeArgumentsKindFor(defaults);
+    ASSERT(kind != DefaultTypeArgumentsKind::kInvalid);
+    set_default_type_arguments_kind(kind);
   }
 }
 
@@ -7761,9 +7775,8 @@
 }
 
 AbstractTypePtr Function::ParameterTypeAt(intptr_t index) const {
-  const Array& parameter_types =
-      Array::Handle(untag()->signature()->untag()->parameter_types());
-  return AbstractType::RawCast(parameter_types.At(index));
+  const Array& types = Array::Handle(parameter_types());
+  return AbstractType::RawCast(types.At(index));
 }
 
 AbstractTypePtr FunctionType::ParameterTypeAt(intptr_t index) const {
@@ -7778,73 +7791,129 @@
   parameter_types.SetAt(index, value);
 }
 
-void Function::set_parameter_types(const Array& value) const {
-  ASSERT(value.IsNull() || value.Length() > 0);
-  untag()->signature()->untag()->set_parameter_types(value.ptr());
-}
-
 void FunctionType::set_parameter_types(const Array& value) const {
   ASSERT(value.IsNull() || value.Length() > 0);
   untag()->set_parameter_types(value.ptr());
 }
 
 StringPtr Function::ParameterNameAt(intptr_t index) const {
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
-  return String::RawCast(parameter_names.At(index));
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    // Without the signature, we're guaranteed not to have any name information.
+    return Symbols::OptimizedOut().ptr();
+  }
+#endif
+  const intptr_t num_fixed = num_fixed_parameters();
+  if (HasOptionalNamedParameters() && index >= num_fixed) {
+    const Array& parameter_names =
+        Array::Handle(signature()->untag()->named_parameter_names());
+    return String::RawCast(parameter_names.At(index - num_fixed));
+  }
+#if defined(DART_PRECOMPILED_RUNTIME)
+  return Symbols::OptimizedOut().ptr();
+#else
+  const Array& names = Array::Handle(untag()->positional_parameter_names());
+  return String::RawCast(names.At(index));
+#endif
 }
 
-void Function::SetParameterNamesFrom(const FunctionType& signature) const {
-  untag()->set_parameter_names(signature.parameter_names());
+void Function::SetParameterNameAt(intptr_t index, const String& value) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
+  ASSERT(!value.IsNull() && value.IsSymbol());
+  if (HasOptionalNamedParameters() && index >= num_fixed_parameters()) {
+    // These should be set on the signature, not the function.
+    UNREACHABLE();
+  }
+  const Array& parameter_names =
+      Array::Handle(untag()->positional_parameter_names());
+  parameter_names.SetAt(index, value);
+#endif
 }
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+void Function::set_positional_parameter_names(const Array& value) const {
+  ASSERT(value.ptr() == Object::empty_array().ptr() || value.Length() > 0);
+  untag()->set_positional_parameter_names(value.ptr());
+}
+#endif
+
 StringPtr FunctionType::ParameterNameAt(intptr_t index) const {
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
-  return String::RawCast(parameter_names.At(index));
+  const intptr_t num_fixed = num_fixed_parameters();
+  if (!HasOptionalNamedParameters() || index < num_fixed) {
+    // The positional parameter names are stored on the function, not here.
+    UNREACHABLE();
+  }
+  const Array& parameter_names =
+      Array::Handle(untag()->named_parameter_names());
+  return String::RawCast(parameter_names.At(index - num_fixed));
 }
 
 void FunctionType::SetParameterNameAt(intptr_t index,
                                       const String& value) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
   ASSERT(!value.IsNull() && value.IsSymbol());
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
-  parameter_names.SetAt(index, value);
+  const intptr_t num_fixed = num_fixed_parameters();
+  if (!HasOptionalNamedParameters() || index < num_fixed) {
+    UNREACHABLE();
+  }
+  const Array& parameter_names =
+      Array::Handle(untag()->named_parameter_names());
+  parameter_names.SetAt(index - num_fixed, value);
+#endif
 }
 
-void Function::set_parameter_names(const Array& value) const {
-  ASSERT(value.IsNull() || value.Length() > 0);
-  untag()->set_parameter_names(value.ptr());
+void FunctionType::set_named_parameter_names(const Array& value) const {
+  ASSERT(value.ptr() == Object::empty_array().ptr() || value.Length() > 0);
+  untag()->set_named_parameter_names(value.ptr());
 }
 
-void FunctionType::set_parameter_names(const Array& value) const {
-  ASSERT(value.IsNull() || value.Length() > 0);
-  untag()->set_parameter_names(value.ptr());
+void Function::CreateNameArray(Heap::Space space) const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
+  const intptr_t num_positional_params =
+      num_fixed_parameters() + NumOptionalPositionalParameters();
+  if (num_positional_params == 0) {
+    set_positional_parameter_names(Object::empty_array());
+  } else {
+    set_positional_parameter_names(
+        Array::Handle(Array::New(num_positional_params, space)));
+  }
+#endif
 }
 
 void FunctionType::CreateNameArrayIncludingFlags(Heap::Space space) const {
-  // Currently, we only store flags for named parameters that are required.
-  const intptr_t num_parameters = NumParameters();
-  if (num_parameters == 0) return;
-  intptr_t num_total_slots = num_parameters;
-  if (HasOptionalNamedParameters()) {
-    const intptr_t last_index = (NumOptionalNamedParameters() - 1) /
-                                compiler::target::kNumParameterFlagsPerElement;
-    const intptr_t num_flag_slots = last_index + 1;
-    num_total_slots += num_flag_slots;
+#if defined(DART_PRECOMPILED_RUNTIME)
+  UNREACHABLE();
+#else
+  const intptr_t num_named_parameters = NumOptionalNamedParameters();
+  if (num_named_parameters == 0) {
+    return set_named_parameter_names(Object::empty_array());
   }
+  // Currently, we only store flags for named parameters.
+  const intptr_t last_index = (num_named_parameters - 1) /
+                              compiler::target::kNumParameterFlagsPerElement;
+  const intptr_t num_flag_slots = last_index + 1;
+  intptr_t num_total_slots = num_named_parameters + num_flag_slots;
   auto& array = Array::Handle(Array::New(num_total_slots, space));
-  if (num_total_slots > num_parameters) {
-    // Set flag slots to Smi 0 before handing off.
-    auto& empty_flags_smi = Smi::Handle(Smi::New(0));
-    for (intptr_t i = num_parameters; i < num_total_slots; i++) {
-      array.SetAt(i, empty_flags_smi);
-    }
+  // Set flag slots to Smi 0 before handing off.
+  auto& empty_flags_smi = Smi::Handle(Smi::New(0));
+  for (intptr_t i = num_named_parameters; i < num_total_slots; i++) {
+    array.SetAt(i, empty_flags_smi);
   }
-  set_parameter_names(array);
+  set_named_parameter_names(array);
+#endif
 }
 
 intptr_t FunctionType::GetRequiredFlagIndex(intptr_t index,
                                             intptr_t* flag_mask) const {
   // If these calculations change, also change
   // FlowGraphBuilder::BuildClosureCallHasRequiredNamedArgumentsCheck.
+  ASSERT(HasOptionalNamedParameters());
   ASSERT(flag_mask != nullptr);
   ASSERT(index >= num_fixed_parameters());
   index -= num_fixed_parameters();
@@ -7852,50 +7921,50 @@
                << ((static_cast<uintptr_t>(index) %
                     compiler::target::kNumParameterFlagsPerElement) *
                    compiler::target::kNumParameterFlags);
-  return NumParameters() +
+  return NumOptionalNamedParameters() +
          index / compiler::target::kNumParameterFlagsPerElement;
 }
 
 bool Function::HasRequiredNamedParameters() const {
-  const FunctionType& sig = FunctionType::Handle(signature());
 #if defined(DART_PRECOMPILED_RUNTIME)
-  if (sig.IsNull()) {
+  if (signature() == FunctionType::null()) {
     // Signature is not dropped in aot when any named parameter is required.
     return false;
   }
-#else
-  ASSERT(!sig.IsNull());
 #endif
-  const Array& parameter_names = Array::Handle(sig.parameter_names());
+  if (!HasOptionalNamedParameters()) {
+    return false;
+  }
+  const FunctionType& sig = FunctionType::Handle(signature());
+  const Array& parameter_names = Array::Handle(sig.named_parameter_names());
   if (parameter_names.IsNull()) {
     return false;
   }
-  return parameter_names.Length() > NumParameters();
+  return parameter_names.Length() > NumOptionalNamedParameters();
 }
 
 bool Function::IsRequiredAt(intptr_t index) const {
-  if (index < num_fixed_parameters() + NumOptionalPositionalParameters()) {
-    return false;
-  }
-  const FunctionType& sig = FunctionType::Handle(signature());
 #if defined(DART_PRECOMPILED_RUNTIME)
-  if (sig.IsNull()) {
+  if (signature() == FunctionType::null()) {
     // Signature is not dropped in aot when any named parameter is required.
     return false;
   }
-#else
-  ASSERT(!sig.IsNull());
 #endif
+  if (!HasOptionalNamedParameters() || index < num_fixed_parameters()) {
+    return false;
+  }
+  const FunctionType& sig = FunctionType::Handle(signature());
   return sig.IsRequiredAt(index);
 }
 
 bool FunctionType::IsRequiredAt(intptr_t index) const {
-  if (index < num_fixed_parameters() + NumOptionalPositionalParameters()) {
+  if (!HasOptionalNamedParameters() || index < num_fixed_parameters()) {
     return false;
   }
   intptr_t flag_mask;
   const intptr_t flag_index = GetRequiredFlagIndex(index, &flag_mask);
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
+  const Array& parameter_names =
+      Array::Handle(untag()->named_parameter_names());
   if (flag_index >= parameter_names.Length()) {
     return false;
   }
@@ -7905,56 +7974,40 @@
 }
 
 void FunctionType::SetIsRequiredAt(intptr_t index) const {
+#if defined(DART_PRECOMPILER_RUNTIME)
+  UNREACHABLE();
+#else
   intptr_t flag_mask;
   const intptr_t flag_index = GetRequiredFlagIndex(index, &flag_mask);
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
+  const Array& parameter_names =
+      Array::Handle(untag()->named_parameter_names());
   ASSERT(flag_index < parameter_names.Length());
   const intptr_t flags =
       Smi::Value(Smi::RawCast(parameter_names.At(flag_index)));
   parameter_names.SetAt(flag_index, Smi::Handle(Smi::New(flags | flag_mask)));
+#endif
 }
 
-void FunctionType::TruncateUnusedParameterFlags() const {
-  const intptr_t num_params = NumParameters();
-  if (num_params == 0) return;
-  const Array& parameter_names = Array::Handle(untag()->parameter_names());
-  if (parameter_names.Length() == num_params) {
-    // No flag slots to truncate.
+void FunctionType::FinalizeNameArray() const {
+#if defined(DART_PRECOMPILER_RUNTIME)
+  UNREACHABLE();
+#else
+  const intptr_t num_named_parameters = NumOptionalNamedParameters();
+  if (num_named_parameters == 0) {
+    ASSERT(untag()->named_parameter_names() == Object::empty_array().ptr());
     return;
   }
+  const Array& parameter_names =
+      Array::Handle(untag()->named_parameter_names());
   // Truncate the parameter names array to remove unused flags from the end.
   intptr_t last_used = parameter_names.Length() - 1;
-  for (; last_used >= num_params; --last_used) {
+  for (; last_used >= num_named_parameters; --last_used) {
     if (Smi::Value(Smi::RawCast(parameter_names.At(last_used))) != 0) {
       break;
     }
   }
   parameter_names.Truncate(last_used + 1);
-}
-
-void FunctionType::FinalizeNameArrays(const Function& function) const {
-  TruncateUnusedParameterFlags();
-  if (!function.IsNull()) {
-    function.SetParameterNamesFrom(*this);
-    // Unless the function is a dispatcher, its number of type parameters
-    // must match the number of type parameters in its signature.
-    ASSERT(function.kind() == UntaggedFunction::kNoSuchMethodDispatcher ||
-           function.kind() == UntaggedFunction::kInvokeFieldDispatcher ||
-           function.kind() == UntaggedFunction::kDynamicInvocationForwarder ||
-           function.NumTypeParameters() == NumTypeParameters());
-  }
-}
-
-void FunctionType::set_type_parameters(const TypeParameters& value) const {
-  untag()->set_type_parameters(value.ptr());
-}
-
-static void ReportTooManyTypeParameters(const Function& function) {
-  Report::MessageF(Report::kError, Script::Handle(), TokenPosition::kNoSource,
-                   Report::AtLocation,
-                   "too many type parameters declared in function '%s'",
-                   function.UserVisibleNameCString());
-  UNREACHABLE();
+#endif
 }
 
 static void ReportTooManyTypeParameters(const FunctionType& sig) {
@@ -7966,39 +8019,24 @@
   UNREACHABLE();
 }
 
+void FunctionType::SetTypeParameters(const TypeParameters& value) const {
+  untag()->set_type_parameters(value.ptr());
+  const intptr_t count = value.Length();
+  if (!UntaggedFunctionType::PackedNumTypeParameters::is_valid(count)) {
+    ReportTooManyTypeParameters(*this);
+  }
+  untag()->packed_type_parameter_counts_.Update<PackedNumTypeParameters>(count);
+}
+
 void FunctionType::SetNumParentTypeArguments(intptr_t value) const {
   ASSERT(value >= 0);
-  if (!Utils::IsUint(UntaggedFunctionType::kMaxParentTypeArgumentsBits,
-                     value)) {
+  if (!PackedNumParentTypeArguments::is_valid(value)) {
     ReportTooManyTypeParameters(*this);
   }
-  const uint32_t* original = &untag()->packed_fields_;
-  StoreNonPointer(original,
-                  UntaggedFunctionType::PackedNumParentTypeArguments::update(
-                      value, *original));
-}
-
-void Function::SetNumTypeParameters(intptr_t value) const {
-  ASSERT(value >= 0);
-  if (!Utils::IsUint(UntaggedFunction::kMaxTypeParametersBits, value)) {
-    ReportTooManyTypeParameters(*this);
-  }
-  untag()->packed_fields_.Update<UntaggedFunction::PackedNumTypeParameters>(
+  untag()->packed_type_parameter_counts_.Update<PackedNumParentTypeArguments>(
       value);
 }
 
-intptr_t FunctionType::NumTypeParameters(Thread* thread) const {
-  if (type_parameters() == TypeParameters::null()) {
-    return 0;
-  }
-  REUSABLE_TYPE_PARAMETERS_HANDLESCOPE(thread);
-  TypeParameters& type_params = thread->TypeParametersHandle();
-  type_params = type_parameters();
-  // We require null to represent a non-generic signature.
-  ASSERT(type_params.Length() != 0);
-  return type_params.Length();
-}
-
 intptr_t Function::NumParentTypeArguments() const {
   // Don't allocate handle in cases where we know it is 0.
   if (!IsClosureFunction()) return 0;
@@ -8720,7 +8758,7 @@
             num_free_fun_type_params, space, trail);
       }
       sig_type_params.set_defaults(type_args);
-      sig.set_type_parameters(sig_type_params);
+      sig.SetTypeParameters(sig_type_params);
     }
   }
 
@@ -8756,7 +8794,7 @@
     }
     sig.SetParameterTypeAt(i, type);
   }
-  sig.set_parameter_names(Array::Handle(zone, parameter_names()));
+  sig.set_named_parameter_names(Array::Handle(zone, named_parameter_names()));
 
   if (delete_type_parameters) {
     ASSERT(sig.IsInstantiated(kFunctions));
@@ -8795,11 +8833,10 @@
 bool FunctionType::HasSameTypeParametersAndBounds(const FunctionType& other,
                                                   TypeEquality kind,
                                                   TrailPtr trail) const {
-  Thread* thread = Thread::Current();
-  Zone* zone = thread->zone();
+  Zone* const zone = Thread::Current()->zone();
 
-  const intptr_t num_type_params = NumTypeParameters(thread);
-  if (num_type_params != other.NumTypeParameters(thread)) {
+  const intptr_t num_type_params = NumTypeParameters();
+  if (num_type_params != other.NumTypeParameters()) {
     return false;
   }
   if (num_type_params > 0) {
@@ -8996,6 +9033,7 @@
                           TokenPosition token_pos,
                           Heap::Space space) {
   ASSERT(!owner.IsNull());
+  ASSERT(!signature.IsNull());
   const Function& result = Function::Handle(Function::New(space));
   result.set_kind_tag(0);
   result.set_packed_fields(0);
@@ -9051,12 +9089,10 @@
   if (result.ForceOptimize()) {
     result.set_is_debuggable(false);
   }
-  if (!signature.IsNull()) {
-    signature.set_num_implicit_parameters(result.NumImplicitParameters());
-    result.set_signature(signature);
-  } else {
-    ASSERT(kind == UntaggedFunction::kFfiTrampoline);
-  }
+  signature.set_num_implicit_parameters(result.NumImplicitParameters());
+  result.SetSignature(signature);
+  NOT_IN_PRECOMPILED(
+      result.set_positional_parameter_names(Object::empty_array()));
   return result.ptr();
 }
 
@@ -9159,9 +9195,8 @@
   // This function cannot be local, therefore it has no generic parent.
   // Its implicit closure function therefore has no generic parent function
   // either. That is why it is safe to simply copy the type parameters.
-  closure_signature.set_type_parameters(
+  closure_signature.SetTypeParameters(
       TypeParameters::Handle(zone, type_parameters()));
-  closure_function.SetNumTypeParameters(NumTypeParameters());
 
   // Set closure function's result type to this result type.
   closure_signature.set_result_type(AbstractType::Handle(zone, result_type()));
@@ -9183,27 +9218,38 @@
   const int num_opt_params = NumOptionalParameters();
   const bool has_opt_pos_params = HasOptionalPositionalParameters();
   const int num_params = num_fixed_params + num_opt_params;
-  closure_function.set_num_fixed_parameters(num_fixed_params);
-  closure_function.SetNumOptionalParameters(num_opt_params, has_opt_pos_params);
+  const int num_pos_params = has_opt_pos_params ? num_params : num_fixed_params;
+  closure_signature.set_num_fixed_parameters(num_fixed_params);
+  closure_signature.SetNumOptionalParameters(num_opt_params,
+                                             has_opt_pos_params);
   closure_signature.set_parameter_types(
       Array::Handle(zone, Array::New(num_params, Heap::kOld)));
-  closure_signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  closure_function.CreateNameArray();
+  closure_signature.CreateNameArrayIncludingFlags();
   AbstractType& param_type = AbstractType::Handle(zone);
   String& param_name = String::Handle(zone);
   // Add implicit closure object parameter.
   param_type = Type::DynamicType();
   closure_signature.SetParameterTypeAt(0, param_type);
-  closure_signature.SetParameterNameAt(0, Symbols::ClosureParameter());
-  for (int i = kClosure; i < num_params; i++) {
+  closure_function.SetParameterNameAt(0, Symbols::ClosureParameter());
+  for (int i = kClosure; i < num_pos_params; i++) {
     param_type = ParameterTypeAt(has_receiver - kClosure + i);
     closure_signature.SetParameterTypeAt(i, param_type);
     param_name = ParameterNameAt(has_receiver - kClosure + i);
+    // Set the name in the function for positional parameters.
+    closure_function.SetParameterNameAt(i, param_name);
+  }
+  for (int i = num_pos_params; i < num_params; i++) {
+    param_type = ParameterTypeAt(has_receiver - kClosure + i);
+    closure_signature.SetParameterTypeAt(i, param_type);
+    param_name = ParameterNameAt(has_receiver - kClosure + i);
+    // Set the name in the signature for named parameters.
     closure_signature.SetParameterNameAt(i, param_name);
     if (IsRequiredAt(has_receiver - kClosure + i)) {
       closure_signature.SetIsRequiredAt(i);
     }
   }
-  closure_signature.FinalizeNameArrays(closure_function);
+  closure_signature.FinalizeNameArray();
   closure_function.InheritKernelOffsetFrom(*this);
 
   // Change covariant parameter types to either Object? for an opted-in implicit
@@ -9230,7 +9276,7 @@
   }
   ASSERT(!closure_signature.IsFinalized());
   closure_signature ^= ClassFinalizer::FinalizeType(closure_signature);
-  closure_function.set_signature(closure_signature);
+  closure_function.SetSignature(closure_signature);
   set_implicit_closure_function(closure_function);
   ASSERT(closure_function.IsImplicitClosureFunction());
   return closure_function.ptr();
@@ -9247,6 +9293,11 @@
 }
 
 StringPtr Function::InternalSignature() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    return String::null();
+  }
+#endif
   Thread* thread = Thread::Current();
   ZoneTextBuffer printer(thread->zone());
   const FunctionType& sig = FunctionType::Handle(signature());
@@ -9255,6 +9306,11 @@
 }
 
 StringPtr Function::UserVisibleSignature() const {
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (signature() == FunctionType::null()) {
+    return String::null();
+  }
+#endif
   Thread* thread = Thread::Current();
   ZoneTextBuffer printer(thread->zone());
   const FunctionType& sig = FunctionType::Handle(signature());
@@ -10140,8 +10196,14 @@
   return buffer.buffer();
 }
 
-void FunctionType::set_packed_fields(uint32_t packed_fields) const {
-  StoreNonPointer(&untag()->packed_fields_, packed_fields);
+void FunctionType::set_packed_parameter_counts(
+    uint32_t packed_parameter_counts) const {
+  untag()->packed_parameter_counts_ = packed_parameter_counts;
+}
+
+void FunctionType::set_packed_type_parameter_counts(
+    uint16_t packed_type_parameter_counts) const {
+  untag()->packed_type_parameter_counts_ = packed_type_parameter_counts;
 }
 
 intptr_t FunctionType::NumParameters() const {
@@ -10150,12 +10212,7 @@
 
 void FunctionType::set_num_implicit_parameters(intptr_t value) const {
   ASSERT(value >= 0);
-  ASSERT(
-      Utils::IsUint(UntaggedFunctionType::kMaxImplicitParametersBits, value));
-  const uint32_t* original = &untag()->packed_fields_;
-  StoreNonPointer(original,
-                  UntaggedFunctionType::PackedNumImplicitParameters::update(
-                      value, *original));
+  untag()->packed_parameter_counts_.Update<PackedNumImplicitParameters>(value);
 }
 
 ClosureData::DefaultTypeArgumentsKind ClosureData::default_type_arguments_kind()
@@ -10195,36 +10252,9 @@
   return buffer.buffer();
 }
 
-void Function::set_num_fixed_parameters(intptr_t value) const {
-  ASSERT(value >= 0);
-  ASSERT(Utils::IsUint(UntaggedFunction::kMaxFixedParametersBits, value));
-  untag()->packed_fields_.Update<UntaggedFunction::PackedNumFixedParameters>(
-      value);
-  // Also store in signature.
-  FunctionType::Handle(signature()).set_num_fixed_parameters(value);
-}
-
 void FunctionType::set_num_fixed_parameters(intptr_t value) const {
   ASSERT(value >= 0);
-  ASSERT(Utils::IsUint(UntaggedFunctionType::kMaxFixedParametersBits, value));
-  const uint32_t* original = &untag()->packed_fields_;
-  StoreNonPointer(
-      original,
-      UntaggedFunctionType::PackedNumFixedParameters::update(value, *original));
-}
-
-void Function::SetNumOptionalParameters(intptr_t value,
-                                        bool are_optional_positional) const {
-  ASSERT(Utils::IsUint(UntaggedFunction::kMaxOptionalParametersBits, value));
-  untag()
-      ->packed_fields_
-      .Update<UntaggedFunction::PackedHasNamedOptionalParameters>(
-          (value > 0) && !are_optional_positional);
-  untag()->packed_fields_.Update<UntaggedFunction::PackedNumOptionalParameters>(
-      value);
-  // Also store in signature.
-  FunctionType::Handle(signature())
-      .SetNumOptionalParameters(value, are_optional_positional);
+  untag()->packed_parameter_counts_.Update<PackedNumFixedParameters>(value);
 }
 
 void FfiTrampolineData::set_callback_target(const Function& value) const {
@@ -10234,15 +10264,9 @@
 void FunctionType::SetNumOptionalParameters(
     intptr_t value,
     bool are_optional_positional) const {
-  ASSERT(
-      Utils::IsUint(UntaggedFunctionType::kMaxOptionalParametersBits, value));
-  uint32_t packed_fields = untag()->packed_fields_;
-  packed_fields =
-      UntaggedFunctionType::PackedHasNamedOptionalParameters::update(
-          (value > 0) && !are_optional_positional, packed_fields);
-  packed_fields = UntaggedFunctionType::PackedNumOptionalParameters::update(
-      value, packed_fields);
-  StoreNonPointer(&untag()->packed_fields_, packed_fields);
+  untag()->packed_parameter_counts_.Update<PackedHasNamedOptionalParameters>(
+      (value > 0) && !are_optional_positional);
+  untag()->packed_parameter_counts_.Update<PackedNumOptionalParameters>(value);
 }
 
 FunctionTypePtr FunctionType::New(Heap::Space space) {
@@ -10258,10 +10282,10 @@
   Zone* Z = Thread::Current()->zone();
   const FunctionType& result =
       FunctionType::Handle(Z, FunctionType::New(space));
-  result.set_packed_fields(0);
+  result.set_packed_parameter_counts(0);
+  result.set_packed_type_parameter_counts(0);
+  result.set_named_parameter_names(Object::empty_array());
   result.SetNumParentTypeArguments(num_parent_type_arguments);
-  result.set_num_fixed_parameters(0);
-  result.SetNumOptionalParameters(0, false);
   result.set_nullability(nullability);
   result.SetHash(0);
   result.StoreNonPointer(&result.untag()->type_state_,
@@ -20712,8 +20736,10 @@
     return false;
   }
   const FunctionType& other_type = FunctionType::Cast(other);
-  if (packed_fields() != other_type.packed_fields()) {
-    // Different number of parent type arguments or of parameters.
+  if ((packed_parameter_counts() != other_type.packed_parameter_counts()) ||
+      (packed_type_parameter_counts() !=
+       other_type.packed_type_parameter_counts())) {
+    // Different number of type parameters or parameters.
     return false;
   }
   Nullability this_type_nullability = nullability();
@@ -20773,17 +20799,15 @@
       return false;
     }
   }
-  // Check the names and types of optional named parameters.
-  if (!HasOptionalNamedParameters()) {
-    ASSERT(!other_type.HasOptionalNamedParameters());  // Same packed_fields.
-    return true;
-  }
-  for (intptr_t i = num_fixed_parameters(); i < num_params; i++) {
-    if (ParameterNameAt(i) != other_type.ParameterNameAt(i)) {
-      return false;
-    }
-    if (IsRequiredAt(i) != other_type.IsRequiredAt(i)) {
-      return false;
+  if (HasOptionalNamedParameters()) {
+    ASSERT(other_type.HasOptionalNamedParameters());  // Same packed counts.
+    for (intptr_t i = num_fixed_parameters(); i < num_params; i++) {
+      if (ParameterNameAt(i) != other_type.ParameterNameAt(i)) {
+        return false;
+      }
+      if (IsRequiredAt(i) != other_type.IsRequiredAt(i)) {
+        return false;
+      }
     }
   }
   return true;
@@ -21040,7 +21064,8 @@
 
 uword FunctionType::ComputeHash() const {
   ASSERT(IsFinalized());
-  uint32_t result = packed_fields();
+  uint32_t result =
+      CombineHashes(packed_parameter_counts(), packed_type_parameter_counts());
   // A legacy type should have the same hash as its non-nullable version to be
   // consistent with the definition of type equality in Dart code.
   Nullability type_nullability = nullability();
@@ -21242,7 +21267,7 @@
     ASSERT(type.IsOld());
     ASSERT(type.IsCanonical());
     ASSERT(Array::Handle(zone, parameter_types()).IsOld());
-    ASSERT(Array::Handle(zone, parameter_names()).IsOld());
+    ASSERT(Array::Handle(zone, named_parameter_names()).IsOld());
     const intptr_t num_params = NumParameters();
     for (intptr_t i = 0; i < num_params; i++) {
       type = ParameterTypeAt(i);
@@ -21291,7 +21316,7 @@
       SetHash(0);
     }
     ASSERT(Array::Handle(zone, parameter_types()).IsOld());
-    ASSERT(Array::Handle(zone, parameter_names()).IsOld());
+    ASSERT(Array::Handle(zone, named_parameter_names()).IsOld());
     const intptr_t num_params = NumParameters();
     for (intptr_t i = 0; i < num_params; i++) {
       type = ParameterTypeAt(i);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0700711..2ed011c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2587,8 +2587,8 @@
   void SetFfiCallbackExceptionalReturn(const Instance& value) const;
 
   // Return the signature of this function.
-  FunctionTypePtr signature() const { return untag()->signature(); }
-  void set_signature(const FunctionType& value) const;
+  PRECOMPILER_WSR_FIELD_DECLARATION(FunctionType, signature);
+  void SetSignature(const FunctionType& value) const;
   static intptr_t signature_offset() {
     return OFFSET_OF(UntaggedFunction, signature_);
   }
@@ -2637,7 +2637,7 @@
   void set_native_name(const String& name) const;
 
   AbstractTypePtr result_type() const {
-    return untag()->signature()->untag()->result_type();
+    return signature()->untag()->result_type();
   }
 
   // The parameters, starting with NumImplicitParameters() parameters which are
@@ -2645,33 +2645,37 @@
   // Note that type checks exclude implicit parameters.
   AbstractTypePtr ParameterTypeAt(intptr_t index) const;
   ArrayPtr parameter_types() const {
-    return untag()->signature()->untag()->parameter_types();
+    return signature()->untag()->parameter_types();
   }
 
-  // Parameter names are valid for all valid parameter indices, and are not
-  // limited to named optional parameters. If there are parameter flags (eg
-  // required) they're stored at the end of this array, so the size of this
-  // array isn't necessarily NumParameters(), but the first NumParameters()
-  // elements are the names.
+  // Outside of the AOT runtime, functions store the names for their positional
+  // parameters, and delegate storage of the names for named parameters to
+  // their signature. These methods handle fetching the name from and
+  // setting the name to the correct location.
   StringPtr ParameterNameAt(intptr_t index) const;
-  ArrayPtr parameter_names() const { return untag()->parameter_names(); }
-  void SetParameterNamesFrom(const FunctionType& signature) const;
+  // Only valid for positional parameter indexes, as this should be called
+  // explicitly on the signature for named parameters.
+  void SetParameterNameAt(intptr_t index, const String& value) const;
+  // Creates an appropriately sized array in the function to hold positional
+  // parameter names, using the positional parameter count in the signature.
+  // Uses same default space as Function::New.
+  void CreateNameArray(Heap::Space space = Heap::kOld) const;
 
-  // The required flags are stored at the end of the parameter_names. The flags
-  // are packed into SMIs, but omitted if they're 0.
+  // Delegates to the signature, which stores the named parameter flags.
   bool IsRequiredAt(intptr_t index) const;
 
   // The formal type parameters, their bounds, and defaults, are specified as an
   // object of type TypeParameters stored in the signature.
   TypeParametersPtr type_parameters() const {
-    return untag()->signature()->untag()->type_parameters();
+    return signature()->untag()->type_parameters();
   }
 
   intptr_t NumTypeParameters() const {
-    return UntaggedFunction::PackedNumTypeParameters::decode(
-        untag()->packed_fields_);
+    return signature()
+        ->untag()
+        ->packed_type_parameter_counts_
+        .Read<UntaggedFunctionType::PackedNumTypeParameters>();
   }
-  void SetNumTypeParameters(intptr_t value) const;
 
   // Return the cumulative number of type arguments in all parent functions.
   intptr_t NumParentTypeArguments() const;
@@ -2993,33 +2997,38 @@
   }
 
   intptr_t num_fixed_parameters() const {
-    return UntaggedFunction::PackedNumFixedParameters::decode(
-        untag()->packed_fields_);
+    return signature()
+        ->untag()
+        ->packed_parameter_counts_
+        .Read<UntaggedFunctionType::PackedNumFixedParameters>();
   }
-  void set_num_fixed_parameters(intptr_t value) const;
 
   bool HasOptionalParameters() const {
-    return UntaggedFunction::PackedNumOptionalParameters::decode(
-               untag()->packed_fields_) > 0;
+    return signature()
+               ->untag()
+               ->packed_parameter_counts_
+               .Read<UntaggedFunctionType::PackedNumOptionalParameters>() > 0;
   }
   bool HasOptionalNamedParameters() const {
     return HasOptionalParameters() &&
-           UntaggedFunction::PackedHasNamedOptionalParameters::decode(
-               untag()->packed_fields_);
+           signature()
+               ->untag()
+               ->packed_parameter_counts_
+               .Read<UntaggedFunctionType::PackedHasNamedOptionalParameters>();
   }
   bool HasRequiredNamedParameters() const;
   bool HasOptionalPositionalParameters() const {
     return HasOptionalParameters() && !HasOptionalNamedParameters();
   }
   intptr_t NumOptionalParameters() const {
-    return UntaggedFunction::PackedNumOptionalParameters::decode(
-        untag()->packed_fields_);
+    return signature()
+        ->untag()
+        ->packed_parameter_counts_
+        .Read<UntaggedFunctionType::PackedNumOptionalParameters>();
   }
   intptr_t NumOptionalPositionalParameters() const {
     return HasOptionalPositionalParameters() ? NumOptionalParameters() : 0;
   }
-  void SetNumOptionalParameters(intptr_t num_optional_parameters,
-                                bool are_optional_positional) const;
 
   intptr_t NumOptionalNamedParameters() const {
     return HasOptionalNamedParameters() ? NumOptionalParameters() : 0;
@@ -3781,8 +3790,6 @@
   DefaultTypeArgumentsKind DefaultTypeArgumentsKindFor(
       const TypeArguments& defaults) const;
 
-  void set_parameter_names(const Array& value) const;
-  void set_parameter_types(const Array& value) const;
   void set_ic_data_array(const Array& value) const;
   void set_name(const String& value) const;
   void set_kind(UntaggedFunction::Kind value) const;
@@ -3796,6 +3803,13 @@
   void set_num_optional_parameters(intptr_t value) const;  // Encoded value.
   void set_kind_tag(uint32_t value) const;
 
+#if !defined(DART_PRECOMPILED_RUNTIME)
+  ArrayPtr positional_parameter_names() const {
+    return untag()->positional_parameter_names();
+  }
+  void set_positional_parameter_names(const Array& value) const;
+#endif
+
   ObjectPtr data() const { return untag()->data<std::memory_order_acquire>(); }
   void set_data(const Object& value) const;
 
@@ -8365,6 +8379,19 @@
 // of parameters, but includes the names of optional named parameters.
 class FunctionType : public AbstractType {
  public:
+  // Reexported so they can be used by the flow graph builders.
+  using PackedNumParentTypeArguments =
+      UntaggedFunctionType::PackedNumParentTypeArguments;
+  using PackedNumTypeParameters = UntaggedFunctionType::PackedNumTypeParameters;
+  using PackedHasNamedOptionalParameters =
+      UntaggedFunctionType::PackedHasNamedOptionalParameters;
+  using PackedNumImplicitParameters =
+      UntaggedFunctionType::PackedNumImplicitParameters;
+  using PackedNumFixedParameters =
+      UntaggedFunctionType::PackedNumFixedParameters;
+  using PackedNumOptionalParameters =
+      UntaggedFunctionType::PackedNumOptionalParameters;
+
   static intptr_t type_state_offset() {
     return OFFSET_OF(UntaggedFunctionType, type_state_);
   }
@@ -8421,41 +8448,46 @@
 
   // Return the number of type arguments in enclosing signature.
   intptr_t NumParentTypeArguments() const {
-    return UntaggedFunctionType::PackedNumParentTypeArguments::decode(
-        untag()->packed_fields_);
+    return untag()
+        ->packed_type_parameter_counts_.Read<PackedNumParentTypeArguments>();
   }
   void SetNumParentTypeArguments(intptr_t value) const;
+  intptr_t NumTypeParameters() const {
+    return PackedNumTypeParameters::decode(
+        untag()->packed_type_parameter_counts_);
+  }
 
   intptr_t NumTypeArguments() const {
     return NumParentTypeArguments() + NumTypeParameters();
   }
 
   intptr_t num_implicit_parameters() const {
-    return UntaggedFunctionType::PackedNumImplicitParameters::decode(
-        untag()->packed_fields_);
+    return untag()
+        ->packed_parameter_counts_.Read<PackedNumImplicitParameters>();
   }
   void set_num_implicit_parameters(intptr_t value) const;
   intptr_t num_fixed_parameters() const {
-    return UntaggedFunctionType::PackedNumFixedParameters::decode(
-        untag()->packed_fields_);
+    return untag()->packed_parameter_counts_.Read<PackedNumFixedParameters>();
   }
   void set_num_fixed_parameters(intptr_t value) const;
 
   bool HasOptionalParameters() const {
-    return UntaggedFunctionType::PackedNumOptionalParameters::decode(
-               untag()->packed_fields_) > 0;
+    return untag()
+               ->packed_parameter_counts_.Read<PackedNumOptionalParameters>() >
+           0;
   }
   bool HasOptionalNamedParameters() const {
     return HasOptionalParameters() &&
-           UntaggedFunctionType::PackedHasNamedOptionalParameters::decode(
-               untag()->packed_fields_);
+           untag()
+               ->packed_parameter_counts_
+               .Read<PackedHasNamedOptionalParameters>();
   }
   bool HasOptionalPositionalParameters() const {
     return HasOptionalParameters() && !HasOptionalNamedParameters();
   }
   intptr_t NumOptionalParameters() const {
-    return UntaggedFunctionType::PackedNumOptionalParameters::decode(
-        untag()->packed_fields_);
+    return untag()
+        ->packed_parameter_counts_.Read<PackedNumOptionalParameters>();
   }
   void SetNumOptionalParameters(intptr_t num_optional_parameters,
                                 bool are_optional_positional) const;
@@ -8467,21 +8499,21 @@
   intptr_t NumOptionalNamedParameters() const {
     return HasOptionalNamedParameters() ? NumOptionalParameters() : 0;
   }
-  uint32_t packed_fields() const { return untag()->packed_fields_; }
-  void set_packed_fields(uint32_t packed_fields) const;
-  static intptr_t packed_fields_offset() {
-    return OFFSET_OF(UntaggedFunctionType, packed_fields_);
-  }
 
-  // Reexported so they can be used by the flow graph builders.
-  using PackedNumParentTypeArguments =
-      UntaggedFunctionType::PackedNumParentTypeArguments;
-  using PackedHasNamedOptionalParameters =
-      UntaggedFunctionType::PackedHasNamedOptionalParameters;
-  using PackedNumFixedParameters =
-      UntaggedFunctionType::PackedNumFixedParameters;
-  using PackedNumOptionalParameters =
-      UntaggedFunctionType::PackedNumOptionalParameters;
+  uint32_t packed_parameter_counts() const {
+    return untag()->packed_parameter_counts_;
+  }
+  void set_packed_parameter_counts(uint32_t packed_parameter_counts) const;
+  static intptr_t packed_parameter_counts_offset() {
+    return OFFSET_OF(UntaggedFunctionType, packed_parameter_counts_);
+  }
+  uint16_t packed_type_parameter_counts() const {
+    return untag()->packed_type_parameter_counts_;
+  }
+  void set_packed_type_parameter_counts(uint16_t packed_parameter_counts) const;
+  static intptr_t packed_type_parameter_counts_offset() {
+    return OFFSET_OF(UntaggedFunctionType, packed_type_parameter_counts_);
+  }
 
   // Return the type parameter declared at index.
   TypeParameterPtr TypeParameterAt(
@@ -8501,20 +8533,24 @@
   static intptr_t parameter_types_offset() {
     return OFFSET_OF(UntaggedFunctionType, parameter_types_);
   }
-  // Parameter names are valid for all valid parameter indices, and are not
-  // limited to named optional parameters. However, they are meaningless after
-  // canonicalization of the function type. Any particular signature may be
-  // selected as the canonical represent as the names are not part of the type.
+  // Parameter names are only stored for named parameters. If there are no named
+  // parameters, named_parameter_names() is null.
   // If there are parameter flags (eg required) they're stored at the end of
-  // this array, so the size of this array isn't necessarily NumParameters(),
-  // but the first NumParameters() elements are the names.
-  StringPtr ParameterNameAt(intptr_t index) const;
-  void SetParameterNameAt(intptr_t index, const String& value) const;
-  ArrayPtr parameter_names() const { return untag()->parameter_names(); }
-  void set_parameter_names(const Array& value) const;
-  static intptr_t parameter_names_offset() {
-    return OFFSET_OF(UntaggedFunctionType, parameter_names_);
+  // this array, so the size of this array isn't necessarily
+  // NumOptionalNamedParameters(), but the first NumOptionalNamedParameters()
+  // elements are the names.
+  ArrayPtr named_parameter_names() const {
+    return untag()->named_parameter_names();
   }
+  void set_named_parameter_names(const Array& value) const;
+  static intptr_t named_parameter_names_offset() {
+    return OFFSET_OF(UntaggedFunctionType, named_parameter_names_);
+  }
+  // The index for these operations is the absolute index of the parameter, not
+  // the index relative to the start of the named parameters (if any).
+  StringPtr ParameterNameAt(intptr_t index) const;
+  // Only valid for absolute indexes of named parameters.
+  void SetParameterNameAt(intptr_t index, const String& value) const;
 
   // The required flags are stored at the end of the parameter_names. The flags
   // are packed into SMIs, but omitted if they're 0.
@@ -8523,20 +8559,16 @@
 
   // Sets up the signature's parameter name array, including appropriate space
   // for any possible parameter flags. This may be an overestimate if some
-  // parameters don't have flags, and so TruncateUnusedParameterFlags() should
+  // parameters don't have flags, and so FinalizeNameArray() should
   // be called after all parameter flags have been appropriately set.
   //
   // Assumes that the number of fixed and optional parameters for the signature
-  // has already been set.
-  void CreateNameArrayIncludingFlags(Heap::Space space) const;
+  // has already been set. Uses same default space as FunctionType::New.
+  void CreateNameArrayIncludingFlags(Heap::Space space = Heap::kOld) const;
 
   // Truncate the parameter names array to remove any unused flag slots. Make
   // sure to only do this after calling SetIsRequiredAt as necessary.
-  void TruncateUnusedParameterFlags() const;
-
-  // Finalize the name arrays by truncating the parameter name array and copying
-  // the names in the given function.
-  void FinalizeNameArrays(const Function& function) const;
+  void FinalizeNameArray() const;
 
   // Returns the length of the parameter names array that is required to store
   // all the names plus all their flags. This may be an overestimate if some
@@ -8548,14 +8580,10 @@
   TypeParametersPtr type_parameters() const {
     return untag()->type_parameters();
   }
-  void set_type_parameters(const TypeParameters& value) const;
+  void SetTypeParameters(const TypeParameters& value) const;
   static intptr_t type_parameters_offset() {
     return OFFSET_OF(UntaggedFunctionType, type_parameters_);
   }
-  intptr_t NumTypeParameters(Thread* thread) const;
-  intptr_t NumTypeParameters() const {
-    return NumTypeParameters(Thread::Current());
-  }
 
   // Returns true if this function type has the same number of type parameters
   // with equal bounds as the other function type. Type parameter names and
@@ -8565,7 +8593,7 @@
                                       TrailPtr trail = nullptr) const;
 
   // Return true if this function type declares type parameters.
-  bool IsGeneric() const { return NumTypeParameters(Thread::Current()) > 0; }
+  bool IsGeneric() const { return NumTypeParameters() > 0; }
 
   // Return true if any enclosing signature of this signature is generic.
   bool HasGenericParent() const { return NumParentTypeArguments() > 0; }
@@ -11071,9 +11099,16 @@
     return OFFSET_OF(UntaggedClosure, function_);
   }
 
+#if defined(DART_PRECOMPILER)
+  FunctionTypePtr signature() const {
+    return FunctionType::RawCast(WeakSerializationReference::Unwrap(
+        untag()->function()->untag()->signature()));
+  }
+#else
   FunctionTypePtr signature() const {
     return untag()->function()->untag()->signature();
   }
+#endif
 
   ContextPtr context() const { return untag()->context(); }
   static intptr_t context_offset() {
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a645736..fb36cf8 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -96,9 +96,9 @@
   const int kNumFixedParameters = 2;
   const int kNumOptionalParameters = 3;
   const bool kAreOptionalPositional = true;
-  function.set_num_fixed_parameters(kNumFixedParameters);
-  function.SetNumOptionalParameters(kNumOptionalParameters,
-                                    kAreOptionalPositional);
+  signature.set_num_fixed_parameters(kNumFixedParameters);
+  signature.SetNumOptionalParameters(kNumOptionalParameters,
+                                     kAreOptionalPositional);
   functions.SetAt(1, function);
 
   function_name = Symbols::New(thread, "baz");
@@ -2599,7 +2599,7 @@
   signature = function.signature();
   signature.set_result_type(Object::dynamic_type());
   signature ^= ClassFinalizer::FinalizeType(signature);
-  function.set_signature(signature);
+  function.SetSignature(signature);
   const Closure& closure = Closure::Handle(
       Closure::New(Object::null_type_arguments(), Object::null_type_arguments(),
                    function, context));
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 4bb663a..3020106b 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -1105,64 +1105,20 @@
     }
 
     void VisitFunction(const Function& function) {
-      list_ = PrepareParameterNames(function);
-      list_ = Dedup(list_);
-      function.set_parameter_names(list_);
-
-      // No need to dedup parameter types, as they are stored in the
-      // canonicalized function type of the function.
-      // However, the function type of the function is only needed in case of
-      // recompilation or if available to mirrors, or for copied types
-      // to lazily generated tear offs. Also avoid attempting to change
-      // read-only VM objects for de-duplication.
-      // We cannot check precisely if a function is an entry point here,
-      // because the metadata has been dropped already. However, we use the
-      // has_pragma flag on the function as a conservative approximation.
-      // Resolution requires the number of parameters (no signature needed) and
-      // their names if any named parameter is required (signature needed).
-      if (FLAG_precompiled_mode && !function.InVMIsolateHeap() &&
-          !function.IsClosureFunction() && !function.IsFfiTrampoline() &&
-          function.name() != Symbols::Call().ptr() && !function.is_native() &&
-          !function.HasRequiredNamedParameters() &&
-          !MayBeEntryPoint(function)) {
-        // Function type not needed for function type tests or resolution.
-        function.set_signature(Object::null_function_type());
+      // Don't bother dedupping the positional names in precompiled mode, as
+      // they'll be dropped anyway.
+      if (!FLAG_precompiled_mode) {
+        list_ = function.positional_parameter_names();
+        if (!list_.IsNull()) {
+          list_ = Dedup(list_);
+          function.set_positional_parameter_names(list_);
+        }
       }
     }
 
    private:
     bool IsCorrectType(const Object& obj) const { return obj.IsArray(); }
 
-    ArrayPtr PrepareParameterNames(const Function& function) {
-      list_ = function.parameter_names();
-      // Preserve parameter names in case of recompilation for the JIT. Also
-      // avoid attempting to change read-only VM objects for de-duplication.
-      if (FLAG_precompiled_mode && !list_.IsNull() &&
-          !list_.InVMIsolateHeap() && !function.HasOptionalNamedParameters()) {
-        // Parameter names not needed for resolution.
-        ASSERT(list_.Length() == function.NumParameters());
-        for (intptr_t i = 0; i < list_.Length(); i++) {
-          list_.SetAt(i, Symbols::OptimizedOut());
-        }
-      }
-      return list_.ptr();
-    }
-
-    bool MayBeEntryPoint(const Function& function) {
-      // Metadata has been dropped already.
-      // Use presence of pragma as conservative approximation.
-      if (function.has_pragma()) return true;
-      auto kind = function.kind();
-      if ((kind == UntaggedFunction::kImplicitGetter) ||
-          (kind == UntaggedFunction::kImplicitSetter) ||
-          (kind == UntaggedFunction::kImplicitStaticGetter) ||
-          (kind == UntaggedFunction::kFieldInitializer)) {
-        field_ = function.accessor_field();
-        if (!field_.IsNull() && field_.has_pragma()) return true;
-      }
-      return false;
-    }
-
     Array& list_;
     Field& field_;
   };
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 6101970..fbbce4c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -10,8 +10,6 @@
 #endif
 
 #include "platform/assert.h"
-#include "platform/atomic.h"
-#include "platform/thread_sanitizer.h"
 #include "vm/class_id.h"
 #include "vm/compiler/method_recognizer.h"
 #include "vm/compiler/runtime_api.h"
@@ -260,108 +258,6 @@
   class ReservedBits
       : public BitField<uword, intptr_t, kReservedTagPos, kReservedTagSize> {};
 
-  template <typename T>
-  class Tags {
-   public:
-    Tags() : tags_(0) {}
-
-    operator T() const { return tags_.load(std::memory_order_relaxed); }
-    T operator=(T tags) {
-      tags_.store(tags, std::memory_order_relaxed);
-      return tags;
-    }
-
-    T load(std::memory_order order) const { return tags_.load(order); }
-    void store(T value, std::memory_order order) { tags_.store(value, order); }
-
-    bool compare_exchange_weak(T old_tags,
-                               T new_tags,
-                               std::memory_order order) {
-      return tags_.compare_exchange_weak(old_tags, new_tags, order);
-    }
-
-    template <class TagBitField,
-              std::memory_order order = std::memory_order_relaxed>
-    typename TagBitField::Type Read() const {
-      return TagBitField::decode(tags_.load(order));
-    }
-
-    template <class TagBitField>
-    NO_SANITIZE_THREAD typename TagBitField::Type ReadIgnoreRace() const {
-      return TagBitField::decode(*reinterpret_cast<const T*>(&tags_));
-    }
-
-    template <class TagBitField,
-              std::memory_order order = std::memory_order_relaxed>
-    void UpdateBool(bool value) {
-      if (value) {
-        tags_.fetch_or(TagBitField::encode(true), order);
-      } else {
-        tags_.fetch_and(~TagBitField::encode(true), order);
-      }
-    }
-
-    template <class TagBitField>
-    void FetchOr(typename TagBitField::Type value) {
-      tags_.fetch_or(TagBitField::encode(value), std::memory_order_relaxed);
-    }
-
-    template <class TagBitField>
-    void Update(typename TagBitField::Type value) {
-      T old_tags = tags_.load(std::memory_order_relaxed);
-      T new_tags;
-      do {
-        new_tags = TagBitField::update(value, old_tags);
-      } while (!tags_.compare_exchange_weak(old_tags, new_tags,
-                                            std::memory_order_relaxed));
-    }
-
-    template <class TagBitField>
-    void UpdateUnsynchronized(typename TagBitField::Type value) {
-      tags_.store(
-          TagBitField::update(value, tags_.load(std::memory_order_relaxed)),
-          std::memory_order_relaxed);
-    }
-
-    template <class TagBitField>
-    typename TagBitField::Type UpdateConditional(
-        typename TagBitField::Type value_to_be_set,
-        typename TagBitField::Type conditional_old_value) {
-      T old_tags = tags_.load(std::memory_order_relaxed);
-      while (true) {
-        // This operation is only performed if the condition is met.
-        auto old_value = TagBitField::decode(old_tags);
-        if (old_value != conditional_old_value) {
-          return old_value;
-        }
-        T new_tags = TagBitField::update(value_to_be_set, old_tags);
-        if (tags_.compare_exchange_weak(old_tags, new_tags,
-                                        std::memory_order_relaxed)) {
-          return value_to_be_set;
-        }
-        // [old_tags] was updated to it's current value.
-      }
-    }
-
-    template <class TagBitField>
-    bool TryAcquire() {
-      T mask = TagBitField::encode(true);
-      T old_tags = tags_.fetch_or(mask, std::memory_order_relaxed);
-      return !TagBitField::decode(old_tags);
-    }
-
-    template <class TagBitField>
-    bool TryClear() {
-      T mask = ~TagBitField::encode(true);
-      T old_tags = tags_.fetch_and(mask, std::memory_order_relaxed);
-      return TagBitField::decode(old_tags);
-    }
-
-   private:
-    std::atomic<T> tags_;
-    COMPILE_ASSERT(sizeof(std::atomic<T>) == sizeof(T));
-  };
-
   // Assumes this is a heap object.
   bool IsNewObject() const {
     uword addr = reinterpret_cast<uword>(this);
@@ -602,7 +498,7 @@
   }
 
  private:
-  Tags<uword> tags_;  // Various object tags (bits).
+  AtomicBitFieldContainer<uword> tags_;  // Various object tags (bits).
 
   intptr_t VisitPointersPredefined(ObjectPointerVisitor* visitor,
                                    intptr_t class_id);
@@ -1360,8 +1256,7 @@
   VISIT_FROM(name)
   // Class or patch class or mixin class where this function is defined.
   COMPRESSED_POINTER_FIELD(ObjectPtr, owner)
-  COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_names)
-  COMPRESSED_POINTER_FIELD(FunctionTypePtr, signature)
+  WSR_COMPRESSED_POINTER_FIELD(FunctionTypePtr, signature)
   // Additional data specific to the function kind. See Function::set_data()
   // for details.
   COMPRESSED_POINTER_FIELD(ObjectPtr, data)
@@ -1384,52 +1279,21 @@
   COMPRESSED_POINTER_FIELD(ArrayPtr, ic_data_array);
   // Currently active code. Accessed from generated code.
   COMPRESSED_POINTER_FIELD(CodePtr, code);
-  // Unoptimized code, keep it after optimization.
-  NOT_IN_PRECOMPILED(COMPRESSED_POINTER_FIELD(CodePtr, unoptimized_code));
 #if defined(DART_PRECOMPILED_RUNTIME)
   VISIT_TO(code);
 #else
+  // Positional parameter names are not needed in the AOT runtime.
+  COMPRESSED_POINTER_FIELD(ArrayPtr, positional_parameter_names);
+  // Unoptimized code, keep it after optimization.
+  COMPRESSED_POINTER_FIELD(CodePtr, unoptimized_code);
   VISIT_TO(unoptimized_code);
+
+  UnboxedParameterBitmap unboxed_parameters_info_;
+  TokenPosition token_pos_;
+  TokenPosition end_token_pos_;
 #endif
 
-  NOT_IN_PRECOMPILED(UnboxedParameterBitmap unboxed_parameters_info_);
-  NOT_IN_PRECOMPILED(TokenPosition token_pos_);
-  NOT_IN_PRECOMPILED(TokenPosition end_token_pos_);
-  Tags<uint32_t> kind_tag_;  // See Function::KindTagBits.
-  Tags<uint32_t> packed_fields_;
-
-  // TODO(regis): Split packed_fields_ in 2 uint32_t if max values are too low.
-
-  static constexpr intptr_t kMaxOptimizableBits = 1;
-  static constexpr intptr_t kMaxTypeParametersBits = 7;
-  static constexpr intptr_t kMaxHasNamedOptionalParametersBits = 1;
-  static constexpr intptr_t kMaxFixedParametersBits = 10;
-  static constexpr intptr_t kMaxOptionalParametersBits = 10;
-
-  typedef BitField<uint32_t, bool, 0, kMaxOptimizableBits> PackedOptimizable;
-  typedef BitField<uint32_t,
-                   uint8_t,
-                   PackedOptimizable::kNextBit,
-                   kMaxTypeParametersBits>
-      PackedNumTypeParameters;
-  typedef BitField<uint32_t,
-                   bool,
-                   PackedNumTypeParameters::kNextBit,
-                   kMaxHasNamedOptionalParametersBits>
-      PackedHasNamedOptionalParameters;
-  typedef BitField<uint32_t,
-                   uint16_t,
-                   PackedHasNamedOptionalParameters::kNextBit,
-                   kMaxFixedParametersBits>
-      PackedNumFixedParameters;
-  typedef BitField<uint32_t,
-                   uint16_t,
-                   PackedNumFixedParameters::kNextBit,
-                   kMaxOptionalParametersBits>
-      PackedNumOptionalParameters;
-  static_assert(PackedNumOptionalParameters::kNextBit <=
-                    kBitsPerByte * sizeof(decltype(packed_fields_)),
-                "UntaggedFunction::packed_fields_ bitfields don't fit.");
+  AtomicBitFieldContainer<uint32_t> kind_tag_;  // See Function::KindTagBits.
 
 #define JIT_FUNCTION_COUNTERS(F)                                               \
   F(intptr_t, int32_t, usage_counter)                                          \
@@ -1448,7 +1312,12 @@
 
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
-  friend class UntaggedFunctionType;  // To use same constants for packing.
+  AtomicBitFieldContainer<uint8_t> packed_fields_;
+
+  static constexpr intptr_t kMaxOptimizableBits = 1;
+
+  using PackedOptimizable =
+      BitField<decltype(packed_fields_), bool, 0, kMaxOptimizableBits>;
 };
 
 class UntaggedClosureData : public UntaggedObject {
@@ -2469,7 +2338,7 @@
   }
   NOT_IN_PRECOMPILED(int32_t deopt_id_);
   // Number of arguments tested in IC, deopt reasons.
-  Tags<uint32_t> state_bits_;
+  AtomicBitFieldContainer<uint32_t> state_bits_;
 };
 
 class UntaggedMegamorphicCache : public UntaggedCallSiteData {
@@ -2682,49 +2551,43 @@
   COMPRESSED_POINTER_FIELD(TypeParametersPtr, type_parameters)
   COMPRESSED_POINTER_FIELD(AbstractTypePtr, result_type)
   COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_types)
-  COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_names);
+  COMPRESSED_POINTER_FIELD(ArrayPtr, named_parameter_names);
   COMPRESSED_POINTER_FIELD(SmiPtr, hash)
   VISIT_TO(hash)
-  uint32_t packed_fields_;  // Number of parent type args and own parameters.
+  AtomicBitFieldContainer<uint32_t> packed_parameter_counts_;
+  AtomicBitFieldContainer<uint16_t> packed_type_parameter_counts_;
   uint8_t type_state_;
   uint8_t nullability_;
 
-  static constexpr intptr_t kMaxParentTypeArgumentsBits = 8;
-  static constexpr intptr_t kMaxImplicitParametersBits = 1;
-  static constexpr intptr_t kMaxHasNamedOptionalParametersBits =
-      UntaggedFunction::kMaxHasNamedOptionalParametersBits;
-  static constexpr intptr_t kMaxFixedParametersBits =
-      UntaggedFunction::kMaxFixedParametersBits;
-  static constexpr intptr_t kMaxOptionalParametersBits =
-      UntaggedFunction::kMaxOptionalParametersBits;
-
   // The bit fields are public for use in kernel_to_il.cc.
  public:
-  typedef BitField<uint32_t, uint8_t, 0, kMaxParentTypeArgumentsBits>
-      PackedNumParentTypeArguments;
-  typedef BitField<uint32_t,
-                   uint8_t,
-                   PackedNumParentTypeArguments::kNextBit,
-                   kMaxImplicitParametersBits>
-      PackedNumImplicitParameters;
-  typedef BitField<uint32_t,
-                   bool,
-                   PackedNumImplicitParameters::kNextBit,
-                   kMaxHasNamedOptionalParametersBits>
-      PackedHasNamedOptionalParameters;
-  typedef BitField<uint32_t,
-                   uint16_t,
-                   PackedHasNamedOptionalParameters::kNextBit,
-                   kMaxFixedParametersBits>
-      PackedNumFixedParameters;
-  typedef BitField<uint32_t,
-                   uint16_t,
-                   PackedNumFixedParameters::kNextBit,
-                   kMaxOptionalParametersBits>
-      PackedNumOptionalParameters;
-  static_assert(PackedNumOptionalParameters::kNextBit <=
-                    kBitsPerByte * sizeof(decltype(packed_fields_)),
-                "UntaggedFunctionType::packed_fields_ bitfields don't fit.");
+  // For packed_type_parameter_counts_.
+  using PackedNumParentTypeArguments =
+      BitField<decltype(packed_type_parameter_counts_), uint8_t, 0, 8>;
+  using PackedNumTypeParameters =
+      BitField<decltype(packed_type_parameter_counts_),
+               uint8_t,
+               PackedNumParentTypeArguments::kNextBit,
+               8>;
+
+  // For packed_parameter_counts_.
+  using PackedNumImplicitParameters =
+      BitField<decltype(packed_parameter_counts_), uint8_t, 0, 1>;
+  using PackedHasNamedOptionalParameters =
+      BitField<decltype(packed_parameter_counts_),
+               bool,
+               PackedNumImplicitParameters::kNextBit,
+               1>;
+  using PackedNumFixedParameters =
+      BitField<decltype(packed_parameter_counts_),
+               uint16_t,
+               PackedHasNamedOptionalParameters::kNextBit,
+               14>;
+  using PackedNumOptionalParameters =
+      BitField<decltype(packed_parameter_counts_),
+               uint16_t,
+               PackedNumFixedParameters::kNextBit,
+               14>;
   static_assert(PackedNumOptionalParameters::kNextBit <=
                     compiler::target::kSmiBits,
                 "In-place mask for number of optional parameters cannot fit in "
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 90b297e..a1d4a89 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -28,7 +28,6 @@
   F(PatchClass, library_kernel_data_)                                          \
   F(Function, name_)                                                           \
   F(Function, owner_)                                                          \
-  F(Function, parameter_names_)                                                \
   F(Function, signature_)                                                      \
   F(Function, data_)                                                           \
   F(Function, ic_data_array_)                                                  \
@@ -137,7 +136,7 @@
   F(FunctionType, hash_)                                                       \
   F(FunctionType, result_type_)                                                \
   F(FunctionType, parameter_types_)                                            \
-  F(FunctionType, parameter_names_)                                            \
+  F(FunctionType, named_parameter_names_)                                      \
   F(FunctionType, type_parameters_)                                            \
   F(TypeRef, type_test_stub_)                                                  \
   F(TypeRef, type_)                                                            \
@@ -214,6 +213,7 @@
   F(Code, deopt_info_array_)                                                   \
   F(Code, static_calls_target_table_)                                          \
   F(ICData, receivers_static_type_)                                            \
+  F(Function, positional_parameter_names_)                                     \
   F(Function, unoptimized_code_)                                               \
   F(Field, type_test_cache_)
 
diff --git a/runtime/vm/regexp.cc b/runtime/vm/regexp.cc
index bceb4e7..a6ad932 100644
--- a/runtime/vm/regexp.cc
+++ b/runtime/vm/regexp.cc
@@ -5537,24 +5537,23 @@
 
   // TODO(zerny): Share these arrays between all irregexp functions.
   // TODO(regis): Better, share a common signature.
-  fn.set_num_fixed_parameters(kParamCount);
+  signature.set_num_fixed_parameters(kParamCount);
   signature.set_parameter_types(
       Array::Handle(zone, Array::New(kParamCount, Heap::kOld)));
-  signature.CreateNameArrayIncludingFlags(Heap::kOld);
+  fn.CreateNameArray();
   signature.SetParameterTypeAt(RegExpMacroAssembler::kParamRegExpIndex,
                                Object::dynamic_type());
-  signature.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
-                               Symbols::This());
+  fn.SetParameterNameAt(RegExpMacroAssembler::kParamRegExpIndex,
+                        Symbols::This());
   signature.SetParameterTypeAt(RegExpMacroAssembler::kParamStringIndex,
                                Object::dynamic_type());
-  signature.SetParameterNameAt(RegExpMacroAssembler::kParamStringIndex,
-                               Symbols::string_param());
+  fn.SetParameterNameAt(RegExpMacroAssembler::kParamStringIndex,
+                        Symbols::string_param());
   signature.SetParameterTypeAt(RegExpMacroAssembler::kParamStartOffsetIndex,
                                Object::dynamic_type());
-  signature.SetParameterNameAt(RegExpMacroAssembler::kParamStartOffsetIndex,
-                               Symbols::start_index_param());
+  fn.SetParameterNameAt(RegExpMacroAssembler::kParamStartOffsetIndex,
+                        Symbols::start_index_param());
   signature.set_result_type(Type::Handle(zone, Type::ArrayType()));
-  signature.FinalizeNameArrays(fn);
 
   // Cache the result.
   regexp.set_function(specialization_cid, sticky, fn);
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index 6593f3e..5c9776b 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -121,6 +121,21 @@
       zone, ResolveDynamicAnyArgsWithCustomLookup(
                 zone, receiver_class, function_name, allow_add, lookup));
 
+#if defined(DART_PRECOMPILED_RUNTIME)
+  if (!function.IsNull() && function.signature() == FunctionType::null()) {
+    // FfiTrampolines are the only functions that can still be called
+    // dynamically without going through a dynamic invocation forwarder.
+    RELEASE_ASSERT(!Function::IsDynamicInvocationForwarderName(function_name) &&
+                   !function.IsFfiTrampoline());
+    // The signature for this function was dropped in the precompiler, which
+    // means it is not a possible target for a dynamic call in the program.
+    // That means we're resolving an UnlinkedCall for an InstanceCall to
+    // a known interface. Since there's no overloading in Dart, the type checker
+    // has already checked the validity of the arguments at compile time.
+    return function.ptr();
+  }
+#endif
+
   if (function.IsNull() || !function.AreValidArguments(args_desc, NULL)) {
     // Return a null function to signal to the upper levels to dispatch to
     // "noSuchMethod" function.
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index c210052..2cd5a19 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -1613,6 +1613,7 @@
 enum class MissHandler {
   kInlineCacheMiss,
   kSwitchableCallMiss,
+  kFixCallersTargetMonomorphic,
 };
 
 // Handles updating of type feedback and possible patching of instance calls.
@@ -2094,7 +2095,8 @@
   // If we instead only insert a new ICData entry and will return to the IC stub
   // which will call the target, the stub will take care of the increment.
   const bool call_target_directly =
-      miss_handler_ == MissHandler::kInlineCacheMiss;
+      miss_handler_ == MissHandler::kInlineCacheMiss ||
+      miss_handler_ == MissHandler::kFixCallersTargetMonomorphic;
   const intptr_t invocation_count = call_target_directly ? 1 : 0;
 
   if (caller_arguments_.length() == 1) {
@@ -2132,12 +2134,21 @@
                                      const Function& target) {
   // In JIT we can have two different miss handlers to which we return slightly
   // differently.
-  if (miss_handler_ == MissHandler::kSwitchableCallMiss) {
-    arguments_.SetArgAt(0, stub);  // Second return value.
-    arguments_.SetReturn(data);
-  } else {
-    ASSERT(miss_handler_ == MissHandler::kInlineCacheMiss);
-    arguments_.SetReturn(target);
+  switch (miss_handler_) {
+    case MissHandler::kSwitchableCallMiss: {
+      arguments_.SetArgAt(0, stub);  // Second return value.
+      arguments_.SetReturn(data);
+      break;
+    }
+    case MissHandler::kFixCallersTargetMonomorphic: {
+      const auto& new_code = Code::Handle(zone_, target.EnsureHasCode());
+      arguments_.SetReturn(new_code);
+      break;
+    }
+    case MissHandler::kInlineCacheMiss: {
+      arguments_.SetReturn(target);
+      break;
+    }
   }
 }
 
@@ -2964,49 +2975,25 @@
 
 // The caller must be a monomorphic call from unoptimized code.
 // Patch call to point to new target.
-DEFINE_RUNTIME_ENTRY(FixCallersTargetMonomorphic, 0) {
+DEFINE_RUNTIME_ENTRY(FixCallersTargetMonomorphic, 2) {
 #if !defined(DART_PRECOMPILED_RUNTIME)
-  StackFrameIterator iterator(ValidationPolicy::kDontValidateFrames, thread,
-                              StackFrameIterator::kNoCrossThreadIteration);
-  StackFrame* frame = iterator.NextFrame();
-  ASSERT(frame != NULL);
-  while (frame->IsStubFrame() || frame->IsExitFrame()) {
-    frame = iterator.NextFrame();
-    ASSERT(frame != NULL);
-  }
-  if (frame->IsEntryFrame()) {
-    // Since function's current code is always unpatched, the entry frame always
-    // calls to unpatched code.
-    UNREACHABLE();
-  }
-  ASSERT(frame->IsDartFrame());
-  const Code& caller_code = Code::Handle(zone, frame->LookupDartCode());
-  RELEASE_ASSERT(!caller_code.is_optimized());
+  const Instance& receiver = Instance::CheckedHandle(zone, arguments.ArgAt(0));
+  const Array& switchable_call_data =
+      Array::CheckedHandle(zone, arguments.ArgAt(1));
 
-  Object& cache = Object::Handle(zone);
-  const Code& old_target_code = Code::Handle(
-      zone, CodePatcher::GetInstanceCallAt(frame->pc(), caller_code, &cache));
-  const Function& target_function =
-      Function::Handle(zone, old_target_code.function());
-  const Code& current_target_code =
-      Code::Handle(zone, target_function.EnsureHasCode());
-  CodePatcher::PatchInstanceCallAt(frame->pc(), caller_code, cache,
-                                   current_target_code);
-  if (FLAG_trace_patching) {
-    OS::PrintErr(
-        "FixCallersTargetMonomorphic: caller %#" Px
-        " "
-        "target '%s' -> %#" Px " (%s)\n",
-        frame->pc(), target_function.ToFullyQualifiedCString(),
-        current_target_code.EntryPoint(),
-        current_target_code.is_optimized() ? "optimized" : "unoptimized");
-  }
-  // With isolate groups enabled, it is possible that the target code
-  // has been deactivated just now(as a result of re-optimizatin for example),
-  // which will result in another run through FixCallersTarget.
-  ASSERT(!current_target_code.IsDisabled() ||
-         IsolateGroup::AreIsolateGroupsEnabled());
-  arguments.SetReturn(current_target_code);
+  DartFrameIterator iterator(thread,
+                             StackFrameIterator::kNoCrossThreadIteration);
+  StackFrame* caller_frame = iterator.NextFrame();
+  const auto& caller_code = Code::Handle(zone, caller_frame->LookupDartCode());
+  const auto& caller_function =
+      Function::Handle(zone, caller_frame->LookupDartFunction());
+
+  GrowableArray<const Instance*> caller_arguments(1);
+  caller_arguments.Add(&receiver);
+  PatchableCallHandler handler(
+      thread, caller_arguments, MissHandler::kFixCallersTargetMonomorphic,
+      arguments, caller_frame, caller_code, caller_function);
+  handler.ResolveSwitchAndReturn(switchable_call_data);
 #else
   UNREACHABLE();
 #endif
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 6cc2388..67501fb 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -193,6 +193,9 @@
 abstract class VMInternalsForTesting {
   // This function can be used by tests to enforce garbage collection.
   static void collectAllGarbage() native "Internal_collectAllGarbage";
+
+  static void deoptimizeFunctionsOnStack()
+      native "Internal_deoptimizeFunctionsOnStack";
 }
 
 @patch
diff --git a/tests/language/language_kernel.status b/tests/language/language_kernel.status
index a0fb2d7..acd118f 100644
--- a/tests/language/language_kernel.status
+++ b/tests/language/language_kernel.status
@@ -228,8 +228,8 @@
 unsorted/inference_enum_list_test: Skip # Issue 35885
 
 [ $compiler == dartk && $mode == product && $runtime == vm ]
-vm/causal_async_exception_stack2_test: SkipByDesign
-vm/causal_async_exception_stack_test: SkipByDesign
+vm/lazy_async_exception_stack2_test: SkipByDesign
+vm/lazy_async_exception_stack_test: SkipByDesign
 
 # ===== dartk + vm status lines =====
 [ $compiler == dartk && $runtime == vm ]
@@ -277,9 +277,9 @@
 optimize/deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
 unsorted/hello_dart_test: Skip # Incompatible flag: --compile_all
 unsorted/invocation_mirror2_test: SkipByDesign
-vm/causal_async_exception_stack2_test: SkipByDesign
-vm/causal_async_exception_stack_test: SkipByDesign
 vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
+vm/lazy_async_exception_stack2_test: SkipByDesign
+vm/lazy_async_exception_stack_test: SkipByDesign
 vm/reflect_core_vm_test: SkipByDesign
 vm/regress_27671_test: Skip # Unsupported
 vm/regress_29145_test: Skip # Issue 29145
diff --git a/tests/language/vm/causal_async_exception_stack2_test.dart b/tests/language/vm/lazy_async_exception_stack2_test.dart
similarity index 95%
rename from tests/language/vm/causal_async_exception_stack2_test.dart
rename to tests/language/vm/lazy_async_exception_stack2_test.dart
index e3ddda0..bd9b8d5 100644
--- a/tests/language/vm/causal_async_exception_stack2_test.dart
+++ b/tests/language/vm/lazy_async_exception_stack2_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_minitest.dart';
 
-import 'causal_async_exception_stack_helper.dart' as h;
+import 'lazy_async_exception_stack_helper.dart' as h;
 
 foo3() async => throw "foo";
 bar3() async => throw "bar";
@@ -93,7 +93,7 @@
 }
 
 main() async {
-  test('causal async exception stack', () async {
+  test('lazy async exception stack', () async {
     await test1();
     await test2();
   });
diff --git a/tests/language/vm/causal_async_exception_stack_helper.dart b/tests/language/vm/lazy_async_exception_stack_helper.dart
similarity index 100%
rename from tests/language/vm/causal_async_exception_stack_helper.dart
rename to tests/language/vm/lazy_async_exception_stack_helper.dart
diff --git a/tests/language/vm/causal_async_exception_stack_test.dart b/tests/language/vm/lazy_async_exception_stack_test.dart
similarity index 94%
rename from tests/language/vm/causal_async_exception_stack_test.dart
rename to tests/language/vm/lazy_async_exception_stack_test.dart
index e9df0a7..9b9705e 100644
--- a/tests/language/vm/causal_async_exception_stack_test.dart
+++ b/tests/language/vm/lazy_async_exception_stack_test.dart
@@ -6,7 +6,7 @@
 
 import 'package:async_helper/async_minitest.dart';
 
-import 'causal_async_exception_stack_helper.dart' as h;
+import 'lazy_async_exception_stack_helper.dart' as h;
 
 thrower() async {
   throw 'oops';
@@ -29,7 +29,7 @@
 
 main() async {
   // Test async and async*.
-  test('causal async exception stack', () async {
+  test('lazy async exception stack', () async {
     try {
       await foo();
       fail("Did not throw");
diff --git a/tests/language/vm/symbols_test.dart b/tests/language/vm/symbols_test.dart
index a68e2f4..d605a3a 100644
--- a/tests/language/vm/symbols_test.dart
+++ b/tests/language/vm/symbols_test.dart
@@ -5,15 +5,15 @@
 import 'package:expect/expect.dart';
 
 void main() {
-  print(const Symbol(null));                                //# 01: compile-time error
-  print(const Symbol(r''));                                 //# 02: ok
-  Expect.isTrue(identical(const Symbol(r'foo'), #foo));     //# 03: ok
-  Expect.isTrue(identical(const Symbol(r'$foo'), #$foo));   //# 03: ok
-  Expect.isTrue(identical(const Symbol(r'$_'), #$_));       //# 03: ok
-  Expect.isTrue(identical(const Symbol(r'+'), #+));         //# 03: ok
-  Expect.isTrue(identical(const Symbol(r'[]='), #[]=));     //# 03: ok
-  Expect.isTrue(identical(const Symbol(r'_foo'), #_foo));   //# 03: compile-time error
-  Expect.isTrue(identical(const Symbol(r'_$'), #_$));       //# 03: compile-time error
-  Expect.isTrue(identical(const Symbol(r'_foo$'), #_foo$)); //# 03: compile-time error
-  print(const Symbol(r'_+'));                               //# 03: compile-time error
+  print(const Symbol(null)); //# 01: compile-time error
+  print(const Symbol(r''));
+  Expect.isTrue(identical(const Symbol(r'foo'), #foo));
+  Expect.isTrue(identical(const Symbol(r'$foo'), #$foo));
+  Expect.isTrue(identical(const Symbol(r'$_'), #$_));
+  Expect.isTrue(identical(const Symbol(r'+'), #+));
+  Expect.isTrue(identical(const Symbol(r'[]='), #[]=));
+  Expect.isFalse(identical(const Symbol(r'_foo'), #_foo));
+  Expect.isFalse(identical(const Symbol(r'_$'), #_$));
+  Expect.isFalse(identical(const Symbol(r'_foo$'), #_foo$));
+  print(const Symbol(r'_+'));
 }
diff --git a/tests/language_2/language_2_kernel.status b/tests/language_2/language_2_kernel.status
index 9b5f403..1db04b4 100644
--- a/tests/language_2/language_2_kernel.status
+++ b/tests/language_2/language_2_kernel.status
@@ -48,8 +48,8 @@
 unsorted/inference_enum_list_test: Skip # Issue 35885
 
 [ $compiler == dartk && $mode == product && $runtime == vm ]
-vm/causal_async_exception_stack2_test: SkipByDesign
-vm/causal_async_exception_stack_test: SkipByDesign
+vm/lazy_async_exception_stack2_test: SkipByDesign
+vm/lazy_async_exception_stack_test: SkipByDesign
 
 # ===== dartk + vm status lines =====
 [ $compiler == dartk && $runtime == vm ]
@@ -91,9 +91,9 @@
 optimize/deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
 unsorted/hello_dart_test: Skip # Incompatible flag: --compile_all
 unsorted/invocation_mirror2_test: SkipByDesign
-vm/causal_async_exception_stack2_test: SkipByDesign
-vm/causal_async_exception_stack_test: SkipByDesign
 vm/closure_memory_retention_test: Skip # KernelVM bug: Hits OOM
+vm/lazy_async_exception_stack2_test: SkipByDesign
+vm/lazy_async_exception_stack_test: SkipByDesign
 vm/reflect_core_vm_test: SkipByDesign
 vm/regress_27671_test: Skip # Unsupported
 vm/regress_29145_test: Skip # Issue 29145
@@ -118,4 +118,4 @@
 optimize/deopt_inlined_function_lazy_test: Skip
 
 [ $mode == debug && ($hot_reload || $hot_reload_rollback) ]
-regress/regress41983_test: Pass, Slow
\ No newline at end of file
+regress/regress41983_test: Pass, Slow
diff --git a/tests/language_2/vm/causal_async_exception_stack2_test.dart b/tests/language_2/vm/lazy_async_exception_stack2_test.dart
similarity index 95%
rename from tests/language_2/vm/causal_async_exception_stack2_test.dart
rename to tests/language_2/vm/lazy_async_exception_stack2_test.dart
index 6e21580..81df6ce 100644
--- a/tests/language_2/vm/causal_async_exception_stack2_test.dart
+++ b/tests/language_2/vm/lazy_async_exception_stack2_test.dart
@@ -8,7 +8,7 @@
 
 import 'package:async_helper/async_minitest.dart';
 
-import 'causal_async_exception_stack_helper.dart' as h;
+import 'lazy_async_exception_stack_helper.dart' as h;
 
 foo3() async => throw "foo";
 bar3() async => throw "bar";
@@ -95,7 +95,7 @@
 }
 
 main() async {
-  test('causal async exception stack', () async {
+  test('lazy async exception stack', () async {
     await test1();
     await test2();
   });
diff --git a/tests/language_2/vm/causal_async_exception_stack_helper.dart b/tests/language_2/vm/lazy_async_exception_stack_helper.dart
similarity index 100%
rename from tests/language_2/vm/causal_async_exception_stack_helper.dart
rename to tests/language_2/vm/lazy_async_exception_stack_helper.dart
diff --git a/tests/language_2/vm/causal_async_exception_stack_test.dart b/tests/language_2/vm/lazy_async_exception_stack_test.dart
similarity index 94%
rename from tests/language_2/vm/causal_async_exception_stack_test.dart
rename to tests/language_2/vm/lazy_async_exception_stack_test.dart
index 8afe38f..46ee9ff 100644
--- a/tests/language_2/vm/causal_async_exception_stack_test.dart
+++ b/tests/language_2/vm/lazy_async_exception_stack_test.dart
@@ -8,7 +8,7 @@
 
 import 'package:async_helper/async_minitest.dart';
 
-import 'causal_async_exception_stack_helper.dart' as h;
+import 'lazy_async_exception_stack_helper.dart' as h;
 
 thrower() async {
   throw 'oops';
@@ -31,7 +31,7 @@
 
 main() async {
   // Test async and async*.
-  test('causal async exception stack', () async {
+  test('lazy async exception stack', () async {
     try {
       await foo();
       fail("Did not throw");
diff --git a/tests/standalone/causal_async_stack_test.dart b/tests/standalone/lazy_async_stack_test.dart
similarity index 100%
rename from tests/standalone/causal_async_stack_test.dart
rename to tests/standalone/lazy_async_stack_test.dart
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index f2d93f5..9f62999 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -41,7 +41,7 @@
 deferred_transitive_import_error_test: Skip
 
 [ $compiler == dartkp ]
-causal_async_stack_test: Skip # Flaky.
+lazy_async_stack_test: Skip # Flaky.
 
 [ $mode == product ]
 io/stdio_implicit_close_test: Skip # SkipByDesign
diff --git a/tests/standalone_2/causal_async_stack_test.dart b/tests/standalone_2/lazy_async_stack_test.dart
similarity index 100%
rename from tests/standalone_2/causal_async_stack_test.dart
rename to tests/standalone_2/lazy_async_stack_test.dart
diff --git a/tests/standalone_2/standalone_2.status b/tests/standalone_2/standalone_2.status
index becc448..6a27a9c 100644
--- a/tests/standalone_2/standalone_2.status
+++ b/tests/standalone_2/standalone_2.status
@@ -41,7 +41,7 @@
 deferred_transitive_import_error_test: Skip
 
 [ $compiler == dartkp ]
-causal_async_stack_test: Skip # Flaky.
+lazy_async_stack_test: Skip # Flaky.
 
 [ $mode == product ]
 io/stdio_implicit_close_test: Skip # SkipByDesign
diff --git a/tools/VERSION b/tools/VERSION
index d1e510e..7d1712c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 271
+PRERELEASE 272
 PRERELEASE_PATCH 0
\ No newline at end of file