Index: src/wasm/module-decoder.cc |
diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc |
index 0f8637f32eeb1785c8a45bad1f585510d13e1f64..b5fcf766bc9ca76dcdfd31b7cc39942a55061f86 100644 |
--- a/src/wasm/module-decoder.cc |
+++ b/src/wasm/module-decoder.cc |
@@ -31,6 +31,9 @@ namespace { |
const char* kNameString = "name"; |
const size_t kNameStringLength = 4; |
+const char* kAsmOffsetsString = "asm_offsets"; |
+const size_t kAsmOffsetsLength = 11; |
+ |
LocalType TypeOf(const WasmModule* module, const WasmInitExpr& expr) { |
switch (expr.kind) { |
case WasmInitExpr::kNone: |
@@ -77,6 +80,12 @@ class WasmSectionIterator { |
return static_cast<uint32_t>(section_end_ - section_start_); |
} |
+ inline const byte* payload_start() const { return payload_start_; } |
+ |
+ inline uint32_t payload_length() const { |
+ return static_cast<uint32_t>(section_end_ - payload_start_); |
+ } |
+ |
inline const byte* section_end() const { return section_end_; } |
// Advances to the next section, checking that decoding the current section |
@@ -97,6 +106,7 @@ class WasmSectionIterator { |
Decoder& decoder_; |
WasmSectionCode section_code_; |
const byte* section_start_; |
+ const byte* payload_start_; |
const byte* section_end_; |
// Reads the section code/name at the current position and sets up |
@@ -111,6 +121,7 @@ class WasmSectionIterator { |
// Read and check the section size. |
uint32_t section_length = decoder_.consume_u32v("section length"); |
section_start_ = decoder_.pc(); |
+ payload_start_ = section_start_; |
if (decoder_.checkAvailable(section_length)) { |
// Get the limit of the section within the module. |
section_end_ = section_start_ + section_length; |
@@ -120,7 +131,7 @@ class WasmSectionIterator { |
} |
if (section_code == kUnknownSectionCode) { |
- // Check for the known "names" section. |
+ // Check for the known "name" or "asm_offsets" section. |
uint32_t string_length = decoder_.consume_u32v("section name length"); |
const byte* section_name_start = decoder_.pc(); |
decoder_.consume_bytes(string_length, "section name"); |
@@ -129,15 +140,20 @@ class WasmSectionIterator { |
section_code_ = kUnknownSectionCode; |
return; |
} |
+ payload_start_ = decoder_.pc(); |
TRACE(" +%d section name : \"%.*s\"\n", |
static_cast<int>(section_name_start - decoder_.start()), |
string_length < 20 ? string_length : 20, section_name_start); |
if (string_length == kNameStringLength && |
- strncmp(reinterpret_cast<const char*>(section_name_start), |
- kNameString, kNameStringLength) == 0) { |
+ memcmp(reinterpret_cast<const char*>(section_name_start), |
+ kNameString, kNameStringLength) == 0) { |
section_code = kNameSectionCode; |
+ } else if (string_length == kAsmOffsetsLength && |
+ memcmp(reinterpret_cast<const char*>(section_name_start), |
+ kAsmOffsetsString, kAsmOffsetsLength) == 0) { |
+ section_code = kAsmOffsetsSectionCode; |
} else { |
section_code = kUnknownSectionCode; |
} |
@@ -590,15 +606,29 @@ class ModuleDecoder : public Decoder { |
uint32_t local_names_count = consume_u32v("local names count"); |
for (uint32_t j = 0; ok() && j < local_names_count; j++) { |
- uint32_t unused = 0; |
- uint32_t offset = consume_string(&unused, false); |
- USE(unused); |
- USE(offset); |
+ skip_string(); |
} |
} |
section_iter.advance(); |
} |
+ // ===== Wasm to asm.js offset table ===================================== |
+ if (section_iter.section_code() == kAsmOffsetsSectionCode) { |
+ const byte* pos = pc_; |
+ uint32_t functions_count = consume_u32v("functions count"); |
+ if (functions_count != module->num_declared_functions) { |
+ error(pos, pos, "function name count %u mismatch (%u expected)", |
+ functions_count, module->num_declared_functions); |
+ } |
+ |
+ for (uint32_t i = 0; ok() && i < functions_count; ++i) { |
+ // Do not store anything yet. Data will be decoded on-demand in |
+ // WasmDebugInfo. |
+ skip_string(); |
+ } |
+ section_iter.advance(); |
+ } |
+ |
// ===== Remaining sections ============================================== |
if (section_iter.more() && ok()) { |
error(pc(), pc(), "unexpected section: %s", |
@@ -799,6 +829,12 @@ class ModuleDecoder : public Decoder { |
return offset; |
} |
+ // Skips over a length-prefixed string, but checks that it is within bounds. |
+ void skip_string() { |
+ uint32_t length = consume_u32v("string length"); |
+ consume_bytes(length, "string"); |
+ } |
+ |
uint32_t consume_sig_index(WasmModule* module, FunctionSig** sig) { |
const byte* pos = pc_; |
uint32_t sig_index = consume_u32v("signature index"); |
@@ -1029,6 +1065,8 @@ class FunctionError : public FunctionResult { |
} |
}; |
+// Find section with given section code. Return Vector of the payload, or null |
+// Vector if section is not found or module bytes are invalid. |
Vector<const byte> FindSection(const byte* module_start, const byte* module_end, |
WasmSectionCode code) { |
Decoder decoder(module_start, module_end); |
@@ -1042,10 +1080,10 @@ Vector<const byte> FindSection(const byte* module_start, const byte* module_end, |
WasmSectionIterator section_iter(decoder); |
while (section_iter.more()) { |
if (section_iter.section_code() == code) { |
- return Vector<const uint8_t>(section_iter.section_start(), |
- section_iter.section_length()); |
+ return Vector<const uint8_t>(section_iter.payload_start(), |
+ section_iter.payload_length()); |
} |
- decoder.consume_bytes(section_iter.section_length(), "section payload"); |
+ decoder.consume_bytes(section_iter.payload_length(), "section payload"); |
section_iter.advance(); |
} |
@@ -1118,16 +1156,14 @@ FunctionOffsetsResult DecodeWasmFunctionOffsets( |
return decoder.toResult(std::move(table)); |
} |
- // Reserve entries for the imported functions. |
- table.reserve(num_imported_functions); |
- for (uint32_t i = 0; i < num_imported_functions; i++) { |
- table.push_back(std::make_pair(0, 0)); |
- } |
- |
uint32_t functions_count = decoder.consume_u32v("functions count"); |
- // Take care of invalid input here. |
+ // Reserve space for the entries, taking care of invalid input. |
if (functions_count < static_cast<unsigned>(code_section.length()) / 2) |
table.reserve(num_imported_functions + functions_count); |
+ |
+ // Add null entries for the imported functions. |
+ table.resize(num_imported_functions); |
+ |
int section_offset = static_cast<int>(code_section.start() - module_start); |
DCHECK_LE(0, section_offset); |
for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { |
@@ -1142,6 +1178,57 @@ FunctionOffsetsResult DecodeWasmFunctionOffsets( |
return decoder.toResult(std::move(table)); |
} |
+AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* module_start, |
+ const byte* module_end, |
+ uint32_t num_imported_functions) { |
+ // Find and decode the code section. |
+ Vector<const byte> asm_offset_section = |
+ FindSection(module_start, module_end, kAsmOffsetsSectionCode); |
+ Decoder decoder(asm_offset_section.start(), asm_offset_section.end()); |
+ AsmJsOffsets table; |
+ if (!asm_offset_section.start()) { |
+ decoder.error("no asm.js offsets section"); |
+ return decoder.toResult(std::move(table)); |
+ } |
+ |
+ uint32_t functions_count = decoder.consume_u32v("functions count"); |
+ // Reserve space for the entries, taking care of invalid input. |
+ if (functions_count < static_cast<unsigned>(asm_offset_section.length())) |
+ table.reserve(num_imported_functions + functions_count); |
+ |
+ // Add null entries for the imported functions. |
+ table.resize(num_imported_functions); |
+ |
+ for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) { |
+ uint32_t size = decoder.consume_u32v("table size"); |
+ if (size == 0) { |
+ table.push_back(std::vector<std::pair<int, int>>()); |
+ continue; |
+ } |
+ if (!decoder.checkAvailable(size)) { |
+ decoder.error("illegal asm function offset table size"); |
+ } |
+ const byte* table_end = decoder.pc() + size; |
+ uint32_t locals_size = decoder.consume_u32("locals size"); |
+ int last_byte_offset = locals_size; |
+ int last_asm_position = 0; |
+ std::vector<std::pair<int, int>> func_asm_offsets; |
+ func_asm_offsets.reserve(size / 4); // conservative estimation |
+ while (decoder.ok() && decoder.pc() < table_end) { |
+ last_byte_offset += decoder.consume_u32v("byte offset delta"); |
+ last_asm_position += decoder.consume_i32v("asm position delta"); |
+ func_asm_offsets.push_back({last_byte_offset, last_asm_position}); |
+ } |
+ if (decoder.pc() != table_end) { |
+ decoder.error("broken asm offset table"); |
+ } |
+ table.push_back(std::move(func_asm_offsets)); |
+ } |
+ if (decoder.more()) decoder.error("unexpected additional bytes"); |
+ |
+ return decoder.toResult(std::move(table)); |
+} |
+ |
} // namespace wasm |
} // namespace internal |
} // namespace v8 |