Commit a8424d59 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Refactor the module decoder to work with section bytes

This CL refactors the module decoder so that it can process a list of
section buffers instead of one module buffer. This change is needed for
streaming compilation. Streaming compilation may require additional
changes.

This CL introduces the following interface to the module decoder:
StartDecoding -- starts the decoding
DecodeModuleHeader -- decodes the module header
DecodeSection -- decodes the section
FinishDecoding -- finishes the decoding and returns the WasmModule

Aside from the different interface the biggest change to the module
decoder is the introduction of a buffer_offset, which is the offset
of the current section buffer of the module decoder in the module bytes.
This buffer_offset is used to translate from section offsets to module
offsets and back.

Another nice change is that the module decoder does not have a zone
anymore. Instead the zone is stored directly in the WasmModule where
it belongs. Zone ownership is also more obvious now.

R=mtrofin@chromium.org, clemensh@chromium.org

Change-Id: I815d777ec380f4c617c39e828ea0c9746c0bae20
Reviewed-on: https://chromium-review.googlesource.com/505490
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#45374}
parent 4bbe2167
......@@ -37,10 +37,11 @@ namespace wasm {
// a buffer of bytes.
class Decoder {
public:
Decoder(const byte* start, const byte* end)
: start_(start), pc_(start), end_(end), error_offset_(0) {}
Decoder(const byte* start, const byte* pc, const byte* end)
: start_(start), pc_(pc), end_(end), error_offset_(0) {}
Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
: start_(start), pc_(start), end_(end), buffer_offset_(buffer_offset) {}
Decoder(const byte* start, const byte* pc, const byte* end,
uint32_t buffer_offset = 0)
: start_(start), pc_(pc), end_(end), buffer_offset_(buffer_offset) {}
virtual ~Decoder() {}
......@@ -183,7 +184,7 @@ class Decoder {
va_end(arguments);
error_msg_.assign(buffer.start(), len);
DCHECK_GE(pc, start_);
error_offset_ = static_cast<uint32_t>(pc - start_);
error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_;
onFirstError();
}
......@@ -214,28 +215,44 @@ class Decoder {
}
// Resets the boundaries of this decoder.
void Reset(const byte* start, const byte* end) {
void Reset(const byte* start, const byte* end, uint32_t buffer_offset = 0) {
start_ = start;
pc_ = start;
end_ = end;
buffer_offset_ = buffer_offset;
error_offset_ = 0;
error_msg_.clear();
}
void Reset(Vector<const uint8_t> bytes, uint32_t buffer_offset = 0) {
Reset(bytes.begin(), bytes.end(), buffer_offset);
}
bool ok() const { return error_msg_.empty(); }
bool failed() const { return !ok(); }
bool more() const { return pc_ < end_; }
const byte* start() const { return start_; }
const byte* pc() const { return pc_; }
uint32_t pc_offset() const { return static_cast<uint32_t>(pc_ - start_); }
uint32_t pc_offset() const {
return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
}
uint32_t buffer_offset() const { return buffer_offset_; }
// Takes an offset relative to the module start and returns an offset relative
// to the current buffer of the decoder.
uint32_t GetBufferRelativeOffset(uint32_t offset) const {
DCHECK_LE(buffer_offset_, offset);
return offset - buffer_offset_;
}
const byte* end() const { return end_; }
protected:
const byte* start_;
const byte* pc_;
const byte* end_;
uint32_t error_offset_;
// The offset of the current buffer in the module. Needed for streaming.
uint32_t buffer_offset_;
uint32_t error_offset_ = 0;
std::string error_msg_;
private:
......
......@@ -120,9 +120,7 @@ class WasmSectionIterator {
next();
}
inline bool more() const {
return section_code_ != kUnknownSectionCode && decoder_.more();
}
inline bool more() const { return decoder_.ok() && decoder_.more(); }
inline SectionCode section_code() const { return section_code_; }
......@@ -132,6 +130,10 @@ class WasmSectionIterator {
return static_cast<uint32_t>(section_end_ - section_start_);
}
inline Vector<const uint8_t> payload() const {
return {payload_start_, payload_length()};
}
inline const byte* payload_start() const { return payload_start_; }
inline uint32_t payload_length() const {
......@@ -142,7 +144,11 @@ class WasmSectionIterator {
// Advances to the next section, checking that decoding the current section
// stopped at {section_end_}.
void advance() {
void advance(bool move_to_section_end = false) {
if (move_to_section_end && decoder_.pc() < section_end_) {
decoder_.consume_bytes(
static_cast<uint32_t>(section_end_ - decoder_.pc()));
}
if (decoder_.pc() != section_end_) {
const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
decoder_.errorf(decoder_.pc(),
......@@ -164,65 +170,59 @@ class WasmSectionIterator {
// Reads the section code/name at the current position and sets up
// the embedder fields.
void next() {
while (true) {
if (!decoder_.more()) {
if (!decoder_.more()) {
section_code_ = kUnknownSectionCode;
return;
}
section_start_ = decoder_.pc();
uint8_t section_code = decoder_.consume_u8("section code");
// Read and check the section size.
uint32_t section_length = decoder_.consume_u32v("section length");
payload_start_ = decoder_.pc();
if (decoder_.checkAvailable(section_length)) {
// Get the limit of the section within the module.
section_end_ = payload_start_ + section_length;
} else {
// The section would extend beyond the end of the module.
section_end_ = payload_start_;
}
if (section_code == kUnknownSectionCode) {
// Check for the known "name" section.
uint32_t string_length;
uint32_t string_offset =
wasm::consume_string(decoder_, &string_length, true, "section name");
if (decoder_.failed() || decoder_.pc() > section_end_) {
section_code_ = kUnknownSectionCode;
return;
}
uint8_t section_code = decoder_.consume_u8("section code");
// 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;
} else {
// The section would extend beyond the end of the module.
section_end_ = section_start_;
}
if (section_code == kUnknownSectionCode) {
// Check for the known "name" section.
uint32_t string_length;
uint32_t string_offset = wasm::consume_string(decoder_, &string_length,
true, "section name");
if (decoder_.failed() || decoder_.pc() > section_end_) {
section_code_ = kUnknownSectionCode;
return;
}
const byte* section_name_start = decoder_.start() + string_offset;
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) {
section_code = kNameSectionCode;
}
} else if (!IsValidSectionCode(section_code)) {
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
section_code);
section_code = kUnknownSectionCode;
}
section_code_ = decoder_.failed()
? kUnknownSectionCode
: static_cast<SectionCode>(section_code);
TRACE("Section: %s\n", SectionName(section_code_));
if (section_code_ == kUnknownSectionCode &&
section_end_ > decoder_.pc()) {
// skip to the end of the unknown section.
uint32_t remaining =
static_cast<uint32_t>(section_end_ - decoder_.pc());
decoder_.consume_bytes(remaining, "section payload");
// fall through and continue to the next section.
} else {
return;
const byte* section_name_start =
decoder_.start() + decoder_.GetBufferRelativeOffset(string_offset);
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) {
section_code = kNameSectionCode;
}
} else if (!IsValidSectionCode(section_code)) {
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
section_code);
section_code = kUnknownSectionCode;
}
section_code_ = decoder_.failed() ? kUnknownSectionCode
: static_cast<SectionCode>(section_code);
TRACE("Section: %s\n", SectionName(section_code_));
if (section_code_ == kUnknownSectionCode && section_end_ > decoder_.pc()) {
// skip to the end of the unknown section.
uint32_t remaining = static_cast<uint32_t>(section_end_ - decoder_.pc());
decoder_.consume_bytes(remaining, "section payload");
}
}
};
......@@ -230,10 +230,9 @@ class WasmSectionIterator {
// The main logic for decoding the bytes of a module.
class ModuleDecoder : public Decoder {
public:
ModuleDecoder(Zone* zone, const byte* module_start, const byte* module_end,
ModuleDecoder(const byte* module_start, const byte* module_end,
ModuleOrigin origin)
: Decoder(module_start, module_end),
module_zone_(zone),
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
if (end_ < start_) {
error(start_, "end is less than start");
......@@ -272,14 +271,19 @@ class ModuleDecoder : public Decoder {
}
}
// Decodes an entire module.
ModuleResult DecodeModule(bool verify_functions = true) {
pc_ = start_;
std::unique_ptr<WasmModule> module(new WasmModule(module_zone_));
module->min_mem_pages = 0;
module->max_mem_pages = 0;
module->mem_export = false;
module->set_origin(origin_);
void StartDecoding(Isolate* isolate) {
CHECK_NULL(module_);
module_.reset(new WasmModule(
std::unique_ptr<Zone>(new Zone(isolate->allocator(), "signatures"))));
module_->min_mem_pages = 0;
module_->max_mem_pages = 0;
module_->mem_export = false;
module_->set_origin(origin_);
}
void DecodeModuleHeader(Vector<const uint8_t> bytes, uint8_t offset) {
if (failed()) return;
Reset(bytes, offset);
const byte* pos = pc_;
uint32_t magic_word = consume_u32("wasm magic");
......@@ -301,426 +305,463 @@ class ModuleDecoder : public Decoder {
BYTES(kWasmVersion), BYTES(magic_version));
}
}
}
WasmSectionIterator section_iter(*this);
// ===== Type section ====================================================
if (section_iter.section_code() == kTypeSectionCode) {
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_));
FunctionSig* s = consume_sig();
module->signatures.push_back(s);
}
section_iter.advance();
void DecodeSection(SectionCode section_code, Vector<const uint8_t> bytes,
uint32_t offset, bool verify_functions = true) {
if (failed()) return;
Reset(bytes, offset);
// Check if the section is out-of-order.
if (section_code < next_section_) {
errorf(pc(), "unexpected section: %s", SectionName(section_code));
return;
}
if (section_code != kUnknownSectionCode) {
next_section_ = section_code;
++next_section_;
}
// ===== Import section ==================================================
if (section_iter.section_code() == kImportSectionCode) {
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_));
module->import_table.push_back({
0, // module_name_length
0, // module_name_offset
0, // field_name_offset
0, // field_name_length
kExternalFunction, // kind
0 // index
});
WasmImport* import = &module->import_table.back();
const byte* pos = pc_;
import->module_name_offset =
consume_string(&import->module_name_length, true, "module name");
import->field_name_offset =
consume_string(&import->field_name_length, true, "field name");
import->kind = static_cast<WasmExternalKind>(consume_u8("import kind"));
switch (import->kind) {
case kExternalFunction: {
// ===== Imported function =======================================
import->index = static_cast<uint32_t>(module->functions.size());
module->num_imported_functions++;
module->functions.push_back({nullptr, // sig
import->index, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
true, // imported
false}); // exported
WasmFunction* function = &module->functions.back();
function->sig_index =
consume_sig_index(module.get(), &function->sig);
break;
}
case kExternalTable: {
// ===== Imported table ==========================================
if (!AddTable(module.get())) break;
import->index =
static_cast<uint32_t>(module->function_tables.size());
module->function_tables.push_back({0, 0, false,
std::vector<int32_t>(), true,
false, SignatureMap()});
expect_u8("element type", kWasmAnyFunctionTypeForm);
WasmIndirectFunctionTable* table = &module->function_tables.back();
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 =========================================
if (!AddMemory(module.get())) 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(
{kWasmStmt, false, WasmInitExpr(), 0, true, false});
WasmGlobal* global = &module->globals.back();
global->type = consume_value_type();
global->mutability = consume_mutability();
if (global->mutability) {
error("mutable globals cannot be imported");
}
break;
switch (section_code) {
case kUnknownSectionCode:
break;
case kTypeSectionCode:
DecodeTypeSection();
break;
case kImportSectionCode:
DecodeImportSection();
break;
case kFunctionSectionCode:
DecodeFunctionSection();
break;
case kTableSectionCode:
DecodeTableSection();
break;
case kMemorySectionCode:
DecodeMemorySection();
break;
case kGlobalSectionCode:
DecodeGlobalSection();
break;
case kExportSectionCode:
DecodeExportSection();
break;
case kStartSectionCode:
DecodeStartSection();
break;
case kCodeSectionCode:
DecodeCodeSection(verify_functions);
break;
case kElementSectionCode:
DecodeElementSection();
break;
case kDataSectionCode:
DecodeDataSection();
break;
case kNameSectionCode:
DecodeNameSection();
break;
default:
errorf(pc(), "unexpected section: %s", SectionName(section_code));
return;
}
if (pc() != bytes.end()) {
const char* msg = pc() < bytes.end() ? "shorter" : "longer";
errorf(pc(),
"section was %s than expected size "
"(%zu bytes expected, %zu decoded)",
msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin()));
}
}
void DecodeTypeSection() {
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_));
FunctionSig* s = consume_sig(module_->signature_zone.get());
module_->signatures.push_back(s);
}
}
void DecodeImportSection() {
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_));
module_->import_table.push_back({
0, // module_name_length
0, // module_name_offset
0, // field_name_offset
0, // field_name_length
kExternalFunction, // kind
0 // index
});
WasmImport* import = &module_->import_table.back();
const byte* pos = pc_;
import->module_name_offset =
consume_string(&import->module_name_length, true, "module name");
import->field_name_offset =
consume_string(&import->field_name_length, true, "field name");
import->kind = static_cast<WasmExternalKind>(consume_u8("import kind"));
switch (import->kind) {
case kExternalFunction: {
// ===== Imported function =======================================
import->index = static_cast<uint32_t>(module_->functions.size());
module_->num_imported_functions++;
module_->functions.push_back({nullptr, // sig
import->index, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
true, // imported
false}); // exported
WasmFunction* function = &module_->functions.back();
function->sig_index =
consume_sig_index(module_.get(), &function->sig);
break;
}
case kExternalTable: {
// ===== Imported table ==========================================
if (!AddTable(module_.get())) break;
import->index =
static_cast<uint32_t>(module_->function_tables.size());
module_->function_tables.push_back({0, 0, false,
std::vector<int32_t>(), true,
false, SignatureMap()});
expect_u8("element type", kWasmAnyFunctionTypeForm);
WasmIndirectFunctionTable* table = &module_->function_tables.back();
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 =========================================
if (!AddMemory(module_.get())) 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(
{kWasmStmt, false, WasmInitExpr(), 0, true, false});
WasmGlobal* global = &module_->globals.back();
global->type = consume_value_type();
global->mutability = consume_mutability();
if (global->mutability) {
error("mutable globals cannot be imported");
}
default:
errorf(pos, "unknown import kind 0x%02x", import->kind);
break;
break;
}
default:
errorf(pos, "unknown import kind 0x%02x", import->kind);
break;
}
section_iter.advance();
}
}
// ===== Function section ================================================
if (section_iter.section_code() == kFunctionSectionCode) {
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());
module->functions.push_back({nullptr, // sig
func_index, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
false, // imported
false}); // exported
WasmFunction* function = &module->functions.back();
function->sig_index = consume_sig_index(module.get(), &function->sig);
}
section_iter.advance();
void DecodeFunctionSection() {
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());
module_->functions.push_back({nullptr, // sig
func_index, // func_index
0, // sig_index
0, // name_offset
0, // name_length
0, // code_start_offset
0, // code_end_offset
false, // imported
false}); // exported
WasmFunction* function = &module_->functions.back();
function->sig_index = consume_sig_index(module_.get(), &function->sig);
}
}
// ===== Table section ===================================================
if (section_iter.section_code() == kTableSectionCode) {
uint32_t table_count = consume_count("table count", kV8MaxWasmTables);
for (uint32_t i = 0; ok() && i < table_count; i++) {
if (!AddTable(module.get())) 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",
FLAG_wasm_max_table_size, &table->min_size,
&table->has_max, FLAG_wasm_max_table_size,
&table->max_size);
}
section_iter.advance();
void DecodeTableSection() {
uint32_t table_count = consume_count("table count", kV8MaxWasmTables);
for (uint32_t i = 0; ok() && i < table_count; i++) {
if (!AddTable(module_.get())) 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",
FLAG_wasm_max_table_size, &table->min_size,
&table->has_max, FLAG_wasm_max_table_size,
&table->max_size);
}
}
// ===== Memory section ==================================================
if (section_iter.section_code() == kMemorySectionCode) {
uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
void DecodeMemorySection() {
uint32_t memory_count = consume_count("memory count", kV8MaxWasmMemories);
for (uint32_t i = 0; ok() && i < memory_count; i++) {
if (!AddMemory(module.get())) break;
consume_resizable_limits("memory", "pages", FLAG_wasm_max_mem_pages,
&module->min_mem_pages, &module->has_max_mem,
kSpecMaxWasmMemoryPages,
&module->max_mem_pages);
}
section_iter.advance();
for (uint32_t i = 0; ok() && i < memory_count; i++) {
if (!AddMemory(module_.get())) break;
consume_resizable_limits("memory", "pages", FLAG_wasm_max_mem_pages,
&module_->min_mem_pages, &module_->has_max_mem,
kSpecMaxWasmMemoryPages,
&module_->max_mem_pages);
}
}
// ===== Global section ==================================================
if (section_iter.section_code() == kGlobalSectionCode) {
uint32_t globals_count =
consume_count("globals count", kV8MaxWasmGlobals);
uint32_t imported_globals = static_cast<uint32_t>(module->globals.size());
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(
{kWasmStmt, false, WasmInitExpr(), 0, false, false});
WasmGlobal* global = &module->globals.back();
DecodeGlobalInModule(module.get(), i + imported_globals, global);
}
section_iter.advance();
void DecodeGlobalSection() {
uint32_t globals_count = consume_count("globals count", kV8MaxWasmGlobals);
uint32_t imported_globals = static_cast<uint32_t>(module_->globals.size());
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(
{kWasmStmt, false, WasmInitExpr(), 0, false, false});
WasmGlobal* global = &module_->globals.back();
DecodeGlobalInModule(module_.get(), i + imported_globals, global);
}
}
// ===== Export section ==================================================
if (section_iter.section_code() == kExportSectionCode) {
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_));
module->export_table.push_back({
0, // name_length
0, // name_offset
kExternalFunction, // kind
0 // index
});
WasmExport* exp = &module->export_table.back();
exp->name_offset =
consume_string(&exp->name_length, true, "field name");
const byte* pos = pc();
exp->kind = static_cast<WasmExternalKind>(consume_u8("export kind"));
switch (exp->kind) {
case kExternalFunction: {
WasmFunction* func = nullptr;
exp->index = consume_func_index(module.get(), &func);
module->num_exported_functions++;
if (func) func->exported = true;
break;
}
case kExternalTable: {
WasmIndirectFunctionTable* table = nullptr;
exp->index = consume_table_index(module.get(), &table);
if (table) table->exported = true;
break;
}
case kExternalMemory: {
uint32_t index = consume_u32v("memory index");
// 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;
}
case kExternalGlobal: {
WasmGlobal* global = nullptr;
exp->index = consume_global_index(module.get(), &global);
if (global) {
if (global->mutability) {
error("mutable globals cannot be exported");
}
global->exported = true;
}
break;
}
default:
errorf(pos, "invalid export kind 0x%02x", exp->kind);
break;
void DecodeExportSection() {
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_));
module_->export_table.push_back({
0, // name_length
0, // name_offset
kExternalFunction, // kind
0 // index
});
WasmExport* exp = &module_->export_table.back();
exp->name_offset = consume_string(&exp->name_length, true, "field name");
const byte* pos = pc();
exp->kind = static_cast<WasmExternalKind>(consume_u8("export kind"));
switch (exp->kind) {
case kExternalFunction: {
WasmFunction* func = nullptr;
exp->index = consume_func_index(module_.get(), &func);
module_->num_exported_functions++;
if (func) func->exported = true;
break;
}
}
// 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) {
// Return true if a < b.
if (a.name_length != b.name_length) {
return a.name_length < b.name_length;
case kExternalTable: {
WasmIndirectFunctionTable* table = nullptr;
exp->index = consume_table_index(module_.get(), &table);
if (table) table->exported = true;
break;
}
case kExternalMemory: {
uint32_t index = consume_u32v("memory index");
// TODO(titzer): This should become more regular
// once we support multiple memories.
if (!module_->has_memory || index != 0) {
error("invalid memory index != 0");
}
return memcmp(base + a.name_offset, base + b.name_offset,
a.name_length) < 0;
};
std::stable_sort(sorted_exports.begin(), sorted_exports.end(),
cmp_less);
auto it = sorted_exports.begin();
WasmExport* last = &*it++;
for (auto end = sorted_exports.end(); it != end; last = &*it++) {
DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
if (!cmp_less(*last, *it)) {
const byte* pc = start_ + it->name_offset;
errorf(pc, "Duplicate export name '%.*s' for functions %d and %d",
it->name_length, pc, last->index, it->index);
break;
module_->mem_export = true;
break;
}
case kExternalGlobal: {
WasmGlobal* global = nullptr;
exp->index = consume_global_index(module_.get(), &global);
if (global) {
if (global->mutability) {
error("mutable globals cannot be exported");
}
global->exported = true;
}
break;
}
default:
errorf(pos, "invalid export kind 0x%02x", exp->kind);
break;
}
section_iter.advance();
}
// ===== Start section ===================================================
if (section_iter.section_code() == kStartSectionCode) {
WasmFunction* func;
const byte* pos = pc_;
module->start_function_index = consume_func_index(module.get(), &func);
if (func &&
(func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
error(pos,
"invalid start function: non-zero parameter or return count");
}
section_iter.advance();
}
// ===== Elements section ================================================
if (section_iter.section_code() == kElementSectionCode) {
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");
if (table_index != 0) {
errorf(pos, "illegal table index %u != 0", table_index);
// 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);
auto cmp_less = [this](const WasmExport& a, const WasmExport& b) {
// Return true if a < b.
if (a.name_length != b.name_length) {
return a.name_length < b.name_length;
}
WasmIndirectFunctionTable* table = nullptr;
if (table_index >= module->function_tables.size()) {
errorf(pos, "out of bounds table index %u", table_index);
const byte* left = start() + GetBufferRelativeOffset(a.name_offset);
const byte* right = start() + GetBufferRelativeOffset(b.name_offset);
return memcmp(left, right, a.name_length) < 0;
};
std::stable_sort(sorted_exports.begin(), sorted_exports.end(), cmp_less);
auto it = sorted_exports.begin();
WasmExport* last = &*it++;
for (auto end = sorted_exports.end(); it != end; last = &*it++) {
DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
if (!cmp_less(*last, *it)) {
const byte* pc = start() + GetBufferRelativeOffset(it->name_offset);
errorf(pc, "Duplicate export name '%.*s' for functions %d and %d",
it->name_length, pc, last->index, it->index);
break;
}
table = &module->function_tables[table_index];
WasmInitExpr offset = consume_init_expr(module.get(), 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();
for (uint32_t j = 0; ok() && j < num_elem; j++) {
WasmFunction* func = nullptr;
uint32_t index = consume_func_index(module.get(), &func);
DCHECK_EQ(func != nullptr, ok());
if (!func) break;
DCHECK_EQ(index, func->func_index);
init->entries.push_back(index);
// Canonicalize signature indices during decoding.
table->map.FindOrInsert(func->sig);
}
}
}
}
section_iter.advance();
void DecodeStartSection() {
WasmFunction* func;
const byte* pos = pc_;
module_->start_function_index = consume_func_index(module_.get(), &func);
if (func &&
(func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
error(pos, "invalid start function: non-zero parameter or return count");
}
}
// ===== Code section ====================================================
if (section_iter.section_code() == kCodeSectionCode) {
const byte* pos = pc_;
uint32_t functions_count = consume_u32v("functions count");
if (functions_count != module->num_declared_functions) {
errorf(pos, "function body count %u mismatch (%u expected)",
functions_count, module->num_declared_functions);
void DecodeElementSection() {
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");
if (table_index != 0) {
errorf(pos, "illegal table index %u != 0", table_index);
}
for (uint32_t i = 0; ok() && i < functions_count; ++i) {
WasmFunction* function =
&module->functions[i + module->num_imported_functions];
uint32_t size = consume_u32v("body size");
function->code_start_offset = pc_offset();
function->code_end_offset = pc_offset() + size;
if (verify_functions) {
ModuleBytesEnv module_env(module.get(), nullptr,
ModuleWireBytes(start_, end_));
VerifyFunctionBody(i + module->num_imported_functions, &module_env,
function);
}
consume_bytes(size, "function body");
WasmIndirectFunctionTable* table = nullptr;
if (table_index >= module_->function_tables.size()) {
errorf(pos, "out of bounds table index %u", table_index);
break;
}
table = &module_->function_tables[table_index];
WasmInitExpr offset = consume_init_expr(module_.get(), 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();
for (uint32_t j = 0; ok() && j < num_elem; j++) {
WasmFunction* func = nullptr;
uint32_t index = consume_func_index(module_.get(), &func);
DCHECK_EQ(func != nullptr, ok());
if (!func) break;
DCHECK_EQ(index, func->func_index);
init->entries.push_back(index);
// Canonicalize signature indices during decoding.
table->map.FindOrInsert(func->sig);
}
section_iter.advance();
}
}
// ===== Data section ====================================================
if (section_iter.section_code() == kDataSectionCode) {
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");
break;
}
TRACE("DecodeDataSegment[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module->data_segments.push_back({
WasmInitExpr(), // dest_addr
0, // source_offset
0 // source_size
});
WasmDataSegment* segment = &module->data_segments.back();
DecodeDataSegmentInModule(module.get(), segment);
void DecodeCodeSection(bool verify_functions) {
const byte* pos = pc_;
uint32_t functions_count = consume_u32v("functions count");
if (functions_count != module_->num_declared_functions) {
errorf(pos, "function body count %u mismatch (%u expected)",
functions_count, module_->num_declared_functions);
}
for (uint32_t i = 0; ok() && i < functions_count; ++i) {
WasmFunction* function =
&module_->functions[i + module_->num_imported_functions];
uint32_t size = consume_u32v("body size");
function->code_start_offset = pc_offset();
function->code_end_offset = pc_offset() + size;
if (verify_functions) {
ModuleBytesEnv module_env(module_.get(), nullptr,
ModuleWireBytes(start_, end_));
VerifyFunctionBody(module_->signature_zone->allocator(),
i + module_->num_imported_functions, &module_env,
function);
}
section_iter.advance();
consume_bytes(size, "function body");
}
}
// ===== Name section ====================================================
if (section_iter.section_code() == kNameSectionCode) {
// 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_);
// Decode all name subsections.
// Be lenient with their order.
while (inner.ok() && inner.more()) {
uint8_t name_type = inner.consume_u8("name type");
if (name_type & 0x80) inner.error("name type if not varuint7");
uint32_t name_payload_len = inner.consume_u32v("name payload length");
if (!inner.checkAvailable(name_payload_len)) break;
// Decode function names, ignore the rest.
// Local names will be decoded when needed.
if (name_type == NameSectionType::kFunction) {
uint32_t functions_count = inner.consume_u32v("functions count");
for (; inner.ok() && functions_count > 0; --functions_count) {
uint32_t function_index = inner.consume_u32v("function index");
uint32_t name_length = 0;
uint32_t name_offset = wasm::consume_string(inner, &name_length,
false, "function name");
// Be lenient with errors in the name section: Ignore illegal
// or out-of-order indexes and non-UTF8 names. You can even assign
// to the same function multiple times (last valid one wins).
if (inner.ok() && function_index < module->functions.size() &&
unibrow::Utf8::Validate(inner.start() + name_offset,
name_length)) {
module->functions[function_index].name_offset = name_offset;
module->functions[function_index].name_length = name_length;
}
}
} else {
inner.consume_bytes(name_payload_len, "name subsection payload");
}
void DecodeDataSection() {
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");
break;
}
// Skip the whole names section in the outer decoder.
consume_bytes(section_iter.payload_length(), nullptr);
section_iter.advance();
TRACE("DecodeDataSegment[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module_->data_segments.push_back({
WasmInitExpr(), // dest_addr
0, // source_offset
0 // source_size
});
WasmDataSegment* segment = &module_->data_segments.back();
DecodeDataSegmentInModule(module_.get(), segment);
}
}
// ===== Remaining sections ==============================================
if (section_iter.more() && ok()) {
errorf(pc(), "unexpected section: %s",
SectionName(section_iter.section_code()));
void DecodeNameSection() {
// 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_, buffer_offset_);
// Decode all name subsections.
// Be lenient with their order.
while (inner.ok() && inner.more()) {
uint8_t name_type = inner.consume_u8("name type");
if (name_type & 0x80) inner.error("name type if not varuint7");
uint32_t name_payload_len = inner.consume_u32v("name payload length");
if (!inner.checkAvailable(name_payload_len)) break;
// Decode function names, ignore the rest.
// Local names will be decoded when needed.
if (name_type == NameSectionType::kFunction) {
uint32_t functions_count = inner.consume_u32v("functions count");
for (; inner.ok() && functions_count > 0; --functions_count) {
uint32_t function_index = inner.consume_u32v("function index");
uint32_t name_length = 0;
uint32_t name_offset =
wasm::consume_string(inner, &name_length, false, "function name");
// Be lenient with errors in the name section: Ignore illegal
// or out-of-order indexes and non-UTF8 names. You can even assign
// to the same function multiple times (last valid one wins).
if (inner.ok() && function_index < module_->functions.size() &&
unibrow::Utf8::Validate(
inner.start() + inner.GetBufferRelativeOffset(name_offset),
name_length)) {
module_->functions[function_index].name_offset = name_offset;
module_->functions[function_index].name_length = name_length;
}
}
} else {
inner.consume_bytes(name_payload_len, "name subsection payload");
}
}
// Skip the whole names section in the outer decoder.
consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
}
ModuleResult FinishDecoding(bool verify_functions = true) {
if (ok()) {
CalculateGlobalOffsets(module.get());
CalculateGlobalOffsets(module_.get());
}
ModuleResult result = toResult(std::move(module));
ModuleResult result = toResult(std::move(module_));
if (verify_functions && result.ok()) {
// Copy error code and location.
result.MoveErrorFrom(intermediate_result_);
......@@ -729,17 +770,51 @@ class ModuleDecoder : public Decoder {
return result;
}
// Decodes an entire module.
ModuleResult DecodeModule(Isolate* isolate, bool verify_functions = true) {
StartDecoding(isolate);
uint32_t offset = 0;
DecodeModuleHeader(Vector<const uint8_t>(start(), end() - start()), offset);
if (failed()) {
return FinishDecoding(verify_functions);
}
// Size of the module header.
offset += 8;
Decoder decoder(start_ + offset, end_, offset);
WasmSectionIterator section_iter(decoder);
while (ok() && section_iter.more()) {
// Shift the offset by the section header length
offset += section_iter.payload_start() - section_iter.section_start();
if (section_iter.section_code() != SectionCode::kUnknownSectionCode) {
DecodeSection(section_iter.section_code(), section_iter.payload(),
offset, verify_functions);
}
// Shift the offset by the remaining section payload
offset += section_iter.payload_length();
section_iter.advance(true);
}
if (decoder.failed()) {
return decoder.toResult<std::unique_ptr<WasmModule>>(nullptr);
}
return FinishDecoding(verify_functions);
}
// Decodes a single anonymous function starting at {start_}.
FunctionResult DecodeSingleFunction(ModuleBytesEnv* module_env,
FunctionResult DecodeSingleFunction(Zone* zone, ModuleBytesEnv* module_env,
std::unique_ptr<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(end_); // ---- code end
function->sig = consume_sig(zone); // 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(end_); // ---- code end
if (ok()) VerifyFunctionBody(0, module_env, function.get());
if (ok())
VerifyFunctionBody(zone->allocator(), 0, module_env, function.get());
FunctionResult result(std::move(function));
// Copy error code and location.
......@@ -748,9 +823,9 @@ class ModuleDecoder : public Decoder {
}
// Decodes a single function signature at {start}.
FunctionSig* DecodeFunctionSignature(const byte* start) {
FunctionSig* DecodeFunctionSignature(Zone* zone, const byte* start) {
pc_ = start;
FunctionSig* result = consume_sig();
FunctionSig* result = consume_sig(zone);
return ok() ? result : nullptr;
}
......@@ -760,11 +835,20 @@ class ModuleDecoder : public Decoder {
}
private:
Zone* module_zone_;
std::unique_ptr<WasmModule> module_;
// The type section is the first section in a module.
uint8_t next_section_ = kFirstSectionInModule;
// We store next_section_ as uint8_t instead of SectionCode so that we can
// increment it. This static_assert should make sure that SectionCode does not
// get bigger than uint8_t accidentially.
static_assert(sizeof(ModuleDecoder::next_section_) == sizeof(SectionCode),
"type mismatch");
Result<bool> intermediate_result_;
ModuleOrigin origin_;
uint32_t off(const byte* ptr) { return static_cast<uint32_t>(ptr - start_); }
uint32_t off(const byte* ptr) {
return static_cast<uint32_t>(ptr - start_) + buffer_offset_;
}
bool AddTable(WasmModule* module) {
if (module->function_tables.size() > 0) {
......@@ -831,13 +915,13 @@ class ModuleDecoder : public Decoder {
expect_u8("linear memory index", 0);
segment->dest_addr = consume_init_expr(module, kWasmI32);
segment->source_size = consume_u32v("source size");
segment->source_offset = static_cast<uint32_t>(pc_ - start_);
segment->source_offset = pc_offset();
// Validate the data is in the module.
uint32_t module_limit = static_cast<uint32_t>(end_ - start_);
if (!IsWithinLimit(module_limit, segment->source_offset,
// Validate the data is in the decoder buffer.
uint32_t limit = static_cast<uint32_t>(end_ - start_);
if (!IsWithinLimit(limit, GetBufferRelativeOffset(segment->source_offset),
segment->source_size)) {
error(start, "segment out of bounds of module");
error(start, "segment out of bounds of the section");
}
consume_bytes(segment->source_size, "segment data");
......@@ -861,20 +945,20 @@ class ModuleDecoder : public Decoder {
}
// Verifies the body (code) of a given function.
void VerifyFunctionBody(uint32_t func_num, ModuleBytesEnv* menv,
WasmFunction* function) {
void VerifyFunctionBody(AccountingAllocator* allocator, 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 " << func_name << std::endl;
}
FunctionBody body = {function->sig, start_,
start_ + function->code_start_offset,
start_ + function->code_end_offset};
FunctionBody body = {
function->sig, start_,
start_ + GetBufferRelativeOffset(function->code_start_offset),
start_ + GetBufferRelativeOffset(function->code_end_offset)};
DecodeResult result = VerifyWasmCode(
module_zone_->allocator(),
menv == nullptr ? nullptr : menv->module_env.module, body);
allocator, menv == nullptr ? nullptr : menv->module_env.module, body);
if (result.failed()) {
// Wrap the error message from the function decoder.
std::ostringstream str;
......@@ -1100,7 +1184,7 @@ class ModuleDecoder : public Decoder {
}
// Parses a type entry, which is currently limited to functions only.
FunctionSig* consume_sig() {
FunctionSig* consume_sig(Zone* zone) {
if (!expect_u8("type form", kWasmFunctionTypeForm)) return nullptr;
// parse parameter types
uint32_t param_count =
......@@ -1127,13 +1211,12 @@ class ModuleDecoder : public Decoder {
if (failed()) return nullptr;
// FunctionSig stores the return types first.
ValueType* buffer =
module_zone_->NewArray<ValueType>(param_count + return_count);
ValueType* buffer = 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];
return new (module_zone_) FunctionSig(return_count, param_count, buffer);
return new (zone) FunctionSig(return_count, param_count, buffer);
}
};
......@@ -1147,28 +1230,30 @@ ModuleResult DecodeWasmModuleInternal(Isolate* isolate,
if (size >= kV8MaxWasmModuleSize)
return ModuleResult::Error("size > maximum module size: %zu", size);
// TODO(bradnelson): Improve histogram handling of size_t.
if (is_sync)
if (is_sync) {
// TODO(karlschimpf): Make this work when asynchronous.
// https://bugs.chromium.org/p/v8/issues/detail?id=6361
(IsWasm(origin) ? isolate->counters()->wasm_wasm_module_size_bytes()
: isolate->counters()->wasm_asm_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);
ModuleDecoder decoder(zone, module_start, module_end, origin);
ModuleResult result = decoder.DecodeModule(verify_functions);
ModuleDecoder decoder(module_start, module_end, origin);
ModuleResult result = decoder.DecodeModule(isolate, 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.
// https://bugs.chromium.org/p/chromium/issues/detail?id=657320
if (is_sync)
if (is_sync && result.ok()) {
// TODO(karlschimpf): Make this work when asynchronous.
// https://bugs.chromium.org/p/v8/issues/detail?id=6361
(IsWasm(origin)
? isolate->counters()->wasm_decode_wasm_module_peak_memory_bytes()
: isolate->counters()->wasm_decode_asm_module_peak_memory_bytes())
->AddSample(static_cast<int>(zone->allocation_size()));
->AddSample(
static_cast<int>(result.val->signature_zone->allocation_size()));
}
return result;
}
......@@ -1192,14 +1277,13 @@ ModuleResult DecodeWasmModule(Isolate* isolate, const byte* module_start,
FunctionSig* DecodeWasmSignatureForTesting(Zone* zone, const byte* start,
const byte* end) {
ModuleDecoder decoder(zone, start, end, kWasmOrigin);
return decoder.DecodeFunctionSignature(start);
ModuleDecoder decoder(start, end, kWasmOrigin);
return decoder.DecodeFunctionSignature(zone, start);
}
WasmInitExpr DecodeWasmInitExprForTesting(const byte* start, const byte* end) {
AccountingAllocator allocator;
Zone zone(&allocator, ZONE_NAME);
ModuleDecoder decoder(&zone, start, end, kWasmOrigin);
ModuleDecoder decoder(start, end, kWasmOrigin);
return decoder.DecodeInitExpr(start);
}
......@@ -1223,9 +1307,9 @@ FunctionResult DecodeWasmFunctionInternal(Isolate* isolate, Zone* zone,
: isolate->counters()->wasm_asm_function_size_bytes())
->AddSample(static_cast<int>(size));
}
ModuleDecoder decoder(zone, function_start, function_end, kWasmOrigin);
ModuleDecoder decoder(function_start, function_end, kWasmOrigin);
return decoder.DecodeSingleFunction(
module_env, std::unique_ptr<WasmFunction>(new WasmFunction()));
zone, module_env, std::unique_ptr<WasmFunction>(new WasmFunction()));
}
} // namespace
......
......@@ -20,7 +20,7 @@ const uint8_t kWasmFunctionTypeForm = 0x60;
const uint8_t kWasmAnyFunctionTypeForm = 0x70;
const uint8_t kResizableMaximumFlag = 1;
enum SectionCode {
enum SectionCode : int8_t {
kUnknownSectionCode = 0, // code for unknown sections
kTypeSectionCode = 1, // Function signature declarations
kImportSectionCode = 2, // Import declarations
......@@ -34,6 +34,9 @@ enum SectionCode {
kCodeSectionCode = 10, // Function code
kDataSectionCode = 11, // Data segments
kNameSectionCode = 12, // Name section (encoded as a string)
// Helper values
kFirstSectionInModule = kTypeSectionCode,
};
enum NameSectionType : uint8_t { kFunction = 1, kLocal = 2 };
......
......@@ -960,8 +960,8 @@ WasmInstanceObject* wasm::GetOwningWasmInstance(Code* code) {
return WasmInstanceObject::cast(cell->value());
}
WasmModule::WasmModule(Zone* owned)
: owned_zone(owned), pending_tasks(new base::Semaphore(0)) {}
WasmModule::WasmModule(std::unique_ptr<Zone> owned)
: signature_zone(std::move(owned)), pending_tasks(new base::Semaphore(0)) {}
namespace {
......
......@@ -152,7 +152,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
static const uint32_t kPageSize = 0x10000; // Page size, 64kb.
static const uint32_t kMinMemPages = 1; // Minimum memory size = 64kb
Zone* owned_zone;
std::unique_ptr<Zone> signature_zone;
uint32_t min_mem_pages = 0; // minimum size of the memory in 64k pages
uint32_t max_mem_pages = 0; // maximum size of the memory in 64k pages
bool has_max_mem = false; // try if a maximum memory size exists
......@@ -185,10 +185,7 @@ struct V8_EXPORT_PRIVATE WasmModule {
std::unique_ptr<base::Semaphore> pending_tasks;
WasmModule() : WasmModule(nullptr) {}
WasmModule(Zone* owned_zone);
~WasmModule() {
if (owned_zone) delete owned_zone;
}
WasmModule(std::unique_ptr<Zone> owned);
ModuleOrigin get_origin() const { return origin_; }
void set_origin(ModuleOrigin new_value) { origin_ = new_value; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment