Index: src/wasm/module-decoder.cc |
diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc |
index 965a22dc19fafe6e434832766ae3892ff8792302..6d4b03666017261231039eee0c3b554a8d9843a6 100644 |
--- a/src/wasm/module-decoder.cc |
+++ b/src/wasm/module-decoder.cc |
@@ -117,6 +117,48 @@ class ModuleDecoder : public Decoder { |
} |
break; |
} |
+ case kDeclFunctionSignatures: { |
+ // Functions require a signature table first. |
+ CheckForPreviousSection(sections, kDeclSignatures, true); |
+ int length; |
+ uint32_t functions_count = consume_u32v(&length, "functions count"); |
+ module->functions.reserve(SafeReserve(functions_count)); |
+ for (uint32_t i = 0; i < functions_count; i++) { |
+ module->functions.push_back( |
+ {nullptr, i, 0, 0, 0, 0, 0, 0, false, false}); |
+ WasmFunction* function = &module->functions.back(); |
+ function->sig_index = consume_sig_index(module, &function->sig); |
+ } |
+ break; |
+ } |
+ case kDeclFunctionBodies: { |
+ // Function bodies should follow signatures. |
+ CheckForPreviousSection(sections, kDeclFunctionSignatures, true); |
+ int length; |
+ const byte* pos = pc_; |
+ uint32_t functions_count = consume_u32v(&length, "functions count"); |
+ if (functions_count != module->functions.size()) { |
+ error(pos, pos, "function body count %u mismatch (%u expected)", |
+ functions_count, |
+ static_cast<uint32_t>(module->functions.size())); |
+ break; |
+ } |
+ for (uint32_t i = 0; i < functions_count; i++) { |
+ WasmFunction* function = &module->functions[i]; |
+ int length; |
+ uint32_t size = consume_u32v(&length, "body size"); |
+ function->code_start_offset = pc_offset(); |
+ function->code_end_offset = pc_offset() + size; |
+ |
+ TRACE(" +%d %-20s: (%d bytes)\n", pc_offset(), "function body", |
+ size); |
+ pc_ += size; |
+ if (pc_ > limit_) { |
+ error(pc_, "function body extends beyond end of file"); |
+ } |
+ } |
+ break; |
+ } |
case kDeclFunctions: { |
// Functions require a signature table first. |
CheckForPreviousSection(sections, kDeclSignatures, true); |
@@ -152,6 +194,35 @@ class ModuleDecoder : public Decoder { |
} |
break; |
} |
+ case kDeclNames: { |
+ // Names correspond to functions. |
+ CheckForPreviousSection(sections, kDeclFunctionSignatures, true); |
+ int length; |
+ const byte* pos = pc_; |
+ uint32_t functions_count = consume_u32v(&length, "functions count"); |
+ if (functions_count != module->functions.size()) { |
+ error(pos, pos, "function name count %u mismatch (%u expected)", |
+ functions_count, |
+ static_cast<uint32_t>(module->functions.size())); |
+ break; |
+ } |
+ |
+ for (uint32_t i = 0; i < functions_count; i++) { |
+ WasmFunction* function = &module->functions[i]; |
+ function->name_offset = |
+ consume_string(&function->name_length, "function name"); |
+ |
+ uint32_t local_names_count = |
+ consume_u32v(&length, "local names count"); |
+ for (uint32_t j = 0; j < local_names_count; j++) { |
+ uint32_t unused = 0; |
+ uint32_t offset = consume_string(&unused, "local name"); |
+ USE(unused); |
+ USE(offset); |
+ } |
+ } |
+ break; |
+ } |
case kDeclGlobals: { |
int length; |
uint32_t globals_count = consume_u32v(&length, "globals count"); |
@@ -185,7 +256,7 @@ class ModuleDecoder : public Decoder { |
} |
case kDeclFunctionTable: { |
// An indirect function table requires functions first. |
- CheckForPreviousSection(sections, kDeclFunctions, true); |
+ CheckForFunctions(module, section); |
int length; |
uint32_t function_table_count = |
consume_u32v(&length, "function table count"); |
@@ -206,23 +277,16 @@ class ModuleDecoder : public Decoder { |
} |
case kDeclStartFunction: { |
// Declares a start function for a module. |
- CheckForPreviousSection(sections, kDeclFunctions, true); |
+ CheckForFunctions(module, section); |
if (module->start_function_index >= 0) { |
error("start function already declared"); |
break; |
} |
- int length; |
- const byte* before = pc_; |
- uint32_t index = consume_u32v(&length, "start function index"); |
- if (index >= module->functions.size()) { |
- error(before, "invalid start function index"); |
- break; |
- } |
- module->start_function_index = static_cast<int>(index); |
- FunctionSig* sig = |
- module->signatures[module->functions[index].sig_index]; |
- if (sig->parameter_count() > 0) { |
- error(before, "invalid start function: non-zero parameter count"); |
+ WasmFunction* func; |
+ const byte* pos = pc_; |
+ module->start_function_index = consume_func_index(module, &func); |
+ if (func && func->sig->parameter_count() > 0) { |
+ error(pos, "invalid start function: non-zero parameter count"); |
break; |
} |
break; |
@@ -243,14 +307,7 @@ class ModuleDecoder : public Decoder { |
module->import_table.push_back({nullptr, 0, 0}); |
WasmImport* import = &module->import_table.back(); |
- const byte* sigpos = pc_; |
- import->sig_index = consume_u32v(&length, "signature index"); |
- |
- if (import->sig_index >= module->signatures.size()) { |
- error(sigpos, "invalid signature index"); |
- } else { |
- import->sig = module->signatures[import->sig_index]; |
- } |
+ import->sig_index = consume_sig_index(module, &import->sig); |
const byte* pos = pc_; |
import->module_name_offset = consume_string( |
&import->module_name_length, "import module name"); |
@@ -264,7 +321,7 @@ class ModuleDecoder : public Decoder { |
} |
case kDeclExportTable: { |
// Declares an export table. |
- CheckForPreviousSection(sections, kDeclFunctions, true); |
+ CheckForFunctions(module, section); |
int length; |
uint32_t export_table_count = |
consume_u32v(&length, "export table count"); |
@@ -278,14 +335,8 @@ class ModuleDecoder : public Decoder { |
module->export_table.push_back({0, 0}); |
WasmExport* exp = &module->export_table.back(); |
- const byte* sigpos = pc_; |
- exp->func_index = consume_u32v(&length, "function index"); |
- if (exp->func_index >= module->functions.size()) { |
- error(sigpos, sigpos, |
- "function index %u out of bounds (%d functions)", |
- exp->func_index, |
- static_cast<int>(module->functions.size())); |
- } |
+ WasmFunction* func; |
+ exp->func_index = consume_func_index(module, &func); |
exp->name_offset = consume_string(&exp->name_length, "export name"); |
} |
break; |
@@ -304,34 +355,37 @@ class ModuleDecoder : public Decoder { |
return count < kMaxReserve ? count : kMaxReserve; |
} |
- void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section, |
- bool present) { |
- if (section >= kMaxModuleSectionCode) return; |
- if (sections[section] == present) return; |
- const char* name = ""; |
+ const char* SectionName(WasmSectionDeclCode section) { |
switch (section) { |
case kDeclMemory: |
- name = "memory"; |
- break; |
+ return "memory"; |
case kDeclSignatures: |
- name = "signatures"; |
- break; |
+ return "signatures"; |
case kDeclFunctions: |
- name = "function declaration"; |
- break; |
+ return "function declaration"; |
case kDeclGlobals: |
- name = "global variable"; |
- break; |
+ return "global variable"; |
case kDeclDataSegments: |
- name = "data segment"; |
- break; |
+ return "data segment"; |
case kDeclFunctionTable: |
- name = "function table"; |
- break; |
+ return "function table"; |
default: |
- name = ""; |
- break; |
+ return ""; |
} |
+ } |
+ |
+ void CheckForFunctions(WasmModule* module, WasmSectionDeclCode section) { |
+ if (module->functions.size() == 0) { |
+ error(pc_ - 1, nullptr, "functions must appear before section %s", |
+ SectionName(section)); |
+ } |
+ } |
+ |
+ void CheckForPreviousSection(bool* sections, WasmSectionDeclCode section, |
+ bool present) { |
+ if (section >= kMaxModuleSectionCode) return; |
+ if (sections[section] == present) return; |
+ const char* name = SectionName(section); |
if (present) { |
error(pc_ - 1, nullptr, "required %s section missing", name); |
} else { |
@@ -382,6 +436,7 @@ class ModuleDecoder : public Decoder { |
} |
// Decodes a single function entry inside a module starting at {pc_}. |
+ // TODO(titzer): legacy function body; remove |
void DecodeFunctionInModule(WasmModule* module, WasmFunction* function, |
bool verify_body = true) { |
byte decl_bits = consume_u8("function decl"); |
@@ -517,11 +572,40 @@ class ModuleDecoder : public Decoder { |
uint32_t consume_string(uint32_t* length, const char* name = nullptr) { |
int varint_length; |
*length = consume_u32v(&varint_length, "string length"); |
- uint32_t offset = static_cast<uint32_t>(pc_ - start_); |
+ uint32_t offset = pc_offset(); |
+ TRACE(" +%u %-20s: (%u bytes)\n", offset, "string", *length); |
consume_bytes(*length); |
return offset; |
} |
+ uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) { |
+ const byte* pos = pc_; |
+ int length; |
+ uint32_t sig_index = consume_u32v(&length, "signature index"); |
+ if (sig_index >= module->signatures.size()) { |
+ error(pos, pos, "signature index %u out of bounds (%d signatures)", |
+ sig_index, static_cast<int>(module->signatures.size())); |
+ *sig = nullptr; |
+ return 0; |
+ } |
+ *sig = module->signatures[sig_index]; |
+ return sig_index; |
+ } |
+ |
+ uint32_t consume_func_index(WasmModule* module, WasmFunction** func) { |
+ const byte* pos = pc_; |
+ int length; |
+ uint32_t func_index = consume_u32v(&length, "function index"); |
+ if (func_index >= module->functions.size()) { |
+ error(pos, pos, "function index %u out of bounds (%d functions)", |
+ func_index, static_cast<int>(module->functions.size())); |
+ *func = nullptr; |
+ return 0; |
+ } |
+ *func = &module->functions[func_index]; |
+ return func_index; |
+ } |
+ |
// Reads a single 8-bit integer, interpreting it as a local type. |
LocalType consume_local_type() { |
byte val = consume_u8("local type"); |