[wasm] Add support for 'except_ref' value type.

This adds experimental support for an 'except_ref' value type for caught
exceptions as per the exception handling proposal. In the current for it
is only allowed to have such types in the stack or in a local, support
for having it as part of any signature was left out.

The default value for a local of type 'except_ref' is the 'ref_null'
value for now. Since this value cannot escape a wasm function, the
concrete value is not actually observable.

R=ahaas@chromium.org
TEST=unittests/LocalDeclDecoderTest.ExceptRef,mjsunit/wasm/exceptions
BUG=v8:8091

Change-Id: I7bd65274327a833262f8749cbe0e24e737f6e0c1
Reviewed-on: https://chromium-review.googlesource.com/1196510
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55526}
This commit is contained in:
Michael Starzinger 2018-08-30 14:46:48 +02:00 committed by Commit Bot
parent b9540d447f
commit f19a70681d
8 changed files with 51 additions and 6 deletions

View File

@ -737,6 +737,13 @@ class WasmDecoder : public Decoder {
} }
decoder->error(decoder->pc() - 1, "invalid local type"); decoder->error(decoder->pc() - 1, "invalid local type");
return false; return false;
case kLocalExceptRef:
if (enabled.eh) {
type = kWasmExceptRef;
break;
}
decoder->error(decoder->pc() - 1, "invalid local type");
return false;
case kLocalS128: case kLocalS128:
if (enabled.simd) { if (enabled.simd) {
type = kWasmS128; type = kWasmS128;

View File

@ -99,6 +99,12 @@ class WasmGraphBuildingInterface {
// instance parameter. // instance parameter.
TFNode* start = builder_->Start( TFNode* start = builder_->Start(
static_cast<int>(decoder->sig_->parameter_count() + 1 + 1)); static_cast<int>(decoder->sig_->parameter_count() + 1 + 1));
ssa_env->effect = start;
ssa_env->control = start;
// Initialize effect and control before initializing the locals default
// values (which might require instance loads) or loading the context.
builder_->set_effect_ptr(&ssa_env->effect);
builder_->set_control_ptr(&ssa_env->control);
// Initialize the instance parameter (index 0). // Initialize the instance parameter (index 0).
builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex)); builder_->set_instance_node(builder_->Param(kWasmInstanceParameterIndex));
// Initialize local variables. Parameters are shifted by 1 because of the // Initialize local variables. Parameters are shifted by 1 because of the
@ -115,11 +121,6 @@ class WasmGraphBuildingInterface {
ssa_env->locals[index++] = node; ssa_env->locals[index++] = node;
} }
} }
ssa_env->effect = start;
ssa_env->control = start;
// Initialize effect and control before loading the context.
builder_->set_effect_ptr(&ssa_env->effect);
builder_->set_control_ptr(&ssa_env->control);
LoadContextIntoSsa(ssa_env); LoadContextIntoSsa(ssa_env);
SetEnv(ssa_env); SetEnv(ssa_env);
} }
@ -596,6 +597,8 @@ class WasmGraphBuildingInterface {
return builder_->Float64Constant(0); return builder_->Float64Constant(0);
case kWasmS128: case kWasmS128:
return builder_->S128Zero(); return builder_->S128Zero();
case kWasmExceptRef:
return builder_->RefNull();
default: default:
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -21,6 +21,7 @@ enum ValueType : uint8_t {
kWasmS128, kWasmS128,
kWasmAnyRef, kWasmAnyRef,
kWasmAnyFunc, kWasmAnyFunc,
kWasmExceptRef,
kWasmVar, kWasmVar,
}; };
@ -220,6 +221,8 @@ class V8_EXPORT_PRIVATE ValueTypes {
return kLocalS128; return kLocalS128;
case kWasmAnyRef: case kWasmAnyRef:
return kLocalAnyRef; return kLocalAnyRef;
case kWasmExceptRef:
return kLocalExceptRef;
case kWasmStmt: case kWasmStmt:
return kLocalVoid; return kLocalVoid;
default: default:

View File

@ -25,7 +25,8 @@ enum ValueTypeCode : uint8_t {
kLocalF64 = 0x7c, kLocalF64 = 0x7c,
kLocalS128 = 0x7b, kLocalS128 = 0x7b,
kLocalAnyFunc = 0x70, kLocalAnyFunc = 0x70,
kLocalAnyRef = 0x6f kLocalAnyRef = 0x6f,
kLocalExceptRef = 0x68,
}; };
// Binary encoding of other types. // Binary encoding of other types.
constexpr uint8_t kWasmFunctionTypeCode = 0x60; constexpr uint8_t kWasmFunctionTypeCode = 0x60;

View File

@ -7,6 +7,19 @@
load("test/mjsunit/wasm/wasm-constants.js"); load("test/mjsunit/wasm/wasm-constants.js");
load("test/mjsunit/wasm/wasm-module-builder.js"); load("test/mjsunit/wasm/wasm-module-builder.js");
// First we just test that "except_ref" local variables are allowed.
(function TestLocalExceptRef() {
let builder = new WasmModuleBuilder();
builder.addFunction("push_and_drop_except_ref", kSig_v_v)
.addBody([
kExprGetLocal, 0,
kExprDrop,
]).addLocals({except_count: 1}).exportFunc();
let instance = builder.instantiate();
assertDoesNotThrow(instance.exports.push_and_drop_except_ref);
})();
// The following method doesn't attempt to catch an raised exception. // The following method doesn't attempt to catch an raised exception.
(function TestThrowSimple() { (function TestThrowSimple() {
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();

View File

@ -91,6 +91,7 @@ let kWasmF32 = 0x7d;
let kWasmF64 = 0x7c; let kWasmF64 = 0x7c;
let kWasmS128 = 0x7b; let kWasmS128 = 0x7b;
let kWasmAnyRef = 0x6f; let kWasmAnyRef = 0x6f;
let kWasmExceptRef = 0x68;
let kExternalFunction = 0; let kExternalFunction = 0;
let kExternalTable = 1; let kExternalTable = 1;

View File

@ -569,6 +569,9 @@ class WasmModuleBuilder {
if (l.s128_count > 0) { if (l.s128_count > 0) {
local_decls.push({count: l.s128_count, type: kWasmS128}); local_decls.push({count: l.s128_count, type: kWasmS128});
} }
if (l.except_count > 0) {
local_decls.push({count: l.except_count, type: kWasmExceptRef});
}
} }
let header = new Binary; let header = new Binary;

View File

@ -3127,6 +3127,20 @@ TEST_F(LocalDeclDecoderTest, UseEncoder) {
pos = ExpectRun(map, pos, kWasmI64, 212); pos = ExpectRun(map, pos, kWasmI64, 212);
} }
TEST_F(LocalDeclDecoderTest, ExceptRef) {
WASM_FEATURE_SCOPE(eh);
ValueType type = kWasmExceptRef;
const byte data[] = {1, 1,
static_cast<byte>(ValueTypes::ValueTypeCodeFor(type))};
BodyLocalDecls decls(zone());
bool result = DecodeLocalDecls(&decls, data, data + sizeof(data));
EXPECT_TRUE(result);
EXPECT_EQ(1u, decls.type_list.size());
TypesOfLocals map = decls.type_list;
EXPECT_EQ(type, map[0]);
}
class BytecodeIteratorTest : public TestWithZone {}; class BytecodeIteratorTest : public TestWithZone {};
TEST_F(BytecodeIteratorTest, SimpleForeach) { TEST_F(BytecodeIteratorTest, SimpleForeach) {