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 { ...@@ -549,8 +549,9 @@ class ModuleDecoderImpl : public Decoder {
break; break;
} }
import->index = static_cast<uint32_t>(module_->exceptions.size()); import->index = static_cast<uint32_t>(module_->exceptions.size());
module_->exceptions.emplace_back( WasmExceptionSig* exception_sig = nullptr;
consume_exception_sig(module_->signature_zone.get())); consume_exception_sig_index(module_.get(), &exception_sig);
module_->exceptions.emplace_back(exception_sig);
break; break;
} }
default: default:
...@@ -890,10 +891,11 @@ class ModuleDecoderImpl : public Decoder { ...@@ -890,10 +891,11 @@ class ModuleDecoderImpl : public Decoder {
uint32_t exception_count = uint32_t exception_count =
consume_count("exception count", kV8MaxWasmExceptions); consume_count("exception count", kV8MaxWasmExceptions);
for (uint32_t i = 0; ok() && i < exception_count; ++i) { 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_)); static_cast<int>(pc_ - start_));
module_->exceptions.emplace_back( WasmExceptionSig* exception_sig = nullptr;
consume_exception_sig(module_->signature_zone.get())); consume_exception_sig_index(module_.get(), &exception_sig);
module_->exceptions.emplace_back(exception_sig);
} }
} }
...@@ -1150,6 +1152,17 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1150,6 +1152,17 @@ class ModuleDecoderImpl : public Decoder {
return sig_index; 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) { uint32_t consume_count(const char* name, size_t maximum) {
const byte* p = pc_; const byte* p = pc_;
uint32_t count = consume_u32v(name); uint32_t count = consume_u32v(name);
...@@ -1408,19 +1421,7 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1408,19 +1421,7 @@ class ModuleDecoderImpl : public Decoder {
} }
FunctionSig* consume_sig(Zone* zone) { FunctionSig* consume_sig(Zone* zone) {
constexpr bool has_return_values = true; if (!expect_u8("type form", kWasmFunctionTypeCode)) return nullptr;
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;
// parse parameter types // parse parameter types
uint32_t param_count = uint32_t param_count =
consume_count("param count", kV8MaxWasmFunctionParams); consume_count("param count", kV8MaxWasmFunctionParams);
...@@ -1432,17 +1433,15 @@ class ModuleDecoderImpl : public Decoder { ...@@ -1432,17 +1433,15 @@ class ModuleDecoderImpl : public Decoder {
} }
std::vector<ValueType> returns; std::vector<ValueType> returns;
uint32_t return_count = 0; uint32_t return_count = 0;
if (has_return_values) { // parse return types
// parse return types const size_t max_return_count = enabled_features_.mv
const size_t max_return_count = enabled_features_.mv ? kV8MaxWasmFunctionMultiReturns
? kV8MaxWasmFunctionMultiReturns : kV8MaxWasmFunctionReturns;
: kV8MaxWasmFunctionReturns; return_count = consume_count("return count", max_return_count);
return_count = consume_count("return count", max_return_count); if (failed()) return nullptr;
if (failed()) return nullptr; for (uint32_t i = 0; ok() && i < return_count; ++i) {
for (uint32_t i = 0; ok() && i < return_count; ++i) { ValueType ret = consume_value_type();
ValueType ret = consume_value_type(); returns.push_back(ret);
returns.push_back(ret);
}
} }
if (failed()) return nullptr; if (failed()) return nullptr;
......
...@@ -228,11 +228,9 @@ class WasmModuleBuilder { ...@@ -228,11 +228,9 @@ class WasmModuleBuilder {
} }
addException(type) { addException(type) {
if (type.results.length != 0) { let type_index = (typeof type) == "number" ? type : this.addType(type);
throw new Error('Exception signature must have void result: ' + type);
}
let except_index = this.exceptions.length + this.num_imported_exceptions; let except_index = this.exceptions.length + this.num_imported_exceptions;
this.exceptions.push(type); this.exceptions.push(type_index);
return except_index; return except_index;
} }
...@@ -278,13 +276,11 @@ class WasmModuleBuilder { ...@@ -278,13 +276,11 @@ class WasmModuleBuilder {
} }
addImportedException(module = "", name, type) { addImportedException(module = "", name, type) {
if (type.results.length != 0) {
throw new Error('Exception signature must have void result: ' + type);
}
if (this.exceptions.length != 0) { if (this.exceptions.length != 0) {
throw new Error('Imported exceptions must be declared before local ones'); 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); this.imports.push(o);
return this.num_imported_exceptions++; return this.num_imported_exceptions++;
} }
...@@ -405,10 +401,7 @@ class WasmModuleBuilder { ...@@ -405,10 +401,7 @@ class WasmModuleBuilder {
section.emit_u32v(imp.initial); // initial section.emit_u32v(imp.initial); // initial
if (has_max) section.emit_u32v(imp.maximum); // maximum if (has_max) section.emit_u32v(imp.maximum); // maximum
} else if (imp.kind == kExternalException) { } else if (imp.kind == kExternalException) {
section.emit_u32v(imp.type.params.length); section.emit_u32v(imp.type);
for (let param of imp.type.params) {
section.emit_u8(param);
}
} else { } else {
throw new Error("unknown/unsupported import kind " + imp.kind); throw new Error("unknown/unsupported import kind " + imp.kind);
} }
...@@ -515,10 +508,7 @@ class WasmModuleBuilder { ...@@ -515,10 +508,7 @@ class WasmModuleBuilder {
binary.emit_section(kExceptionSectionCode, section => { binary.emit_section(kExceptionSectionCode, section => {
section.emit_u32v(wasm.exceptions.length); section.emit_u32v(wasm.exceptions.length);
for (let type of wasm.exceptions) { for (let type of wasm.exceptions) {
section.emit_u32v(type.params.length); section.emit_u32v(type);
for (let param of type.params) {
section.emit_u8(param);
}
} }
}); });
} }
......
...@@ -476,9 +476,12 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) { ...@@ -476,9 +476,12 @@ TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
} }
TEST_F(WasmModuleVerifyTest, OneI32Exception) { TEST_F(WasmModuleVerifyTest, OneI32Exception) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1, static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIG_ENTRY_v_x),
// except[0] (i32) 1,
1, kLocalI32}; 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); FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh); WASM_FEATURE_SCOPE(eh);
...@@ -492,11 +495,17 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) { ...@@ -492,11 +495,17 @@ TEST_F(WasmModuleVerifyTest, OneI32Exception) {
} }
TEST_F(WasmModuleVerifyTest, TwoExceptions) { TEST_F(WasmModuleVerifyTest, TwoExceptions) {
static const byte data[] = {SECTION_EXCEPTIONS(6), 2, constexpr int SIZEOF_SIGs = SIZEOF_SIG_ENTRY_v_x + SIZEOF_SIG_ENTRY_v_xx;
// except[0] (f32, i64) static const byte data[] = {SECTION(Type, 1 + SIZEOF_SIGs), 2,
2, kLocalF32, kLocalI64, // sig#0 (i32)
// except[1] (i32) SIG_ENTRY_v_x(kLocalI32),
1, 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); FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh); WASM_FEATURE_SCOPE(eh);
...@@ -511,10 +520,24 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) { ...@@ -511,10 +520,24 @@ TEST_F(WasmModuleVerifyTest, TwoExceptions) {
EXPECT_EQ(kWasmI32, e1.sig->GetParam(0)); EXPECT_EQ(kWasmI32, e1.sig->GetParam(0));
} }
TEST_F(WasmModuleVerifyTest, Exception_invalid_type) { TEST_F(WasmModuleVerifyTest, Exception_invalid_sig_index) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1, static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
// except[0] (?) SECTION_EXCEPTIONS(2), 1,
1, 64}; // 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); FAIL_IF_NO_EXPERIMENTAL_EH(data);
// Should fail decoding exception section. // Should fail decoding exception section.
...@@ -552,15 +575,16 @@ TEST_F(WasmModuleVerifyTest, ExceptionSectionBeforeImport) { ...@@ -552,15 +575,16 @@ TEST_F(WasmModuleVerifyTest, ExceptionSectionBeforeImport) {
} }
TEST_F(WasmModuleVerifyTest, ExceptionImport) { TEST_F(WasmModuleVerifyTest, ExceptionImport) {
static const byte data[] = {SECTION(Import, 9), // section header static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
1, // number of imports SECTION(Import, 8), // section header
NAME_LENGTH(1), // -- 1, // number of imports
'm', // module name NAME_LENGTH(1), // --
NAME_LENGTH(2), // -- 'm', // module name
'e', 'x', // exception name NAME_LENGTH(2), // --
kExternalException, // import kind 'e', // exception name
// except[0] (i32) 'x', // --
1, kLocalI32}; kExternalException, // import kind
IMPORT_SIG_INDEX(0)}; // except[0] (sig#0)
FAIL_IF_NO_EXPERIMENTAL_EH(data); FAIL_IF_NO_EXPERIMENTAL_EH(data);
WASM_FEATURE_SCOPE(eh); WASM_FEATURE_SCOPE(eh);
...@@ -571,12 +595,14 @@ TEST_F(WasmModuleVerifyTest, ExceptionImport) { ...@@ -571,12 +595,14 @@ TEST_F(WasmModuleVerifyTest, ExceptionImport) {
} }
TEST_F(WasmModuleVerifyTest, ExceptionExport) { TEST_F(WasmModuleVerifyTest, ExceptionExport) {
static const byte data[] = {SECTION_EXCEPTIONS(3), 1, static const byte data[] = {SIGNATURES_SECTION_VOID_VOID,
// except[0] (i32) SECTION_EXCEPTIONS(2),
1, kLocalI32, SECTION(Export, 4), 1,
1, // exports IMPORT_SIG_INDEX(0), // except[0] (sig#0)
NO_NAME, // -- SECTION(Export, 4), // section header
kExternalException, // -- 1, // number of exports
NO_NAME, // --
kExternalException, // --
EXCEPTION_INDEX(0)}; EXCEPTION_INDEX(0)};
FAIL_IF_NO_EXPERIMENTAL_EH(data); 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