Skip to content

Commit d68d2e9

Browse files
rmacnak-googlecommit-bot@chromium.org
authored andcommitted
[vm, gc] Account for unbounded number of images pages in the compactor.
Bug: #41974 Change-Id: I23201f28e5d1e2ba298611206fc3eb0a9a989c2b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155241 Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent 9b04db0 commit d68d2e9

10 files changed

+161
-24
lines changed

runtime/vm/heap/compactor.cc

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -569,29 +569,27 @@ void CompactorTask::PlanMoveToContiguousSize(intptr_t size) {
569569
}
570570

571571
void GCCompactor::SetupImagePageBoundaries() {
572-
for (intptr_t i = 0; i < kMaxImagePages; i++) {
573-
image_page_ranges_[i].base = 0;
574-
image_page_ranges_[i].size = 0;
575-
}
576-
intptr_t next_offset = 0;
572+
MallocGrowableArray<ImagePageRange> ranges(4);
573+
577574
OldPage* image_page = Dart::vm_isolate()->heap()->old_space()->image_pages_;
578575
while (image_page != NULL) {
579-
RELEASE_ASSERT(next_offset <= kMaxImagePages);
580-
image_page_ranges_[next_offset].base = image_page->object_start();
581-
image_page_ranges_[next_offset].size =
582-
image_page->object_end() - image_page->object_start();
576+
ImagePageRange range = {image_page->object_start(),
577+
image_page->object_end()};
578+
ranges.Add(range);
583579
image_page = image_page->next();
584-
next_offset++;
585580
}
586581
image_page = heap_->old_space()->image_pages_;
587582
while (image_page != NULL) {
588-
RELEASE_ASSERT(next_offset <= kMaxImagePages);
589-
image_page_ranges_[next_offset].base = image_page->object_start();
590-
image_page_ranges_[next_offset].size =
591-
image_page->object_end() - image_page->object_start();
583+
ImagePageRange range = {image_page->object_start(),
584+
image_page->object_end()};
585+
ranges.Add(range);
592586
image_page = image_page->next();
593-
next_offset++;
594587
}
588+
589+
ranges.Sort(CompareImagePageRanges);
590+
intptr_t image_page_count;
591+
ranges.StealBuffer(&image_page_ranges_, &image_page_count);
592+
image_page_hi_ = image_page_count - 1;
595593
}
596594

597595
DART_FORCE_INLINE
@@ -602,8 +600,17 @@ void GCCompactor::ForwardPointer(ObjectPtr* ptr) {
602600
}
603601

