[vm, gc] Extend alignment helpers to work with alignment offsets.
TEST=ci
Change-Id: I02bad1feba3a16360aa52414c94cdef81b158ed6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/262000
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index fb223da..087e042 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -73,35 +73,45 @@
}
template <typename T>
- static constexpr bool IsAligned(T x, intptr_t n) {
- assert(IsPowerOfTwo(n));
- return (x & (n - 1)) == 0;
+ static constexpr bool IsAligned(T x,
+ uintptr_t alignment,
+ uintptr_t offset = 0) {
+ ASSERT(IsPowerOfTwo(alignment));
+ ASSERT(offset < alignment);
+ return (x & (alignment - 1)) == offset;
}
template <typename T>
- static constexpr bool IsAligned(T* x, intptr_t n) {
- return IsAligned(reinterpret_cast<uword>(x), n);
+ static constexpr bool IsAligned(T* x,
+ uintptr_t alignment,
+ uintptr_t offset = 0) {
+ return IsAligned(reinterpret_cast<uword>(x), alignment, offset);
}
template <typename T>
- static constexpr inline T RoundDown(T x, intptr_t n) {
- ASSERT(IsPowerOfTwo(n));
- return (x & -n);
+ static constexpr inline T RoundDown(T x, intptr_t alignment) {
+ ASSERT(IsPowerOfTwo(alignment));
+ return (x & -alignment);
}
template <typename T>
- static inline T* RoundDown(T* x, intptr_t n) {
- return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uword>(x), n));
+ static inline T* RoundDown(T* x, intptr_t alignment) {
+ return reinterpret_cast<T*>(
+ RoundDown(reinterpret_cast<uword>(x), alignment));
}
template <typename T>
- static constexpr inline T RoundUp(T x, intptr_t n) {
- return RoundDown(x + n - 1, n);
+ static constexpr inline T RoundUp(T x,
+ uintptr_t alignment,
+ uintptr_t offset = 0) {
+ ASSERT(offset < alignment);
+ return RoundDown(x + alignment - 1 + offset, alignment) - offset;
}
template <typename T>
- static inline T* RoundUp(T* x, intptr_t n) {
- return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uword>(x), n));
+ static inline T* RoundUp(T* x, uintptr_t alignment, uintptr_t offset = 0) {
+ return reinterpret_cast<T*>(
+ RoundUp(reinterpret_cast<uword>(x), alignment, offset));
}
static uintptr_t RoundUpToPowerOfTwo(uintptr_t x);
diff --git a/runtime/vm/app_snapshot.h b/runtime/vm/app_snapshot.h
index 3445cb4..cf33a78 100644
--- a/runtime/vm/app_snapshot.h
+++ b/runtime/vm/app_snapshot.h
@@ -332,7 +332,9 @@
void WriteBytes(const uint8_t* addr, intptr_t len) {
stream_->WriteBytes(addr, len);
}
- void Align(intptr_t alignment) { stream_->Align(alignment); }
+ void Align(intptr_t alignment, intptr_t offset = 0) {
+ stream_->Align(alignment, offset);
+ }
V8SnapshotProfileWriter::ObjectId GetProfileId(ObjectPtr object) const;
V8SnapshotProfileWriter::ObjectId GetProfileId(intptr_t ref) const;
@@ -645,7 +647,9 @@
}
void Advance(intptr_t value) { stream_.Advance(value); }
- void Align(intptr_t alignment) { stream_.Align(alignment); }
+ void Align(intptr_t alignment, intptr_t offset = 0) {
+ stream_.Align(alignment, offset);
+ }
void AddBaseObject(ObjectPtr base_object) { AssignRef(base_object); }
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 974cb88..4b9cfa1 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -128,9 +128,10 @@
current_ = buffer_ + value;
}
- void Align(intptr_t alignment) {
+ void Align(intptr_t alignment, intptr_t offset = 0) {
intptr_t position_before = Position();
- intptr_t position_after = Utils::RoundUp(position_before, alignment);
+ intptr_t position_after =
+ Utils::RoundUp(position_before, alignment, offset);
Advance(position_after - position_before);
}
@@ -335,9 +336,10 @@
DART_FORCE_INLINE intptr_t bytes_written() const { return Position(); }
virtual intptr_t Position() const { return current_ - buffer_; }
- intptr_t Align(intptr_t alignment) {
+ intptr_t Align(intptr_t alignment, intptr_t offset = 0) {
const intptr_t position_before = Position();
- const intptr_t position_after = Utils::RoundUp(position_before, alignment);
+ const intptr_t position_after =
+ Utils::RoundUp(position_before, alignment, offset);
const intptr_t length = position_after - position_before;
if (length != 0) {
EnsureSpace(length);
diff --git a/runtime/vm/heap/page.h b/runtime/vm/heap/page.h
index 5aba1ae..08331b7 100644
--- a/runtime/vm/heap/page.h
+++ b/runtime/vm/heap/page.h
@@ -104,17 +104,15 @@
void WriteProtect(bool read_only);
- static intptr_t OldObjectStartOffset() {
- return Utils::RoundUp(sizeof(Page) - kOldObjectAlignmentOffset,
- kObjectStartAlignment) +
- kOldObjectAlignmentOffset;
+ constexpr static intptr_t OldObjectStartOffset() {
+ return Utils::RoundUp(sizeof(Page), kObjectStartAlignment,
+ kOldObjectAlignmentOffset);
}
- static intptr_t NewObjectStartOffset() {
+ constexpr static intptr_t NewObjectStartOffset() {
// Note weaker alignment because the bool/null offset tricks don't apply to
// new-space.
- return Utils::RoundUp(sizeof(Page) - kNewObjectAlignmentOffset,
- kObjectAlignment) +
- kNewObjectAlignmentOffset;
+ return Utils::RoundUp(sizeof(Page), kObjectAlignment,
+ kNewObjectAlignmentOffset);
}
// Warning: This does not work for objects on image pages because image pages
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index 01cd7af..297665f 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -710,7 +710,7 @@
WriteTargetWord(FLAG_precompiled_mode ? Image::kHeaderSize
: Image::kNoInstructionsSection);
// Zero values for the rest of the Image object header bytes.
- text_offset += Align(Image::kHeaderSize, text_offset);
+ text_offset += Align(Image::kHeaderSize, 0, text_offset);
ASSERT_EQUAL(text_offset, Image::kHeaderSize);
#if defined(DART_PRECOMPILER)
@@ -776,11 +776,14 @@
bare_instruction_payloads
? compiler::target::Instructions::kBarePayloadAlignment
: compiler::target::ObjectAlignment::kObjectAlignment;
+ const intptr_t alignment_offset =
+ compiler::target::ObjectAlignment::kOldObjectAlignmentOffset;
const intptr_t expected_size =
bare_instruction_payloads
? compiler::target::InstructionsSection::HeaderSize()
: compiler::target::InstructionsSection::InstanceSize(0);
- text_offset += Align(section_contents_alignment, text_offset);
+ text_offset +=
+ Align(section_contents_alignment, alignment_offset, text_offset);
ASSERT_EQUAL(text_offset - id.nonce(), expected_size);
}
#endif
@@ -837,6 +840,7 @@
text_offset += WriteFixed(insns.untag()->size_and_flags_);
text_offset +=
Align(compiler::target::Instructions::kNonBarePayloadAlignment,
+ compiler::target::ObjectAlignment::kOldObjectAlignmentOffset,
text_offset);
}
@@ -1367,7 +1371,7 @@
if (global_symbol) {
assembly_stream_->Printf(".globl %s\n", current_section_symbol_);
}
- intptr_t padding = Align(alignment);
+ intptr_t padding = Align(alignment, 0, 0);
if (alignment_padding != nullptr) {
*alignment_padding = padding;
}
@@ -1599,7 +1603,10 @@
return size;
}
-intptr_t AssemblyImageWriter::Align(intptr_t alignment, intptr_t position) {
+intptr_t AssemblyImageWriter::Align(intptr_t alignment,
+ intptr_t offset,
+ intptr_t position) {
+ ASSERT(offset == 0);
const intptr_t next_position = Utils::RoundUp(position, alignment);
assembly_stream_->Printf(".balign %" Pd ", 0\n", alignment);
return next_position - position;
@@ -1731,10 +1738,14 @@
return compiler::target::kWordSize;
}
-intptr_t BlobImageWriter::Align(intptr_t alignment, intptr_t offset) {
- const intptr_t stream_padding = current_section_stream_->Align(alignment);
- // Double-check that the offset has the same alignment.
- ASSERT_EQUAL(Utils::RoundUp(offset, alignment) - offset, stream_padding);
+intptr_t BlobImageWriter::Align(intptr_t alignment,
+ intptr_t offset,
+ intptr_t position) {
+ const intptr_t stream_padding =
+ current_section_stream_->Align(alignment, offset);
+ // Double-check that the position has the same alignment.
+ ASSERT_EQUAL(Utils::RoundUp(position, alignment, offset) - position,
+ stream_padding);
return stream_padding;
}
diff --git a/runtime/vm/image_snapshot.h b/runtime/vm/image_snapshot.h
index abbcabf..fa755fd 100644
--- a/runtime/vm/image_snapshot.h
+++ b/runtime/vm/image_snapshot.h
@@ -442,7 +442,9 @@
// section contents.
virtual intptr_t WriteBytes(const void* bytes, intptr_t size) = 0;
// Pads the section contents to a given alignment with zeroes.
- virtual intptr_t Align(intptr_t alignment, intptr_t offset) = 0;
+ virtual intptr_t Align(intptr_t alignment,
+ intptr_t offset,
+ intptr_t position) = 0;
#if defined(DART_PRECOMPILER)
// Writes a target word-sized value that depends on the final relocated
// addresses of the sections named by the two symbols. If T is the final
@@ -610,7 +612,9 @@
virtual void ExitSection(ProgramSection name, bool vm, intptr_t size);
virtual intptr_t WriteTargetWord(word value);
virtual intptr_t WriteBytes(const void* bytes, intptr_t size);
- virtual intptr_t Align(intptr_t alignment, intptr_t offset = 0);
+ virtual intptr_t Align(intptr_t alignment,
+ intptr_t offset,
+ intptr_t position);
virtual intptr_t Relocation(intptr_t section_offset,
const char* source_symbol,
intptr_t source_offset,
@@ -662,7 +666,9 @@
virtual void ExitSection(ProgramSection name, bool vm, intptr_t size);
virtual intptr_t WriteTargetWord(word value);
virtual intptr_t WriteBytes(const void* bytes, intptr_t size);
- virtual intptr_t Align(intptr_t alignment, intptr_t offset);
+ virtual intptr_t Align(intptr_t alignment,
+ intptr_t offset,
+ intptr_t position);
// TODO(rmacnak): Generate .debug_frame / .eh_frame / .arm.exidx to
// provide unwinding information.
virtual void FrameUnwindPrologue() {}
diff --git a/runtime/vm/utils_test.cc b/runtime/vm/utils_test.cc
index 2b0369f..8cc9cb8 100644
--- a/runtime/vm/utils_test.cc
+++ b/runtime/vm/utils_test.cc
@@ -110,6 +110,13 @@
EXPECT(Utils::IsAligned(32, 8));
EXPECT(!Utils::IsAligned(33, 8));
EXPECT(Utils::IsAligned(40, 8));
+
+ EXPECT(!Utils::IsAligned(0, 8, 4));
+ EXPECT(!Utils::IsAligned(1, 8, 4));
+ EXPECT(Utils::IsAligned(4, 8, 4));
+ EXPECT(!Utils::IsAligned(8, 8, 4));
+ EXPECT(!Utils::IsAligned(9, 8, 4));
+ EXPECT(Utils::IsAligned(12, 8, 4));
}
VM_UNIT_TEST_CASE(RoundDown) {
@@ -128,6 +135,13 @@
uword* address = reinterpret_cast<uword*>(63);
uword* roundup_address = reinterpret_cast<uword*>(64);
EXPECT_EQ(roundup_address, Utils::RoundUp(address, 32));
+
+ EXPECT_EQ(4, Utils::RoundUp(0, 8, 4));
+ EXPECT_EQ(4, Utils::RoundUp(1, 8, 4));
+ EXPECT_EQ(4, Utils::RoundUp(4, 8, 4));
+ EXPECT_EQ(12, Utils::RoundUp(8, 8, 4));
+ EXPECT_EQ(12, Utils::RoundUp(9, 8, 4));
+ EXPECT_EQ(12, Utils::RoundUp(12, 8, 4));
}
VM_UNIT_TEST_CASE(RoundUpToPowerOfTwo) {