Version 2.13.0-41.0.dev
Merge commit '4302f058dd6a4a54b602e9a5a4db0bc5cedd578e' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 02af79d..87231e2 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -116,9 +116,12 @@
server.clientCapabilities?.workspace,
edits
.map((e) => FileEditInformation(
- server.getVersionedDocumentIdentifier(e.file),
- server.getLineInfo(e.file),
- e.edits))
+ server.getVersionedDocumentIdentifier(e.file),
+ server.getLineInfo(e.file),
+ e.edits,
+ // fileStamp == 1 is used by the server to indicate the file needs creating.
+ newFile: e.fileStamp == -1,
+ ))
.toList());
}
@@ -1253,14 +1256,36 @@
final clientSupportsTextDocumentEdits =
capabilities?.workspaceEdit?.documentChanges == true;
if (clientSupportsTextDocumentEdits) {
+ final clientSupportsCreate = capabilities?.workspaceEdit?.resourceOperations
+ ?.contains(ResourceOperationKind.Create) ??
+ false;
+ final changes = <
+ Either4<lsp.TextDocumentEdit, lsp.CreateFile, lsp.RenameFile,
+ lsp.DeleteFile>>[];
+
+ // Convert each SourceEdit to either a TextDocumentEdit or a
+ // CreateFile + a TextDocumentEdit depending on whether it's a new
+ // file.
+ for (final edit in edits) {
+ if (clientSupportsCreate && edit.newFile) {
+ final create = lsp.CreateFile(uri: edit.doc.uri);
+ final createUnion = Either4<lsp.TextDocumentEdit, lsp.CreateFile,
+ lsp.RenameFile, lsp.DeleteFile>.t2(create);
+ changes.add(createUnion);
+ }
+
+ final textDocEdit = toTextDocumentEdit(edit);
+ final textDocEditUnion = Either4<lsp.TextDocumentEdit, lsp.CreateFile,
+ lsp.RenameFile, lsp.DeleteFile>.t1(textDocEdit);
+ changes.add(textDocEditUnion);
+ }
+
return lsp.WorkspaceEdit(
documentChanges: Either2<
List<lsp.TextDocumentEdit>,
List<
Either4<lsp.TextDocumentEdit, lsp.CreateFile, lsp.RenameFile,
- lsp.DeleteFile>>>.t1(
- edits.map(toTextDocumentEdit).toList(),
- ));
+ lsp.DeleteFile>>>.t2(changes));
} else {
return lsp.WorkspaceEdit(changes: toWorkspaceEditChanges(edits));
}
diff --git a/pkg/analysis_server/lib/src/lsp/source_edits.dart b/pkg/analysis_server/lib/src/lsp/source_edits.dart
index 0307417..e1cc013 100644
--- a/pkg/analysis_server/lib/src/lsp/source_edits.dart
+++ b/pkg/analysis_server/lib/src/lsp/source_edits.dart
@@ -305,6 +305,8 @@
final OptionalVersionedTextDocumentIdentifier doc;
final LineInfo lineInfo;
final List<server.SourceEdit> edits;
+ final bool newFile;
- FileEditInformation(this.doc, this.lineInfo, this.edits);
+ FileEditInformation(this.doc, this.lineInfo, this.edits,
+ {this.newFile = false});
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c2753fe..cb7e610 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -161,8 +161,6 @@
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/parser.dart';
-import 'package:analyzer_plugin/protocol/protocol_common.dart'
- hide AnalysisError, Element, ElementKind;
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
import 'package:analyzer_plugin/utilities/change_builder/conflicting_edit_exception.dart';
@@ -182,96 +180,13 @@
try {
var processor = FixProcessor(context);
var fixes = await processor.compute();
- var fixAllFixes = await _computeFixAllFixes(context, fixes);
- return List.from(fixes)..addAll(fixAllFixes);
+ // todo (pq): add fixes from FixInFileProcessor
+ // https://github.com/dart-lang/sdk/issues/45026
+ return fixes;
} on CancelCorrectionException {
return const <Fix>[];
}
}
-
- Future<List<Fix>> _computeFixAllFixes(
- DartFixContext context, List<Fix> fixes) async {
- final analysisError = context.error;
- final allAnalysisErrors = context.resolveResult.errors.toList();
-
- // Validate inputs:
- // - return if no fixes
- // - return if no other analysis errors
- if (fixes.isEmpty || allAnalysisErrors.length < 2) {
- return const <Fix>[];
- }
-
- // Remove any analysis errors that don't have the expected error code name
- allAnalysisErrors
- .removeWhere((e) => analysisError.errorCode.name != e.errorCode.name);
- if (allAnalysisErrors.length < 2) {
- return const <Fix>[];
- }
-
- // A map between each FixKind and the List of associated fixes
- var map = <FixKind, List<Fix>>{};
-
- // Populate the HashMap by looping through all AnalysisErrors, creating a
- // new FixProcessor to compute the other fixes that can be applied with this
- // one.
- // For each fix, put the fix into the HashMap.
- for (var i = 0; i < allAnalysisErrors.length; i++) {
- final FixContext fixContext = DartFixContextImpl(
- context.instrumentationService,
- context.workspace,
- context.resolveResult,
- allAnalysisErrors[i],
- (name) => [],
- );
- var processorI = FixProcessor(fixContext);
- var fixesListI = await processorI.compute();
- for (var f in fixesListI) {
- if (!map.containsKey(f.kind)) {
- map[f.kind] = <Fix>[]..add(f);
- } else {
- map[f.kind].add(f);
- }
- }
- }
-
- // For each FixKind in the HashMap, union each list together, then return
- // the set of unioned fixes.
- var result = <Fix>[];
- map.forEach((FixKind kind, List<Fix> fixesList) {
- if (fixesList.first.kind.canBeAppliedTogether()) {
- var unionFix = _unionFixList(fixesList);
- if (unionFix != null) {
- result.add(unionFix);
- }
- }
- });
- return result;
- }
-
- Fix _unionFixList(List<Fix> fixList) {
- if (fixList == null || fixList.isEmpty) {
- return null;
- } else if (fixList.length == 1) {
- return fixList[0];
- }
- var sourceChange = SourceChange(fixList[0].kind.appliedTogetherMessage);
- sourceChange.edits = List.from(fixList[0].change.edits);
- var edits = <SourceEdit>[];
- edits.addAll(fixList[0].change.edits[0].edits);
- sourceChange.linkedEditGroups =
- List.from(fixList[0].change.linkedEditGroups);
- for (var i = 1; i < fixList.length; i++) {
- edits.addAll(fixList[i].change.edits[0].edits);
- sourceChange.linkedEditGroups.addAll(fixList[i].change.linkedEditGroups);
- }
- // Sort the list of SourceEdits so that when the edits are applied, they
- // are applied from the end of the file to the top of the file.
- edits.sort((s1, s2) => s2.offset - s1.offset);
-
- sourceChange.edits[0].edits = edits;
-
- return Fix(fixList[0].kind, sourceChange);
- }
}
/// Computer for Dart "fix all in file" fixes.
diff --git a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
index a0c3f5b..eadaf30 100644
--- a/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
+++ b/pkg/analysis_server/test/lsp/code_actions_fixes_test.dart
@@ -4,6 +4,7 @@
import 'package:analysis_server/lsp_protocol/protocol_generated.dart';
import 'package:linter/src/rules.dart';
+import 'package:path/path.dart' as path;
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -96,6 +97,38 @@
expect(contents[mainFilePath], equals(expectedContent));
}
+ Future<void> test_createFile() async {
+ const content = '''
+ import '[[newfile.dart]]';
+ ''';
+
+ final expectedCreatedFile =
+ path.join(path.dirname(mainFilePath), 'newfile.dart');
+
+ newFile(mainFilePath, content: withoutMarkers(content));
+ await initialize(
+ textDocumentCapabilities: withCodeActionKinds(
+ emptyTextDocumentClientCapabilities, [CodeActionKind.QuickFix]),
+ workspaceCapabilities: withResourceOperationKinds(
+ emptyWorkspaceClientCapabilities, [ResourceOperationKind.Create]),
+ );
+
+ final codeActions = await getCodeActions(mainFileUri.toString(),
+ range: rangeFromMarkers(content));
+ final fixAction = findEditAction(codeActions,
+ CodeActionKind('quickfix.create.file'), "Create file 'newfile.dart'");
+
+ expect(fixAction, isNotNull);
+ expect(fixAction.edit.documentChanges, isNotNull);
+
+ // Ensure applying the changes creates the file and with the expected content.
+ final contents = {
+ mainFilePath: withoutMarkers(content),
+ };
+ applyDocumentChanges(contents, fixAction.edit.documentChanges);
+ expect(contents[expectedCreatedFile], isNotEmpty);
+ }
+
Future<void> test_filtersCorrectly() async {
const content = '''
import 'dart:async';
@@ -239,8 +272,6 @@
@override
String get testPackageLanguageVersion => latestLanguageVersion;
- /// todo (pq): prefer_is_empty newly produces fix-all-fixes; update this test appropriately
- @failingTest
Future<void> test_fixAll_notForAmbigiousProducers() async {
// The ReplaceWithIsEmpty producer does not provide a FixKind up-front, as
// it may produce `REPLACE_WITH_IS_EMPTY` or `REPLACE_WITH_IS_NOT_EMPTY`
diff --git a/pkg/analysis_server/test/lsp/server_abstract.dart b/pkg/analysis_server/test/lsp/server_abstract.dart
index ce6fb8b..f9d072c 100644
--- a/pkg/analysis_server/test/lsp/server_abstract.dart
+++ b/pkg/analysis_server/test/lsp/server_abstract.dart
@@ -403,6 +403,19 @@
});
}
+ ClientCapabilitiesWorkspace withResourceOperationKinds(
+ ClientCapabilitiesWorkspace source,
+ List<ResourceOperationKind> kinds,
+ ) {
+ return extendWorkspaceCapabilities(source, {
+ 'workspaceEdit': {
+ 'documentChanges':
+ true, // docChanges aren't included in resourceOperations
+ 'resourceOperations': kinds.map((k) => k.toJson()).toList(),
+ }
+ });
+ }
+
TextDocumentClientCapabilities withSignatureHelpContentFormat(
TextDocumentClientCapabilities source,
List<MarkupKind> formats,
@@ -572,8 +585,23 @@
Map<String, String> oldFileContent,
List<Either4<TextDocumentEdit, CreateFile, RenameFile, DeleteFile>> changes,
) {
- // TODO(dantup): Implement handling of resource changes (not currently used).
- throw 'Test helper applyResourceChanges not currently supported';
+ for (final change in changes) {
+ change.map(
+ (textDocEdit) => applyTextDocumentEdits(oldFileContent, [textDocEdit]),
+ (create) => applyResourceCreate(oldFileContent, create),
+ (rename) => throw 'applyResourceChanges:Delete not currently supported',
+ (delete) => throw 'applyResourceChanges:Delete not currently supported',
+ );
+ }
+ }
+
+ void applyResourceCreate(
+ Map<String, String> oldFileContent, CreateFile create) {
+ final path = Uri.parse(create.uri).toFilePath();
+ if (oldFileContent.containsKey(path)) {
+ throw 'Recieved create instruction for $path which already existed.';
+ }
+ oldFileContent[path] = '';
}
String applyTextDocumentEdit(String content, TextDocumentEdit edit) {
@@ -585,7 +613,8 @@
edits.forEach((edit) {
final path = Uri.parse(edit.textDocument.uri).toFilePath();
if (!oldFileContent.containsKey(path)) {
- throw 'Recieved edits for $path which was not provided as a file to be edited';
+ throw 'Recieved edits for $path which was not provided as a file to be edited. '
+ 'Perhaps a CreateFile change was missing from the edits?';
}
oldFileContent[path] = applyTextDocumentEdit(oldFileContent[path], edit);
});
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_explicit_cast_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_explicit_cast_test.dart
index ebf1233..797f097 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_explicit_cast_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_explicit_cast_test.dart
@@ -56,6 +56,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_general_all() async {
await resolveTestCode('''
f(A a) {
@@ -98,6 +99,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_list_all() async {
await resolveTestCode('''
f(List<A> a) {
@@ -140,6 +142,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_map_all() async {
await resolveTestCode('''
f(Map<A, B> a) {
@@ -186,6 +189,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_needsParens_all() async {
await resolveTestCode('''
f(A a) {
@@ -232,6 +236,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_set_all() async {
await resolveTestCode('''
f(Set<A> a) {
@@ -284,6 +289,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_declaration_general_all() async {
await resolveTestCode('''
f(A a) {
@@ -322,6 +328,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_declaration_list_all() async {
await resolveTestCode('''
f(List<A> a) {
@@ -360,6 +367,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_declaration_map_all() async {
await resolveTestCode('''
f(Map<A, B> a) {
@@ -402,6 +410,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_declaration_needsParens_all() async {
await resolveTestCode('''
f(A a) {
@@ -444,6 +453,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_declaration_set_all() async {
await resolveTestCode('''
f(Set<A> a) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
index 95302e6..c7b5820 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_ne_null_test.dart
@@ -37,6 +37,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_nonBoolCondition_all() async {
await resolveTestCode('''
main(String p, String q) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_cast_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_cast_test.dart
index 09cfd74..14c84b6 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_cast_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_cast_test.dart
@@ -39,6 +39,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_assignment_all() async {
await resolveTestCode('''
main(Object p, Object q) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
index 88b7f30..c8c9629 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unnecessary_parentheses_test.dart
@@ -23,6 +23,7 @@
@override
String get lintCode => LintNames.unnecessary_parenthesis;
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_all() async {
await resolveTestCode('''
void f() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
index 3fb232f..6a9cc3e 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_unused_import_test.dart
@@ -27,6 +27,7 @@
useLineEndingsForPlatform = false;
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_all_diverseImports() async {
await resolveTestCode('''
import 'dart:math';
@@ -41,6 +42,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_all_diverseImports2() async {
await resolveTestCode('''
import 'dart:async';
@@ -62,6 +64,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_all_singleLine() async {
await resolveTestCode('''
import 'dart:math'; import 'dart:math'; import 'dart:math';
@@ -111,6 +114,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_multipleOfSame_all() async {
await resolveTestCode('''
import 'dart:math';
diff --git a/pkg/analysis_server/test/src/services/correction/fix/replace_boolean_with_bool_test.dart b/pkg/analysis_server/test/src/services/correction/fix/replace_boolean_with_bool_test.dart
index 1e38a6f..0fa2fd0 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/replace_boolean_with_bool_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/replace_boolean_with_bool_test.dart
@@ -20,6 +20,7 @@
@override
FixKind get kind => DartFixKind.REPLACE_BOOLEAN_WITH_BOOL;
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_all() async {
await resolveTestCode('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_eq_eq_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_eq_eq_null_test.dart
index 89ecb3f..9a6d0ed 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_eq_eq_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_eq_eq_null_test.dart
@@ -33,6 +33,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_isNull_all() async {
await resolveTestCode('''
main(p, q) {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/use_not_eq_null_test.dart b/pkg/analysis_server/test/src/services/correction/fix/use_not_eq_null_test.dart
index a22c3f8..bf7e9db 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/use_not_eq_null_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/use_not_eq_null_test.dart
@@ -33,6 +33,7 @@
''');
}
+ @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/45026')
Future<void> test_isNotNull_all() async {
await resolveTestCode('''
main(p, q) {
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 550c6e1..4a7f62a 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -579,9 +579,7 @@
return CompilerResult(0);
}
-// Compute code size to embed in the generated JavaScript
-// for this module. Return `null` to indicate when size could not be properly
-// computed for this module.
+/// Compute code size to embed in the generated JavaScript for this module.
int _computeDartSize(Component component) {
var dartSize = 0;
var uriToSource = component.uriToSource;
@@ -589,7 +587,11 @@
var libUri = lib.fileUri;
var importUri = lib.importUri;
var source = uriToSource[libUri];
- if (source == null) return null;
+ if (source == null) {
+ // Sources that only contain external declarations have nothing to add to
+ // the sum.
+ continue;
+ }
dartSize += source.source.length;
for (var part in lib.parts) {
var partUri = part.partUri;
@@ -599,7 +601,11 @@
}
var fileUri = libUri.resolve(partUri);
var partSource = uriToSource[fileUri];
- if (partSource == null) return null;
+ if (partSource == null) {
+ // Sources that only contain external declarations have nothing to add
+ // to the sum.
+ continue;
+ }
dartSize += partSource.source.length;
}
}
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index aa9a2c4..d2de37c 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -145,18 +145,30 @@
private:
void VisitPointers(ObjectPtr* from, ObjectPtr* to) {
- for (ObjectPtr* raw = from; raw <= to; raw++) {
- if (!(*raw)->IsHeapObject() || (*raw)->untag()->IsCanonical()) {
- continue;
- }
- if (visited_->GetValueExclusive(*raw) == 1) {
- continue;
- }
- visited_->SetValueExclusive(*raw, 1);
- working_set_->Add(*raw);
+ for (ObjectPtr* ptr = from; ptr <= to; ptr++) {
+ VisitObject(*ptr);
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ for (CompressedObjectPtr* ptr = from; ptr <= to; ptr++) {
+ VisitObject(ptr->Decompress(heap_base));
+ }
+ }
+
+ void VisitObject(ObjectPtr obj) {
+ if (!obj->IsHeapObject() || obj->untag()->IsCanonical()) {
+ return;
+ }
+ if (visited_->GetValueExclusive(obj) == 1) {
+ return;
+ }
+ visited_->SetValueExclusive(obj, 1);
+ working_set_->Add(obj);
+ }
+
WeakTable* visited_;
MallocGrowableArray<ObjectPtr>* const working_set_;
};
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 2c1ebd4..22ded31 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -962,7 +962,7 @@
precompiler_(precompiler),
subinstance_(Object::Handle()) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* current = first; current <= last; current++) {
subinstance_ = *current;
if (subinstance_.IsInstance()) {
@@ -972,6 +972,18 @@
subinstance_ = Object::null();
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ subinstance_ = current->Decompress(heap_base);
+ if (subinstance_.IsInstance()) {
+ precompiler_->AddConstObject(Instance::Cast(subinstance_));
+ }
+ }
+ subinstance_ = Object::null();
+ }
+
private:
Precompiler* precompiler_;
Object& subinstance_;
diff --git a/runtime/vm/gdb_helpers.cc b/runtime/vm/gdb_helpers.cc
index 61baa78..0dfa825 100644
--- a/runtime/vm/gdb_helpers.cc
+++ b/runtime/vm/gdb_helpers.cc
@@ -64,6 +64,15 @@
OS::PrintErr("%p: %s\n", p, obj.ToCString());
}
}
+
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* p = first; p <= last; p++) {
+ Object& obj = Object::Handle(p->Decompress(heap_base));
+ OS::PrintErr("%p: %s\n", p, obj.ToCString());
+ }
+ }
};
DART_EXPORT
diff --git a/runtime/vm/heap/become.cc b/runtime/vm/heap/become.cc
index ea959e1..e51678a 100644
--- a/runtime/vm/heap/become.cc
+++ b/runtime/vm/heap/become.cc
@@ -83,7 +83,7 @@
thread_(thread),
visiting_object_(nullptr) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* p = first; p <= last; p++) {
ObjectPtr old_target = *p;
ObjectPtr new_target;
@@ -107,6 +107,32 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* p = first; p <= last; p++) {
+ ObjectPtr old_target = p->Decompress(heap_base);
+ ObjectPtr new_target;
+ if (IsForwardingObject(old_target)) {
+ new_target = GetForwardedObject(old_target);
+ } else {
+ // Though we do not need to update the slot's value when it is not
+ // forwarded, we do need to recheck the generational barrier. In
+ // particular, the remembered bit may be incorrectly false if this
+ // become was the result of aborting a scavenge while visiting the
+ // remembered set.
+ new_target = old_target;
+ }
+ if (visiting_object_ == nullptr) {
+ *p = new_target;
+ } else if (visiting_object_->untag()->IsCardRemembered()) {
+ visiting_object_->untag()->StoreArrayPointer(p, new_target, thread_);
+ } else {
+ visiting_object_->untag()->StorePointer(p, new_target, thread_);
+ }
+ }
+ }
+
void VisitingObject(ObjectPtr obj) {
visiting_object_ = obj;
// The incoming remembered bit may be unreliable. Clear it so we can
diff --git a/runtime/vm/heap/compactor.cc b/runtime/vm/heap/compactor.cc
index 5a432f7..7006f3e 100644
--- a/runtime/vm/heap/compactor.cc
+++ b/runtime/vm/heap/compactor.cc
@@ -631,6 +631,42 @@
*ptr = new_target;
}
+DART_FORCE_INLINE
+void GCCompactor::ForwardCompressedPointer(uword heap_base,
+ CompressedObjectPtr* ptr) {
+ ObjectPtr old_target = ptr->Decompress(heap_base);
+ if (old_target->IsSmiOrNewObject()) {
+ return; // Not moved.
+ }
+
+ uword old_addr = UntaggedObject::ToAddr(old_target);
+ intptr_t lo = 0;
+ intptr_t hi = image_page_hi_;
+ while (lo <= hi) {
+ intptr_t mid = (hi - lo + 1) / 2 + lo;
+ ASSERT(mid >= lo);
+ ASSERT(mid <= hi);
+ if (old_addr < image_page_ranges_[mid].start) {
+ hi = mid - 1;
+ } else if (old_addr >= image_page_ranges_[mid].end) {
+ lo = mid + 1;
+ } else {
+ return; // Not moved (unaligned image page).
+ }
+ }
+
+ OldPage* page = OldPage::Of(old_target);
+ ForwardingPage* forwarding_page = page->forwarding_page();
+ if (forwarding_page == NULL) {
+ return; // Not moved (VM isolate, large page, code page).
+ }
+
+ ObjectPtr new_target =
+ UntaggedObject::FromAddr(forwarding_page->Lookup(old_addr));
+ ASSERT(!new_target->IsSmiOrNewObject());
+ *ptr = new_target;
+}
+
void GCCompactor::VisitTypedDataViewPointers(TypedDataViewPtr view,
ObjectPtr* first,
ObjectPtr* last) {
@@ -673,6 +709,14 @@
}
}
+void GCCompactor::VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* ptr = first; ptr <= last; ptr++) {
+ ForwardCompressedPointer(heap_base, ptr);
+ }
+}
+
void GCCompactor::VisitHandle(uword addr) {
FinalizablePersistentHandle* handle =
reinterpret_cast<FinalizablePersistentHandle*>(addr);
diff --git a/runtime/vm/heap/compactor.h b/runtime/vm/heap/compactor.h
index 4ba033b..9dfa96d 100644
--- a/runtime/vm/heap/compactor.h
+++ b/runtime/vm/heap/compactor.h
@@ -38,10 +38,14 @@
void SetupImagePageBoundaries();
void ForwardStackPointers();
void ForwardPointer(ObjectPtr* ptr);
+ void ForwardCompressedPointer(uword heap_base, CompressedObjectPtr* ptr);
void VisitTypedDataViewPointers(TypedDataViewPtr view,
ObjectPtr* first,
ObjectPtr* last);
void VisitPointers(ObjectPtr* first, ObjectPtr* last);
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last);
void VisitHandle(uword addr);
Heap* heap_;
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 5a6229b..3a79f14 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -121,6 +121,11 @@
// is safe.
NO_SANITIZE_THREAD
ObjectPtr LoadPointerIgnoreRace(ObjectPtr* ptr) { return *ptr; }
+ NO_SANITIZE_THREAD
+ CompressedObjectPtr LoadCompressedPointerIgnoreRace(
+ CompressedObjectPtr* ptr) {
+ return *ptr;
+ }
void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* current = first; current <= last; current++) {
@@ -128,6 +133,15 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ MarkObject(
+ LoadCompressedPointerIgnoreRace(current).Decompress(heap_base));
+ }
+ }
+
void EnqueueWeakProperty(WeakPropertyPtr raw_weak) {
ASSERT(raw_weak->IsHeapObject());
ASSERT(raw_weak->IsOldObject());
@@ -479,6 +493,12 @@
}
}
}
+
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ UNREACHABLE(); // ObjectIdRing is not compressed.
+ }
};
void GCMarker::ProcessObjectIdTable(Thread* thread) {
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 3004841..1add15e 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -145,6 +145,20 @@
ASSERT((index >= 0) && (index < card_table_size()));
card_table_[index] = 1;
}
+#if defined(DART_COMPRESSED_POINTERS)
+ void RememberCard(CompressedObjectPtr const* slot) {
+ ASSERT(Contains(reinterpret_cast<uword>(slot)));
+ if (card_table_ == NULL) {
+ card_table_ = reinterpret_cast<uint8_t*>(
+ calloc(card_table_size(), sizeof(uint8_t)));
+ }
+ intptr_t offset =
+ reinterpret_cast<uword>(slot) - reinterpret_cast<uword>(this);
+ intptr_t index = offset >> kBytesPerCardLog2;
+ ASSERT((index >= 0) && (index < card_table_size()));
+ card_table_[index] = 1;
+ }
+#endif
void VisitRememberedCards(ObjectPointerVisitor* visitor);
private:
diff --git a/runtime/vm/heap/scavenger.cc b/runtime/vm/heap/scavenger.cc
index baba05a..5a8c0d5 100644
--- a/runtime/vm/heap/scavenger.cc
+++ b/runtime/vm/heap/scavenger.cc
@@ -160,7 +160,7 @@
view->untag()->RecomputeDataFieldForInternalTypedData();
}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
ASSERT(Utils::IsAligned(first, sizeof(*first)));
ASSERT(Utils::IsAligned(last, sizeof(*last)));
for (ObjectPtr* current = first; current <= last; current++) {
@@ -168,6 +168,16 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ ASSERT(Utils::IsAligned(first, sizeof(*first)));
+ ASSERT(Utils::IsAligned(last, sizeof(*last)));
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ ScavengeCompressedPointer(heap_base, current);
+ }
+ }
+
void VisitingOldObject(ObjectPtr obj) {
ASSERT((obj == nullptr) || obj->IsOldObject());
visiting_old_object_ = obj;
@@ -253,7 +263,7 @@
NewPage* tail() const { return tail_; }
private:
- void UpdateStoreBuffer(ObjectPtr* p, ObjectPtr obj) {
+ void UpdateStoreBuffer(ObjectPtr obj) {
ASSERT(obj->IsHeapObject());
// If the newly written object is not a new object, drop it immediately.
if (!obj->IsNewObject() || visiting_old_object_->untag()->IsRemembered()) {
@@ -272,6 +282,57 @@
return;
}
+ ObjectPtr new_obj = ScavengeObject(raw_obj);
+
+ // Update the reference.
+ if (!new_obj->IsNewObject()) {
+ // Setting the mark bit above must not be ordered after a publishing store
+ // of this object. Note this could be a publishing store even if the
+ // object was promoted by an early invocation of ScavengePointer. Compare
+ // Object::Allocate.
+ reinterpret_cast<std::atomic<ObjectPtr>*>(p)->store(
+ new_obj, std::memory_order_release);
+ } else {
+ *p = new_obj;
+ }
+
+ // Update the store buffer as needed.
+ if (visiting_old_object_ != nullptr) {
+ UpdateStoreBuffer(new_obj);
+ }
+ }
+
+ DART_FORCE_INLINE
+ void ScavengeCompressedPointer(uword heap_base, CompressedObjectPtr* p) {
+ // ScavengePointer cannot be called recursively.
+ ObjectPtr raw_obj = p->Decompress(heap_base);
+
+ if (raw_obj->IsSmiOrOldObject()) { // Could be tested without decompression
+ return;
+ }
+
+ ObjectPtr new_obj = ScavengeObject(raw_obj);
+
+ // Update the reference.
+ if (!new_obj->IsNewObject()) {
+ // Setting the mark bit above must not be ordered after a publishing store
+ // of this object. Note this could be a publishing store even if the
+ // object was promoted by an early invocation of ScavengePointer. Compare
+ // Object::Allocate.
+ reinterpret_cast<std::atomic<ObjectPtr>*>(p)->store(
+ new_obj, std::memory_order_release);
+ } else {
+ *p = new_obj;
+ }
+
+ // Update the store buffer as needed.
+ if (visiting_old_object_ != nullptr) {
+ UpdateStoreBuffer(new_obj);
+ }
+ }
+
+ DART_FORCE_INLINE
+ ObjectPtr ScavengeObject(ObjectPtr raw_obj) {
uword raw_addr = UntaggedObject::ToAddr(raw_obj);
// The scavenger is only expects objects located in the from space.
ASSERT(from_->Contains(raw_addr));
@@ -356,21 +417,7 @@
}
}
- // Update the reference.
- if (!new_obj->IsNewObject()) {
- // Setting the mark bit above must not be ordered after a publishing store
- // of this object. Note this could be a publishing store even if the
- // object was promoted by an early invocation of ScavengePointer. Compare
- // Object::Allocate.
- reinterpret_cast<std::atomic<ObjectPtr>*>(p)->store(
- new_obj, std::memory_order_release);
- } else {
- *p = new_obj;
- }
- // Update the store buffer as needed.
- if (visiting_old_object_ != nullptr) {
- UpdateStoreBuffer(p, new_obj);
- }
+ return new_obj;
}
DART_FORCE_INLINE
@@ -783,6 +830,12 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ UNREACHABLE(); // Store buffer blocks are not compressed.
+ }
+
private:
ObjectSet* const in_store_buffer_;
};
@@ -831,6 +884,12 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ UNREACHABLE(); // Store buffer blocks are not compressed.
+ }
+
private:
const ObjectSet* const in_store_buffer_;
const SemiSpace* const to_;
diff --git a/runtime/vm/heap/scavenger_test.cc b/runtime/vm/heap/scavenger_test.cc
index 8d405eb..03c8f94 100644
--- a/runtime/vm/heap/scavenger_test.cc
+++ b/runtime/vm/heap/scavenger_test.cc
@@ -20,7 +20,10 @@
class FailingObjectPointerVisitor : public ObjectPointerVisitor {
public:
FailingObjectPointerVisitor() : ObjectPointerVisitor(NULL) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) { EXPECT(false); }
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
EXPECT(false);
}
};
diff --git a/runtime/vm/heap/verifier.cc b/runtime/vm/heap/verifier.cc
index b0e0d70..abeb1cc 100644
--- a/runtime/vm/heap/verifier.cc
+++ b/runtime/vm/heap/verifier.cc
@@ -60,6 +60,24 @@
}
}
+void VerifyPointersVisitor::VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ ObjectPtr raw_obj = current->Decompress(heap_base);
+ if (raw_obj->IsHeapObject()) {
+ if (!allocated_set_->Contains(raw_obj)) {
+ if (raw_obj->IsInstructions() &&
+ allocated_set_->Contains(OldPage::ToWritable(raw_obj))) {
+ continue;
+ }
+ uword raw_addr = UntaggedObject::ToAddr(raw_obj);
+ FATAL1("Invalid object pointer encountered %#" Px "\n", raw_addr);
+ }
+ }
+ }
+}
+
void VerifyWeakPointersVisitor::VisitHandle(uword addr) {
FinalizablePersistentHandle* handle =
reinterpret_cast<FinalizablePersistentHandle*>(addr);
diff --git a/runtime/vm/heap/verifier.h b/runtime/vm/heap/verifier.h
index 3733125..0b490cd 100644
--- a/runtime/vm/heap/verifier.h
+++ b/runtime/vm/heap/verifier.h
@@ -47,7 +47,10 @@
ObjectSet* allocated_set)
: ObjectPointerVisitor(isolate_group), allocated_set_(allocated_set) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last);
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last);
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last);
static void VerifyPointers(MarkExpectation mark_expectation = kForbidMarked);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 15d93cc..8aa06a4 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2642,6 +2642,26 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ if (old_obj_->IsArray()) {
+ for (CompressedObjectPtr* slot = from; slot <= to; ++slot) {
+ ObjectPtr value = slot->Decompress(heap_base);
+ if (value->IsHeapObject()) {
+ old_obj_->untag()->CheckArrayPointerStore(slot, value, thread_);
+ }
+ }
+ } else {
+ for (CompressedObjectPtr* slot = from; slot <= to; ++slot) {
+ ObjectPtr value = slot->Decompress(heap_base);
+ if (value->IsHeapObject()) {
+ old_obj_->untag()->CheckHeapPointerStore(value, thread_);
+ }
+ }
+ }
+ }
+
private:
Thread* thread_;
ObjectPtr old_obj_;
@@ -18406,6 +18426,14 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ if (first != last) {
+ has_pointers_ = true;
+ }
+ }
+
private:
bool has_pointers_;
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index e66e67b..aae4940 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -53,21 +53,32 @@
// Marks and pushes. Used to initialize this stack with roots.
// We can use ObjectIdTable normally used by serializers because it
// won't be in use while handling a service request (ObjectGraph's only use).
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* current = first; current <= last; ++current) {
- if ((*current)->IsHeapObject() &&
- !(*current)->untag()->InVMIsolateHeap() &&
- object_ids_->GetValueExclusive(*current) == 0) { // not visited yet
- if (!include_vm_objects_ && !IsUserClass((*current)->GetClassId())) {
- continue;
- }
- object_ids_->SetValueExclusive(*current, 1);
- Node node;
- node.ptr = current;
- node.obj = *current;
- node.gc_root_type = gc_root_type();
- data_.Add(node);
+ Visit(current, *current);
+ }
+ }
+
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current = first; current <= last; ++current) {
+ Visit(current, current->Decompress(heap_base));
+ }
+ }
+
+ void Visit(void* ptr, ObjectPtr obj) {
+ if (obj->IsHeapObject() && !obj->untag()->InVMIsolateHeap() &&
+ object_ids_->GetValueExclusive(obj) == 0) { // not visited yet
+ if (!include_vm_objects_ && !IsUserClass(obj->GetClassId())) {
+ return;
}
+ object_ids_->SetValueExclusive(obj, 1);
+ Node node;
+ node.ptr = ptr;
+ node.obj = obj;
+ node.gc_root_type = gc_root_type();
+ data_.Add(node);
}
}
@@ -112,7 +123,7 @@
private:
struct Node {
- ObjectPtr* ptr; // kSentinel for the sentinel node.
+ void* ptr; // kSentinel for the sentinel node.
ObjectPtr obj;
const char* gc_root_type;
};
@@ -165,7 +176,6 @@
Stack::Node parent = stack_->data_[parent_index];
uword parent_start = UntaggedObject::ToAddr(parent.obj);
Stack::Node child = stack_->data_[index_];
- ASSERT(child.obj == *child.ptr);
uword child_ptr_addr = reinterpret_cast<uword>(child.ptr);
intptr_t offset = child_ptr_addr - parent_start;
if (offset > 0 && offset < parent.obj->untag()->HeapSize()) {
@@ -484,7 +494,7 @@
raw_obj->untag()->VisitPointers(this);
}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* current_ptr = first; current_ptr <= last; current_ptr++) {
ObjectPtr current_obj = *current_ptr;
if (current_obj == target_) {
@@ -515,6 +525,40 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current_ptr = first; current_ptr <= last;
+ current_ptr++) {
+ ObjectPtr current_obj = current_ptr->Decompress(heap_base);
+ if (current_obj == target_) {
+ intptr_t obj_index = length_ * 2;
+ intptr_t offset_index = obj_index + 1;
+ if (!references_.IsNull() && offset_index < references_.Length()) {
+ *scratch_ = source_;
+ references_.SetAt(obj_index, *scratch_);
+
+ *scratch_ = Smi::New(0);
+ uword source_start = UntaggedObject::ToAddr(source_);
+ uword current_ptr_addr = reinterpret_cast<uword>(current_ptr);
+ intptr_t offset = current_ptr_addr - source_start;
+ if (offset > 0 && offset < source_->untag()->HeapSize()) {
+ ASSERT(Utils::IsAligned(offset, kWordSize));
+ *scratch_ = Smi::New(offset >> kWordSizeLog2);
+ } else {
+ // Some internal VM objects visit pointers not contained within the
+ // parent. For instance, UntaggedCode::VisitCodePointers visits
+ // pointers in instructions.
+ ASSERT(!source_->IsDartInstance());
+ *scratch_ = Smi::New(-1);
+ }
+ references_.SetAt(offset_index, *scratch_);
+ }
+ ++length_;
+ }
+ }
+ }
+
private:
ObjectPtr source_;
ObjectPtr target_;
@@ -786,6 +830,14 @@
writer_->CountReferences(count);
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ intptr_t count = to - from + 1;
+ ASSERT(count >= 0);
+ writer_->CountReferences(count);
+ }
+
void VisitHandle(uword addr) {
FinalizablePersistentHandle* weak_persistent_handle =
reinterpret_cast<FinalizablePersistentHandle*>(addr);
@@ -981,6 +1033,23 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* from,
+ CompressedObjectPtr* to) {
+ if (writing_) {
+ for (CompressedObjectPtr* ptr = from; ptr <= to; ptr++) {
+ ObjectPtr target = ptr->Decompress(heap_base);
+ written_++;
+ total_++;
+ writer_->WriteUnsigned(writer_->GetObjectId(target));
+ }
+ } else {
+ intptr_t count = to - from + 1;
+ ASSERT(count >= 0);
+ counted_ += count;
+ }
+ }
+
void VisitHandle(uword addr) {
FinalizablePersistentHandle* weak_persistent_handle =
reinterpret_cast<FinalizablePersistentHandle*>(addr);
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 6a03bff..6bd76cd 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -434,6 +434,22 @@
return Type::InstanceSize(); \
}
+#if !defined(DART_COMPRESSED_POINTERS)
+#define COMPRESSED_VISITOR(Type) REGULAR_VISITOR(Type)
+#else
+#define COMPRESSED_VISITOR(Type) \
+ intptr_t Untagged##Type::Visit##Type##Pointers( \
+ Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
+ /* Make sure that we got here with the tagged pointer as this. */ \
+ ASSERT(raw_obj->IsHeapObject()); \
+ ASSERT_UNCOMPRESSED(Type); \
+ visitor->VisitCompressedPointers(raw_obj->heap_base(), \
+ raw_obj->untag()->from(), \
+ raw_obj->untag()->to()); \
+ return Type::InstanceSize(); \
+ }
+#endif
+
// It calls the from() and to() methods on the raw object to get the first and
// last cells that need visiting.
//
@@ -463,10 +479,22 @@
return Type::InstanceSize(length); \
}
-// For now there are no compressed pointers:
-#define COMPRESSED_VISITOR(Type) REGULAR_VISITOR(Type)
+#if !defined(DART_COMPRESSED_POINTERS)
#define VARIABLE_COMPRESSED_VISITOR(Type, get_length) \
VARIABLE_VISITOR(Type, get_length)
+#else
+#define VARIABLE_COMPRESSED_VISITOR(Type, get_length) \
+ intptr_t Untagged##Type::Visit##Type##Pointers( \
+ Type##Ptr raw_obj, ObjectPointerVisitor* visitor) { \
+ /* Make sure that we got here with the tagged pointer as this. */ \
+ ASSERT(raw_obj->IsHeapObject()); \
+ intptr_t length = get_length; \
+ visitor->VisitCompressedPointers(raw_obj->heap_base(), \
+ raw_obj->untag()->from(), \
+ raw_obj->untag()->to(length)); \
+ return Type::InstanceSize(length); \
+ }
+#endif
// For fixed-length objects that don't have any pointers that need visiting.
#define NULL_VISITOR(Type) \
@@ -505,7 +533,7 @@
REGULAR_VISITOR(TypeParameter)
REGULAR_VISITOR(PatchClass)
REGULAR_VISITOR(Function)
-COMPRESSED_VISITOR(Closure)
+REGULAR_VISITOR(Closure)
REGULAR_VISITOR(ClosureData)
REGULAR_VISITOR(FfiTrampolineData)
REGULAR_VISITOR(Script)
@@ -523,9 +551,9 @@
REGULAR_VISITOR(UnwindError)
REGULAR_VISITOR(ExternalOneByteString)
REGULAR_VISITOR(ExternalTwoByteString)
-COMPRESSED_VISITOR(GrowableObjectArray)
-COMPRESSED_VISITOR(LinkedHashMap)
-COMPRESSED_VISITOR(ExternalTypedData)
+REGULAR_VISITOR(GrowableObjectArray)
+REGULAR_VISITOR(LinkedHashMap)
+REGULAR_VISITOR(ExternalTypedData)
TYPED_DATA_VIEW_VISITOR(TypedDataView)
REGULAR_VISITOR(ReceivePort)
REGULAR_VISITOR(StackTrace)
@@ -541,11 +569,10 @@
VARIABLE_VISITOR(LocalVarDescriptors, raw_obj->untag()->num_entries_)
VARIABLE_VISITOR(ExceptionHandlers, raw_obj->untag()->num_entries_)
VARIABLE_VISITOR(Context, raw_obj->untag()->num_variables_)
-VARIABLE_COMPRESSED_VISITOR(Array, Smi::Value(raw_obj->untag()->length()))
-VARIABLE_COMPRESSED_VISITOR(
- TypedData,
- TypedData::ElementSizeInBytes(raw_obj->GetClassId()) *
- Smi::Value(raw_obj->untag()->length_))
+VARIABLE_VISITOR(Array, Smi::Value(raw_obj->untag()->length()))
+VARIABLE_VISITOR(TypedData,
+ TypedData::ElementSizeInBytes(raw_obj->GetClassId()) *
+ Smi::Value(raw_obj->untag()->length_))
VARIABLE_VISITOR(ContextScope, raw_obj->untag()->num_variables_)
NULL_VISITOR(Mint)
NULL_VISITOR(Double)
@@ -689,6 +716,12 @@
OldPage::Of(static_cast<ObjectPtr>(this))->RememberCard(slot);
}
+#if defined(DART_COMPRESSED_POINTERS)
+void UntaggedObject::RememberCard(CompressedObjectPtr const* slot) {
+ OldPage::Of(static_cast<ObjectPtr>(this))->RememberCard(slot);
+}
+#endif
+
DEFINE_LEAF_RUNTIME_ENTRY(void,
RememberCard,
2,
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ca51cc9..6b6cf9a 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -36,9 +36,6 @@
namespace dart {
-// For now there are no compressed pointers.
-typedef ObjectPtr RawCompressed;
-
// Forward declarations.
class Isolate;
class IsolateGroup;
@@ -560,6 +557,15 @@
}
}
+ void StorePointer(CompressedObjectPtr* addr,
+ ObjectPtr value,
+ Thread* thread) {
+ *addr = value;
+ if (value->IsHeapObject()) {
+ CheckHeapPointerStore(value, thread);
+ }
+ }
+
template <typename type>
void StorePointerUnaligned(type const* addr, type value, Thread* thread) {
StoreUnaligned(const_cast<type*>(addr), value);
@@ -585,6 +591,15 @@
}
}
+ void StoreArrayPointer(CompressedObjectPtr* addr,
+ ObjectPtr value,
+ Thread* thread) {
+ *addr = value;
+ if (value->IsHeapObject()) {
+ CheckArrayPointerStore(addr, value, thread);
+ }
+ }
+
template <typename type, std::memory_order order = std::memory_order_relaxed>
type LoadSmi(type const* addr) const {
return reinterpret_cast<std::atomic<type>*>(const_cast<type*>(addr))
@@ -642,7 +657,7 @@
// old-and-not-remembered -> new reference.
ASSERT(!this->IsRemembered());
if (this->IsCardRemembered()) {
- RememberCard(reinterpret_cast<ObjectPtr const*>(addr));
+ RememberCard(addr);
} else {
this->SetRememberedBit();
thread->StoreBufferAddObject(static_cast<ObjectPtr>(this));
@@ -667,6 +682,9 @@
friend class StoreBufferUpdateVisitor; // RememberCard
void RememberCard(ObjectPtr const* slot);
+#if defined(DART_COMPRESSED_POINTERS)
+ void RememberCard(CompressedObjectPtr const* slot);
+#endif
friend class Array;
friend class ByteBuffer;
@@ -2415,7 +2433,7 @@
// The following fields are also declared in the Dart source of class
// _Closure.
- VISIT_FROM(RawCompressed, instantiator_type_arguments)
+ VISIT_FROM(ObjectPtr, instantiator_type_arguments)
POINTER_FIELD(TypeArgumentsPtr, instantiator_type_arguments)
POINTER_FIELD(TypeArgumentsPtr, function_type_arguments)
POINTER_FIELD(TypeArgumentsPtr, delayed_type_arguments)
@@ -2423,7 +2441,7 @@
POINTER_FIELD(ContextPtr, context)
POINTER_FIELD(SmiPtr, hash)
- VISIT_TO(RawCompressed, hash)
+ VISIT_TO(ObjectPtr, hash)
ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
@@ -2586,8 +2604,8 @@
void RecomputeDataField() { data_ = internal_data(); }
protected:
- VISIT_FROM(RawCompressed, length)
- VISIT_TO_LENGTH(RawCompressed, &length_)
+ VISIT_FROM(ObjectPtr, length)
+ VISIT_TO_LENGTH(ObjectPtr, &length_)
// Variable length data follows here.
@@ -2704,12 +2722,12 @@
class UntaggedArray : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(Array);
- VISIT_FROM(RawCompressed, type_arguments)
+ VISIT_FROM(ObjectPtr, type_arguments)
ARRAY_POINTER_FIELD(TypeArgumentsPtr, type_arguments)
SMI_FIELD(SmiPtr, length)
// Variable length data follows here.
VARIABLE_POINTER_FIELDS(ObjectPtr, element, data)
- VISIT_TO_LENGTH(RawCompressed, &data()[length - 1])
+ VISIT_TO_LENGTH(ObjectPtr, &data()[length - 1])
friend class LinkedHashMapSerializationCluster;
friend class LinkedHashMapDeserializationCluster;
@@ -2739,11 +2757,11 @@
class UntaggedGrowableObjectArray : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(GrowableObjectArray);
- VISIT_FROM(RawCompressed, type_arguments)
+ VISIT_FROM(ObjectPtr, type_arguments)
POINTER_FIELD(TypeArgumentsPtr, type_arguments)
SMI_FIELD(SmiPtr, length)
POINTER_FIELD(ArrayPtr, data)
- VISIT_TO(RawCompressed, data)
+ VISIT_TO(ObjectPtr, data)
ObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
friend class SnapshotReader;
@@ -2753,14 +2771,14 @@
class UntaggedLinkedHashMap : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(LinkedHashMap);
- VISIT_FROM(RawCompressed, type_arguments)
+ VISIT_FROM(ObjectPtr, type_arguments)
POINTER_FIELD(TypeArgumentsPtr, type_arguments)
POINTER_FIELD(TypedDataPtr, index)
POINTER_FIELD(SmiPtr, hash_mask)
POINTER_FIELD(ArrayPtr, data)
POINTER_FIELD(SmiPtr, used_data)
POINTER_FIELD(SmiPtr, deleted_keys)
- VISIT_TO(RawCompressed, deleted_keys)
+ VISIT_TO(ObjectPtr, deleted_keys)
friend class SnapshotReader;
};
@@ -2828,16 +2846,16 @@
RAW_HEAP_OBJECT_IMPLEMENTATION(ExternalTypedData);
protected:
- VISIT_FROM(RawCompressed, length)
- VISIT_TO(RawCompressed, length)
+ VISIT_FROM(ObjectPtr, length)
+ VISIT_TO(ObjectPtr, length)
};
class UntaggedPointer : public UntaggedPointerBase {
RAW_HEAP_OBJECT_IMPLEMENTATION(Pointer);
- VISIT_FROM(RawCompressed, type_arguments)
+ VISIT_FROM(ObjectPtr, type_arguments)
POINTER_FIELD(TypeArgumentsPtr, type_arguments)
- VISIT_TO(RawCompressed, type_arguments)
+ VISIT_TO(ObjectPtr, type_arguments)
friend class Pointer;
};
@@ -2995,9 +3013,9 @@
class UntaggedFutureOr : public UntaggedInstance {
RAW_HEAP_OBJECT_IMPLEMENTATION(FutureOr);
- VISIT_FROM(RawCompressed, type_arguments)
+ VISIT_FROM(ObjectPtr, type_arguments)
POINTER_FIELD(TypeArgumentsPtr, type_arguments)
- VISIT_TO(RawCompressed, type_arguments)
+ VISIT_TO(ObjectPtr, type_arguments)
friend class SnapshotReader;
};
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index f90b098..b3ee8a3 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1585,6 +1585,17 @@
}
}
+void SnapshotWriterVisitor::VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ ASSERT(Utils::IsAligned(first, sizeof(*first)));
+ ASSERT(Utils::IsAligned(last, sizeof(*last)));
+ for (CompressedObjectPtr* current = first; current <= last; current++) {
+ ObjectPtr raw_obj = current->Decompress(heap_base);
+ writer_->WriteObjectImpl(raw_obj, as_references_);
+ }
+}
+
MessageWriter::MessageWriter(bool can_send_any_object)
: SnapshotWriter(Thread::Current(),
Snapshot::kMessage,
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 8ad3cb1..93678d0 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -740,7 +740,10 @@
writer_(writer),
as_references_(as_references) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last);
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last);
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last);
private:
SnapshotWriter* writer_;
diff --git a/runtime/vm/tagged_pointer.h b/runtime/vm/tagged_pointer.h
index 68dc056..c191404 100644
--- a/runtime/vm/tagged_pointer.h
+++ b/runtime/vm/tagged_pointer.h
@@ -188,6 +188,14 @@
: tagged_pointer_(reinterpret_cast<uword>(heap_object) + kHeapObjectTag) {
}
+ ObjectPtr Decompress(uword heap_base) const { return *this; }
+ uword heap_base() const {
+ ASSERT(IsHeapObject());
+ ASSERT(!IsInstructions());
+ ASSERT(!IsInstructionsSection());
+ return tagged_pointer_ & ~(4ULL * GB - 1);
+ }
+
protected:
uword untagged_pointer() const {
ASSERT(IsHeapObject());
@@ -205,6 +213,34 @@
}
#endif
+#if !defined(DART_COMPRESSED_POINTERS)
+typedef ObjectPtr CompressedObjectPtr;
+#define DEFINE_COMPRESSED_POINTER(klass, base) \
+ typedef klass##Ptr Compressed##klass##Ptr;
+#else
+class CompressedObjectPtr {
+ public:
+ explicit CompressedObjectPtr(ObjectPtr uncompressed)
+ : compressed_pointer_(
+ static_cast<int32_t>(static_cast<uword>(uncompressed))) {}
+
+ ObjectPtr Decompress(uword heap_base) const {
+ return static_cast<ObjectPtr>(
+ static_cast<uword>(static_cast<word>(compressed_pointer_)) + heap_base);
+ }
+
+ const ObjectPtr& operator=(const ObjectPtr& other) {
+ compressed_pointer_ = static_cast<int32_t>(static_cast<uword>(other));
+ return other;
+ }
+
+ protected:
+ int32_t compressed_pointer_;
+};
+#define DEFINE_COMPRESSED_POINTER(klass, base) \
+ class Compressed##klass##Ptr : public Compressed##base##Ptr {};
+#endif
+
#define DEFINE_TAGGED_POINTER(klass, base) \
class Untagged##klass; \
class klass##Ptr : public base##Ptr { \
@@ -228,7 +264,8 @@
constexpr klass##Ptr(std::nullptr_t) : base##Ptr(nullptr) {} /* NOLINT */ \
explicit klass##Ptr(const UntaggedObject* untagged) \
: base##Ptr(reinterpret_cast<uword>(untagged) + kHeapObjectTag) {} \
- };
+ }; \
+ DEFINE_COMPRESSED_POINTER(klass, base)
DEFINE_TAGGED_POINTER(Class, Object)
DEFINE_TAGGED_POINTER(PatchClass, Object)
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index caff423..3308788 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -734,6 +734,12 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ UNREACHABLE(); // Stack slots are not compressed.
+ }
+
private:
Thread* const thread_;
Thread* const current_;
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 80be01e..4303b5f 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -83,7 +83,7 @@
explicit ObjectCounter(IsolateGroup* isolate_group, const Object* obj)
: ObjectPointerVisitor(isolate_group), obj_(obj), count_(0) {}
- virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
+ void VisitPointers(ObjectPtr* first, ObjectPtr* last) {
for (ObjectPtr* current = first; current <= last; ++current) {
if (*current == obj_->ptr()) {
++count_;
@@ -91,6 +91,16 @@
}
}
+ void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) {
+ for (CompressedObjectPtr* current = first; current <= last; ++current) {
+ if (current->Decompress(heap_base) == obj_->ptr()) {
+ ++count_;
+ }
+ }
+ }
+
intptr_t count() const { return count_; }
private:
diff --git a/runtime/vm/visitor.h b/runtime/vm/visitor.h
index eb9d343..8365418 100644
--- a/runtime/vm/visitor.h
+++ b/runtime/vm/visitor.h
@@ -35,6 +35,9 @@
// Range of pointers to visit 'first' <= pointer <= 'last'.
virtual void VisitPointers(ObjectPtr* first, ObjectPtr* last) = 0;
+ virtual void VisitCompressedPointers(uword heap_base,
+ CompressedObjectPtr* first,
+ CompressedObjectPtr* last) = 0;
// len argument is the number of pointers to visit starting from 'p'.
void VisitPointers(ObjectPtr* p, intptr_t len) {
diff --git a/tools/VERSION b/tools/VERSION
index b2b8996..0933579 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 40
+PRERELEASE 41
PRERELEASE_PATCH 0
\ No newline at end of file