diff --git a/runtime/tests/vm/dart/heap_snapshot_regress_49710_test.dart b/runtime/tests/vm/dart/heap_snapshot_regress_49710_test.dart new file mode 100644 index 00000000000..ad5adb4f6f2 --- /dev/null +++ b/runtime/tests/vm/dart/heap_snapshot_regress_49710_test.dart @@ -0,0 +1,30 @@ +// Copyright (c) 2022, 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:_internal'; + +import 'package:expect/expect.dart'; +import 'package:path/path.dart' as path; + +import 'heap_snapshot_test.dart'; +import 'use_flag_test_helper.dart'; + +main() async { + if (const bool.fromEnvironment('dart.vm.product')) return; + + await withTempDir('heap_snapshot_test', (String dir) async { + final file = path.join(dir, 'state1.heapsnapshot'); + VMInternalsForTesting.writeHeapSnapshotToFile(file); + final snapshot = loadHeapSnapshotFromFile(file); + for (final klass in snapshot.classes) { + // Ensure field indices are unique. + final fields = klass.fields.toList()..sort((a, b) => a.index - b.index); + int lastIndex = -1; + for (int i = 0; i < fields.length; ++i) { + Expect.notEquals(lastIndex, fields[i].index); + lastIndex = fields[i].index; + } + } + }); +} diff --git a/runtime/tests/vm/dart_2/heap_snapshot_regress_49710_test.dart b/runtime/tests/vm/dart_2/heap_snapshot_regress_49710_test.dart new file mode 100644 index 00000000000..be1c5461518 --- /dev/null +++ b/runtime/tests/vm/dart_2/heap_snapshot_regress_49710_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// @dart=2.9 + +import 'dart:_internal'; + +import 'package:expect/expect.dart'; +import 'package:path/path.dart' as path; + +import 'heap_snapshot_test.dart'; +import 'use_flag_test_helper.dart'; + +main() async { + if (const bool.fromEnvironment('dart.vm.product')) return; + + await withTempDir('heap_snapshot_test', (String dir) async { + final file = path.join(dir, 'state1.heapsnapshot'); + VMInternalsForTesting.writeHeapSnapshotToFile(file); + final snapshot = loadHeapSnapshotFromFile(file); + for (final klass in snapshot.classes) { + // Ensure field indices are unique. + final fields = klass.fields.toList()..sort((a, b) => a.index - b.index); + int lastIndex = -1; + for (int i = 0; i < fields.length; ++i) { + Expect.notEquals(lastIndex, fields[i].index); + lastIndex = fields[i].index; + } + } + }); +} diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc index 6265e3e7d99..9ff005026b6 100644 --- a/runtime/vm/object_graph.cc +++ b/runtime/vm/object_graph.cc @@ -1338,16 +1338,18 @@ void HeapSnapshotWriter::Write() { } WriteUtf8(""); // Reserved + bool via_offsets_table = false; intptr_t field_count = 0; intptr_t min_offset = kIntptrMax; for (const auto& entry : OffsetsTable::offsets_table()) { if (entry.class_id == cid) { + via_offsets_table = true; field_count++; intptr_t offset = entry.offset; min_offset = Utils::Minimum(min_offset, offset); } } - if (cls.is_finalized()) { + if (!via_offsets_table && cls.is_finalized()) { do { fields = cls.fields(); if (!fields.IsNull()) { @@ -1376,7 +1378,7 @@ void HeapSnapshotWriter::Write() { WriteUtf8(""); // Reserved } } - if (cls.is_finalized()) { + if (!via_offsets_table && cls.is_finalized()) { do { fields = cls.fields(); if (!fields.IsNull()) { diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc index a7e7a92331e..37532369187 100644 --- a/runtime/vm/raw_object_fields.cc +++ b/runtime/vm/raw_object_fields.cc @@ -166,7 +166,7 @@ namespace dart { F(LinkedHashMap, hash_mask_) \ F(LinkedHashMap, data_) \ F(LinkedHashMap, used_data_) \ - F(LinkedHashSet, deleted_keys_) \ + F(LinkedHashMap, deleted_keys_) \ F(LinkedHashSet, type_arguments_) \ F(LinkedHashSet, index_) \ F(LinkedHashSet, hash_mask_) \