Commit 9c431505 authored by Karl Schimpf's avatar Karl Schimpf Committed by Commit Bot

Decode the exception section.

Modifies V8 to be able to parse the exception section (defining
exception types), when the experimental_wasm_eh flag is true.

Bug: v8:6577
Change-Id: I5d8b3fddaf5b0dec6b14ddd0992f9fb883e8dc90
Reviewed-on: https://chromium-review.googlesource.com/561757
Commit-Queue: Karl Schimpf <kschimpf@chromium.org>
Reviewed-by: 's avatarBill Budge <bbudge@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46539}
parent 1edb46cc
......@@ -29,6 +29,18 @@ namespace wasm {
#else
#define TRACE(...)
#endif
namespace {
const char kNameString[] = "name";
const char kExceptionString[] = "exception";
template <size_t N>
constexpr size_t num_chars(const char (&)[N]) {
return N - 1; // remove null character at end.
}
} // namespace
const char* SectionName(SectionCode code) {
switch (code) {
......@@ -57,7 +69,9 @@ const char* SectionName(SectionCode code) {
case kDataSectionCode:
return "Data";
case kNameSectionCode:
return "Name";
return kNameString;
case kExceptionSectionCode:
return kExceptionString;
default:
return "<unknown>";
}
......@@ -65,9 +79,6 @@ const char* SectionName(SectionCode code) {
namespace {
const char* kNameString = "name";
const size_t kNameStringLength = 4;
ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
switch (expr.kind) {
case WasmInitExpr::kNone:
......@@ -203,10 +214,15 @@ class WasmSectionIterator {
static_cast<int>(section_name_start - decoder_.start()),
string.length() < 20 ? string.length() : 20, section_name_start);
if (string.length() == kNameStringLength &&
if (string.length() == num_chars(kNameString) &&
strncmp(reinterpret_cast<const char*>(section_name_start),
kNameString, kNameStringLength) == 0) {
kNameString, num_chars(kNameString)) == 0) {
section_code = kNameSectionCode;
} else if (FLAG_experimental_wasm_eh &&
string.length() == num_chars(kExceptionString) &&
strncmp(reinterpret_cast<const char*>(section_name_start),
kExceptionString, num_chars(kExceptionString)) == 0) {
section_code = kExceptionSectionCode;
}
} else if (!IsValidSectionCode(section_code)) {
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
......@@ -359,6 +375,9 @@ class ModuleDecoder : public Decoder {
case kNameSectionCode:
DecodeNameSection();
break;
case kExceptionSectionCode:
DecodeExceptionSection();
break;
default:
errorf(pc(), "unexpected section: %s", SectionName(section_code));
return;
......@@ -752,6 +771,17 @@ class ModuleDecoder : public Decoder {
consume_bytes(static_cast<uint32_t>(end_ - start_), nullptr);
}
void DecodeExceptionSection() {
uint32_t exception_count =
consume_count("exception count", kV8MaxWasmExceptions);
for (uint32_t i = 0; ok() && i < exception_count; ++i) {
TRACE("DecodeExceptionSignature[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module_->exceptions.emplace_back(
consume_exception_sig(module_->signature_zone.get()));
}
}
ModuleResult FinishDecoding(bool verify_functions = true) {
if (ok()) {
CalculateGlobalOffsets(module_.get());
......@@ -1177,9 +1207,20 @@ class ModuleDecoder : public Decoder {
}
}
// Parses a type entry, which is currently limited to functions only.
FunctionSig* consume_sig(Zone* zone) {
if (!expect_u8("type form", kWasmFunctionTypeForm)) return nullptr;
constexpr bool has_return_values = true;
return consume_sig_internal(zone, has_return_values);
}
WasmExceptionSig* consume_exception_sig(Zone* zone) {
constexpr bool has_return_values = true;
return consume_sig_internal(zone, !has_return_values);
}
private:
FunctionSig* consume_sig_internal(Zone* zone, bool has_return_values) {
if (has_return_values && !expect_u8("type form", kWasmFunctionTypeForm))
return nullptr;
// parse parameter types
uint32_t param_count =
consume_count("param count", kV8MaxWasmFunctionParams);
......@@ -1189,17 +1230,19 @@ class ModuleDecoder : public Decoder {
ValueType param = consume_value_type();
params.push_back(param);
}
// parse return types
const size_t max_return_count = FLAG_experimental_wasm_mv
? 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) {
ValueType ret = consume_value_type();
returns.push_back(ret);
uint32_t return_count = 0;
if (has_return_values) {
// parse return types
const size_t max_return_count = FLAG_experimental_wasm_mv
? kV8MaxWasmFunctionMultiReturns
: kV8MaxWasmFunctionReturns;
return_count = consume_count("return count", max_return_count);
if (failed()) return nullptr;
for (uint32_t i = 0; ok() && i < return_count; ++i) {
ValueType ret = consume_value_type();
returns.push_back(ret);
}
}
if (failed()) return nullptr;
......
......@@ -21,19 +21,20 @@ const uint8_t kWasmAnyFunctionTypeForm = 0x70;
const uint8_t kResizableMaximumFlag = 1;
enum SectionCode : int8_t {
kUnknownSectionCode = 0, // code for unknown sections
kTypeSectionCode = 1, // Function signature declarations
kImportSectionCode = 2, // Import declarations
kFunctionSectionCode = 3, // Function declarations
kTableSectionCode = 4, // Indirect function table and other tables
kMemorySectionCode = 5, // Memory attributes
kGlobalSectionCode = 6, // Global declarations
kExportSectionCode = 7, // Exports
kStartSectionCode = 8, // Start function declaration
kElementSectionCode = 9, // Elements section
kCodeSectionCode = 10, // Function code
kDataSectionCode = 11, // Data segments
kNameSectionCode = 12, // Name section (encoded as a string)
kUnknownSectionCode = 0, // code for unknown sections
kTypeSectionCode = 1, // Function signature declarations
kImportSectionCode = 2, // Import declarations
kFunctionSectionCode = 3, // Function declarations
kTableSectionCode = 4, // Indirect function table and other tables
kMemorySectionCode = 5, // Memory attributes
kGlobalSectionCode = 6, // Global declarations
kExportSectionCode = 7, // Exports
kStartSectionCode = 8, // Start function declaration
kElementSectionCode = 9, // Elements section
kCodeSectionCode = 10, // Function code
kDataSectionCode = 11, // Data segments
kNameSectionCode = 12, // Name section (encoded as a string)
kExceptionSectionCode = 13, // Exception section (encoded as a string)
// Helper values
kFirstSectionInModule = kTypeSectionCode,
......
......@@ -20,6 +20,8 @@ constexpr size_t kV8MaxWasmFunctions = 1000000;
constexpr size_t kV8MaxWasmImports = 100000;
constexpr size_t kV8MaxWasmExports = 100000;
constexpr size_t kV8MaxWasmGlobals = 1000000;
constexpr size_t kV8MaxWasmExceptions = 1000000;
constexpr size_t kV8MaxWasmExceptionTypes = 1000000;
constexpr size_t kV8MaxWasmDataSegments = 100000;
// Don't use this limit directly, but use the value of FLAG_wasm_max_mem_pages.
// Current limit mimics the maximum allowed allocation on an ArrayBuffer
......
......@@ -213,6 +213,9 @@ void RecordLazyCodeStats(Code* code, Counters* counters) {
} // namespace
// static
const WasmExceptionSig wasm::WasmException::empty_sig_(0, 0, nullptr);
Handle<JSArrayBuffer> wasm::SetupArrayBuffer(Isolate* isolate,
void* allocation_base,
size_t allocation_length,
......
......@@ -112,6 +112,20 @@ struct WasmGlobal {
bool exported; // true if exported.
};
// Note: An exception signature only uses the params portion of a
// function signature.
typedef FunctionSig WasmExceptionSig;
struct WasmException {
explicit WasmException(const WasmExceptionSig* sig = &empty_sig_)
: sig(sig) {}
const WasmExceptionSig* sig; // type signature of the exception.
private:
static const WasmExceptionSig empty_sig_;
};
// Static representation of a wasm data segment.
struct WasmDataSegment {
WasmInitExpr dest_addr; // destination memory address of the data.
......@@ -169,20 +183,21 @@ struct V8_EXPORT_PRIVATE WasmModule {
bool mem_export = false; // true if the memory is exported
int start_function_index = -1; // start function, >= 0 if any
std::vector<WasmGlobal> globals; // globals in this module.
uint32_t globals_size = 0; // size of globals table.
uint32_t num_imported_functions = 0; // number of imported functions.
uint32_t num_declared_functions = 0; // number of declared functions.
uint32_t num_exported_functions = 0; // number of exported functions.
WireBytesRef name = {0, 0}; // module name, if any.
std::vector<WasmGlobal> globals;
uint32_t globals_size = 0;
uint32_t num_imported_functions = 0;
uint32_t num_declared_functions = 0;
uint32_t num_exported_functions = 0;
WireBytesRef name = {0, 0};
// TODO(wasm): Add url here, for spec'ed location information.
std::vector<FunctionSig*> signatures; // signatures in this module.
std::vector<WasmFunction> functions; // functions in this module.
std::vector<WasmDataSegment> data_segments; // data segments in this module.
std::vector<WasmIndirectFunctionTable> function_tables; // function tables.
std::vector<WasmImport> import_table; // import table.
std::vector<WasmExport> export_table; // export table.
std::vector<WasmTableInit> table_inits; // initializations of tables
std::vector<FunctionSig*> signatures;
std::vector<WasmFunction> functions;
std::vector<WasmDataSegment> data_segments;
std::vector<WasmIndirectFunctionTable> function_tables;
std::vector<WasmImport> import_table;
std::vector<WasmExport> export_table;
std::vector<WasmException> exceptions;
std::vector<WasmTableInit> table_inits;
WasmModule() : WasmModule(nullptr) {}
WasmModule(std::unique_ptr<Zone> owned);
......
......@@ -50,6 +50,8 @@ namespace wasm {
#define EMPTY_FUNCTION_SIGNATURES_SECTION SECTION(Function, 1), 0
#define EMPTY_FUNCTION_BODIES_SECTION SECTION(Code, 1), 0
#define SECTION_NAMES(size) SECTION(Unknown, size + 5), 4, 'n', 'a', 'm', 'e'
#define SECTION_EXCEPTIONS(size) \
SECTION(Unknown, size + 10), 9, 'e', 'x', 'c', 'e', 'p', 't', 'i', 'o', 'n'
#define EMPTY_NAMES_SECTION SECTION_NAMES(1), 0
#define X1(...) __VA_ARGS__
......@@ -363,6 +365,98 @@ TEST_F(WasmModuleVerifyTest, TwoGlobals) {
EXPECT_OFF_END_FAILURE(data, 1, sizeof(data));
}
TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
static const byte data[] = {
SECTION_EXCEPTIONS(1), 0,
};
{
// Should decode exception section with no exceptions
EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
}
TEST_F(WasmModuleVerifyTest, OneI32Exception) {
static const byte data[] = {
SECTION_EXCEPTIONS(3), 1,
1, // except[0] (i32)
kLocalI32,
};
{
// Should decode to exactly one exception
EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(1u, result.val->exceptions.size());
const WasmException& e0 = result.val->exceptions.front();
EXPECT_EQ(1u, e0.sig->parameter_count());
EXPECT_EQ(MachineRepresentation::kWord32, e0.sig->GetParam(0));
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
}
TEST_F(WasmModuleVerifyTest, TwoExceptions) {
static const byte data[] = {SECTION_EXCEPTIONS(6),
2,
2, // except[0] (f32, i64)
kLocalF32,
kLocalI64,
1, // except[1] (i32)
kLocalI32};
{
// Should decode to exactly two exceptions
EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(2u, result.val->exceptions.size());
const WasmException& e0 = result.val->exceptions.front();
EXPECT_EQ(2u, e0.sig->parameter_count());
EXPECT_EQ(MachineRepresentation::kFloat32, e0.sig->GetParam(0));
EXPECT_EQ(MachineRepresentation::kWord64, e0.sig->GetParam(1));
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
}
TEST_F(WasmModuleVerifyTest, Exception_invalid_type) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1,
1, // except[0] (?)
64};
{
// Should fail decoding exception section.
EXPERIMENTAL_FLAG_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_FALSE(result.ok());
}
{
// Should read exception section as unknown section.
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
EXPECT_EQ(0u, result.val->exceptions.size());
}
}
TEST_F(WasmModuleVerifyTest, OneSignature) {
{
static const byte data[] = {SIGNATURES_SECTION_VOID_VOID};
......
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