a2bb7301c5
Instead of storing the PC offset inside the StackMap object, store it instead in the `Array` containing `StackMap`s in `Code` objects. That is, the `Array` provided by `Code::stackmaps()` no longer contains just `StackMap` objects, but instead contains `Smi`s and `StackMap` objects in alternating fashion. Each `Smi` is the PC offset for the `StackMap` object that follows. This ends up changing very little code outside of `StackMap`, `Code::GetStackMap`, and `StackMapTableBuilder`, as there are only two types of `StackMap` users: * Users that call `Code::GetStackMap` already have the PC offset. * Users that call Code::stackmaps() can just fetch the PC offset from the returned `Array` instead. On 64-bit architectures, we will use more space to represent the PC offset as a Smi in the Array than the old uint32_t field. However, the drop in total number of StackMap objects due to an increased ability to canonicalize them should offset this. On 32-bit architectures, we can only represent 30 bit PC offsets, not 32 bit PC offsets, but that shouldn't be a problem in practice except for pathological cases. _Numbers from building the Flutter gallery in android_release mode_ Since PC offsets are no longer in the `StackMap` objects, this enables a lot more canonicalization than before. Previously, we generated 49379 `StackMap`s, but now we only generate 16139 `StackMap`s, just under a third of the original number. This is because there were a lot of `StackMap`s that differed only in their PC offset, and now they can be canonicalized into the same `StackMap` object. When building the Flutter gallery with android_release, the app.so size drops from 11276896 bytes to 10908256 bytes, a difference of 368640 bytes, or 3.27%. Using the AOT snapshot profiling support, we see the following drops: Heap snapshot size drops from 10.7 MB to 10.4 MB. `Code` | Before | After | Difference --------------------------------------------------------- Shallow size | 352363 | 352363 | 0 Retained size | 9114801 | 8796064 | -318737 Percent of snapshot | 81.2% | 80.7% | -0.5% `(RO)StackMap` | Before | After | Difference --------------------------------------------------------- Shallow size | 49381 | 16141 | -33240 Retained size | 893965 | 286613 | -607352 Percent of snapshot | 7.97% | 2.63% | -5.34% `StackMap` | Before | After | Difference --------------------------------------------------------- Shallow size | 844584 | 270472 | -574112 Retained size | 844584 | 270472 | -574112 Percent of snapshot | 7.53% | 2.48% | -5.05% As we'd expect from the `StackMap` numbers above, we end up using a little under a third of the space for `StackMap`s. We actually use even less space (32.0% of the original) than the drop in `StackMap` numbers (32.7%), because each `RawStackMap` instance is 32 bits smaller due to dropping the `pc_offset_` field. Note that even though these PC offsets now show up in the `Code::stackmaps()` `Array`, we can see this is still a net drop in space used by looking at the retained size of `Code` objects. Bug: https://github.com/dart-lang/sdk/issues/35274 Change-Id: I0910a43e7a5a7e2e721676209196be1884c5a71c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/119147 Commit-Queue: Teagan Strickland <sstrickl@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
105 lines
2.9 KiB
C++
105 lines
2.9 KiB
C++
// Copyright (c) 2012, 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.
|
|
|
|
#include "vm/bitmap.h"
|
|
#include "platform/assert.h"
|
|
#include "vm/object.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
ISOLATE_UNIT_TEST_CASE(BitmapBuilder) {
|
|
// Test basic bit map builder operations.
|
|
BitmapBuilder* builder1 = new BitmapBuilder();
|
|
EXPECT_EQ(0, builder1->Length());
|
|
|
|
bool value = true;
|
|
for (int32_t i = 0; i < 128; i++) {
|
|
builder1->Set(i, value);
|
|
value = !value;
|
|
}
|
|
EXPECT_EQ(128, builder1->Length());
|
|
value = true;
|
|
for (int32_t i = 0; i < 128; i++) {
|
|
EXPECT_EQ(value, builder1->Get(i));
|
|
value = !value;
|
|
}
|
|
value = true;
|
|
for (int32_t i = 0; i < 1024; i++) {
|
|
builder1->Set(i, value);
|
|
value = !value;
|
|
}
|
|
EXPECT_EQ(1024, builder1->Length());
|
|
value = true;
|
|
for (int32_t i = 0; i < 1024; i++) {
|
|
EXPECT_EQ(value, builder1->Get(i));
|
|
value = !value;
|
|
}
|
|
// Create a StackMap object from the builder and verify its contents.
|
|
const StackMap& stackmap1 = StackMap::Handle(StackMap::New(builder1, 0));
|
|
EXPECT_EQ(1024, stackmap1.Length());
|
|
OS::PrintErr("%s\n", stackmap1.ToCString());
|
|
value = true;
|
|
for (int32_t i = 0; i < 1024; i++) {
|
|
EXPECT_EQ(value, stackmap1.IsObject(i));
|
|
value = !value;
|
|
}
|
|
|
|
// Test the SetRange function in the builder.
|
|
builder1->SetRange(0, 256, false);
|
|
EXPECT_EQ(1024, builder1->Length());
|
|
builder1->SetRange(257, 1024, true);
|
|
EXPECT_EQ(1025, builder1->Length());
|
|
builder1->SetRange(1025, 2048, false);
|
|
EXPECT_EQ(2049, builder1->Length());
|
|
for (int32_t i = 0; i <= 256; i++) {
|
|
EXPECT(!builder1->Get(i));
|
|
}
|
|
for (int32_t i = 257; i <= 1024; i++) {
|
|
EXPECT(builder1->Get(i));
|
|
}
|
|
for (int32_t i = 1025; i <= 2048; i++) {
|
|
EXPECT(!builder1->Get(i));
|
|
}
|
|
const StackMap& stackmap2 = StackMap::Handle(StackMap::New(builder1, 0));
|
|
EXPECT_EQ(2049, stackmap2.Length());
|
|
for (int32_t i = 0; i <= 256; i++) {
|
|
EXPECT(!stackmap2.IsObject(i));
|
|
}
|
|
for (int32_t i = 257; i <= 1024; i++) {
|
|
EXPECT(stackmap2.IsObject(i));
|
|
}
|
|
for (int32_t i = 1025; i <= 2048; i++) {
|
|
EXPECT(!stackmap2.IsObject(i));
|
|
}
|
|
|
|
// Test using SetLength to shorten the builder, followed by lengthening.
|
|
builder1->SetLength(747);
|
|
EXPECT_EQ(747, builder1->Length());
|
|
for (int32_t i = 257; i < 747; ++i) {
|
|
EXPECT(builder1->Get(i));
|
|
}
|
|
|
|
builder1->Set(800, false);
|
|
EXPECT_EQ(801, builder1->Length());
|
|
for (int32_t i = 257; i < 747; ++i) {
|
|
EXPECT(builder1->Get(i));
|
|
}
|
|
for (int32_t i = 747; i < 801; ++i) {
|
|
EXPECT(!builder1->Get(i));
|
|
}
|
|
|
|
builder1->Set(900, true);
|
|
EXPECT_EQ(901, builder1->Length());
|
|
for (int32_t i = 257; i < 747; ++i) {
|
|
EXPECT(builder1->Get(i));
|
|
}
|
|
for (int32_t i = 747; i < 900; ++i) {
|
|
EXPECT(!builder1->Get(i));
|
|
}
|
|
EXPECT(builder1->Get(900));
|
|
}
|
|
|
|
} // namespace dart
|