5#include "tpde/Assembler.hpp"
6#include "tpde/base.hpp"
7#include "tpde/util/SmallVector.hpp"
12enum class Label : u32 {
15enum class LabelFixupKind : u8 {
18 X64_JMP_OR_MEM_DISP = ArchKindBegin,
21 AARCH64_BR = ArchKindBegin,
28template <
typename Derived>
31 DataSection *section =
nullptr;
32 u8 *data_begin =
nullptr;
33 u8 *data_cur =
nullptr;
34 u8 *data_reserve_end =
nullptr;
54 FunctionWriter() noexcept = default;
57 assert(data_cur == data_reserve_end &&
58 "must flush section writer before destructing");
62 Derived *derived() noexcept {
return static_cast<Derived *
>(
this); }
70 assert(section !=
nullptr);
76 assert(data_cur == data_reserve_end &&
77 "must flush section writer before switching sections");
78 section = &new_section;
79 data_begin = section->data.data();
80 data_cur = data_begin + section->data.size();
81 data_reserve_end = data_cur;
84 void begin_func(u32 expected_size)
noexcept {
88 ensure_space(expected_size);
91 void finish_func() noexcept { derived()->handle_fixups(); }
97 size_t offset() const noexcept {
return data_cur - data_begin; }
101 return data_reserve_end - data_begin;
111 void ensure_space(
size_t size)
noexcept {
112 assert(data_reserve_end >= data_cur);
113 if (
size_t(data_reserve_end - data_cur) < size) [[unlikely]] {
114 derived()->more_space(size);
118 void more_space(
size_t size)
noexcept;
120 template <std::
integral T>
121 void write_unchecked(T t)
noexcept {
122 assert(
size_t(data_reserve_end - data_cur) >=
sizeof(T));
123 std::memcpy(data_cur, &t,
sizeof(T));
124 data_cur +=
sizeof(T);
127 template <std::
integral T>
128 void write(T t)
noexcept {
129 ensure_space(
sizeof(T));
130 write_unchecked<T>(t);
133 void flush() noexcept {
134 if (data_cur != data_reserve_end) {
135 section->data.resize(
offset());
136 data_reserve_end = data_cur;
138 section->locked =
false;
143 void align(
size_t align)
noexcept {
144 assert(align > 0 && (align & (align - 1)) == 0);
147 std::memset(
cur_ptr(), 0, align);
148 data_cur = data_begin + util::align_up(
offset(), align);
149 section->align = std::max(section->align, u32(align));
164 bool label_is_pending(Label label)
const noexcept {
168 u32 label_offset(Label label)
const noexcept {
169 assert(!label_is_pending(label));
175 assert(label_is_pending(label));
180 void label_ref(Label label, u32 off, LabelFixupKind kind)
noexcept {
181 assert(label_is_pending(label));
182 label_fixups.emplace_back(LabelFixup{label, off, kind});
188template <
typename Derived>
189void FunctionWriter<Derived>::more_space(
size_t size)
noexcept {
190 size_t cur_size = section->data.size();
192 if (cur_size + size <= section->data.capacity()) {
193 new_size = section->data.capacity();
195 new_size = cur_size + (size <= growth_size ? growth_size : size);
198 growth_size = growth_size + (growth_size >> 1);
200 growth_size = growth_size < 0x1000000 ? growth_size : 0x1000000;
203 const size_t off = offset();
204 section->data.resize_uninitialized(new_size);
206 thread_local uint8_t rand = 1;
207 std::memset(section->data.data() + off, rand += 2, new_size - off);
208 section->locked =
true;
211 data_begin = section->data.data();
212 data_cur = data_begin + off;
213 data_reserve_end = data_begin + section->data.size();
u32 growth_size
Growth size for more_space; adjusted exponentially after every grow.
void label_ref(Label label, u32 off, LabelFixupKind kind) noexcept
Reference label at given offset inside the code section.
size_t offset() const noexcept
Get the current offset into the section.
util::SmallVector< LabelFixup > label_fixups
Fixups for labels placed after their first use, processed at function end.
size_t allocated_size() const noexcept
Get the current allocated size of the section.
DataSection & get_section() const noexcept
Get the current section.
SecRef get_sec_ref() const noexcept
Get the SecRef of the current section.
u8 * begin_ptr() noexcept
Pointer to beginning of section data.
Label label_create() noexcept
Create a new unplaced label.
void switch_section(DataSection &new_section) noexcept
Switch section writer to new section; must be flushed.
util::SmallVector< u32 > label_offsets
Label offsets into section, ~0u indicates unplaced label.
void label_place(Label label, u32 off) noexcept
Place unplaced label at the specified offset inside the section.