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, ¬_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