Index: src/wasm/encoder.cc |
diff --git a/src/wasm/encoder.cc b/src/wasm/encoder.cc |
index 869952e2ced2860733dbff801d72385500ed7a75..8e18dd8450a0fc5c7006fa47a4253def93e096e6 100644 |
--- a/src/wasm/encoder.cc |
+++ b/src/wasm/encoder.cc |
@@ -16,6 +16,15 @@ |
#include "src/v8memory.h" |
+#if DEBUG |
+#define TRACE(...) \ |
+ do { \ |
+ if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \ |
+ } while (false) |
+#else |
+#define TRACE(...) |
+#endif |
+ |
namespace v8 { |
namespace internal { |
namespace wasm { |
@@ -41,6 +50,11 @@ void EmitUint32(byte** b, uint32_t x) { |
*b += 4; |
} |
+// Sections all start with a size, but it's unknown at the start. |
+// We generate a large varint which we then fixup later when the size is known. |
+// |
+// TODO(jfb) Not strictly necessary since sizes are calculated ahead of time. |
+const size_t padded_varint = 5; |
void EmitVarInt(byte** b, size_t val) { |
while (true) { |
@@ -65,8 +79,37 @@ size_t SizeOfVarInt(size_t value) { |
return size; |
} |
-} // namespace |
+void FixupSection(byte* start, byte* end) { |
+ // Same as EmitVarInt, but fixed-width with zeroes in the MSBs. |
+ size_t val = end - start - padded_varint; |
+ TRACE(" fixup %u\n", (unsigned)val); |
+ for (size_t pos = 0; pos != padded_varint; ++pos) { |
+ size_t next = val >> 7; |
+ byte out = static_cast<byte>(val & 0x7f); |
+ if (pos != padded_varint - 1) { |
+ *(start++) = 0x80 | out; |
+ val = next; |
+ } else { |
+ *(start++) = out; |
+ // TODO(jfb) check that the pre-allocated fixup size isn't overflowed. |
+ } |
+ } |
+} |
+// Returns the start of the section, where the section VarInt size is. |
+byte* EmitSection(WasmSection::Code code, byte** b) { |
+ byte* start = *b; |
+ const char* name = WasmSection::getName(code); |
+ size_t length = WasmSection::getNameLength(code); |
+ TRACE("emit section: %s\n", name); |
+ for (size_t padding = 0; padding != padded_varint; ++padding) { |
+ EmitUint8(b, 0xff); // Will get fixed up later. |
+ } |
+ EmitVarInt(b, length); // Section name string size. |
+ for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]); |
+ return start; |
+} |
+} // namespace |
struct WasmFunctionBuilder::Type { |
bool param_; |
@@ -498,57 +541,83 @@ struct Sizes { |
body_size += body; |
} |
- void AddSection(size_t size) { |
- if (size > 0) { |
- Add(1, 0); |
- Add(SizeOfVarInt(size), 0); |
- } |
+ void AddSection(WasmSection::Code code, size_t other_size) { |
+ Add(padded_varint + SizeOfVarInt(WasmSection::getNameLength(code)) + |
+ WasmSection::getNameLength(code), |
+ 0); |
+ if (other_size) Add(SizeOfVarInt(other_size), 0); |
} |
}; |
- |
WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { |
Sizes sizes = {0, 0}; |
sizes.Add(2 * sizeof(uint32_t), 0); // header |
- sizes.Add(1, 0); |
+ sizes.AddSection(WasmSection::Code::Memory, 0); |
sizes.Add(kDeclMemorySize, 0); |
+ TRACE("Size after memory: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
- sizes.AddSection(signatures_.size()); |
- for (auto sig : signatures_) { |
- sizes.Add(1 + SizeOfVarInt(sig->parameter_count()) + sig->parameter_count(), |
- 0); |
- } |
- |
- sizes.AddSection(globals_.size()); |
if (globals_.size() > 0) { |
+ sizes.AddSection(WasmSection::Code::Globals, globals_.size()); |
/* These globals never have names, so are always 3 bytes. */ |
sizes.Add(3 * globals_.size(), 0); |
+ TRACE("Size after globals: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
} |
- sizes.AddSection(functions_.size()); |
- for (auto function : functions_) { |
- sizes.Add(function->HeaderSize() + function->BodySize(), |
- function->NameSize()); |
+ if (signatures_.size() > 0) { |
+ sizes.AddSection(WasmSection::Code::Signatures, signatures_.size()); |
+ for (auto sig : signatures_) { |
+ sizes.Add( |
+ 1 + SizeOfVarInt(sig->parameter_count()) + sig->parameter_count(), 0); |
+ } |
+ TRACE("Size after signatures: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
+ } |
+ |
+ if (functions_.size() > 0) { |
+ sizes.AddSection(WasmSection::Code::Functions, functions_.size()); |
+ for (auto function : functions_) { |
+ sizes.Add(function->HeaderSize() + function->BodySize(), |
+ function->NameSize()); |
+ } |
+ TRACE("Size after functions: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
} |
if (start_function_index_ >= 0) { |
- sizes.Add(1, 0); |
+ sizes.AddSection(WasmSection::Code::StartFunction, 0); |
sizes.Add(SizeOfVarInt(start_function_index_), 0); |
+ TRACE("Size after start: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
} |
- sizes.AddSection(data_segments_.size()); |
- for (auto segment : data_segments_) { |
- sizes.Add(segment->HeaderSize(), segment->BodySize()); |
+ if (data_segments_.size() > 0) { |
+ sizes.AddSection(WasmSection::Code::DataSegments, data_segments_.size()); |
+ for (auto segment : data_segments_) { |
+ sizes.Add(segment->HeaderSize(), segment->BodySize()); |
+ } |
+ TRACE("Size after data segments: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
} |
- sizes.AddSection(indirect_functions_.size()); |
- for (auto function_index : indirect_functions_) { |
- sizes.Add(SizeOfVarInt(function_index), 0); |
+ if (indirect_functions_.size() > 0) { |
+ sizes.AddSection(WasmSection::Code::FunctionTable, |
+ indirect_functions_.size()); |
+ for (auto function_index : indirect_functions_) { |
+ sizes.Add(SizeOfVarInt(function_index), 0); |
+ } |
+ TRACE("Size after indirect functions: %u, %u\n", |
+ (unsigned)sizes.header_size, (unsigned)sizes.body_size); |
} |
- if (sizes.body_size > 0) sizes.Add(1, 0); |
+ if (sizes.body_size > 0) { |
+ sizes.AddSection(WasmSection::Code::End, 0); |
+ TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size, |
+ (unsigned)sizes.body_size); |
+ } |
ZoneVector<uint8_t> buffer_vector(sizes.total(), zone); |
byte* buffer = &buffer_vector[0]; |
@@ -556,18 +625,23 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { |
byte* body = buffer + sizes.header_size; |
// -- emit magic ------------------------------------------------------------- |
+ TRACE("emit magic\n"); |
EmitUint32(&header, kWasmMagic); |
EmitUint32(&header, kWasmVersion); |
// -- emit memory declaration ------------------------------------------------ |
- EmitUint8(&header, kDeclMemory); |
- EmitVarInt(&header, 16); // min memory size |
- EmitVarInt(&header, 16); // max memory size |
- EmitUint8(&header, 0); // memory export |
+ { |
+ byte* section = EmitSection(WasmSection::Code::Memory, &header); |
+ EmitVarInt(&header, 16); // min memory size |
+ EmitVarInt(&header, 16); // max memory size |
+ EmitUint8(&header, 0); // memory export |
+ static_assert(kDeclMemorySize == 3, "memory size must match emit above"); |
+ FixupSection(section, header); |
+ } |
// -- emit globals ----------------------------------------------------------- |
if (globals_.size() > 0) { |
- EmitUint8(&header, kDeclGlobals); |
+ byte* section = EmitSection(WasmSection::Code::Globals, &header); |
EmitVarInt(&header, globals_.size()); |
for (auto global : globals_) { |
@@ -575,11 +649,12 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { |
EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first)); |
EmitUint8(&header, global.second); |
} |
+ FixupSection(section, header); |
} |
// -- emit signatures -------------------------------------------------------- |
if (signatures_.size() > 0) { |
- EmitUint8(&header, kDeclSignatures); |
+ byte* section = EmitSection(WasmSection::Code::Signatures, &header); |
EmitVarInt(&header, signatures_.size()); |
for (FunctionSig* sig : signatures_) { |
@@ -593,45 +668,53 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { |
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j))); |
} |
} |
+ FixupSection(section, header); |
} |
// -- emit functions --------------------------------------------------------- |
if (functions_.size() > 0) { |
- EmitUint8(&header, kDeclFunctions); |
+ byte* section = EmitSection(WasmSection::Code::Functions, &header); |
EmitVarInt(&header, functions_.size()); |
for (auto func : functions_) { |
func->Serialize(buffer, &header, &body); |
} |
+ FixupSection(section, header); |
} |
// -- emit start function index ---------------------------------------------- |
if (start_function_index_ >= 0) { |
- EmitUint8(&header, kDeclStartFunction); |
+ byte* section = EmitSection(WasmSection::Code::StartFunction, &header); |
EmitVarInt(&header, start_function_index_); |
+ FixupSection(section, header); |
} |
// -- emit data segments ----------------------------------------------------- |
if (data_segments_.size() > 0) { |
- EmitUint8(&header, kDeclDataSegments); |
+ byte* section = EmitSection(WasmSection::Code::DataSegments, &header); |
EmitVarInt(&header, data_segments_.size()); |
for (auto segment : data_segments_) { |
segment->Serialize(buffer, &header, &body); |
} |
+ FixupSection(section, header); |
} |
// -- emit function table ---------------------------------------------------- |
if (indirect_functions_.size() > 0) { |
- EmitUint8(&header, kDeclFunctionTable); |
+ byte* section = EmitSection(WasmSection::Code::FunctionTable, &header); |
EmitVarInt(&header, indirect_functions_.size()); |
for (auto index : indirect_functions_) { |
EmitVarInt(&header, index); |
} |
+ FixupSection(section, header); |
} |
- if (sizes.body_size > 0) EmitUint8(&header, kDeclEnd); |
+ if (sizes.body_size > 0) { |
+ byte* section = EmitSection(WasmSection::Code::End, &header); |
+ FixupSection(section, header); |
+ } |
return new (zone) WasmModuleIndex(buffer, buffer + sizes.total()); |
} |