Skip to content

Commit d84d376

Browse files
authored
[NFC] Move optimal-LEB emitting logic to a shared place (#7575)
This allows generating sections in side buffers, rather than just on the main output buffer ("o"). This will help code annotations, where it is useful to emit them to a side buffer, then copy them into the right place (which is before the code section, but we must emit the code first, to know the offsets for the annotations, so reordering is unavoidable).
1 parent 9e6bae0 commit d84d376

File tree

2 files changed

+58
-26
lines changed

2 files changed

+58
-26
lines changed

src/wasm-binary.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,52 @@ class BufferWithRandomAccess : public std::vector<uint8_t> {
258258
std::copy(begin(), end(), ret.begin());
259259
return ret;
260260
}
261+
262+
// Writes bytes in the maximum amount for a U32 LEB placeholder. Return the
263+
// offset we wrote it at. The LEB can then be patched with the proper value
264+
// later, when the size is known.
265+
BinaryLocation writeU32LEBPlaceholder() {
266+
BinaryLocation ret = size();
267+
*this << int32_t(0);
268+
*this << int8_t(0);
269+
return ret;
270+
}
271+
272+
// Given the location of a maximum-size LEB placeholder, as returned from
273+
// writeU32LEBPlaceholder, use the current buffer size to figure out the size
274+
// that should be written there, and emit an optimal-size LEB. Move contents
275+
// backwards if we used fewer bytes, and return the number of bytes we moved.
276+
// (Thus, if we return >0, we moved code backwards, and the caller may need to
277+
// adjust things.)
278+
BinaryLocation emitRetroactiveSectionSizeLEB(BinaryLocation start) {
279+
// Do not include the LEB itself in the section size.
280+
auto sectionSize = size() - start - MaxLEB32Bytes;
281+
auto sizeFieldSize = writeAt(start, U32LEB(sectionSize));
282+
283+
// We can move things back if the actual LEB for the size doesn't use the
284+
// maximum 5 bytes. In that case we need to adjust offsets after we move
285+
// things backwards.
286+
auto adjustmentForLEBShrinking = MaxLEB32Bytes - sizeFieldSize;
287+
if (adjustmentForLEBShrinking) {
288+
// We can save some room.
289+
assert(sizeFieldSize < MaxLEB32Bytes);
290+
std::move(&(*this)[start] + MaxLEB32Bytes,
291+
&(*this)[start] + MaxLEB32Bytes + sectionSize,
292+
&(*this)[start] + sizeFieldSize);
293+
resize(size() - adjustmentForLEBShrinking);
294+
}
295+
296+
return adjustmentForLEBShrinking;
297+
}
298+
299+
void writeInlineString(std::string_view name) {
300+
auto size = name.size();
301+
auto data = name.data();
302+
*this << U32LEB(size);
303+
for (size_t i = 0; i < size; i++) {
304+
*this << int8_t(data[i]);
305+
}
306+
}
261307
};
262308

263309
namespace BinaryConsts {

src/wasm/wasm-binary.cpp

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,7 @@ void WasmBinaryWriter::writeHeader() {
107107
}
108108

109109
int32_t WasmBinaryWriter::writeU32LEBPlaceholder() {
110-
int32_t ret = o.size();
111-
o << int32_t(0);
112-
o << int8_t(0);
113-
return ret;
110+
return o.writeU32LEBPlaceholder();
114111
}
115112

116113
void WasmBinaryWriter::writeResizableLimits(
@@ -142,26 +139,12 @@ template<typename T> int32_t WasmBinaryWriter::startSection(T code) {
142139
}
143140

144141
void WasmBinaryWriter::finishSection(int32_t start) {
145-
// section size does not include the reserved bytes of the size field itself
146-
int32_t size = o.size() - start - MaxLEB32Bytes;
147-
auto sizeFieldSize = o.writeAt(start, U32LEB(size));
148-
// We can move things back if the actual LEB for the size doesn't use the
149-
// maximum 5 bytes. In that case we need to adjust offsets after we move
150-
// things backwards.
151-
auto adjustmentForLEBShrinking = MaxLEB32Bytes - sizeFieldSize;
152-
if (adjustmentForLEBShrinking) {
153-
// we can save some room, nice
154-
assert(sizeFieldSize < MaxLEB32Bytes);
155-
std::move(&o[start] + MaxLEB32Bytes,
156-
&o[start] + MaxLEB32Bytes + size,
157-
&o[start] + sizeFieldSize);
158-
o.resize(o.size() - adjustmentForLEBShrinking);
159-
if (sourceMap) {
160-
for (auto i = sourceMapLocationsSizeAtSectionStart;
161-
i < sourceMapLocations.size();
162-
++i) {
163-
sourceMapLocations[i].first -= adjustmentForLEBShrinking;
164-
}
142+
auto adjustmentForLEBShrinking = o.emitRetroactiveSectionSizeLEB(start);
143+
if (adjustmentForLEBShrinking && sourceMap) {
144+
for (auto i = sourceMapLocationsSizeAtSectionStart;
145+
i < sourceMapLocations.size();
146+
++i) {
147+
sourceMapLocations[i].first -= adjustmentForLEBShrinking;
165148
}
166149
}
167150

@@ -172,6 +155,10 @@ void WasmBinaryWriter::finishSection(int32_t start) {
172155
// The section type byte is right before the LEB for the size; we want
173156
// offsets that are relative to the body, which is after that section type
174157
// byte and the the size LEB.
158+
//
159+
// We can compute the size of the size field LEB by considering the original
160+
// size of the maximal LEB, and the adjustment due to shrinking.
161+
auto sizeFieldSize = MaxLEB32Bytes - adjustmentForLEBShrinking;
175162
auto body = start + sizeFieldSize;
176163
// Offsets are relative to the body of the code section: after the
177164
// section type byte and the size.
@@ -1538,8 +1525,7 @@ void WasmBinaryWriter::writeData(const char* data, size_t size) {
15381525
}
15391526

15401527
void WasmBinaryWriter::writeInlineString(std::string_view name) {
1541-
o << U32LEB(name.size());
1542-
writeData(name.data(), name.size());
1528+
o.writeInlineString(name);
15431529
}
15441530

15451531
static bool isHexDigit(char ch) {

0 commit comments

Comments
 (0)