dc808f3fcb
When we are writing a snapshot, canonicalize all entries within CompressedStackMaps payloads. We do this by creating a global table of stack map information (bit counts + bit payload) that we store in the isolate object store, and then for each existing CSM, we replace it with an alternate version that refers to the global table. This gets back some of the canonicalization we lost when we moved from individual StackMap objects to per-Code CompressedStackMaps objects. Here, we also represent the global table as a CompressedStackMaps object. This means that there are three types of CompressedStackMaps: * The original version that directly contains all entry information. * The version where each entry is just the PC offset delta and an offset into the global table payload. * A version representing the global table where the entries are like the original version except they don't contain a PC offset delta. ----- The impact on AOT snapshot size when compiling the Flutter Gallery in release mode: armv7: Total size -0.88% (Isolate RO: -5.05%, Isolate snapshot: +0.00%) armv8: Total size -1.04% (Isolate RO: -5.28%, Isolate snapshot: +0.00%) ----- Bug: https://github.com/dart-lang/sdk/issues/35274 Change-Id: I1ce0f8b3cc58e2f11584f3c218e0fdf8984b799b Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/120667 Commit-Queue: Teagan Strickland <sstrickl@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com>
133 lines
3.7 KiB
C++
133 lines
3.7 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/code_descriptors.h"
|
|
#include "vm/object.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
// 0x4 is just a placeholder PC offset because no entry of a CSM should
|
|
// have a PC offset of 0, otherwise internal assumptions break.
|
|
static const uint32_t kTestPcOffset = 0x4;
|
|
static const intptr_t kTestSpillSlotBitCount = 0;
|
|
|
|
static RawCompressedStackMaps* MapsFromBuilder(BitmapBuilder* bmap) {
|
|
CompressedStackMapsBuilder builder;
|
|
builder.AddEntry(kTestPcOffset, bmap, kTestSpillSlotBitCount);
|
|
return builder.Finalize();
|
|
}
|
|
|
|
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 CompressedStackMaps object and verify its contents.
|
|
const auto& maps1 = CompressedStackMaps::Handle(MapsFromBuilder(builder1));
|
|
CompressedStackMapsIterator it1(maps1);
|
|
EXPECT(it1.MoveNext());
|
|
|
|
EXPECT_EQ(kTestPcOffset, it1.pc_offset());
|
|
EXPECT_EQ(kTestSpillSlotBitCount, it1.SpillSlotBitCount());
|
|
EXPECT_EQ(1024, it1.Length());
|
|
value = true;
|
|
for (int32_t i = 0; i < 1024; i++) {
|
|
EXPECT_EQ(value, it1.IsObject(i));
|
|
value = !value;
|
|
}
|
|
|
|
EXPECT(!it1.MoveNext());
|
|
|
|
// 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 auto& maps2 = CompressedStackMaps::Handle(MapsFromBuilder(builder1));
|
|
CompressedStackMapsIterator it2(maps2);
|
|
EXPECT(it2.MoveNext());
|
|
|
|
EXPECT_EQ(kTestPcOffset, it2.pc_offset());
|
|
EXPECT_EQ(kTestSpillSlotBitCount, it2.SpillSlotBitCount());
|
|
EXPECT_EQ(2049, it2.Length());
|
|
for (int32_t i = 0; i <= 256; i++) {
|
|
EXPECT(!it2.IsObject(i));
|
|
}
|
|
for (int32_t i = 257; i <= 1024; i++) {
|
|
EXPECT(it2.IsObject(i));
|
|
}
|
|
for (int32_t i = 1025; i <= 2048; i++) {
|
|
EXPECT(!it2.IsObject(i));
|
|
}
|
|
|
|
EXPECT(!it2.MoveNext());
|
|
|
|
// 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
|