604602
uword old_addr = ObjectLayout::ToAddr(old_target);
605-
for (intptr_t i = 0; i < kMaxImagePages; i++) {
606-
if ((old_addr - image_page_ranges_[i].base) < image_page_ranges_[i].size) {
603+
intptr_t lo = 0;
604+
intptr_t hi = image_page_hi_;
605+
while (lo <= hi) {
606+
intptr_t mid = (hi - lo + 1) / 2 + lo;
607+
ASSERT(mid >= lo);
608+
ASSERT(mid <= hi);
609+
if (old_addr < image_page_ranges_[mid].start) {
610+
hi = mid - 1;
611+
} else if (old_addr >= image_page_ranges_[mid].end) {
612+
lo = mid + 1;
613+
} else {
607614
return; // Not moved (unaligned image page).
608615
}
609616
}

runtime/vm/heap/compactor.h

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class GCCompactor : public ValueObject,
2828
: HandleVisitor(thread),
2929
ObjectPointerVisitor(thread->isolate_group()),
3030
heap_(heap) {}
31-
~GCCompactor() {}
31+
~GCCompactor() { free(image_page_ranges_); }
3232

3333
void Compact(OldPage* pages, FreeList* freelist, Mutex* mutex);
3434

@@ -47,13 +47,21 @@ class GCCompactor : public ValueObject,
4747
Heap* heap_;
4848

4949
struct ImagePageRange {
50-
uword base;
51-
uword size;
50+
uword start;
51+
uword end;
5252
};
53-
// There are up to 4 images to consider:
54-
// {instructions, data} x {vm isolate, current isolate}
55-
static const intptr_t kMaxImagePages = 4;
56-
ImagePageRange image_page_ranges_[kMaxImagePages];
53+
static int CompareImagePageRanges(const ImagePageRange* a,
54+
const ImagePageRange* b) {
55+
if (a->start < b->start) {
56+
return -1;
57+
} else if (a->start == b->start) {
58+
return 0;
59+
} else {
60+
return 1;
61+
}
62+
}
63+
intptr_t image_page_hi_ = 0;
64+
ImagePageRange* image_page_ranges_ = nullptr;
5765

5866
// The typed data views whose inner pointer must be updated after sliding is
5967
// complete.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "one!";
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "two!";
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "three!";
7+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--use_compactor
6+
7+
// Each loading unit creates more image pages in the heap, which unfortunately
8+
// cannot be aligned stronger than virtual memory page alignment, so the
9+
// compactor must detect references to these image pages separately. Before
10+
// these loading units were implemented, the compactor could assume a small
11+
// upper bound on the number of image pages.
12+
13+
import "package:expect/expect.dart";
14+
import "fragmentation_deferred_load_lib1.dart" deferred as lib1;
15+
import "fragmentation_deferred_load_lib2.dart" deferred as lib2;
16+
import "fragmentation_deferred_load_lib3.dart" deferred as lib3;
17+
18+
main() async {
19+
await lib1.loadLibrary();
20+
Expect.equals("one!", lib1.foo());
21+
await lib2.loadLibrary();
22+
Expect.equals("two!", lib2.foo());
23+
await lib3.loadLibrary();
24+
Expect.equals("three!", lib3.foo());
25+
26+
final List<List?> arrays = [];
27+
// Fill up heap with alternate large-small items.
28+
for (int i = 0; i < 500000; i++) {
29+
arrays.add(new List<dynamic>.filled(260, null));
30+
arrays.add(new List<dynamic>.filled(1, null));
31+
}
32+
// Clear the large items so that the heap is full of 260-word gaps.
33+
for (int i = 0; i < arrays.length; i += 2) {
34+
arrays[i] = null;
35+
}
36+
// Allocate a lot of 300-word objects that don't fit in the gaps.
37+
for (int i = 0; i < 600000; i++) {
38+
arrays.add(new List<dynamic>.filled(300, null));
39+
}
40+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "one!";
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "two!";
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
foo() {
6+
return "three!";
7+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// VMOptions=--use_compactor
6+
7+
// Each loading unit creates more image pages in the heap, which unfortunately
8+
// cannot be aligned stronger than virtual memory page alignment, so the
9+
// compactor must detect references to these image pages separately. Before
10+
// these loading units were implemented, the compactor could assume a small
11+
// upper bound on the number of image pages.
12+
13+
import "package:expect/expect.dart";
14+
import "fragmentation_deferred_load_lib1.dart" deferred as lib1;
15+
import "fragmentation_deferred_load_lib2.dart" deferred as lib2;
16+
import "fragmentation_deferred_load_lib3.dart" deferred as lib3;
17+
18+
main() async {
19+
await lib1.loadLibrary();
20+
Expect.equals("one!", lib1.foo());
21+
await lib2.loadLibrary();
22+
Expect.equals("two!", lib2.foo());
23+
await lib3.loadLibrary();
24+
Expect.equals("three!", lib3.foo());
25+
26+
final List<List> arrays = [];
27+
// Fill up heap with alternate large-small items.
28+
for (int i = 0; i < 500000; i++) {
29+
arrays.add(new List(260));
30+
arrays.add(new List(1));
31+
}
32+
// Clear the large items so that the heap is full of 260-word gaps.
33+
for (int i = 0; i < arrays.length; i += 2) {
34+
arrays[i] = null;
35+
}
36+
// Allocate a lot of 300-word objects that don't fit in the gaps.
37+
for (int i = 0; i < 600000; i++) {
38+
arrays.add(new List(300));
39+
}
40+
}

0 commit comments

Comments
 (0)