Commit c113f71a authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[wasm] Switch exception section encoding to new proposal.

This switches the encoding of the exceptions (in the exceptions as well
as the import section) to use a signature index instead of a flat type
vector encoding. Note that only signatures that have a void return type
can be used for declaring exceptions.

R=clemensh@chromium.org
BUG=v8:8153

Change-Id: I481ccbce9ddf29becdf4ed7ceffe80d6145446e1
Reviewed-on: https://chromium-review.googlesource.com/c/1280323
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56654}
parent c73fa4fc
......@@ -549,8 +549,9 @@ class ModuleDecoderImpl : public Decoder {
break;
}
import->index = static_cast<uint32_t>(module_->exceptions.size());
module_->exceptions.emplace_back(
consume_exception_sig(module_->signature_zone.get()));
WasmExceptionSig* exception_sig = nullptr;
consume_exception_sig_index(module_.get(), &exception_sig);
module_->exceptions.emplace_back(exception_sig);
break;
}
default:
......@@ -890,10 +891,11 @@ class ModuleDecoderImpl : public Decoder {
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,
TRACE("DecodeException[%d] module+%d\n", i,
static_cast<int>(pc_ - start_));
module_->exceptions.emplace_back(
consume_exception_sig(module_->signature_zone.get()));
WasmExceptionSig* exception_sig = nullptr;
consume_exception_sig_index(module_.get(), &exception_sig);
module_->exceptions.emplace_back(exception_sig);
}
}
......@@ -1150,6 +1152,17 @@ class ModuleDecoderImpl : public Decoder {
return sig_index;
}
uint32_t consume_exception_sig_index(WasmModule* module, FunctionSig** sig) {
const byte* pos = pc_;
uint32_t sig_index = consume_sig_index(module, sig);
if (*sig && (*sig)->return_count() != 0) {
errorf(pos, "exception signature %u has non-void return", sig_index);
*sig = nullptr;
return 0;
}
return sig_index;
}
uint32_t consume_count(const char* name, size_t maximum) {
const byte* p = pc_;
uint32_t count = consume_u32v(name);
......@@ -1408,19 +1421,7 @@ class ModuleDecoderImpl : public Decoder {
}
FunctionSig* consume_sig(Zone* zone) {
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", kWasmFunctionTypeCode))
return nullptr;
if (!expect_u8("type form", kWasmFunctionTypeCode)) return nullptr;
// parse parameter types
uint32_t param_count =
consume_count("param count", kV8MaxWasmFunctionParams);
......@@ -1432,17 +1433,15 @@ class ModuleDecoderImpl : public Decoder {
}
std::vector<ValueType> returns;
uint32_t return_count = 0;
if (has_return_values) {
// parse return types
const size_t max_return_count = enabled_features_.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);
}
// parse return types
const size_t max_return_count = enabled_features_.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;
......
......@@ -228,11 +228,9 @@ class WasmModuleBuilder {
}
addException(type) {
if (type.results.length != 0) {
throw new Error('Exception signature must have void result: ' + type);
}
let type_index = (typeof type) == "number" ? type : this.addType(type);
let except_index = this.exceptions.length + this.num_imported_exceptions;
this.exceptions.push(type);
this.exceptions.push(type_index);
return except_index;
}
......@@ -278,13 +276,11 @@ class WasmModuleBuilder {
}
addImportedException(module = "", name, type) {
if (type.results.length != 0) {
throw new Error('Exception signature must have void result: ' + type);
}
if (this.exceptions.length != 0) {
throw new Error('Imported exceptions must be declared before local ones');
}
let o = {module: module, name: name, kind: kExternalException, type: type};
let type_index = (typeof type) == "number" ? type : this.addType(type);
let o = {module: module, name: name, kind: kExternalException, type: type_index};
this.imports.push(o);
return this.num_imported_exceptions++;
}
......@@ -405,10 +401,7 @@ class WasmModuleBuilder {
section.emit_u32v(imp.initial); // initial
if (has_max) section.emit_u32v(imp.maximum); // maximum
} else if (imp.kind == kExternalException) {
section.emit_u32v(imp.type.params.length);
for (let param of imp.type.params) {
section.emit_u8(param);
}
section.emit_u32v(imp.type);
} else {
throw new Error("unknown/unsupported import kind " + imp.kind);
}
......@@ -515,10 +508,7 @@ class WasmModuleBuilder {
binary.emit_section(kExceptionSectionCode, section => {
section.emit_u32v(wasm.exceptions.length);
for (let type of wasm.exceptions) {
section.emit_u32v(type.params.length);
for (let param of type.params) {
section.emit_u8(param);
}
section.emit_u32v(type);
}
});
}
......
......@@ -476,9 +476,12 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
}
TEST_F(WasmModuleVerifyTest, OneI32Exception) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1,
// except[0] (i32)
1, kLocalI32};
static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIG_ENTRY_v_x),
1,
SIG_ENTRY_v_x(kLocalI32), // sig#0 (i32)
SECTION_EXCEPTIONS(2), // section header
1, // # of exceptions
IMPORT_SIG_INDEX(0)}; // except[0] (sig#0)
FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh);
......@@ -492,11 +495,17 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) {
}
TEST_F(WasmModuleVerifyTest, TwoExceptions) {
static const byte data[] = {SECTION_EXCEPTIONS(6), 2,
// except[0] (f32, i64)
2, kLocalF32, kLocalI64,
// except[1] (i32)
1, kLocalI32};
constexpr int SIZEOF_SIGs = SIZEOF_SIG_ENTRY_v_x + SIZEOF_SIG_ENTRY_v_xx;
static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIGs), 2,
// sig#0 (i32)
SIG_ENTRY_v_x(kLocalI32),
// sig#1 (f32, i64)
SIG_ENTRY_v_xx(kLocalF32, kLocalI64),
SECTION_EXCEPTIONS(3), 2,
// except[0] (sig#1)
IMPORT_SIG_INDEX(1),
// except[1] (sig#0)
IMPORT_SIG_INDEX(0)};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh);
......@@ -511,10 +520,24 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) {
EXPECT_EQ(kWasmI32, e1.sig->GetParam(0));
}
TEST_F(WasmModuleVerifyTest, Exception_invalid_type) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1,
// except[0] (?)
1, 64};
TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_index) {
static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
SECTION_EXCEPTIONS(2), 1,
// except[0] (sig#23 [out-of-bounds])
IMPORT_SIG_INDEX(23)};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
// Should fail decoding exception section.
WASM_FEATURE_SCOPE(eh);
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_FALSE(result.ok());
}
TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_return) {
static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIG_ENTRY_x_x), 1,
SIG_ENTRY_i_i, SECTION_EXCEPTIONS(2), 1,
// except[0] (sig#0 [invalid-return-type])
IMPORT_SIG_INDEX(0)};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
// Should fail decoding exception section.
......@@ -552,15 +575,16 @@ TEST_F(WasmModuleVerifyTest, ExceptionSectionBeforeImport) {
}
TEST_F(WasmModuleVerifyTest, ExceptionImport) {
static const byte data[] = {SECTION(Import, 9), // section header
1, // number of imports
NAME_LENGTH(1), // --
'm', // module name
NAME_LENGTH(2), // --
'e', 'x', // exception name
kExternalException, // import kind
// except[0] (i32)
1, kLocalI32};
static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
SECTION(Import, 8), // section header
1, // number of imports
NAME_LENGTH(1), // --
'm', // module name
NAME_LENGTH(2), // --
'e', // exception name
'x', // --
kExternalException, // import kind
IMPORT_SIG_INDEX(0)}; // except[0] (sig#0)
FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh);
......@@ -571,12 +595,14 @@ TEST_F(WasmModuleVerifyTest, ExceptionImport) {
}
TEST_F(WasmModuleVerifyTest, ExceptionExport) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1,
// except[0] (i32)
1, kLocalI32, SECTION(Export, 4),
1, // exports
NO_NAME, // --
kExternalException, // --
static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
SECTION_EXCEPTIONS(2),
1,
IMPORT_SIG_INDEX(0), // except[0] (sig#0)
SECTION(Export, 4), // section header
1, // number of exports
NO_NAME, // --
kExternalException, // --
EXCEPTION_INDEX(0)};
FAIL_IF_NO_EXPERIMENTAL_EH(data);
......
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