Commit b3cf031e authored by titzer's avatar titzer Committed by Commit bot

[wasm] Enforce strict ordering of WASM module sections.

R=jfb@chromium.org,rossberg@chromium.org
BUG=

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

Cr-Commit-Position: refs/heads/master@{#35698}
parent 4a6a0f55
...@@ -59,16 +59,16 @@ void EmitVarInt(byte** b, size_t val) { ...@@ -59,16 +59,16 @@ void EmitVarInt(byte** b, size_t val) {
// We generate a large varint which we then fixup later when the size is known. // 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. // TODO(jfb) Not strictly necessary since sizes are calculated ahead of time.
const size_t padded_varint = 5; const size_t kPaddedVarintSize = 5;
void FixupSection(byte* start, byte* end) { void FixupSection(byte* start, byte* end) {
// Same as LEBHelper::write_u32v, but fixed-width with zeroes in the MSBs. // Same as LEBHelper::write_u32v, but fixed-width with zeroes in the MSBs.
size_t val = end - start - padded_varint; size_t val = end - start - kPaddedVarintSize;
TRACE(" fixup %u\n", (unsigned)val); TRACE(" fixup %u\n", (unsigned)val);
for (size_t pos = 0; pos != padded_varint; ++pos) { for (size_t pos = 0; pos != kPaddedVarintSize; ++pos) {
size_t next = val >> 7; size_t next = val >> 7;
byte out = static_cast<byte>(val & 0x7f); byte out = static_cast<byte>(val & 0x7f);
if (pos != padded_varint - 1) { if (pos != kPaddedVarintSize - 1) {
*(start++) = 0x80 | out; *(start++) = 0x80 | out;
val = next; val = next;
} else { } else {
...@@ -80,15 +80,18 @@ void FixupSection(byte* start, byte* end) { ...@@ -80,15 +80,18 @@ void FixupSection(byte* start, byte* end) {
// Returns the start of the section, where the section VarInt size is. // Returns the start of the section, where the section VarInt size is.
byte* EmitSection(WasmSection::Code code, byte** b) { byte* EmitSection(WasmSection::Code code, byte** b) {
// Emit a placeholder for the length.
byte* start = *b; byte* start = *b;
const char* name = WasmSection::getName(code); for (size_t padding = 0; padding != kPaddedVarintSize; ++padding) {
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. EmitUint8(b, 0xff); // Will get fixed up later.
} }
// Emit the section name.
const char* name = WasmSection::getName(code);
TRACE("emit section: %s\n", name);
size_t length = WasmSection::getNameLength(code);
EmitVarInt(b, length); // Section name string size. EmitVarInt(b, length); // Section name string size.
for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]); for (size_t i = 0; i != length; ++i) EmitUint8(b, name[i]);
return start; return start;
} }
} // namespace } // namespace
...@@ -548,7 +551,7 @@ struct Sizes { ...@@ -548,7 +551,7 @@ struct Sizes {
} }
void AddSection(WasmSection::Code code, size_t other_size) { void AddSection(WasmSection::Code code, size_t other_size) {
Add(padded_varint + Add(kPaddedVarintSize +
LEBHelper::sizeof_u32v(WasmSection::getNameLength(code)) + LEBHelper::sizeof_u32v(WasmSection::getNameLength(code)) +
WasmSection::getNameLength(code), WasmSection::getNameLength(code),
0); 0);
...@@ -561,11 +564,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -561,11 +564,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
sizes.Add(2 * sizeof(uint32_t), 0); // header sizes.Add(2 * sizeof(uint32_t), 0); // header
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);
if (globals_.size() > 0) { if (globals_.size() > 0) {
sizes.AddSection(WasmSection::Code::Globals, globals_.size()); sizes.AddSection(WasmSection::Code::Globals, globals_.size());
/* These globals never have names, so are always 3 bytes. */ /* These globals never have names, so are always 3 bytes. */
...@@ -595,6 +593,21 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -595,6 +593,21 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
(unsigned)sizes.body_size); (unsigned)sizes.body_size);
} }
if (indirect_functions_.size() > 0) {
sizes.AddSection(WasmSection::Code::FunctionTable,
indirect_functions_.size());
for (auto function_index : indirect_functions_) {
sizes.Add(LEBHelper::sizeof_u32v(function_index), 0);
}
TRACE("Size after indirect functions: %u, %u\n",
(unsigned)sizes.header_size, (unsigned)sizes.body_size);
}
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);
if (start_function_index_ >= 0) { if (start_function_index_ >= 0) {
sizes.AddSection(WasmSection::Code::StartFunction, 0); sizes.AddSection(WasmSection::Code::StartFunction, 0);
sizes.Add(LEBHelper::sizeof_u32v(start_function_index_), 0); sizes.Add(LEBHelper::sizeof_u32v(start_function_index_), 0);
...@@ -611,16 +624,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -611,16 +624,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
(unsigned)sizes.body_size); (unsigned)sizes.body_size);
} }
if (indirect_functions_.size() > 0) {
sizes.AddSection(WasmSection::Code::FunctionTable,
indirect_functions_.size());
for (auto function_index : indirect_functions_) {
sizes.Add(LEBHelper::sizeof_u32v(function_index), 0);
}
TRACE("Size after indirect functions: %u, %u\n",
(unsigned)sizes.header_size, (unsigned)sizes.body_size);
}
if (sizes.body_size > 0) { if (sizes.body_size > 0) {
sizes.AddSection(WasmSection::Code::End, 0); sizes.AddSection(WasmSection::Code::End, 0);
TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size, TRACE("Size after end: %u, %u\n", (unsigned)sizes.header_size,
...@@ -637,16 +640,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -637,16 +640,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
EmitUint32(&header, kWasmMagic); EmitUint32(&header, kWasmMagic);
EmitUint32(&header, kWasmVersion); EmitUint32(&header, kWasmVersion);
// -- emit memory declaration ------------------------------------------------
{
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 ----------------------------------------------------------- // -- emit globals -----------------------------------------------------------
if (globals_.size() > 0) { if (globals_.size() > 0) {
byte* section = EmitSection(WasmSection::Code::Globals, &header); byte* section = EmitSection(WasmSection::Code::Globals, &header);
...@@ -690,6 +683,27 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -690,6 +683,27 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
FixupSection(section, header); FixupSection(section, header);
} }
// -- emit function table ----------------------------------------------------
if (indirect_functions_.size() > 0) {
byte* section = EmitSection(WasmSection::Code::FunctionTable, &header);
EmitVarInt(&header, indirect_functions_.size());
for (auto index : indirect_functions_) {
EmitVarInt(&header, index);
}
FixupSection(section, header);
}
// -- emit memory declaration ------------------------------------------------
{
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 start function index ---------------------------------------------- // -- emit start function index ----------------------------------------------
if (start_function_index_ >= 0) { if (start_function_index_ >= 0) {
byte* section = EmitSection(WasmSection::Code::StartFunction, &header); byte* section = EmitSection(WasmSection::Code::StartFunction, &header);
...@@ -708,17 +722,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const { ...@@ -708,17 +722,6 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
FixupSection(section, header); FixupSection(section, header);
} }
// -- emit function table ----------------------------------------------------
if (indirect_functions_.size() > 0) {
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) { if (sizes.body_size > 0) {
byte* section = EmitSection(WasmSection::Code::End, &header); byte* section = EmitSection(WasmSection::Code::End, &header);
FixupSection(section, header); FixupSection(section, header);
......
...@@ -25,7 +25,6 @@ namespace wasm { ...@@ -25,7 +25,6 @@ namespace wasm {
#define TRACE(...) #define TRACE(...)
#endif #endif
// The main logic for decoding the bytes of a module. // The main logic for decoding the bytes of a module.
class ModuleDecoder : public Decoder { class ModuleDecoder : public Decoder {
public: public:
...@@ -79,9 +78,8 @@ class ModuleDecoder : public Decoder { ...@@ -79,9 +78,8 @@ class ModuleDecoder : public Decoder {
module->mem_external = false; module->mem_external = false;
module->origin = origin_; module->origin = origin_;
bool sections[(size_t)WasmSection::Code::Max] = {false};
const byte* pos = pc_; const byte* pos = pc_;
int current_order = 0;
uint32_t magic_word = consume_u32("wasm magic"); uint32_t magic_word = consume_u32("wasm magic");
#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff #define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
if (magic_word != kWasmMagic) { if (magic_word != kWasmMagic) {
...@@ -109,33 +107,37 @@ class ModuleDecoder : public Decoder { ...@@ -109,33 +107,37 @@ class ModuleDecoder : public Decoder {
TRACE("DecodeSection\n"); TRACE("DecodeSection\n");
pos = pc_; pos = pc_;
int length; // Read and check the section size.
uint32_t section_length = consume_u32v(&length, "section size"); int section_leb_length = 0;
uint32_t section_length =
int section_string_leb_length = 0; consume_u32v(&section_leb_length, "section length");
uint32_t section_string_length = 0; if (!checkAvailable(section_length)) {
WasmSection::Code section = consume_section_name( // The section would extend beyond the end of the module.
&section_string_leb_length, &section_string_length);
uint32_t string_and_leb_length =
section_string_leb_length + section_string_length;
if (string_and_leb_length > section_length) {
error(pos, pos,
"section string of size %u longer than total section bytes %u",
string_and_leb_length, section_length);
break; break;
} }
const byte* section_start = pc_;
if (section == WasmSection::Code::Max) { const byte* expected_section_end = pc_ + section_length;
// Skip unknown section.
uint32_t skip = section_length - string_and_leb_length; // Read the section name.
TRACE("skipping %u bytes from unknown section\n", skip); int string_leb_length = 0;
consume_bytes(skip); uint32_t string_length =
continue; consume_u32v(&string_leb_length, "section name length");
const byte* section_name_start = pc_;
consume_bytes(string_length);
if (failed()) {
TRACE("Section name of length %u couldn't be read\n", string_length);
break;
} }
if (pc_ > expected_section_end) {
error(section_name_start, pc_,
"section name string %u longer than total section bytes %u",
string_length, section_length);
}
WasmSection::Code section =
WasmSection::lookup(section_name_start, string_length);
// Each section should appear at most once. current_order = CheckSectionOrder(current_order, section);
CheckForPreviousSection(sections, section, false);
sections[(size_t)section] = true;
switch (section) { switch (section) {
case WasmSection::Code::End: case WasmSection::Code::End:
...@@ -163,9 +165,6 @@ class ModuleDecoder : public Decoder { ...@@ -163,9 +165,6 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::FunctionSignatures: { case WasmSection::Code::FunctionSignatures: {
// Functions require a signature table first.
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
true);
int length; int length;
uint32_t functions_count = consume_u32v(&length, "functions count"); uint32_t functions_count = consume_u32v(&length, "functions count");
module->functions.reserve(SafeReserve(functions_count)); module->functions.reserve(SafeReserve(functions_count));
...@@ -178,9 +177,6 @@ class ModuleDecoder : public Decoder { ...@@ -178,9 +177,6 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::FunctionBodies: { case WasmSection::Code::FunctionBodies: {
// Function bodies should follow signatures.
CheckForPreviousSection(sections,
WasmSection::Code::FunctionSignatures, true);
int length; int length;
const byte* pos = pc_; const byte* pos = pc_;
uint32_t functions_count = consume_u32v(&length, "functions count"); uint32_t functions_count = consume_u32v(&length, "functions count");
...@@ -207,9 +203,6 @@ class ModuleDecoder : public Decoder { ...@@ -207,9 +203,6 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::Functions: { case WasmSection::Code::Functions: {
// Functions require a signature table first.
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
true);
int length; int length;
uint32_t functions_count = consume_u32v(&length, "functions count"); uint32_t functions_count = consume_u32v(&length, "functions count");
module->functions.reserve(SafeReserve(functions_count)); module->functions.reserve(SafeReserve(functions_count));
...@@ -243,9 +236,6 @@ class ModuleDecoder : public Decoder { ...@@ -243,9 +236,6 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::Names: { case WasmSection::Code::Names: {
// Names correspond to functions.
CheckForPreviousSection(sections,
WasmSection::Code::FunctionSignatures, true);
int length; int length;
const byte* pos = pc_; const byte* pos = pc_;
uint32_t functions_count = consume_u32v(&length, "functions count"); uint32_t functions_count = consume_u32v(&length, "functions count");
...@@ -341,9 +331,6 @@ class ModuleDecoder : public Decoder { ...@@ -341,9 +331,6 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::ImportTable: { case WasmSection::Code::ImportTable: {
// Declares an import table.
CheckForPreviousSection(sections, WasmSection::Code::Signatures,
true);
int length; int length;
uint32_t import_table_count = uint32_t import_table_count =
consume_u32v(&length, "import table count"); consume_u32v(&length, "import table count");
...@@ -392,7 +379,25 @@ class ModuleDecoder : public Decoder { ...@@ -392,7 +379,25 @@ class ModuleDecoder : public Decoder {
break; break;
} }
case WasmSection::Code::Max: case WasmSection::Code::Max:
UNREACHABLE(); // Already skipped unknown sections. // Skip unknown sections.
TRACE("Unknown section: '");
for (uint32_t i = 0; i != string_length; ++i) {
TRACE("%c", *(section_name_start + i));
}
TRACE("'\n");
consume_bytes(section_length - string_length - string_leb_length);
break;
}
if (pc_ != expected_section_end) {
const char* diff = pc_ < expected_section_end ? "shorter" : "longer";
size_t expected_length = static_cast<size_t>(section_length);
size_t actual_length = static_cast<size_t>(pc_ - section_start);
error(pc_, pc_,
"section \"%s\" %s (%zu bytes) than specified (%zu bytes)",
WasmSection::getName(section), diff, actual_length,
expected_length);
break;
} }
} }
...@@ -417,17 +422,18 @@ class ModuleDecoder : public Decoder { ...@@ -417,17 +422,18 @@ class ModuleDecoder : public Decoder {
} }
} }
void CheckForPreviousSection(bool* sections, WasmSection::Code section, int CheckSectionOrder(int current_order, WasmSection::Code section) {
bool present) { int next_order = WasmSection::getOrder(section);
if (section >= WasmSection::Code::Max) return; if (next_order == 0) return current_order;
if (sections[(size_t)section] == present) return; if (next_order == current_order) {
if (present) { error(pc_, pc_, "section \"%s\" already defined",
error(pc_ - 1, nullptr, "required %s section missing",
WasmSection::getName(section)); WasmSection::getName(section));
} else { }
error(pc_ - 1, nullptr, "%s section already present", if (next_order < current_order) {
error(pc_, pc_, "section \"%s\" out of order",
WasmSection::getName(section)); WasmSection::getName(section));
} }
return next_order;
} }
// Decodes a single anonymous function starting at {start_}. // Decodes a single anonymous function starting at {start_}.
...@@ -643,30 +649,6 @@ class ModuleDecoder : public Decoder { ...@@ -643,30 +649,6 @@ class ModuleDecoder : public Decoder {
return func_index; return func_index;
} }
// Reads a section name.
WasmSection::Code consume_section_name(int* string_leb_length,
uint32_t* string_length) {
*string_length = consume_u32v(string_leb_length, "name length");
const byte* start = pc_;
consume_bytes(*string_length);
if (failed()) {
TRACE("Section name of length %u couldn't be read\n", *string_length);
return WasmSection::Code::Max;
}
// TODO(jfb) Linear search, it may be better to do a common-prefix search.
for (WasmSection::Code i = WasmSection::begin(); i != WasmSection::end();
i = WasmSection::next(i)) {
if (WasmSection::getNameLength(i) == *string_length &&
0 == memcmp(WasmSection::getName(i), start, *string_length)) {
return i;
}
}
TRACE("Unknown section: '");
for (uint32_t i = 0; i != *string_length; ++i) TRACE("%c", *(start + i));
TRACE("'\n");
return WasmSection::Code::Max;
}
// Reads a single 8-bit integer, interpreting it as a local type. // Reads a single 8-bit integer, interpreting it as a local type.
LocalType consume_local_type() { LocalType consume_local_type() {
byte val = consume_u8("local type"); byte val = consume_u8("local type");
......
...@@ -20,19 +20,28 @@ namespace internal { ...@@ -20,19 +20,28 @@ namespace internal {
namespace wasm { namespace wasm {
static const char* wasmSections[] = { static const char* wasmSections[] = {
#define F(enumerator, string) string, #define F(enumerator, order, string) string,
FOR_EACH_WASM_SECTION_TYPE(F) FOR_EACH_WASM_SECTION_TYPE(F)
#undef F #undef F
"<unknown>" // entry for "Max"
}; };
static uint8_t wasmSectionsLengths[]{ static uint8_t wasmSectionsLengths[]{
#define F(enumerator, string) sizeof(string) - 1, #define F(enumerator, order, string) sizeof(string) - 1,
FOR_EACH_WASM_SECTION_TYPE(F) FOR_EACH_WASM_SECTION_TYPE(F)
#undef F #undef F
9 // entry for "Max"
};
static uint8_t wasmSectionsOrders[]{
#define F(enumerator, order, string) order,
FOR_EACH_WASM_SECTION_TYPE(F)
#undef F
0 // entry for "Max"
}; };
static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) == static_assert(sizeof(wasmSections) / sizeof(wasmSections[0]) ==
(size_t)WasmSection::Code::Max, (size_t)WasmSection::Code::Max + 1,
"expected enum WasmSection::Code to be monotonic from 0"); "expected enum WasmSection::Code to be monotonic from 0");
WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; } WasmSection::Code WasmSection::begin() { return (WasmSection::Code)0; }
...@@ -49,6 +58,20 @@ size_t WasmSection::getNameLength(WasmSection::Code code) { ...@@ -49,6 +58,20 @@ size_t WasmSection::getNameLength(WasmSection::Code code) {
return wasmSectionsLengths[(size_t)code]; return wasmSectionsLengths[(size_t)code];
} }
int WasmSection::getOrder(WasmSection::Code code) {
return wasmSectionsOrders[(size_t)code];
}
WasmSection::Code WasmSection::lookup(const byte* string, uint32_t length) {
// TODO(jfb) Linear search, it may be better to do a common-prefix search.
for (Code i = begin(); i != end(); i = next(i)) {
if (getNameLength(i) == length && 0 == memcmp(getName(i), string, length)) {
return i;
}
}
return Code::Max;
}
std::ostream& operator<<(std::ostream& os, const WasmModule& module) { std::ostream& operator<<(std::ostream& os, const WasmModule& module) {
os << "WASM module with "; os << "WASM module with ";
os << (module.min_mem_pages * module.kPageSize) << " min mem"; os << (module.min_mem_pages * module.kPageSize) << " min mem";
......
...@@ -28,21 +28,21 @@ const uint32_t kWasmVersion = 0x0a; ...@@ -28,21 +28,21 @@ const uint32_t kWasmVersion = 0x0a;
// WebAssembly sections are named as strings in the binary format, but // WebAssembly sections are named as strings in the binary format, but
// internally V8 uses an enum to handle them. // internally V8 uses an enum to handle them.
// //
// Entries have the form F(enumerator, string). // Entries have the form F(enumerator, order, string).
#define FOR_EACH_WASM_SECTION_TYPE(F) \ #define FOR_EACH_WASM_SECTION_TYPE(F) \
F(Memory, "memory") \ F(Signatures, 1, "signatures") \
F(Signatures, "signatures") \ F(ImportTable, 2, "import_table") \
F(Functions, "functions") \ F(FunctionSignatures, 3, "function_signatures") \
F(Globals, "globals") \ F(FunctionTable, 4, "function_table") \
F(DataSegments, "data_segments") \ F(Memory, 5, "memory") \
F(FunctionTable, "function_table") \ F(ExportTable, 6, "export_table") \
F(End, "end") \ F(StartFunction, 7, "start_function") \
F(StartFunction, "start_function") \ F(FunctionBodies, 8, "function_bodies") \
F(ImportTable, "import_table") \ F(DataSegments, 9, "data_segments") \
F(ExportTable, "export_table") \ F(Names, 10, "names") \
F(FunctionSignatures, "function_signatures") \ F(Globals, 0, "globals") \
F(FunctionBodies, "function_bodies") \ F(Functions, 0, "functions") \
F(Names, "names") F(End, 0, "end")
// Contants for the above section types: {LEB128 length, characters...}. // Contants for the above section types: {LEB128 length, characters...}.
#define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y' #define WASM_SECTION_MEMORY 6, 'm', 'e', 'm', 'o', 'r', 'y'
...@@ -85,7 +85,7 @@ const uint32_t kWasmVersion = 0x0a; ...@@ -85,7 +85,7 @@ const uint32_t kWasmVersion = 0x0a;
struct WasmSection { struct WasmSection {
enum class Code : uint32_t { enum class Code : uint32_t {
#define F(enumerator, string) enumerator, #define F(enumerator, order, string) enumerator,
FOR_EACH_WASM_SECTION_TYPE(F) FOR_EACH_WASM_SECTION_TYPE(F)
#undef F #undef F
Max Max
...@@ -94,7 +94,9 @@ struct WasmSection { ...@@ -94,7 +94,9 @@ struct WasmSection {
static WasmSection::Code end(); static WasmSection::Code end();
static WasmSection::Code next(WasmSection::Code code); static WasmSection::Code next(WasmSection::Code code);
static const char* getName(Code code); static const char* getName(Code code);
static int getOrder(Code code);
static size_t getNameLength(Code code); static size_t getNameLength(Code code);
static WasmSection::Code lookup(const byte* string, uint32_t length);
}; };
enum WasmFunctionDeclBit { enum WasmFunctionDeclBit {
......
...@@ -149,16 +149,6 @@ WasmModuleBuilder.prototype.toArray = function(debug) { ...@@ -149,16 +149,6 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
var wasm = this; var wasm = this;
// Add memory section
if (wasm.memory != undefined) {
if (debug) print("emitting memory @ " + bytes.length);
emit_section(bytes, kDeclMemory, function(bytes) {
emit_varint(bytes, wasm.memory.min);
emit_varint(bytes, wasm.memory.max);
emit_u8(bytes, wasm.memory.exp ? 1 : 0);
});
}
// Add signatures section // Add signatures section
if (wasm.signatures.length > 0) { if (wasm.signatures.length > 0) {
if (debug) print("emitting signatures @ " + bytes.length); if (debug) print("emitting signatures @ " + bytes.length);
...@@ -187,7 +177,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) { ...@@ -187,7 +177,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
}); });
} }
// Add functions section // Add functions declarations
var names = false; var names = false;
var exports = 0; var exports = 0;
if (wasm.functions.length > 0) { if (wasm.functions.length > 0) {
...@@ -206,6 +196,54 @@ WasmModuleBuilder.prototype.toArray = function(debug) { ...@@ -206,6 +196,54 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
} }
}); });
}
// Add function table.
if (wasm.function_table.length > 0) {
if (debug) print("emitting function table @ " + bytes.length);
emit_section(bytes, kDeclFunctionTable, function(bytes) {
emit_varint(bytes, wasm.function_table.length);
for (index of wasm.function_table) {
emit_varint(bytes, index);
}
});
}
// Add memory section
if (wasm.memory != undefined) {
if (debug) print("emitting memory @ " + bytes.length);
emit_section(bytes, kDeclMemory, function(bytes) {
emit_varint(bytes, wasm.memory.min);
emit_varint(bytes, wasm.memory.max);
emit_u8(bytes, wasm.memory.exp ? 1 : 0);
});
}
// Add export table.
if (exports > 0) {
if (debug) print("emitting exports @ " + bytes.length);
emit_section(bytes, kDeclExportTable, function(bytes) {
emit_varint(bytes, exports);
for (func of wasm.functions) {
for (exp of func.exports) {
emit_varint(bytes, func.index);
emit_string(bytes, exp);
}
}
});
}
// Add start function section.
if (wasm.start_index != undefined) {
if (debug) print("emitting start function @ " + bytes.length);
emit_section(bytes, kDeclStartFunction, function(bytes) {
emit_varint(bytes, wasm.start_index);
});
}
// Add function bodies.
if (wasm.functions.length > 0) {
// emit function bodies // emit function bodies
if (debug) print("emitting function bodies @ " + bytes.length); if (debug) print("emitting function bodies @ " + bytes.length);
emit_section(bytes, kDeclFunctionBodies, function(bytes) { emit_section(bytes, kDeclFunctionBodies, function(bytes) {
...@@ -244,50 +282,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) { ...@@ -244,50 +282,7 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
}); });
} }
// emit function names // Add data segments.
if (has_names) {
if (debug) print("emitting names @ " + bytes.length);
emit_section(bytes, kDeclNames, function(bytes) {
emit_varint(bytes, wasm.functions.length);
for (func of wasm.functions) {
var name = func.name == undefined ? "" : func.name;
emit_string(bytes, name);
emit_u8(bytes, 0); // local names count == 0
}
});
}
// Add start function section.
if (wasm.start_index != undefined) {
if (debug) print("emitting start function @ " + bytes.length);
emit_section(bytes, kDeclStartFunction, function(bytes) {
emit_varint(bytes, wasm.start_index);
});
}
if (wasm.function_table.length > 0) {
if (debug) print("emitting function table @ " + bytes.length);
emit_section(bytes, kDeclFunctionTable, function(bytes) {
emit_varint(bytes, wasm.function_table.length);
for (index of wasm.function_table) {
emit_varint(bytes, index);
}
});
}
if (exports > 0) {
if (debug) print("emitting exports @ " + bytes.length);
emit_section(bytes, kDeclExportTable, function(bytes) {
emit_varint(bytes, exports);
for (func of wasm.functions) {
for (exp of func.exports) {
emit_varint(bytes, func.index);
emit_string(bytes, exp);
}
}
});
}
if (wasm.data_segments.length > 0) { if (wasm.data_segments.length > 0) {
if (debug) print("emitting data segments @ " + bytes.length); if (debug) print("emitting data segments @ " + bytes.length);
emit_section(bytes, kDeclDataSegments, function(bytes) { emit_section(bytes, kDeclDataSegments, function(bytes) {
...@@ -300,12 +295,25 @@ WasmModuleBuilder.prototype.toArray = function(debug) { ...@@ -300,12 +295,25 @@ WasmModuleBuilder.prototype.toArray = function(debug) {
}); });
} }
// Emit any explicitly added sections // Add any explicitly added sections
for (exp of wasm.explicit) { for (exp of wasm.explicit) {
if (debug) print("emitting explicit @ " + bytes.length); if (debug) print("emitting explicit @ " + bytes.length);
emit_bytes(bytes, exp); emit_bytes(bytes, exp);
} }
// Add function names.
if (has_names) {
if (debug) print("emitting names @ " + bytes.length);
emit_section(bytes, kDeclNames, function(bytes) {
emit_varint(bytes, wasm.functions.length);
for (func of wasm.functions) {
var name = func.name == undefined ? "" : func.name;
emit_string(bytes, name);
emit_u8(bytes, 0); // local names count == 0
}
});
}
// End the module. // End the module.
if (debug) print("emitting end @ " + bytes.length); if (debug) print("emitting end @ " + bytes.length);
emit_section(bytes, kDeclEnd, function(bytes) {}); emit_section(bytes, kDeclEnd, function(bytes) {});
......
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