Commit abbdca94 authored by jfb's avatar jfb Committed by Commit bot

wasm: use strings for section names

This will require an equivalent sexpr-wasm change.

See:
https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#high-level-structure

R=titzer@chromium.org, binji@chronium.org

Review URL: https://codereview.chromium.org/1765843002

Cr-Commit-Position: refs/heads/master@{#34668}
parent 4bbd051a
......@@ -478,6 +478,7 @@ DEFINE_BOOL(turbo_stress_instruction_scheduling, false,
// Flags for native WebAssembly.
DEFINE_BOOL(expose_wasm, false, "expose WASM interface to JavaScript")
DEFINE_BOOL(trace_wasm_encoder, false, "trace encoding of wasm code")
DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code")
DEFINE_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code")
......
......@@ -303,6 +303,7 @@ class Decoder {
Result<T> toResult(T val) {
Result<T> result;
if (error_pc_) {
TRACE("Result error: %s\n", error_msg_.get());
result.error_code = kError;
result.start = start_;
result.error_pc = error_pc_;
......
......@@ -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());
}
......
This diff is collapsed.
......@@ -19,6 +19,36 @@ namespace v8 {
namespace internal {
namespace wasm {
static const char* wasmSections[] = {
#define F(enumerator, string) string,
FOR_EACH_WASM_SECTION_TYPE(F)
#undef F
};
static uint8_t wasmSectionsLengths[]{
#define F(enumerator, string) sizeof(string) - 1,
FOR_EACH_WASM_SECTION_TYPE(F)
#undef F
};
static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
(size_t)WasmSection::Code::Max,
"expected enum WasmSection::Code to be monotonic from 0");
WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
WasmSection::Code WasmSection::end() { return WasmSection::Code::Max; }
WasmSection::Code WasmSection::next(WasmSection::Code code) {
return (WasmSection::Code)(1 + (uint32_t)code);
}
const char* WasmSection::getName(WasmSection::Code code) {
return wasmSections[(size_t)code];
}
size_t WasmSection::getNameLength(WasmSection::Code code) {
return wasmSectionsLengths[(size_t)code];
}
std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
os << "WASM module with ";
os << (module.min_mem_pages * module.kPageSize) << " min mem";
......
......@@ -29,26 +29,72 @@ const uint32_t kWasmVersion = 0x0a;
// internally V8 uses an enum to handle them.
//
// Entries have the form F(enumerator, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(kDeclMemory, "memory") \
F(kDeclSignatures, "signatures") \
F(kDeclFunctions, "functions") \
F(kDeclGlobals, "globals") \
F(kDeclDataSegments, "data_segments") \
F(kDeclFunctionTable, "function_table") \
F(kDeclEnd, "end") \
F(kDeclStartFunction, "start_function") \
F(kDeclImportTable, "import_table") \
F(kDeclExportTable, "export_table") \
F(kDeclFunctionSignatures, "function_signatures") \
F(kDeclFunctionBodies, "function_bodies") \
F(kDeclNames, "names")
enum WasmSectionDeclCode : uint32_t {
#define FOR_EACH_WASM_SECTION_TYPE(F) \
F(Memory, "memory") \
F(Signatures, "signatures") \
F(Functions, "functions") \
F(Globals, "globals") \
F(DataSegments, "data_segments") \
F(FunctionTable, "function_table") \
F(End, "end") \
F(StartFunction, "start_function") \
F(ImportTable, "import_table") \
F(ExportTable, "export_table") \
F(FunctionSignatures, "function_signatures") \
F(FunctionBodies, "function_bodies") \
F(Names, "names")
// Contants for the above section types: {LEB128 length, characters...}.
#define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y'
#define WASM_SECTION_SIGNATURES \
10, 's', 'i', 'g', 'n', 'a', 't', 'u', 'r', 'e', 's'
#define WASM_SECTION_FUNCTIONS 9, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', 's'
#define WASM_SECTION_GLOBALS 7, 'g', 'l', 'o', 'b', 'a', 'l', 's'
#define WASM_SECTION_DATA_SEGMENTS \
13, 'd', 'a', 't', 'a', '_', 's', 'e', 'g', 'm', 'e', 'n', 't', 's'
#define WASM_SECTION_FUNCTION_TABLE \
14, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 't', 'a', 'b', 'l', 'e'
#define WASM_SECTION_END 3, 'e', 'n', 'd'
#define WASM_SECTION_START_FUNCTION \
14, 's', 't', 'a', 'r', 't', '_', 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n'
#define WASM_SECTION_IMPORT_TABLE \
12, 'i', 'm', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
#define WASM_SECTION_EXPORT_TABLE \
12, 'e', 'x', 'p', 'o', 'r', 't', '_', 't', 'a', 'b', 'l', 'e'
#define WASM_SECTION_FUNCTION_SIGNATURES \
19, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 's', 'i', 'g', 'n', 'a', \
't', 'u', 'r', 'e', 's'
#define WASM_SECTION_FUNCTION_BODIES \
15, 'f', 'u', 'n', 'c', 't', 'i', 'o', 'n', '_', 'b', 'o', 'd', 'i', 'e', 's'
#define WASM_SECTION_NAMES 5, 'n', 'a', 'm', 'e', 's'
// Constants for the above section headers' size (LEB128 + characters).
#define WASM_SECTION_MEMORY_SIZE ((size_t)7)
#define WASM_SECTION_SIGNATURES_SIZE ((size_t)11)
#define WASM_SECTION_FUNCTIONS_SIZE ((size_t)10)
#define WASM_SECTION_GLOBALS_SIZE ((size_t)8)
#define WASM_SECTION_DATA_SEGMENTS_SIZE ((size_t)14)
#define WASM_SECTION_FUNCTION_TABLE_SIZE ((size_t)15)
#define WASM_SECTION_END_SIZE ((size_t)4)
#define WASM_SECTION_START_FUNCTION_SIZE ((size_t)15)
#define WASM_SECTION_IMPORT_TABLE_SIZE ((size_t)13)
#define WASM_SECTION_EXPORT_TABLE_SIZE ((size_t)13)
#define WASM_SECTION_FUNCTION_SIGNATURES_SIZE ((size_t)20)
#define WASM_SECTION_FUNCTION_BODIES_SIZE ((size_t)16)
#define WASM_SECTION_NAMES_SIZE ((size_t)6)
struct WasmSection {
enum class Code : uint32_t {
#define F(enumerator, string) enumerator,
FOR_EACH_WASM_SECTION_TYPE(F)
FOR_EACH_WASM_SECTION_TYPE(F)
#undef F
kMaxModuleSectionCode
Max
};
static WasmSection::Code begin();
static WasmSection::Code end();
static WasmSection::Code next(WasmSection::Code code);
static const char* getName(Code code);
static size_t getNameLength(Code code);
};
enum WasmFunctionDeclBit {
......
......@@ -38,15 +38,17 @@ TEST(Run_WasmModule_CallAdd_rev) {
static const byte data[] = {
WASM_MODULE_HEADER,
// sig#0 ------------------------------------------
kDeclSignatures, 2, 0, kLocalI32, // void -> int
2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int
WASM_SECTION_SIGNATURES_SIZE + 7, // Section size.
WASM_SECTION_SIGNATURES, 2, 0, kLocalI32, // void -> int
2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int
// func#0 (main) ----------------------------------
kDeclFunctions, 2, kDeclFunctionExport, 0, 0, // sig index
7, 0, // body size
0, // locals
kExprCallFunction, 1, // --
kExprI8Const, 77, // --
kExprI8Const, 22, // --
WASM_SECTION_FUNCTIONS_SIZE + 24, WASM_SECTION_FUNCTIONS, 2,
kDeclFunctionExport, 0, 0, // sig index
7, 0, // body size
0, // locals
kExprCallFunction, 1, // --
kExprI8Const, 77, // --
kExprI8Const, 22, // --
// func#1 -----------------------------------------
0, // no name, not exported
1, 0, // sig index
......
......@@ -57,14 +57,19 @@ var kDeclFunctions = 0x02;
var kDeclGlobals = 0x03;
var kDeclDataSegments = 0x04;
var kDeclFunctionTable = 0x05;
var kDeclEnd = 0x06;
var kDeclStartFunction = 0x07;
var kDeclImportTable = 0x08;
var kDeclExportTable = 0x09;
var kDeclEnd = 0x06;
var kDeclFunctionSignatures = 0x0a;
var kDeclFunctionBodies = 0x0b;
var kDeclNames = 0x0c;
var section_names = [
"memory", "signatures", "functions", "globals", "data_segments",
"function_table", "end", "start_function", "import_table", "export_table",
"function_signatures", "function_bodies", "names"];
// Function declaration flags
var kDeclFunctionName = 0x01;
var kDeclFunctionImport = 0x02;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment