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}
This commit is contained in:
parent
4bbd051acc
commit
abbdca947f
@ -478,6 +478,7 @@ DEFINE_BOOL(turbo_stress_instruction_scheduling, false,
|
|||||||
|
|
||||||
// Flags for native WebAssembly.
|
// Flags for native WebAssembly.
|
||||||
DEFINE_BOOL(expose_wasm, false, "expose WASM interface to JavaScript")
|
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_decoder, false, "trace decoding of wasm code")
|
||||||
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time 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")
|
DEFINE_BOOL(trace_wasm_compiler, false, "trace compiling of wasm code")
|
||||||
|
@ -303,6 +303,7 @@ class Decoder {
|
|||||||
Result<T> toResult(T val) {
|
Result<T> toResult(T val) {
|
||||||
Result<T> result;
|
Result<T> result;
|
||||||
if (error_pc_) {
|
if (error_pc_) {
|
||||||
|
TRACE("Result error: %s\n", error_msg_.get());
|
||||||
result.error_code = kError;
|
result.error_code = kError;
|
||||||
result.start = start_;
|
result.start = start_;
|
||||||
result.error_pc = error_pc_;
|
result.error_pc = error_pc_;
|
||||||
|
@ -16,6 +16,15 @@
|
|||||||
|
|
||||||
#include "src/v8memory.h"
|
#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 v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
namespace wasm {
|
namespace wasm {
|
||||||
@ -41,6 +50,11 @@ void EmitUint32(byte** b, uint32_t x) {
|
|||||||
*b += 4;
|
*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) {
|
void EmitVarInt(byte** b, size_t val) {
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -65,8 +79,37 @@ size_t SizeOfVarInt(size_t value) {
|
|||||||
return size;
|
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 {
|
struct WasmFunctionBuilder::Type {
|
||||||
bool param_;
|
bool param_;
|
||||||
@ -498,57 +541,83 @@ struct Sizes {
|
|||||||
body_size += body;
|
body_size += body;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddSection(size_t size) {
|
void AddSection(WasmSection::Code code, size_t other_size) {
|
||||||
if (size > 0) {
|
Add(padded_varint + SizeOfVarInt(WasmSection::getNameLength(code)) +
|
||||||
Add(1, 0);
|
WasmSection::getNameLength(code),
|
||||||
Add(SizeOfVarInt(size), 0);
|
0);
|
||||||
}
|
if (other_size) Add(SizeOfVarInt(other_size), 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
||||||
Sizes sizes = {0, 0};
|
Sizes sizes = {0, 0};
|
||||||
|
|
||||||
sizes.Add(2 * sizeof(uint32_t), 0); // header
|
sizes.Add(2 * sizeof(uint32_t), 0); // header
|
||||||
|
|
||||||
sizes.Add(1, 0);
|
sizes.AddSection(WasmSection::Code::Memory, 0);
|
||||||
sizes.Add(kDeclMemorySize, 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) {
|
if (globals_.size() > 0) {
|
||||||
|
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. */
|
||||||
sizes.Add(3 * globals_.size(), 0);
|
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());
|
if (signatures_.size() > 0) {
|
||||||
for (auto function : functions_) {
|
sizes.AddSection(WasmSection::Code::Signatures, signatures_.size());
|
||||||
sizes.Add(function->HeaderSize() + function->BodySize(),
|
for (auto sig : signatures_) {
|
||||||
function->NameSize());
|
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) {
|
if (start_function_index_ >= 0) {
|
||||||
sizes.Add(1, 0);
|
sizes.AddSection(WasmSection::Code::StartFunction, 0);
|
||||||
sizes.Add(SizeOfVarInt(start_function_index_), 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());
|
if (data_segments_.size() > 0) {
|
||||||
for (auto segment : data_segments_) {
|
sizes.AddSection(WasmSection::Code::DataSegments, data_segments_.size());
|
||||||
sizes.Add(segment->HeaderSize(), segment->BodySize());
|
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());
|
if (indirect_functions_.size() > 0) {
|
||||||
for (auto function_index : indirect_functions_) {
|
sizes.AddSection(WasmSection::Code::FunctionTable,
|
||||||
sizes.Add(SizeOfVarInt(function_index), 0);
|
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);
|
ZoneVector<uint8_t> buffer_vector(sizes.total(), zone);
|
||||||
byte* buffer = &buffer_vector[0];
|
byte* buffer = &buffer_vector[0];
|
||||||
@ -556,18 +625,23 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
|||||||
byte* body = buffer + sizes.header_size;
|
byte* body = buffer + sizes.header_size;
|
||||||
|
|
||||||
// -- emit magic -------------------------------------------------------------
|
// -- emit magic -------------------------------------------------------------
|
||||||
|
TRACE("emit magic\n");
|
||||||
EmitUint32(&header, kWasmMagic);
|
EmitUint32(&header, kWasmMagic);
|
||||||
EmitUint32(&header, kWasmVersion);
|
EmitUint32(&header, kWasmVersion);
|
||||||
|
|
||||||
// -- emit memory declaration ------------------------------------------------
|
// -- emit memory declaration ------------------------------------------------
|
||||||
EmitUint8(&header, kDeclMemory);
|
{
|
||||||
EmitVarInt(&header, 16); // min memory size
|
byte* section = EmitSection(WasmSection::Code::Memory, &header);
|
||||||
EmitVarInt(&header, 16); // max memory size
|
EmitVarInt(&header, 16); // min memory size
|
||||||
EmitUint8(&header, 0); // memory export
|
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) {
|
||||||
EmitUint8(&header, kDeclGlobals);
|
byte* section = EmitSection(WasmSection::Code::Globals, &header);
|
||||||
EmitVarInt(&header, globals_.size());
|
EmitVarInt(&header, globals_.size());
|
||||||
|
|
||||||
for (auto global : globals_) {
|
for (auto global : globals_) {
|
||||||
@ -575,11 +649,12 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
|||||||
EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
|
EmitUint8(&header, WasmOpcodes::MemTypeCodeFor(global.first));
|
||||||
EmitUint8(&header, global.second);
|
EmitUint8(&header, global.second);
|
||||||
}
|
}
|
||||||
|
FixupSection(section, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- emit signatures --------------------------------------------------------
|
// -- emit signatures --------------------------------------------------------
|
||||||
if (signatures_.size() > 0) {
|
if (signatures_.size() > 0) {
|
||||||
EmitUint8(&header, kDeclSignatures);
|
byte* section = EmitSection(WasmSection::Code::Signatures, &header);
|
||||||
EmitVarInt(&header, signatures_.size());
|
EmitVarInt(&header, signatures_.size());
|
||||||
|
|
||||||
for (FunctionSig* sig : signatures_) {
|
for (FunctionSig* sig : signatures_) {
|
||||||
@ -593,45 +668,53 @@ WasmModuleIndex* WasmModuleWriter::WriteTo(Zone* zone) const {
|
|||||||
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
|
EmitUint8(&header, WasmOpcodes::LocalTypeCodeFor(sig->GetParam(j)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FixupSection(section, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- emit functions ---------------------------------------------------------
|
// -- emit functions ---------------------------------------------------------
|
||||||
if (functions_.size() > 0) {
|
if (functions_.size() > 0) {
|
||||||
EmitUint8(&header, kDeclFunctions);
|
byte* section = EmitSection(WasmSection::Code::Functions, &header);
|
||||||
EmitVarInt(&header, functions_.size());
|
EmitVarInt(&header, functions_.size());
|
||||||
|
|
||||||
for (auto func : functions_) {
|
for (auto func : functions_) {
|
||||||
func->Serialize(buffer, &header, &body);
|
func->Serialize(buffer, &header, &body);
|
||||||
}
|
}
|
||||||
|
FixupSection(section, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- emit start function index ----------------------------------------------
|
// -- emit start function index ----------------------------------------------
|
||||||
if (start_function_index_ >= 0) {
|
if (start_function_index_ >= 0) {
|
||||||
EmitUint8(&header, kDeclStartFunction);
|
byte* section = EmitSection(WasmSection::Code::StartFunction, &header);
|
||||||
EmitVarInt(&header, start_function_index_);
|
EmitVarInt(&header, start_function_index_);
|
||||||
|
FixupSection(section, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- emit data segments -----------------------------------------------------
|
// -- emit data segments -----------------------------------------------------
|
||||||
if (data_segments_.size() > 0) {
|
if (data_segments_.size() > 0) {
|
||||||
EmitUint8(&header, kDeclDataSegments);
|
byte* section = EmitSection(WasmSection::Code::DataSegments, &header);
|
||||||
EmitVarInt(&header, data_segments_.size());
|
EmitVarInt(&header, data_segments_.size());
|
||||||
|
|
||||||
for (auto segment : data_segments_) {
|
for (auto segment : data_segments_) {
|
||||||
segment->Serialize(buffer, &header, &body);
|
segment->Serialize(buffer, &header, &body);
|
||||||
}
|
}
|
||||||
|
FixupSection(section, header);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- emit function table ----------------------------------------------------
|
// -- emit function table ----------------------------------------------------
|
||||||
if (indirect_functions_.size() > 0) {
|
if (indirect_functions_.size() > 0) {
|
||||||
EmitUint8(&header, kDeclFunctionTable);
|
byte* section = EmitSection(WasmSection::Code::FunctionTable, &header);
|
||||||
EmitVarInt(&header, indirect_functions_.size());
|
EmitVarInt(&header, indirect_functions_.size());
|
||||||
|
|
||||||
for (auto index : indirect_functions_) {
|
for (auto index : indirect_functions_) {
|
||||||
EmitVarInt(&header, index);
|
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());
|
return new (zone) WasmModuleIndex(buffer, buffer + sizes.total());
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
module->mem_external = false;
|
module->mem_external = false;
|
||||||
module->origin = origin_;
|
module->origin = origin_;
|
||||||
|
|
||||||
bool sections[kMaxModuleSectionCode] = {false};
|
bool sections[(size_t)WasmSection::Code::Max] = {false};
|
||||||
|
|
||||||
const byte* pos = pc_;
|
const byte* pos = pc_;
|
||||||
uint32_t magic_word = consume_u32("wasm magic");
|
uint32_t magic_word = consume_u32("wasm magic");
|
||||||
@ -77,33 +77,48 @@ class ModuleDecoder : public Decoder {
|
|||||||
// Decode the module sections.
|
// Decode the module sections.
|
||||||
while (pc_ < limit_) {
|
while (pc_ < limit_) {
|
||||||
TRACE("DecodeSection\n");
|
TRACE("DecodeSection\n");
|
||||||
uint8_t section_u8 = consume_u8("section");
|
pos = pc_;
|
||||||
|
|
||||||
if (section_u8 >= kMaxModuleSectionCode) {
|
int length;
|
||||||
|
uint32_t section_length = consume_u32v(&length, "section size");
|
||||||
|
|
||||||
|
int section_string_leb_length = 0;
|
||||||
|
uint32_t section_string_length = 0;
|
||||||
|
WasmSection::Code section = consume_section_name(
|
||||||
|
§ion_string_leb_length, §ion_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section == WasmSection::Code::Max) {
|
||||||
// Skip unknown section.
|
// Skip unknown section.
|
||||||
int length;
|
uint32_t skip = section_length - string_and_leb_length;
|
||||||
uint32_t section_bytes = consume_u32v(&length, "section size");
|
TRACE("skipping %u bytes from unknown section\n", skip);
|
||||||
consume_bytes(section_bytes);
|
consume_bytes(skip);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each section should appear at most once.
|
// Each section should appear at most once.
|
||||||
auto section = static_cast<WasmSectionDeclCode>(section_u8);
|
|
||||||
CheckForPreviousSection(sections, section, false);
|
CheckForPreviousSection(sections, section, false);
|
||||||
sections[section] = true;
|
sections[(size_t)section] = true;
|
||||||
|
|
||||||
switch (section) {
|
switch (section) {
|
||||||
case kDeclEnd:
|
case WasmSection::Code::End:
|
||||||
// Terminate section decoding.
|
// Terminate section decoding.
|
||||||
limit_ = pc_;
|
limit_ = pc_;
|
||||||
break;
|
break;
|
||||||
case kDeclMemory:
|
case WasmSection::Code::Memory:
|
||||||
int length;
|
int length;
|
||||||
module->min_mem_pages = consume_u32v(&length, "min memory");
|
module->min_mem_pages = consume_u32v(&length, "min memory");
|
||||||
module->max_mem_pages = consume_u32v(&length, "max memory");
|
module->max_mem_pages = consume_u32v(&length, "max memory");
|
||||||
module->mem_export = consume_u8("export memory") != 0;
|
module->mem_export = consume_u8("export memory") != 0;
|
||||||
break;
|
break;
|
||||||
case kDeclSignatures: {
|
case WasmSection::Code::Signatures: {
|
||||||
int length;
|
int length;
|
||||||
uint32_t signatures_count = consume_u32v(&length, "signatures count");
|
uint32_t signatures_count = consume_u32v(&length, "signatures count");
|
||||||
module->signatures.reserve(SafeReserve(signatures_count));
|
module->signatures.reserve(SafeReserve(signatures_count));
|
||||||
@ -117,9 +132,10 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclFunctionSignatures: {
|
case WasmSection::Code::FunctionSignatures: {
|
||||||
// Functions require a signature table first.
|
// Functions require a signature table first.
|
||||||
CheckForPreviousSection(sections, kDeclSignatures, true);
|
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));
|
||||||
@ -131,9 +147,10 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclFunctionBodies: {
|
case WasmSection::Code::FunctionBodies: {
|
||||||
// Function bodies should follow signatures.
|
// Function bodies should follow signatures.
|
||||||
CheckForPreviousSection(sections, kDeclFunctionSignatures, true);
|
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");
|
||||||
@ -159,9 +176,10 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclFunctions: {
|
case WasmSection::Code::Functions: {
|
||||||
// Functions require a signature table first.
|
// Functions require a signature table first.
|
||||||
CheckForPreviousSection(sections, kDeclSignatures, true);
|
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));
|
||||||
@ -194,9 +212,10 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclNames: {
|
case WasmSection::Code::Names: {
|
||||||
// Names correspond to functions.
|
// Names correspond to functions.
|
||||||
CheckForPreviousSection(sections, kDeclFunctionSignatures, true);
|
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");
|
||||||
@ -223,7 +242,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclGlobals: {
|
case WasmSection::Code::Globals: {
|
||||||
int length;
|
int length;
|
||||||
uint32_t globals_count = consume_u32v(&length, "globals count");
|
uint32_t globals_count = consume_u32v(&length, "globals count");
|
||||||
module->globals.reserve(SafeReserve(globals_count));
|
module->globals.reserve(SafeReserve(globals_count));
|
||||||
@ -238,7 +257,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclDataSegments: {
|
case WasmSection::Code::DataSegments: {
|
||||||
int length;
|
int length;
|
||||||
uint32_t data_segments_count =
|
uint32_t data_segments_count =
|
||||||
consume_u32v(&length, "data segments count");
|
consume_u32v(&length, "data segments count");
|
||||||
@ -254,7 +273,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclFunctionTable: {
|
case WasmSection::Code::FunctionTable: {
|
||||||
// An indirect function table requires functions first.
|
// An indirect function table requires functions first.
|
||||||
CheckForFunctions(module, section);
|
CheckForFunctions(module, section);
|
||||||
int length;
|
int length;
|
||||||
@ -275,7 +294,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclStartFunction: {
|
case WasmSection::Code::StartFunction: {
|
||||||
// Declares a start function for a module.
|
// Declares a start function for a module.
|
||||||
CheckForFunctions(module, section);
|
CheckForFunctions(module, section);
|
||||||
if (module->start_function_index >= 0) {
|
if (module->start_function_index >= 0) {
|
||||||
@ -291,9 +310,10 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclImportTable: {
|
case WasmSection::Code::ImportTable: {
|
||||||
// Declares an import table.
|
// Declares an import table.
|
||||||
CheckForPreviousSection(sections, kDeclSignatures, true);
|
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");
|
||||||
@ -319,7 +339,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kDeclExportTable: {
|
case WasmSection::Code::ExportTable: {
|
||||||
// Declares an export table.
|
// Declares an export table.
|
||||||
CheckForFunctions(module, section);
|
CheckForFunctions(module, section);
|
||||||
int length;
|
int length;
|
||||||
@ -341,7 +361,7 @@ class ModuleDecoder : public Decoder {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case kMaxModuleSectionCode:
|
case WasmSection::Code::Max:
|
||||||
UNREACHABLE(); // Already skipped unknown sections.
|
UNREACHABLE(); // Already skipped unknown sections.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -355,41 +375,23 @@ class ModuleDecoder : public Decoder {
|
|||||||
return count < kMaxReserve ? count : kMaxReserve;
|
return count < kMaxReserve ? count : kMaxReserve;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* SectionName(WasmSectionDeclCode section) {
|
void CheckForFunctions(WasmModule* module, WasmSection::Code section) {
|
||||||
switch (section) {
|
|
||||||
case kDeclMemory:
|
|
||||||
return "memory";
|
|
||||||
case kDeclSignatures:
|
|
||||||
return "signatures";
|
|
||||||
case kDeclFunctions:
|
|
||||||
return "function declaration";
|
|
||||||
case kDeclGlobals:
|
|
||||||
return "global variable";
|
|
||||||
case kDeclDataSegments:
|
|
||||||
return "data segment";
|
|
||||||
case kDeclFunctionTable:
|
|
||||||
return "function table";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckForFunctions(WasmModule* module, WasmSectionDeclCode section) {
|
|
||||||
if (module->functions.size() == 0) {
|
if (module->functions.size() == 0) {
|
||||||
error(pc_ - 1, nullptr, "functions must appear before section %s",
|
error(pc_ - 1, nullptr, "functions must appear before section %s",
|
||||||
SectionName(section));
|
WasmSection::getName(section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section,
|
void CheckForPreviousSection(bool* sections, WasmSection::Code section,
|
||||||
bool present) {
|
bool present) {
|
||||||
if (section >= kMaxModuleSectionCode) return;
|
if (section >= WasmSection::Code::Max) return;
|
||||||
if (sections[section] == present) return;
|
if (sections[(size_t)section] == present) return;
|
||||||
const char* name = SectionName(section);
|
|
||||||
if (present) {
|
if (present) {
|
||||||
error(pc_ - 1, nullptr, "required %s section missing", name);
|
error(pc_ - 1, nullptr, "required %s section missing",
|
||||||
|
WasmSection::getName(section));
|
||||||
} else {
|
} else {
|
||||||
error(pc_ - 1, nullptr, "%s section already present", name);
|
error(pc_ - 1, nullptr, "%s section already present",
|
||||||
|
WasmSection::getName(section));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -606,6 +608,30 @@ 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");
|
||||||
|
@ -19,6 +19,36 @@ namespace v8 {
|
|||||||
namespace internal {
|
namespace internal {
|
||||||
namespace wasm {
|
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) {
|
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";
|
||||||
|
@ -29,26 +29,72 @@ const uint32_t kWasmVersion = 0x0a;
|
|||||||
// 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, string).
|
||||||
#define FOR_EACH_WASM_SECTION_TYPE(F) \
|
#define FOR_EACH_WASM_SECTION_TYPE(F) \
|
||||||
F(kDeclMemory, "memory") \
|
F(Memory, "memory") \
|
||||||
F(kDeclSignatures, "signatures") \
|
F(Signatures, "signatures") \
|
||||||
F(kDeclFunctions, "functions") \
|
F(Functions, "functions") \
|
||||||
F(kDeclGlobals, "globals") \
|
F(Globals, "globals") \
|
||||||
F(kDeclDataSegments, "data_segments") \
|
F(DataSegments, "data_segments") \
|
||||||
F(kDeclFunctionTable, "function_table") \
|
F(FunctionTable, "function_table") \
|
||||||
F(kDeclEnd, "end") \
|
F(End, "end") \
|
||||||
F(kDeclStartFunction, "start_function") \
|
F(StartFunction, "start_function") \
|
||||||
F(kDeclImportTable, "import_table") \
|
F(ImportTable, "import_table") \
|
||||||
F(kDeclExportTable, "export_table") \
|
F(ExportTable, "export_table") \
|
||||||
F(kDeclFunctionSignatures, "function_signatures") \
|
F(FunctionSignatures, "function_signatures") \
|
||||||
F(kDeclFunctionBodies, "function_bodies") \
|
F(FunctionBodies, "function_bodies") \
|
||||||
F(kDeclNames, "names")
|
F(Names, "names")
|
||||||
|
|
||||||
enum WasmSectionDeclCode : uint32_t {
|
// 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,
|
#define F(enumerator, string) enumerator,
|
||||||
FOR_EACH_WASM_SECTION_TYPE(F)
|
FOR_EACH_WASM_SECTION_TYPE(F)
|
||||||
#undef 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 {
|
enum WasmFunctionDeclBit {
|
||||||
|
@ -38,15 +38,17 @@ TEST(Run_WasmModule_CallAdd_rev) {
|
|||||||
static const byte data[] = {
|
static const byte data[] = {
|
||||||
WASM_MODULE_HEADER,
|
WASM_MODULE_HEADER,
|
||||||
// sig#0 ------------------------------------------
|
// sig#0 ------------------------------------------
|
||||||
kDeclSignatures, 2, 0, kLocalI32, // void -> int
|
WASM_SECTION_SIGNATURES_SIZE + 7, // Section size.
|
||||||
2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int
|
WASM_SECTION_SIGNATURES, 2, 0, kLocalI32, // void -> int
|
||||||
|
2, kLocalI32, kLocalI32, kLocalI32, // int,int -> int
|
||||||
// func#0 (main) ----------------------------------
|
// func#0 (main) ----------------------------------
|
||||||
kDeclFunctions, 2, kDeclFunctionExport, 0, 0, // sig index
|
WASM_SECTION_FUNCTIONS_SIZE + 24, WASM_SECTION_FUNCTIONS, 2,
|
||||||
7, 0, // body size
|
kDeclFunctionExport, 0, 0, // sig index
|
||||||
0, // locals
|
7, 0, // body size
|
||||||
kExprCallFunction, 1, // --
|
0, // locals
|
||||||
kExprI8Const, 77, // --
|
kExprCallFunction, 1, // --
|
||||||
kExprI8Const, 22, // --
|
kExprI8Const, 77, // --
|
||||||
|
kExprI8Const, 22, // --
|
||||||
// func#1 -----------------------------------------
|
// func#1 -----------------------------------------
|
||||||
0, // no name, not exported
|
0, // no name, not exported
|
||||||
1, 0, // sig index
|
1, 0, // sig index
|
||||||
|
@ -57,14 +57,19 @@ var kDeclFunctions = 0x02;
|
|||||||
var kDeclGlobals = 0x03;
|
var kDeclGlobals = 0x03;
|
||||||
var kDeclDataSegments = 0x04;
|
var kDeclDataSegments = 0x04;
|
||||||
var kDeclFunctionTable = 0x05;
|
var kDeclFunctionTable = 0x05;
|
||||||
|
var kDeclEnd = 0x06;
|
||||||
var kDeclStartFunction = 0x07;
|
var kDeclStartFunction = 0x07;
|
||||||
var kDeclImportTable = 0x08;
|
var kDeclImportTable = 0x08;
|
||||||
var kDeclExportTable = 0x09;
|
var kDeclExportTable = 0x09;
|
||||||
var kDeclEnd = 0x06;
|
|
||||||
var kDeclFunctionSignatures = 0x0a;
|
var kDeclFunctionSignatures = 0x0a;
|
||||||
var kDeclFunctionBodies = 0x0b;
|
var kDeclFunctionBodies = 0x0b;
|
||||||
var kDeclNames = 0x0c;
|
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
|
// Function declaration flags
|
||||||
var kDeclFunctionName = 0x01;
|
var kDeclFunctionName = 0x01;
|
||||||
var kDeclFunctionImport = 0x02;
|
var kDeclFunctionImport = 0x02;
|
||||||
|
@ -131,162 +131,184 @@ function emit_bytes(bytes, data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function emit_section(bytes, section_code, content_generator) {
|
||||||
|
// Start the section in a temporary buffer: its full length isn't know yet.
|
||||||
|
var tmp_bytes = [];
|
||||||
|
emit_string(tmp_bytes, section_names[section_code]);
|
||||||
|
content_generator(tmp_bytes);
|
||||||
|
// Now that we know the section length, emit it and copy the section.
|
||||||
|
emit_varint(bytes, tmp_bytes.length);
|
||||||
|
Array.prototype.push.apply(bytes, tmp_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
WasmModuleBuilder.prototype.toArray = function(debug) {
|
WasmModuleBuilder.prototype.toArray = function(debug) {
|
||||||
// Add header bytes
|
// Add header bytes
|
||||||
var bytes = [];
|
var bytes = [];
|
||||||
bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3,
|
bytes = bytes.concat([kWasmH0, kWasmH1, kWasmH2, kWasmH3,
|
||||||
kWasmV0, kWasmV1, kWasmV2, kWasmV3]);
|
kWasmV0, kWasmV1, kWasmV2, kWasmV3]);
|
||||||
|
|
||||||
|
var wasm = this;
|
||||||
|
|
||||||
// Add memory section
|
// Add memory section
|
||||||
if (this.memory != undefined) {
|
if (wasm.memory != undefined) {
|
||||||
if (debug) print("emitting memory @ " + bytes.length);
|
if (debug) print("emitting memory @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclMemory);
|
emit_section(bytes, kDeclMemory, function(bytes) {
|
||||||
emit_varint(bytes, this.memory.min);
|
emit_varint(bytes, wasm.memory.min);
|
||||||
emit_varint(bytes, this.memory.max);
|
emit_varint(bytes, wasm.memory.max);
|
||||||
emit_u8(bytes, this.memory.exp ? 1 : 0);
|
emit_u8(bytes, wasm.memory.exp ? 1 : 0);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add signatures section
|
// Add signatures section
|
||||||
if (this.signatures.length > 0) {
|
if (wasm.signatures.length > 0) {
|
||||||
if (debug) print("emitting signatures @ " + bytes.length);
|
if (debug) print("emitting signatures @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclSignatures);
|
emit_section(bytes, kDeclSignatures, function(bytes) {
|
||||||
emit_varint(bytes, this.signatures.length);
|
emit_varint(bytes, wasm.signatures.length);
|
||||||
for (sig of this.signatures) {
|
for (sig of wasm.signatures) {
|
||||||
var params = sig.length - 1;
|
var params = sig.length - 1;
|
||||||
emit_varint(bytes, params);
|
emit_varint(bytes, params);
|
||||||
for (var j = 0; j < sig.length; j++) {
|
for (var j = 0; j < sig.length; j++) {
|
||||||
emit_u8(bytes, sig[j]);
|
emit_u8(bytes, sig[j]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add imports section
|
// Add imports section
|
||||||
if (this.imports.length > 0) {
|
if (wasm.imports.length > 0) {
|
||||||
if (debug) print("emitting imports @ " + bytes.length);
|
if (debug) print("emitting imports @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclImportTable);
|
emit_section(bytes, kDeclImportTable, function(bytes) {
|
||||||
emit_varint(bytes, this.imports.length);
|
emit_varint(bytes, wasm.imports.length);
|
||||||
for (imp of this.imports) {
|
for (imp of wasm.imports) {
|
||||||
emit_varint(bytes, imp.sig_index);
|
emit_varint(bytes, imp.sig_index);
|
||||||
emit_string(bytes, imp.module);
|
emit_string(bytes, imp.module);
|
||||||
emit_string(bytes, imp.name || '');
|
emit_string(bytes, imp.name || '');
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add functions section
|
// Add functions section
|
||||||
var names = false;
|
var names = false;
|
||||||
var exports = 0;
|
var exports = 0;
|
||||||
if (this.functions.length > 0) {
|
if (wasm.functions.length > 0) {
|
||||||
var has_names = false;
|
var has_names = false;
|
||||||
|
|
||||||
// emit function signatures
|
// emit function signatures
|
||||||
if (debug) print("emitting function sigs @ " + bytes.length);
|
if (debug) print("emitting function sigs @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclFunctionSignatures);
|
emit_section(bytes, kDeclFunctionSignatures, function(bytes) {
|
||||||
emit_varint(bytes, this.functions.length);
|
emit_varint(bytes, wasm.functions.length);
|
||||||
for (func of this.functions) {
|
for (func of wasm.functions) {
|
||||||
has_names = has_names || (func.name != undefined &&
|
has_names = has_names || (func.name != undefined &&
|
||||||
func.name.length > 0);
|
func.name.length > 0);
|
||||||
exports += func.exports.length;
|
exports += func.exports.length;
|
||||||
|
|
||||||
emit_varint(bytes, func.sig_index);
|
emit_varint(bytes, func.sig_index);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// emit function bodies
|
// emit function bodies
|
||||||
if (debug) print("emitting function bodies @ " + bytes.length);
|
if (debug) print("emitting function bodies @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclFunctionBodies);
|
emit_section(bytes, kDeclFunctionBodies, function(bytes) {
|
||||||
emit_varint(bytes, this.functions.length);
|
emit_varint(bytes, wasm.functions.length);
|
||||||
for (func of this.functions) {
|
for (func of wasm.functions) {
|
||||||
// Function body length will be patched later.
|
// Function body length will be patched later.
|
||||||
var local_decls = [];
|
var local_decls = [];
|
||||||
var l = func.locals;
|
var l = func.locals;
|
||||||
if (l != undefined) {
|
if (l != undefined) {
|
||||||
var local_decls_count = 0;
|
var local_decls_count = 0;
|
||||||
if (l.i32_count > 0) {
|
if (l.i32_count > 0) {
|
||||||
local_decls.push({count: l.i32_count, type: kAstI32});
|
local_decls.push({count: l.i32_count, type: kAstI32});
|
||||||
}
|
}
|
||||||
if (l.i64_count > 0) {
|
if (l.i64_count > 0) {
|
||||||
local_decls.push({count: l.i64_count, type: kAstI64});
|
local_decls.push({count: l.i64_count, type: kAstI64});
|
||||||
}
|
}
|
||||||
if (l.f32_count > 0) {
|
if (l.f32_count > 0) {
|
||||||
local_decls.push({count: l.f32_count, type: kAstF32});
|
local_decls.push({count: l.f32_count, type: kAstF32});
|
||||||
}
|
}
|
||||||
if (l.f64_count > 0) {
|
if (l.f64_count > 0) {
|
||||||
local_decls.push({count: l.f64_count, type: kAstF64});
|
local_decls.push({count: l.f64_count, type: kAstF64});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var header = new Array();
|
var header = new Array();
|
||||||
|
|
||||||
emit_varint(header, local_decls.length);
|
emit_varint(header, local_decls.length);
|
||||||
for (decl of local_decls) {
|
for (decl of local_decls) {
|
||||||
emit_varint(header, decl.count);
|
emit_varint(header, decl.count);
|
||||||
emit_u8(header, decl.type);
|
emit_u8(header, decl.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit_varint(bytes, header.length + func.body.length);
|
emit_varint(bytes, header.length + func.body.length);
|
||||||
emit_bytes(bytes, header);
|
emit_bytes(bytes, header);
|
||||||
emit_bytes(bytes, func.body);
|
emit_bytes(bytes, func.body);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// emit function names
|
// emit function names
|
||||||
if (has_names) {
|
if (has_names) {
|
||||||
if (debug) print("emitting names @ " + bytes.length);
|
if (debug) print("emitting names @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclNames);
|
emit_section(bytes, kDeclNames, function(bytes) {
|
||||||
emit_varint(bytes, this.functions.length);
|
emit_varint(bytes, wasm.functions.length);
|
||||||
for (func of this.functions) {
|
for (func of wasm.functions) {
|
||||||
var name = func.name == undefined ? "" : func.name;
|
var name = func.name == undefined ? "" : func.name;
|
||||||
emit_string(bytes, name);
|
emit_string(bytes, name);
|
||||||
emit_u8(bytes, 0); // local names count == 0
|
emit_u8(bytes, 0); // local names count == 0
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add start function section.
|
// Add start function section.
|
||||||
if (this.start_index != undefined) {
|
if (wasm.start_index != undefined) {
|
||||||
if (debug) print("emitting start function @ " + bytes.length);
|
if (debug) print("emitting start function @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclStartFunction);
|
emit_section(bytes, kDeclStartFunction, function(bytes) {
|
||||||
emit_varint(bytes, this.start_index);
|
emit_varint(bytes, wasm.start_index);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.function_table.length > 0) {
|
if (wasm.function_table.length > 0) {
|
||||||
if (debug) print("emitting function table @ " + bytes.length);
|
if (debug) print("emitting function table @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclFunctionTable);
|
emit_section(bytes, kDeclFunctionTable, function(bytes) {
|
||||||
emit_varint(bytes, this.function_table.length);
|
emit_varint(bytes, wasm.function_table.length);
|
||||||
for (index of this.function_table) {
|
for (index of wasm.function_table) {
|
||||||
emit_varint(bytes, index);
|
emit_varint(bytes, index);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exports > 0) {
|
if (exports > 0) {
|
||||||
if (debug) print("emitting exports @ " + bytes.length);
|
if (debug) print("emitting exports @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclExportTable);
|
emit_section(bytes, kDeclExportTable, function(bytes) {
|
||||||
emit_varint(bytes, exports);
|
emit_varint(bytes, exports);
|
||||||
for (func of this.functions) {
|
for (func of wasm.functions) {
|
||||||
for (exp of func.exports) {
|
for (exp of func.exports) {
|
||||||
emit_varint(bytes, func.index);
|
emit_varint(bytes, func.index);
|
||||||
emit_string(bytes, exp);
|
emit_string(bytes, exp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.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_u8(bytes, kDeclDataSegments);
|
emit_section(bytes, kDeclDataSegments, function(bytes) {
|
||||||
emit_varint(bytes, this.data_segments.length);
|
emit_varint(bytes, wasm.data_segments.length);
|
||||||
for (seg of this.data_segments) {
|
for (seg of wasm.data_segments) {
|
||||||
emit_varint(bytes, seg.addr);
|
emit_varint(bytes, seg.addr);
|
||||||
emit_varint(bytes, seg.data.length);
|
emit_varint(bytes, seg.data.length);
|
||||||
emit_bytes(bytes, seg.data);
|
emit_bytes(bytes, seg.data);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit any explicitly added sections
|
// Emit any explicitly added sections
|
||||||
for (exp of this.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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End the module.
|
// End the module.
|
||||||
if (debug) print("emitting end @ " + bytes.length);
|
if (debug) print("emitting end @ " + bytes.length);
|
||||||
emit_u8(bytes, kDeclEnd);
|
emit_section(bytes, kDeclEnd, function(bytes) {});
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user