mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 15:42:20 +00:00
[vm, gc] Account for unbounded number of images pages in the compactor.
Bug: https://github.com/dart-lang/sdk/issues/41974 Change-Id: I23201f28e5d1e2ba298611206fc3eb0a9a989c2b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/155241 Reviewed-by: Alexander Markov <alexmarkov@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
9b04db0683
commit
d68d2e9e0a
|
@ -569,29 +569,27 @@ void CompactorTask::PlanMoveToContiguousSize(intptr_t size) {
|
|||
}
|
||||
|
||||
void GCCompactor::SetupImagePageBoundaries() {
|
||||
for (intptr_t i = 0; i < kMaxImagePages; i++) {
|
||||
image_page_ranges_[i].base = 0;
|
||||
image_page_ranges_[i].size = 0;
|
||||
}
|
||||
intptr_t next_offset = 0;
|
||||
MallocGrowableArray<ImagePageRange> ranges(4);
|
||||
|
||||
OldPage* image_page = Dart::vm_isolate()->heap()->old_space()->image_pages_;
|
||||
while (image_page != NULL) {
|
||||
RELEASE_ASSERT(next_offset <= kMaxImagePages);
|
||||
image_page_ranges_[next_offset].base = image_page->object_start();
|
||||
image_page_ranges_[next_offset].size =
|
||||
image_page->object_end() - image_page->object_start();
|
||||
ImagePageRange range = {image_page->object_start(),
|
||||
image_page->object_end()};
|
||||
ranges.Add(range);
|
||||
image_page = image_page->next();
|
||||
next_offset++;
|
||||
}
|
||||
image_page = heap_->old_space()->image_pages_;
|
||||
while (image_page != NULL) {
|
||||
RELEASE_ASSERT(next_offset <= kMaxImagePages);
|
||||
image_page_ranges_[next_offset].base = image_page->object_start();
|
||||
image_page_ranges_[next_offset].size =
|
||||
image_page->object_end() - image_page->object_start();
|
||||
ImagePageRange range = {image_page->object_start(),
|
||||
image_page->object_end()};
|
||||
ranges.Add(range);
|
||||
image_page = image_page->next();
|
||||
next_offset++;
|
||||
}
|
||||
|
||||
ranges.Sort(CompareImagePageRanges);
|
||||
intptr_t image_page_count;
|
||||
ranges.StealBuffer(&image_page_ranges_, &image_page_count);
|
||||
image_page_hi_ = image_page_count - 1;
|
||||
}
|
||||
|
||||
DART_FORCE_INLINE
|
||||
|
@ -602,8 +600,17 @@ void GCCompactor::ForwardPointer(ObjectPtr* ptr) {
|
|||
}
|
||||
|
||||
uword old_addr = ObjectLayout::ToAddr(old_target);
|
||||
for (intptr_t i = 0; i < kMaxImagePages; i++) {
|
||||
if ((old_addr - image_page_ranges_[i].base) < image_page_ranges_[i].size) {
|
||||
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).
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ class GCCompactor : public ValueObject,
|
|||
: HandleVisitor(thread),
|
||||
ObjectPointerVisitor(thread->isolate_group()),
|
||||
heap_(heap) {}
|
||||
~GCCompactor() {}
|
||||
~GCCompactor() { free(image_page_ranges_); }
|
||||
|
||||
void Compact(OldPage* pages, FreeList* freelist, Mutex* mutex);
|
||||
|
||||
|
@ -47,13 +47,21 @@ class GCCompactor : public ValueObject,
|
|||
Heap* heap_;
|
||||
|
||||
struct ImagePageRange {
|
||||
uword base;
|
||||
uword size;
|
||||
uword start;
|
||||
uword end;
|
||||
};
|
||||
// There are up to 4 images to consider:
|
||||
// {instructions, data} x {vm isolate, current isolate}
|
||||
static const intptr_t kMaxImagePages = 4;
|
||||
ImagePageRange image_page_ranges_[kMaxImagePages];
|
||||
static int CompareImagePageRanges(const ImagePageRange* a,
|
||||
const ImagePageRange* b) {
|
||||
if (a->start < b->start) {
|
||||
return -1;
|
||||
} else if (a->start == b->start) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
intptr_t image_page_hi_ = 0;
|
||||
ImagePageRange* image_page_ranges_ = nullptr;
|
||||
|
||||
// The typed data views whose inner pointer must be updated after sliding is
|
||||
// complete.
|
||||
|
|
7
tests/standalone/fragmentation_deferred_load_lib1.dart
Normal file
7
tests/standalone/fragmentation_deferred_load_lib1.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "one!";
|
||||
}
|
7
tests/standalone/fragmentation_deferred_load_lib2.dart
Normal file
7
tests/standalone/fragmentation_deferred_load_lib2.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "two!";
|
||||
}
|
7
tests/standalone/fragmentation_deferred_load_lib3.dart
Normal file
7
tests/standalone/fragmentation_deferred_load_lib3.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "three!";
|
||||
}
|
40
tests/standalone/fragmentation_deferred_load_test.dart
Normal file
40
tests/standalone/fragmentation_deferred_load_test.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2020, 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=--use_compactor
|
||||
|
||||
// Each loading unit creates more image pages in the heap, which unfortunately
|
||||
// cannot be aligned stronger than virtual memory page alignment, so the
|
||||
// compactor must detect references to these image pages separately. Before
|
||||
// these loading units were implemented, the compactor could assume a small
|
||||
// upper bound on the number of image pages.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "fragmentation_deferred_load_lib1.dart" deferred as lib1;
|
||||
import "fragmentation_deferred_load_lib2.dart" deferred as lib2;
|
||||
import "fragmentation_deferred_load_lib3.dart" deferred as lib3;
|
||||
|
||||
main() async {
|
||||
await lib1.loadLibrary();
|
||||
Expect.equals("one!", lib1.foo());
|
||||
await lib2.loadLibrary();
|
||||
Expect.equals("two!", lib2.foo());
|
||||
await lib3.loadLibrary();
|
||||
Expect.equals("three!", lib3.foo());
|
||||
|
||||
final List<List?> arrays = [];
|
||||
// Fill up heap with alternate large-small items.
|
||||
for (int i = 0; i < 500000; i++) {
|
||||
arrays.add(new List<dynamic>.filled(260, null));
|
||||
arrays.add(new List<dynamic>.filled(1, null));
|
||||
}
|
||||
// Clear the large items so that the heap is full of 260-word gaps.
|
||||
for (int i = 0; i < arrays.length; i += 2) {
|
||||
arrays[i] = null;
|
||||
}
|
||||
// Allocate a lot of 300-word objects that don't fit in the gaps.
|
||||
for (int i = 0; i < 600000; i++) {
|
||||
arrays.add(new List<dynamic>.filled(300, null));
|
||||
}
|
||||
}
|
7
tests/standalone_2/fragmentation_deferred_load_lib1.dart
Normal file
7
tests/standalone_2/fragmentation_deferred_load_lib1.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "one!";
|
||||
}
|
7
tests/standalone_2/fragmentation_deferred_load_lib2.dart
Normal file
7
tests/standalone_2/fragmentation_deferred_load_lib2.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "two!";
|
||||
}
|
7
tests/standalone_2/fragmentation_deferred_load_lib3.dart
Normal file
7
tests/standalone_2/fragmentation_deferred_load_lib3.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Copyright (c) 2020, 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.
|
||||
|
||||
foo() {
|
||||
return "three!";
|
||||
}
|
40
tests/standalone_2/fragmentation_deferred_load_test.dart
Normal file
40
tests/standalone_2/fragmentation_deferred_load_test.dart
Normal file
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2020, 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=--use_compactor
|
||||
|
||||
// Each loading unit creates more image pages in the heap, which unfortunately
|
||||
// cannot be aligned stronger than virtual memory page alignment, so the
|
||||
// compactor must detect references to these image pages separately. Before
|
||||
// these loading units were implemented, the compactor could assume a small
|
||||
// upper bound on the number of image pages.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "fragmentation_deferred_load_lib1.dart" deferred as lib1;
|
||||
import "fragmentation_deferred_load_lib2.dart" deferred as lib2;
|
||||
import "fragmentation_deferred_load_lib3.dart" deferred as lib3;
|
||||
|
||||
main() async {
|
||||
await lib1.loadLibrary();
|
||||
Expect.equals("one!", lib1.foo());
|
||||
await lib2.loadLibrary();
|
||||
Expect.equals("two!", lib2.foo());
|
||||
await lib3.loadLibrary();
|
||||
Expect.equals("three!", lib3.foo());
|
||||
|
||||
final List<List> arrays = [];
|
||||
// Fill up heap with alternate large-small items.
|
||||
for (int i = 0; i < 500000; i++) {
|
||||
arrays.add(new List(260));
|
||||
arrays.add(new List(1));
|
||||
}
|
||||
// Clear the large items so that the heap is full of 260-word gaps.
|
||||
for (int i = 0; i < arrays.length; i += 2) {
|
||||
arrays[i] = null;
|
||||
}
|
||||
// Allocate a lot of 300-word objects that don't fit in the gaps.
|
||||
for (int i = 0; i < 600000; i++) {
|
||||
arrays.add(new List(300));
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue