Commit 8b9c2ac3 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Preparation for rtt global initializers

Motivation: With rtt.sub now allowed in constant expressions, we have
to generalize WasmInitExpr to be able to handle expressions with
operands. This is the second CL that prepares the ground for this
change.

Changes:
- Remove the error from read-value-type when reading a generic rtt.
- Add validation for HeapTypeImmediate in ModuleDecoder. Use it to
  validate null constants immediates, which was missing. Add tests.
- Change ValueType::name to print rtt depths as integers.
- Move global initializer building in wasm-module-builder to its own
  function.

Bug: v8:7748
Change-Id: Ic041e1c7d032f2a1063a21fec1bfe96cb0d8120e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2284983
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68767}
parent f85021ca
......@@ -262,11 +262,6 @@ ValueType read_value_type(Decoder* decoder, const byte* pc,
}
HeapType heap_type = read_heap_type<validate>(
decoder, pc + depth_length + 1, length, enabled);
// TODO(7748): Support RTTs for generic types.
if (heap_type.is_generic()) {
decoder->error(pc, "UNIMPLEMENTED");
return kWasmBottom;
}
*length += depth_length + 1;
return heap_type.is_bottom() ? kWasmBottom
: ValueType::Rtt(heap_type, depth);
......
......@@ -1605,6 +1605,25 @@ class ModuleDecoderImpl : public Decoder {
return true;
}
// TODO(manoskouk): This is copy-modified from function-body-decoder-impl.h.
// We should find a way to share this code.
V8_INLINE bool Validate(const byte* pc, HeapTypeImmediate<kValidate>& imm) {
if (V8_UNLIKELY(imm.type.is_bottom())) {
error(pc, "invalid heap type");
return false;
}
if (V8_UNLIKELY(!(imm.type.is_generic() ||
module_->has_array(imm.type.ref_index()) ||
module_->has_struct(imm.type.ref_index())))) {
errorf(
pc,
"Type index %u does not refer to a struct or array type definition",
imm.type.ref_index());
return false;
}
return true;
}
WasmInitExpr consume_init_expr(WasmModule* module, ValueType expected) {
constexpr Decoder::ValidateFlag validate = Decoder::kValidate;
WasmOpcode opcode = kExprNop;
......@@ -1665,9 +1684,10 @@ class ModuleDecoderImpl : public Decoder {
}
HeapTypeImmediate<Decoder::kValidate> imm(enabled_features_, this,
pc() + 1);
len = 1 + imm.length;
if (!Validate(pc() + 1, imm)) break;
stack.push_back(
WasmInitExpr::RefNullConst(imm.type.representation()));
len = 1 + imm.length;
break;
}
case kExprRefFunc: {
......
......@@ -381,7 +381,8 @@ class ValueType {
}
break;
case kRtt:
buf << "(rtt " << depth() << " " << heap_type().name() + ")";
buf << "(rtt " << static_cast<uint32_t>(depth()) << " "
<< heap_type().name() + ")";
break;
default:
buf << kind_name();
......
......@@ -422,6 +422,75 @@ void WriteValueType(ZoneBuffer* buffer, const ValueType& type) {
}
}
void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
ValueType type) {
switch (init.kind()) {
case WasmInitExpr::kI32Const:
buffer->write_u8(kExprI32Const);
buffer->write_i32v(init.immediate().i32_const);
break;
case WasmInitExpr::kI64Const:
buffer->write_u8(kExprI64Const);
buffer->write_i64v(init.immediate().i64_const);
break;
case WasmInitExpr::kF32Const:
buffer->write_u8(kExprF32Const);
buffer->write_f32(init.immediate().f32_const);
break;
case WasmInitExpr::kF64Const:
buffer->write_u8(kExprF64Const);
buffer->write_f64(init.immediate().f64_const);
break;
case WasmInitExpr::kGlobalGet:
buffer->write_u8(kExprGlobalGet);
buffer->write_u32v(init.immediate().index);
break;
case WasmInitExpr::kRefNullConst:
buffer->write_u8(kExprRefNull);
buffer->write_i32v(HeapType(init.immediate().heap_type).code());
break;
case WasmInitExpr::kRefFuncConst:
buffer->write_u8(kExprRefFunc);
buffer->write_u32v(init.immediate().index);
break;
case WasmInitExpr::kNone: {
// No initializer, emit a default value.
switch (type.kind()) {
case ValueType::kI32:
buffer->write_u8(kExprI32Const);
// LEB encoding of 0.
buffer->write_u8(0);
break;
case ValueType::kI64:
buffer->write_u8(kExprI64Const);
// LEB encoding of 0.
buffer->write_u8(0);
break;
case ValueType::kF32:
buffer->write_u8(kExprF32Const);
buffer->write_f32(0.f);
break;
case ValueType::kF64:
buffer->write_u8(kExprF64Const);
buffer->write_f64(0.);
break;
case ValueType::kOptRef:
buffer->write_u8(kExprRefNull);
break;
case ValueType::kI8:
case ValueType::kI16:
case ValueType::kStmt:
case ValueType::kS128:
case ValueType::kBottom:
case ValueType::kRef:
case ValueType::kRtt:
UNREACHABLE();
}
break;
}
}
}
} // namespace
void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
......@@ -542,75 +611,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
for (const WasmGlobal& global : globals_) {
WriteValueType(buffer, global.type);
buffer->write_u8(global.mutability ? 1 : 0);
switch (global.init.kind()) {
case WasmInitExpr::kI32Const:
DCHECK_EQ(kWasmI32, global.type);
buffer->write_u8(kExprI32Const);
buffer->write_i32v(global.init.immediate().i32_const);
break;
case WasmInitExpr::kI64Const:
DCHECK_EQ(kWasmI64, global.type);
buffer->write_u8(kExprI64Const);
buffer->write_i64v(global.init.immediate().i64_const);
break;
case WasmInitExpr::kF32Const:
DCHECK_EQ(kWasmF32, global.type);
buffer->write_u8(kExprF32Const);
buffer->write_f32(global.init.immediate().f32_const);
break;
case WasmInitExpr::kF64Const:
DCHECK_EQ(kWasmF64, global.type);
buffer->write_u8(kExprF64Const);
buffer->write_f64(global.init.immediate().f64_const);
break;
case WasmInitExpr::kGlobalGet:
buffer->write_u8(kExprGlobalGet);
buffer->write_u32v(global.init.immediate().index);
break;
case WasmInitExpr::kRefNullConst:
buffer->write_u8(kExprRefNull);
buffer->write_i32v(
HeapType(global.init.immediate().heap_type).code());
break;
case WasmInitExpr::kRefFuncConst:
UNIMPLEMENTED();
break;
case WasmInitExpr::kNone: {
// No initializer, emit a default value.
switch (global.type.kind()) {
case ValueType::kI32:
buffer->write_u8(kExprI32Const);
// LEB encoding of 0.
buffer->write_u8(0);
break;
case ValueType::kI64:
buffer->write_u8(kExprI64Const);
// LEB encoding of 0.
buffer->write_u8(0);
break;
case ValueType::kF32:
buffer->write_u8(kExprF32Const);
buffer->write_f32(0.f);
break;
case ValueType::kF64:
buffer->write_u8(kExprF64Const);
buffer->write_f64(0.);
break;
case ValueType::kOptRef:
buffer->write_u8(kExprRefNull);
break;
case ValueType::kI8:
case ValueType::kI16:
case ValueType::kStmt:
case ValueType::kS128:
case ValueType::kBottom:
case ValueType::kRef:
case ValueType::kRtt:
UNREACHABLE();
}
break;
}
}
WriteGlobalInitializer(buffer, global.init, global.type);
buffer->write_u8(kExprEnd);
}
FixupSection(buffer, start);
......
......@@ -595,6 +595,36 @@ TEST_F(WasmModuleVerifyTest, TwoGlobals) {
EXPECT_OFF_END_FAILURE(data, 1);
}
TEST_F(WasmModuleVerifyTest, RefNullGlobal) {
WASM_FEATURE_SCOPE(reftypes);
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kLocalFuncRef, 1,
WASM_REF_NULL(kLocalFuncRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
}
TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid1) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kLocalOptRef, 0,
1, WASM_REF_NULL(0), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(
result,
"Type index 0 does not refer to a struct or array type definition");
}
TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid2) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1), kLocalFuncRef, 1,
kExprRefNull, U32V_5(1000001), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result,
"Type index 1000001 is greater than the maximum number 1000000 "
"of type definitions supported by V8");
}
TEST_F(WasmModuleVerifyTest, ZeroExceptions) {
static const byte data[] = {SECTION(Exception, ENTRY_COUNT(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