aboutsummaryrefslogtreecommitdiff
path: root/src/wasm/module-decoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/module-decoder.cc')
-rw-r--r--src/wasm/module-decoder.cc454
1 files changed, 281 insertions, 173 deletions
diff --git a/src/wasm/module-decoder.cc b/src/wasm/module-decoder.cc
index c8eace3c..440e5dcb 100644
--- a/src/wasm/module-decoder.cc
+++ b/src/wasm/module-decoder.cc
@@ -3,15 +3,19 @@
// found in the LICENSE file.
#include "src/wasm/module-decoder.h"
+#include "src/wasm/function-body-decoder-impl.h"
#include "src/base/functional.h"
#include "src/base/platform/platform.h"
+#include "src/counters.h"
#include "src/flags.h"
#include "src/macro-assembler.h"
-#include "src/objects.h"
+#include "src/objects-inl.h"
+#include "src/ostreams.h"
#include "src/v8.h"
#include "src/wasm/decoder.h"
+#include "src/wasm/wasm-limits.h"
namespace v8 {
namespace internal {
@@ -26,30 +30,63 @@ namespace wasm {
#define TRACE(...)
#endif
+const char* SectionName(WasmSectionCode code) {
+ switch (code) {
+ case kUnknownSectionCode:
+ return "Unknown";
+ case kTypeSectionCode:
+ return "Type";
+ case kImportSectionCode:
+ return "Import";
+ case kFunctionSectionCode:
+ return "Function";
+ case kTableSectionCode:
+ return "Table";
+ case kMemorySectionCode:
+ return "Memory";
+ case kGlobalSectionCode:
+ return "Global";
+ case kExportSectionCode:
+ return "Export";
+ case kStartSectionCode:
+ return "Start";
+ case kCodeSectionCode:
+ return "Code";
+ case kElementSectionCode:
+ return "Element";
+ case kDataSectionCode:
+ return "Data";
+ case kNameSectionCode:
+ return "Name";
+ default:
+ return "<unknown>";
+ }
+}
+
namespace {
const char* kNameString = "name";
const size_t kNameStringLength = 4;
-LocalType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
+ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
switch (expr.kind) {
case WasmInitExpr::kNone:
- return kAstStmt;
+ return kWasmStmt;
case WasmInitExpr::kGlobalIndex:
return expr.val.global_index < module->globals.size()
? module->globals[expr.val.global_index].type
- : kAstStmt;
+ : kWasmStmt;
case WasmInitExpr::kI32Const:
- return kAstI32;
+ return kWasmI32;
case WasmInitExpr::kI64Const:
- return kAstI64;
+ return kWasmI64;
case WasmInitExpr::kF32Const:
- return kAstF32;
+ return kWasmF32;
case WasmInitExpr::kF64Const:
- return kAstF64;
+ return kWasmF64;
default:
UNREACHABLE();
- return kAstStmt;
+ return kWasmStmt;
}
}
@@ -177,19 +214,21 @@ class ModuleDecoder : public Decoder {
public:
ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
ModuleOrigin origin)
- : Decoder(module_start, module_end), module_zone(zone), origin_(origin) {
+ : Decoder(module_start, module_end),
+ module_zone(zone),
+ origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
result_.start = start_;
- if (limit_ < start_) {
+ if (end_ < start_) {
error(start_, "end is less than start");
- limit_ = start_;
+ end_ = start_;
}
}
virtual void onFirstError() {
- pc_ = limit_; // On error, terminate section decoding loop.
+ pc_ = end_; // On error, terminate section decoding loop.
}
- static void DumpModule(WasmModule* module, const ModuleResult& result) {
+ void DumpModule(const ModuleResult& result) {
std::string path;
if (FLAG_dump_wasm_module_path) {
path = FLAG_dump_wasm_module_path;
@@ -199,7 +238,7 @@ class ModuleDecoder : public Decoder {
}
}
// File are named `HASH.{ok,failed}.wasm`.
- size_t hash = base::hash_range(module->module_start, module->module_end);
+ size_t hash = base::hash_range(start_, end_);
char buf[32] = {'\0'};
#if V8_OS_WIN && _MSC_VER < 1900
#define snprintf sprintf_s
@@ -208,17 +247,15 @@ class ModuleDecoder : public Decoder {
result.ok() ? "ok" : "failed");
std::string name(buf);
if (FILE* wasm_file = base::OS::FOpen((path + name).c_str(), "wb")) {
- fwrite(module->module_start, module->module_end - module->module_start, 1,
- wasm_file);
+ fwrite(start_, end_ - start_, 1, wasm_file);
fclose(wasm_file);
}
}
// Decodes an entire module.
- ModuleResult DecodeModule(WasmModule* module, bool verify_functions = true) {
+ ModuleResult DecodeModule(bool verify_functions = true) {
pc_ = start_;
- module->module_start = start_;
- module->module_end = limit_;
+ WasmModule* module = new WasmModule(module_zone);
module->min_mem_pages = 0;
module->max_mem_pages = 0;
module->mem_export = false;
@@ -249,8 +286,8 @@ class ModuleDecoder : public Decoder {
// ===== Type section ====================================================
if (section_iter.section_code() == kTypeSectionCode) {
- uint32_t signatures_count = consume_u32v("signatures count");
- module->signatures.reserve(SafeReserve(signatures_count));
+ uint32_t signatures_count = consume_count("types count", kV8MaxWasmTypes);
+ module->signatures.reserve(signatures_count);
for (uint32_t i = 0; ok() && i < signatures_count; ++i) {
TRACE("DecodeSignature[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
@@ -262,8 +299,9 @@ class ModuleDecoder : public Decoder {
// ===== Import section ==================================================
if (section_iter.section_code() == kImportSectionCode) {
- uint32_t import_table_count = consume_u32v("import table count");
- module->import_table.reserve(SafeReserve(import_table_count));
+ uint32_t import_table_count =
+ consume_count("imports count", kV8MaxWasmImports);
+ module->import_table.reserve(import_table_count);
for (uint32_t i = 0; ok() && i < import_table_count; ++i) {
TRACE("DecodeImportTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
@@ -280,9 +318,6 @@ class ModuleDecoder : public Decoder {
const byte* pos = pc_;
import->module_name_offset =
consume_string(&import->module_name_length, true);
- if (import->module_name_length == 0) {
- error(pos, "import module name cannot be NULL");
- }
import->field_name_offset =
consume_string(&import->field_name_length, true);
@@ -307,6 +342,7 @@ class ModuleDecoder : public Decoder {
}
case kExternalTable: {
// ===== Imported table ==========================================
+ if (!AddTable(module)) break;
import->index =
static_cast<uint32_t>(module->function_tables.size());
module->function_tables.push_back({0, 0, false,
@@ -314,30 +350,29 @@ class ModuleDecoder : public Decoder {
false, SignatureMap()});
expect_u8("element type", kWasmAnyFunctionTypeForm);
WasmIndirectFunctionTable* table = &module->function_tables.back();
- consume_resizable_limits(
- "element count", "elements", WasmModule::kV8MaxTableSize,
- &table->min_size, &table->has_max, WasmModule::kV8MaxTableSize,
- &table->max_size);
+ consume_resizable_limits("element count", "elements",
+ FLAG_wasm_max_table_size, &table->min_size,
+ &table->has_max, FLAG_wasm_max_table_size,
+ &table->max_size);
break;
}
case kExternalMemory: {
// ===== Imported memory =========================================
- bool has_max = false;
- consume_resizable_limits("memory", "pages", WasmModule::kV8MaxPages,
- &module->min_mem_pages, &has_max,
- WasmModule::kSpecMaxPages,
- &module->max_mem_pages);
- module->has_memory = true;
+ if (!AddMemory(module)) break;
+ consume_resizable_limits(
+ "memory", "pages", FLAG_wasm_max_mem_pages,
+ &module->min_mem_pages, &module->has_max_mem,
+ kSpecMaxWasmMemoryPages, &module->max_mem_pages);
break;
}
case kExternalGlobal: {
// ===== Imported global =========================================
import->index = static_cast<uint32_t>(module->globals.size());
module->globals.push_back(
- {kAstStmt, false, WasmInitExpr(), 0, true, false});
+ {kWasmStmt, false, WasmInitExpr(), 0, true, false});
WasmGlobal* global = &module->globals.back();
global->type = consume_value_type();
- global->mutability = consume_u8("mutability") != 0;
+ global->mutability = consume_mutability();
if (global->mutability) {
error("mutable globals cannot be imported");
}
@@ -353,8 +388,9 @@ class ModuleDecoder : public Decoder {
// ===== Function section ================================================
if (section_iter.section_code() == kFunctionSectionCode) {
- uint32_t functions_count = consume_u32v("functions count");
- module->functions.reserve(SafeReserve(functions_count));
+ uint32_t functions_count =
+ consume_count("functions count", kV8MaxWasmFunctions);
+ module->functions.reserve(functions_count);
module->num_declared_functions = functions_count;
for (uint32_t i = 0; ok() && i < functions_count; ++i) {
uint32_t func_index = static_cast<uint32_t>(module->functions.size());
@@ -375,23 +411,17 @@ class ModuleDecoder : public Decoder {
// ===== Table section ===================================================
if (section_iter.section_code() == kTableSectionCode) {
- const byte* pos = pc_;
- uint32_t table_count = consume_u32v("table count");
- // Require at most one table for now.
- if (table_count > 1) {
- error(pos, pos, "invalid table count %d, maximum 1", table_count);
- }
- if (module->function_tables.size() < 1) {
- module->function_tables.push_back({0, 0, false, std::vector<int32_t>(),
- false, false, SignatureMap()});
- }
+ uint32_t table_count = consume_count("table count", kV8MaxWasmTables);
for (uint32_t i = 0; ok() && i < table_count; i++) {
+ if (!AddTable(module)) break;
+ module->function_tables.push_back({0, 0, false, std::vector<int32_t>(),
+ false, false, SignatureMap()});
WasmIndirectFunctionTable* table = &module->function_tables.back();
expect_u8("table type", kWasmAnyFunctionTypeForm);
consume_resizable_limits("table elements", "elements",
- WasmModule::kV8MaxTableSize, &table->min_size,
- &table->has_max, WasmModule::kV8MaxTableSize,
+ FLAG_wasm_max_table_size, &table->min_size,
+ &table->has_max, FLAG_wasm_max_table_size,
&table->max_size);
}
section_iter.advance();
@@ -399,39 +429,30 @@ class ModuleDecoder : public Decoder {
// ===== Memory section ==================================================
if (section_iter.section_code() == kMemorySectionCode) {
- const byte* pos = pc_;
- uint32_t memory_count = consume_u32v("memory count");
- // Require at most one memory for now.
- if (memory_count > 1) {
- error(pos, pos, "invalid memory count %d, maximum 1", memory_count);
- }
+ uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
for (uint32_t i = 0; ok() && i < memory_count; i++) {
- bool has_max = false;
- consume_resizable_limits(
- "memory", "pages", WasmModule::kV8MaxPages, &module->min_mem_pages,
- &has_max, WasmModule::kSpecMaxPages, &module->max_mem_pages);
+ if (!AddMemory(module)) break;
+ consume_resizable_limits("memory", "pages", FLAG_wasm_max_mem_pages,
+ &module->min_mem_pages, &module->has_max_mem,
+ kSpecMaxWasmMemoryPages,
+ &module->max_mem_pages);
}
- module->has_memory = true;
section_iter.advance();
}
// ===== Global section ==================================================
if (section_iter.section_code() == kGlobalSectionCode) {
- uint32_t globals_count = consume_u32v("globals count");
+ uint32_t globals_count =
+ consume_count("globals count", kV8MaxWasmGlobals);
uint32_t imported_globals = static_cast<uint32_t>(module->globals.size());
- if (!IsWithinLimit(std::numeric_limits<int32_t>::max(), globals_count,
- imported_globals)) {
- error(pos, pos, "too many imported+defined globals: %u + %u",
- imported_globals, globals_count);
- }
- module->globals.reserve(SafeReserve(imported_globals + globals_count));
+ module->globals.reserve(imported_globals + globals_count);
for (uint32_t i = 0; ok() && i < globals_count; ++i) {
TRACE("DecodeGlobal[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
// Add an uninitialized global and pass a pointer to it.
module->globals.push_back(
- {kAstStmt, false, WasmInitExpr(), 0, false, false});
+ {kWasmStmt, false, WasmInitExpr(), 0, false, false});
WasmGlobal* global = &module->globals.back();
DecodeGlobalInModule(module, i + imported_globals, global);
}
@@ -440,8 +461,9 @@ class ModuleDecoder : public Decoder {
// ===== Export section ==================================================
if (section_iter.section_code() == kExportSectionCode) {
- uint32_t export_table_count = consume_u32v("export table count");
- module->export_table.reserve(SafeReserve(export_table_count));
+ uint32_t export_table_count =
+ consume_count("exports count", kV8MaxWasmImports);
+ module->export_table.reserve(export_table_count);
for (uint32_t i = 0; ok() && i < export_table_count; ++i) {
TRACE("DecodeExportTable[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
@@ -473,7 +495,11 @@ class ModuleDecoder : public Decoder {
}
case kExternalMemory: {
uint32_t index = consume_u32v("memory index");
- if (index != 0) error("invalid memory index != 0");
+ // TODO(titzer): This should become more regular
+ // once we support multiple memories.
+ if (!module->has_memory || index != 0) {
+ error("invalid memory index != 0");
+ }
module->mem_export = true;
break;
}
@@ -493,8 +519,8 @@ class ModuleDecoder : public Decoder {
break;
}
}
- // Check for duplicate exports.
- if (ok() && module->export_table.size() > 1) {
+ // Check for duplicate exports (except for asm.js).
+ if (ok() && origin_ != kAsmJsOrigin && module->export_table.size() > 1) {
std::vector<WasmExport> sorted_exports(module->export_table);
const byte* base = start_;
auto cmp_less = [base](const WasmExport& a, const WasmExport& b) {
@@ -538,7 +564,8 @@ class ModuleDecoder : public Decoder {
// ===== Elements section ================================================
if (section_iter.section_code() == kElementSectionCode) {
- uint32_t element_count = consume_u32v("element count");
+ uint32_t element_count =
+ consume_count("element count", FLAG_wasm_max_table_size);
for (uint32_t i = 0; ok() && i < element_count; ++i) {
const byte* pos = pc();
uint32_t table_index = consume_u32v("table index");
@@ -551,19 +578,18 @@ class ModuleDecoder : public Decoder {
} else {
table = &module->function_tables[table_index];
}
- WasmInitExpr offset = consume_init_expr(module, kAstI32);
- uint32_t num_elem = consume_u32v("number of elements");
+ WasmInitExpr offset = consume_init_expr(module, kWasmI32);
+ uint32_t num_elem =
+ consume_count("number of elements", kV8MaxWasmTableEntries);
std::vector<uint32_t> vector;
module->table_inits.push_back({table_index, offset, vector});
WasmTableInit* init = &module->table_inits.back();
- init->entries.reserve(SafeReserve(num_elem));
for (uint32_t j = 0; ok() && j < num_elem; j++) {
WasmFunction* func = nullptr;
uint32_t index = consume_func_index(module, &func);
init->entries.push_back(index);
if (table && index < module->functions.size()) {
// Canonicalize signature indices during decoding.
- // TODO(titzer): suboptimal, redundant when verifying only.
table->map.FindOrInsert(module->functions[index].sig);
}
}
@@ -587,10 +613,8 @@ class ModuleDecoder : public Decoder {
function->code_start_offset = pc_offset();
function->code_end_offset = pc_offset() + size;
if (verify_functions) {
- ModuleEnv module_env;
- module_env.module = module;
- module_env.origin = module->origin;
-
+ ModuleBytesEnv module_env(module, nullptr,
+ ModuleWireBytes(start_, end_));
VerifyFunctionBody(i + module->num_imported_functions, &module_env,
function);
}
@@ -601,8 +625,9 @@ class ModuleDecoder : public Decoder {
// ===== Data section ====================================================
if (section_iter.section_code() == kDataSectionCode) {
- uint32_t data_segments_count = consume_u32v("data segments count");
- module->data_segments.reserve(SafeReserve(data_segments_count));
+ uint32_t data_segments_count =
+ consume_count("data segments count", kV8MaxWasmDataSegments);
+ module->data_segments.reserve(data_segments_count);
for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
if (!module->has_memory) {
error("cannot load data without memory");
@@ -623,22 +648,29 @@ class ModuleDecoder : public Decoder {
// ===== Name section ====================================================
if (section_iter.section_code() == kNameSectionCode) {
- uint32_t functions_count = consume_u32v("functions count");
+ // TODO(titzer): find a way to report name errors as warnings.
+ // Use an inner decoder so that errors don't fail the outer decoder.
+ Decoder inner(start_, pc_, end_);
+ uint32_t functions_count = inner.consume_u32v("functions count");
- for (uint32_t i = 0; ok() && i < functions_count; ++i) {
+ for (uint32_t i = 0; inner.ok() && i < functions_count; ++i) {
uint32_t function_name_length = 0;
- uint32_t name_offset = consume_string(&function_name_length, false);
+ uint32_t name_offset =
+ consume_string(inner, &function_name_length, false);
uint32_t func_index = i;
- if (func_index < module->functions.size()) {
+ if (inner.ok() && func_index < module->functions.size()) {
module->functions[func_index].name_offset = name_offset;
module->functions[func_index].name_length = function_name_length;
}
- uint32_t local_names_count = consume_u32v("local names count");
- for (uint32_t j = 0; ok() && j < local_names_count; j++) {
- skip_string();
+ uint32_t local_names_count = inner.consume_u32v("local names count");
+ for (uint32_t j = 0; inner.ok() && j < local_names_count; j++) {
+ uint32_t length = inner.consume_u32v("string length");
+ inner.consume_bytes(length, "string");
}
}
+ // Skip the whole names section in the outer decoder.
+ consume_bytes(section_iter.payload_length(), nullptr);
section_iter.advance();
}
@@ -656,25 +688,19 @@ class ModuleDecoder : public Decoder {
if (verify_functions && result.ok()) {
result.MoveFrom(result_); // Copy error code and location.
}
- if (FLAG_dump_wasm_module) DumpModule(module, result);
+ if (FLAG_dump_wasm_module) DumpModule(result);
return result;
}
- uint32_t SafeReserve(uint32_t count) {
- // Avoid OOM by only reserving up to a certain size.
- const uint32_t kMaxReserve = 20000;
- return count < kMaxReserve ? count : kMaxReserve;
- }
-
// Decodes a single anonymous function starting at {start_}.
- FunctionResult DecodeSingleFunction(ModuleEnv* module_env,
+ FunctionResult DecodeSingleFunction(ModuleBytesEnv* module_env,
WasmFunction* function) {
pc_ = start_;
function->sig = consume_sig(); // read signature
function->name_offset = 0; // ---- name
function->name_length = 0; // ---- name length
function->code_start_offset = off(pc_); // ---- code start
- function->code_end_offset = off(limit_); // ---- code end
+ function->code_end_offset = off(end_); // ---- code end
if (ok()) VerifyFunctionBody(0, module_env, function);
@@ -693,7 +719,7 @@ class ModuleDecoder : public Decoder {
WasmInitExpr DecodeInitExpr(const byte* start) {
pc_ = start;
- return consume_init_expr(nullptr, kAstStmt);
+ return consume_init_expr(nullptr, kWasmStmt);
}
private:
@@ -703,13 +729,32 @@ class ModuleDecoder : public Decoder {
uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
+ bool AddTable(WasmModule* module) {
+ if (module->function_tables.size() > 0) {
+ error("At most one table is supported");
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ bool AddMemory(WasmModule* module) {
+ if (module->has_memory) {
+ error("At most one memory is supported");
+ return false;
+ } else {
+ module->has_memory = true;
+ return true;
+ }
+ }
+
// Decodes a single global entry inside a module starting at {pc_}.
void DecodeGlobalInModule(WasmModule* module, uint32_t index,
WasmGlobal* global) {
global->type = consume_value_type();
- global->mutability = consume_u8("mutability") != 0;
+ global->mutability = consume_mutability();
const byte* pos = pc();
- global->init = consume_init_expr(module, kAstStmt);
+ global->init = consume_init_expr(module, kWasmStmt);
switch (global->init.kind) {
case WasmInitExpr::kGlobalIndex: {
uint32_t other_index = global->init.val.global_index;
@@ -747,12 +792,12 @@ class ModuleDecoder : public Decoder {
void DecodeDataSegmentInModule(WasmModule* module, WasmDataSegment* segment) {
const byte* start = pc_;
expect_u8("linear memory index", 0);
- segment->dest_addr = consume_init_expr(module, kAstI32);
+ segment->dest_addr = consume_init_expr(module, kWasmI32);
segment->source_size = consume_u32v("source size");
segment->source_offset = static_cast<uint32_t>(pc_ - start_);
// Validate the data is in the module.
- uint32_t module_limit = static_cast<uint32_t>(limit_ - start_);
+ uint32_t module_limit = static_cast<uint32_t>(end_ - start_);
if (!IsWithinLimit(module_limit, segment->source_offset,
segment->source_size)) {
error(start, "segment out of bounds of module");
@@ -779,21 +824,24 @@ class ModuleDecoder : public Decoder {
}
// Verifies the body (code) of a given function.
- void VerifyFunctionBody(uint32_t func_num, ModuleEnv* menv,
+ void VerifyFunctionBody(uint32_t func_num, ModuleBytesEnv* menv,
WasmFunction* function) {
+ WasmFunctionName func_name(function,
+ menv->wire_bytes.GetNameOrNull(function));
if (FLAG_trace_wasm_decoder || FLAG_trace_wasm_decode_time) {
OFStream os(stdout);
- os << "Verifying WASM function " << WasmFunctionName(function, menv)
- << std::endl;
+ os << "Verifying WASM function " << func_name << std::endl;
}
- FunctionBody body = {menv, function->sig, start_,
+ FunctionBody body = {function->sig, start_,
start_ + function->code_start_offset,
start_ + function->code_end_offset};
- DecodeResult result = VerifyWasmCode(module_zone->allocator(), body);
+ DecodeResult result = VerifyWasmCode(
+ module_zone->allocator(),
+ menv == nullptr ? nullptr : menv->module_env.module, body);
if (result.failed()) {
// Wrap the error message from the function decoder.
std::ostringstream str;
- str << "in function " << WasmFunctionName(function, menv) << ": ";
+ str << "in function " << func_name << ": ";
str << result;
std::string strval = str.str();
const char* raw = strval.c_str();
@@ -808,27 +856,26 @@ class ModuleDecoder : public Decoder {
}
}
+ uint32_t consume_string(uint32_t* length, bool validate_utf8) {
+ return consume_string(*this, length, validate_utf8);
+ }
+
// Reads a length-prefixed string, checking that it is within bounds. Returns
// the offset of the string, and the length as an out parameter.
- uint32_t consume_string(uint32_t* length, bool validate_utf8) {
- *length = consume_u32v("string length");
- uint32_t offset = pc_offset();
- const byte* string_start = pc_;
+ uint32_t consume_string(Decoder& decoder, uint32_t* length,
+ bool validate_utf8) {
+ *length = decoder.consume_u32v("string length");
+ uint32_t offset = decoder.pc_offset();
+ const byte* string_start = decoder.pc();
// Consume bytes before validation to guarantee that the string is not oob.
- if (*length > 0) consume_bytes(*length, "string");
- if (ok() && validate_utf8 &&
+ if (*length > 0) decoder.consume_bytes(*length, "string");
+ if (decoder.ok() && validate_utf8 &&
!unibrow::Utf8::Validate(string_start, *length)) {
- error(string_start, "no valid UTF-8 string");
+ decoder.error(string_start, "no valid UTF-8 string");
}
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");
@@ -842,6 +889,17 @@ class ModuleDecoder : public Decoder {
return sig_index;
}
+ uint32_t consume_count(const char* name, size_t maximum) {
+ const byte* p = pc_;
+ uint32_t count = consume_u32v(name);
+ if (count > maximum) {
+ error(p, p, "%s of %u exceeds internal limit of %zu", name, count,
+ maximum);
+ return static_cast<uint32_t>(maximum);
+ }
+ return count;
+ }
+
uint32_t consume_func_index(WasmModule* module, WasmFunction** func) {
return consume_index("function index", module->functions, func);
}
@@ -912,7 +970,7 @@ class ModuleDecoder : public Decoder {
return true;
}
- WasmInitExpr consume_init_expr(WasmModule* module, LocalType expected) {
+ WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
const byte* pos = pc();
uint8_t opcode = consume_u8("opcode");
WasmInitExpr expr;
@@ -978,7 +1036,7 @@ class ModuleDecoder : public Decoder {
if (!expect_u8("end opcode", kExprEnd)) {
expr.kind = WasmInitExpr::kNone;
}
- if (expected != kAstStmt && TypeOf(module, expr) != kAstI32) {
+ if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
error(pos, pos, "type error in init expression, expected %s, got %s",
WasmOpcodes::TypeName(expected),
WasmOpcodes::TypeName(TypeOf(module, expr)));
@@ -986,29 +1044,43 @@ class ModuleDecoder : public Decoder {
return expr;
}
+ // Read a mutability flag
+ bool consume_mutability() {
+ byte val = consume_u8("mutability");
+ if (val > 1) error(pc_ - 1, "invalid mutability");
+ return val != 0;
+ }
+
// Reads a single 8-bit integer, interpreting it as a local type.
- LocalType consume_value_type() {
+ ValueType consume_value_type() {
byte val = consume_u8("value type");
- LocalTypeCode t = static_cast<LocalTypeCode>(val);
+ ValueTypeCode t = static_cast<ValueTypeCode>(val);
switch (t) {
case kLocalI32:
- return kAstI32;
+ return kWasmI32;
case kLocalI64:
- return kAstI64;
+ return kWasmI64;
case kLocalF32:
- return kAstF32;
+ return kWasmF32;
case kLocalF64:
- return kAstF64;
- case kLocalS128:
+ return kWasmF64;
+ default:
if (origin_ != kAsmJsOrigin && FLAG_wasm_simd_prototype) {
- return kAstS128;
- } else {
- error(pc_ - 1, "invalid local type");
- return kAstStmt;
+ switch (t) {
+ case kLocalS128:
+ return kWasmS128;
+ case kLocalS1x4:
+ return kWasmS1x4;
+ case kLocalS1x8:
+ return kWasmS1x8;
+ case kLocalS1x16:
+ return kWasmS1x16;
+ default:
+ break;
+ }
}
- default:
error(pc_ - 1, "invalid local type");
- return kAstStmt;
+ return kWasmStmt;
}
}
@@ -1016,35 +1088,32 @@ class ModuleDecoder : public Decoder {
FunctionSig* consume_sig() {
if (!expect_u8("type form", kWasmFunctionTypeForm)) return nullptr;
// parse parameter types
- uint32_t param_count = consume_u32v("param count");
- std::vector<LocalType> params;
+ uint32_t param_count =
+ consume_count("param count", kV8MaxWasmFunctionParams);
+ if (failed()) return nullptr;
+ std::vector<ValueType> params;
for (uint32_t i = 0; ok() && i < param_count; ++i) {
- LocalType param = consume_value_type();
+ ValueType param = consume_value_type();
params.push_back(param);
}
// parse return types
- const byte* pt = pc_;
- uint32_t return_count = consume_u32v("return count");
- if (return_count > kMaxReturnCount) {
- error(pt, pt, "return count of %u exceeds maximum of %u", return_count,
- kMaxReturnCount);
- return nullptr;
- }
- std::vector<LocalType> returns;
+ const size_t max_return_count = FLAG_wasm_mv_prototype
+ ? kV8MaxWasmFunctionMultiReturns
+ : kV8MaxWasmFunctionReturns;
+ uint32_t return_count = consume_count("return count", max_return_count);
+ if (failed()) return nullptr;
+ std::vector<ValueType> returns;
for (uint32_t i = 0; ok() && i < return_count; ++i) {
- LocalType ret = consume_value_type();
+ ValueType ret = consume_value_type();
returns.push_back(ret);
}
- if (failed()) {
- // Decoding failed, return void -> void
- return new (module_zone) FunctionSig(0, 0, nullptr);
- }
+ if (failed()) return nullptr;
// FunctionSig stores the return types first.
- LocalType* buffer =
- module_zone->NewArray<LocalType>(param_count + return_count);
+ ValueType* buffer =
+ module_zone->NewArray<ValueType>(param_count + return_count);
uint32_t b = 0;
for (uint32_t i = 0; i < return_count; ++i) buffer[b++] = returns[i];
for (uint32_t i = 0; i < param_count; ++i) buffer[b++] = params[i];
@@ -1113,16 +1182,16 @@ ModuleResult DecodeWasmModule(Isolate* isolate, const byte* module_start,
isolate->counters()->wasm_decode_module_time());
size_t size = module_end - module_start;
if (module_start > module_end) return ModuleError("start > end");
- if (size >= kMaxModuleSize) return ModuleError("size > maximum module size");
+ if (size >= kV8MaxWasmModuleSize)
+ return ModuleError("size > maximum module size");
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_module_size_bytes()->AddSample(
static_cast<int>(size));
// Signatures are stored in zone memory, which have the same lifetime
// as the {module}.
Zone* zone = new Zone(isolate->allocator(), ZONE_NAME);
- WasmModule* module = new WasmModule(zone, module_start);
ModuleDecoder decoder(zone, module_start, module_end, origin);
- ModuleResult result = decoder.DecodeModule(module, verify_functions);
+ ModuleResult result = decoder.DecodeModule(verify_functions);
// TODO(bradnelson): Improve histogram handling of size_t.
// TODO(titzer): this isn't accurate, since it doesn't count the data
// allocated on the C++ heap.
@@ -1146,14 +1215,14 @@ WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) {
}
FunctionResult DecodeWasmFunction(Isolate* isolate, Zone* zone,
- ModuleEnv* module_env,
+ ModuleBytesEnv* module_env,
const byte* function_start,
const byte* function_end) {
HistogramTimerScope wasm_decode_function_time_scope(
isolate->counters()->wasm_decode_function_time());
size_t size = function_end - function_start;
if (function_start > function_end) return FunctionError("start > end");
- if (size > kMaxFunctionSize)
+ if (size > kV8MaxWasmFunctionSize)
return FunctionError("size > maximum function size");
isolate->counters()->wasm_function_size_bytes()->AddSample(
static_cast<int>(size));
@@ -1185,7 +1254,7 @@ FunctionOffsetsResult DecodeWasmFunctionOffsets(const byte* module_start,
for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
uint32_t size = decoder.consume_u32v("body size");
int offset = static_cast<int>(section_offset + decoder.pc_offset());
- table.push_back(std::make_pair(offset, static_cast<int>(size)));
+ table.emplace_back(offset, static_cast<int>(size));
DCHECK(table.back().first >= 0 && table.back().second >= 0);
decoder.consume_bytes(size);
}
@@ -1208,22 +1277,31 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
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>>());
+ table.emplace_back();
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");
+ uint32_t locals_size = decoder.consume_u32v("locals size");
+ int function_start_position = decoder.consume_u32v("function start pos");
int last_byte_offset = locals_size;
- int last_asm_position = 0;
- std::vector<std::pair<int, int>> func_asm_offsets;
+ int last_asm_position = function_start_position;
+ std::vector<AsmJsOffsetEntry> func_asm_offsets;
func_asm_offsets.reserve(size / 4); // conservative estimation
+ // Add an entry for the stack check, associated with position 0.
+ func_asm_offsets.push_back(
+ {0, function_start_position, function_start_position});
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});
+ int call_position =
+ last_asm_position + decoder.consume_i32v("call position delta");
+ int to_number_position =
+ call_position + decoder.consume_i32v("to_number position delta");
+ last_asm_position = to_number_position;
+ func_asm_offsets.push_back(
+ {last_byte_offset, call_position, to_number_position});
}
if (decoder.pc() != table_end) {
decoder.error("broken asm offset table");
@@ -1235,6 +1313,36 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
return decoder.toResult(std::move(table));
}
+std::vector<CustomSectionOffset> DecodeCustomSections(const byte* start,
+ const byte* end) {
+ Decoder decoder(start, end);
+ decoder.consume_bytes(4, "wasm magic");
+ decoder.consume_bytes(4, "wasm version");
+
+ std::vector<CustomSectionOffset> result;
+
+ while (decoder.more()) {
+ byte section_code = decoder.consume_u8("section code");
+ uint32_t section_length = decoder.consume_u32v("section length");
+ uint32_t section_start = decoder.pc_offset();
+ if (section_code != 0) {
+ // Skip known sections.
+ decoder.consume_bytes(section_length, "section bytes");
+ continue;
+ }
+ uint32_t name_length = decoder.consume_u32v("name length");
+ uint32_t name_offset = decoder.pc_offset();
+ decoder.consume_bytes(name_length, "section name");
+ uint32_t payload_offset = decoder.pc_offset();
+ uint32_t payload_length = section_length - (payload_offset - section_start);
+ decoder.consume_bytes(payload_length);
+ result.push_back({section_start, name_offset, name_length, payload_offset,
+ payload_length, section_length});
+ }
+
+ return result;
+}
+
} // namespace wasm
} // namespace internal
} // namespace v8