Skip to content

Commit 21d06ae

Browse files
authored
Emit optimal-size LEBs in section/subsection/function body sizes (#1128)
* emit optimal-size LEBs in section/subsection/function body sizes, instead of preallocating 5 bytes
1 parent 4216894 commit 21d06ae

9 files changed

+49
-19
lines changed

src/wasm-binary.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535

3636
namespace wasm {
3737

38+
enum {
39+
// the maximum amount of bytes we emit per LEB
40+
MaxLEB32Bytes = 5
41+
};
42+
3843
template<typename T, typename MiniT>
3944
struct LEB {
4045
static_assert(sizeof(MiniT) == 1, "MiniT must be a byte");
@@ -63,7 +68,9 @@ struct LEB {
6368
} while (more);
6469
}
6570

66-
void writeAt(std::vector<uint8_t>* out, size_t at, size_t minimum = 0) {
71+
// @minimum: a minimum number of bytes to write, padding as necessary
72+
// returns the number of bytes written
73+
size_t writeAt(std::vector<uint8_t>* out, size_t at, size_t minimum = 0) {
6774
T temp = value;
6875
size_t offset = 0;
6976
bool more;
@@ -77,6 +84,7 @@ struct LEB {
7784
(*out)[at + offset] = byte;
7885
offset++;
7986
} while (more);
87+
return offset;
8088
}
8189

8290
void read(std::function<MiniT()> get) {
@@ -258,9 +266,18 @@ class BufferWithRandomAccess : public std::vector<uint8_t> {
258266
(*this)[i+2] = x & 0xff; x >>= 8;
259267
(*this)[i+3] = x & 0xff;
260268
}
261-
void writeAt(size_t i, U32LEB x) {
269+
270+
// writes out an LEB to an arbitrary location. this writes the LEB as a full
271+
// 5 bytes, the fixed amount that can easily be set aside ahead of time
272+
void writeAtFullFixedSize(size_t i, U32LEB x) {
262273
if (debug) std::cerr << "backpatchU32LEB: " << x.value << " (at " << i << ")" << std::endl;
263-
x.writeAt(this, i, 5); // fill all 5 bytes, we have to do this when backpatching
274+
x.writeAt(this, i, MaxLEB32Bytes); // fill all 5 bytes, we have to do this when backpatching
275+
}
276+
// writes out an LEB of normal size
277+
// returns how many bytes were written
278+
size_t writeAt(size_t i, U32LEB x) {
279+
if (debug) std::cerr << "writeAtU32LEB: " << x.value << " (at " << i << ")" << std::endl;
280+
return x.writeAt(this, i);
264281
}
265282

266283
template <typename T>
@@ -647,7 +664,8 @@ class WasmBinaryWriter : public Visitor<WasmBinaryWriter, void> {
647664
void writeHeader();
648665
int32_t writeU32LEBPlaceholder();
649666
void writeResizableLimits(Address initial, Address maximum, bool hasMaximum, bool shared);
650-
int32_t startSection(BinaryConsts::Section code);
667+
template<typename T>
668+
int32_t startSection(T code);
651669
void finishSection(int32_t start);
652670
int32_t startSubsection(BinaryConsts::UserSections::Subsection code);
653671
void finishSubsection(int32_t start);

src/wasm/wasm-binary.cpp

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include <algorithm>
1718
#include <fstream>
1819

1920
#include "support/bits.h"
@@ -84,24 +85,29 @@ void WasmBinaryWriter::writeResizableLimits(Address initial, Address maximum,
8485
}
8586
}
8687

87-
int32_t WasmBinaryWriter::startSection(BinaryConsts::Section code) {
88+
template<typename T>
89+
int32_t WasmBinaryWriter::startSection(T code) {
8890
o << U32LEB(code);
8991
return writeU32LEBPlaceholder(); // section size to be filled in later
9092
}
9193

9294
void WasmBinaryWriter::finishSection(int32_t start) {
93-
int32_t size = o.size() - start - 5; // section size does not include the 5 bytes of the size field itself
94-
o.writeAt(start, U32LEB(size));
95+
int32_t size = o.size() - start - MaxLEB32Bytes; // section size does not include the reserved bytes of the size field itself
96+
auto sizeFieldSize = o.writeAt(start, U32LEB(size));
97+
if (sizeFieldSize != MaxLEB32Bytes) {
98+
// we can save some room, nice
99+
assert(sizeFieldSize < MaxLEB32Bytes);
100+
std::move(&o[start + MaxLEB32Bytes], &o[start + MaxLEB32Bytes + size], &o[start + sizeFieldSize]);
101+
o.resize(o.size() - (MaxLEB32Bytes - sizeFieldSize));
102+
}
95103
}
96104

97105
int32_t WasmBinaryWriter::startSubsection(BinaryConsts::UserSections::Subsection code) {
98-
o << U32LEB(code);
99-
return writeU32LEBPlaceholder(); // section size to be filled in later
106+
return startSection(code);
100107
}
101108

102109
void WasmBinaryWriter::finishSubsection(int32_t start) {
103-
int32_t size = o.size() - start - 5; // section size does not include the 5 bytes of the size field itself
104-
o.writeAt(start, U32LEB(size));
110+
finishSection(start);
105111
}
106112

107113
void WasmBinaryWriter::writeStart() {
@@ -270,7 +276,13 @@ void WasmBinaryWriter::writeFunctions() {
270276
size_t size = o.size() - start;
271277
assert(size <= std::numeric_limits<uint32_t>::max());
272278
if (debug) std::cerr << "body size: " << size << ", writing at " << sizePos << ", next starts at " << o.size() << std::endl;
273-
o.writeAt(sizePos, U32LEB(size));
279+
auto sizeFieldSize = o.writeAt(sizePos, U32LEB(size));
280+
if (sizeFieldSize != MaxLEB32Bytes) {
281+
// we can save some room, nice
282+
assert(sizeFieldSize < MaxLEB32Bytes);
283+
std::move(&o[start], &o[start + size], &o[sizePos + sizeFieldSize]);
284+
o.resize(o.size() - (MaxLEB32Bytes - sizeFieldSize));
285+
}
274286
}
275287
currFunction = nullptr;
276288
finishSection(start);

test/debugInfo.fromasm.clamp.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/debugInfo.fromasm.clamp.no-opts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/debugInfo.fromasm.imprecise.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/debugInfo.fromasm.imprecise.no-opts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/debugInfo.fromasm.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/debugInfo.fromasm.no-opts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/example/c-api-unused-mem.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
(call $main)
4747
)
4848
)
49-
213
49+
177
5050
(module
5151
(type $0 (func))
5252
(type $1 (func))

0 commit comments

Comments
 (0)