Commit 0a7d77ec authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Implement rtt global initializers

Bug: v8:7748
Change-Id: I925be7942f4825aeac7364bc7c899b6bef8001c3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2284985
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68811}
parent 0a825922
......@@ -126,6 +126,19 @@ ValueType TypeOf(const WasmModule* module, const WasmInitExpr& expr) {
return ValueType::Ref(HeapType::kFunc, kNonNullable);
case WasmInitExpr::kRefNullConst:
return ValueType::Ref(expr.immediate().heap_type, kNullable);
case WasmInitExpr::kRttCanon:
// TODO(7748): If heaptype is "anyref" (not introduced yet),
// then this should be uint8_t{0}.
return ValueType::Rtt(expr.immediate().heap_type, uint8_t{1});
case WasmInitExpr::kRttSub: {
ValueType operand_type = TypeOf(module, *expr.operand());
if (operand_type.is_rtt()) {
return ValueType::Rtt(expr.immediate().heap_type,
operand_type.depth() + 1);
} else {
return kWasmStmt;
}
}
}
}
......@@ -1710,6 +1723,50 @@ class ModuleDecoderImpl : public Decoder {
module->functions[imm.index].declared = true;
break;
}
case kGCPrefix: {
opcode = read_prefixed_opcode<validate>(pc(), &len);
switch (opcode) {
case kExprRttCanon: {
HeapTypeImmediate<validate> imm(enabled_features_, this,
pc() + 2);
len += 1 + imm.length;
if (!Validate(pc() + 2, imm)) break;
stack.push_back(
WasmInitExpr::RttCanon(imm.type.representation()));
break;
}
case kExprRttSub: {
HeapTypeImmediate<validate> imm(enabled_features_, this,
pc() + 2);
len += 1 + imm.length;
if (!Validate(pc() + 2, imm)) break;
if (stack.empty()) {
error(pc(), "calling rtt.sub without arguments");
break;
}
WasmInitExpr parent = std::move(stack.back());
stack.pop_back();
ValueType parent_type = TypeOf(module_.get(), parent);
if (V8_UNLIKELY(
parent_type.kind() != ValueType::kRtt ||
!IsSubtypeOf(
ValueType::Ref(imm.type, kNonNullable),
ValueType::Ref(parent_type.heap_type(), kNonNullable),
module_.get()))) {
error(pc(), "rtt.sub requires a supertype rtt on stack");
break;
}
stack.push_back(WasmInitExpr::RttSub(imm.type.representation(),
std::move(parent)));
break;
}
default: {
errorf(pc(), "invalid opcode 0x%x in global initializer", opcode);
break;
}
}
break;
}
case kExprEnd:
if (V8_UNLIKELY(stack.size() != 1)) {
errorf(pc(),
......
......@@ -488,6 +488,17 @@ void WriteGlobalInitializer(ZoneBuffer* buffer, const WasmInitExpr& init,
}
break;
}
case WasmInitExpr::kRttCanon:
buffer->write_u16(kExprRttCanon);
buffer->write_u32v(init.immediate().heap_type);
break;
case WasmInitExpr::kRttSub:
// TODO(7748): If immediates for rtts remain in the standard, adapt this
// to emit them.
buffer->write_u16(kExprRttSub);
buffer->write_u32v(init.immediate().heap_type);
WriteGlobalInitializer(buffer, *init.operand(), kWasmBottom);
break;
}
}
......
......@@ -5,6 +5,8 @@
#ifndef V8_WASM_WASM_OPCODES_H_
#define V8_WASM_WASM_OPCODES_H_
#include <memory>
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/wasm/value-type.h"
......@@ -757,7 +759,9 @@ class WasmInitExpr {
kF32Const,
kF64Const,
kRefNullConst,
kRefFuncConst
kRefFuncConst,
kRttCanon,
kRttSub
};
union Immediate {
......@@ -806,12 +810,59 @@ class WasmInitExpr {
return expr;
}
static WasmInitExpr RttCanon(HeapType::Representation heap_type) {
WasmInitExpr expr;
expr.kind_ = kRttCanon;
expr.immediate_.heap_type = heap_type;
return expr;
}
static WasmInitExpr RttSub(HeapType::Representation heap_type,
WasmInitExpr supertype) {
WasmInitExpr expr;
expr.kind_ = kRttSub;
expr.immediate_.heap_type = heap_type;
expr.operand_ = std::make_unique<WasmInitExpr>(std::move(supertype));
return expr;
}
Immediate immediate() const { return immediate_; }
Operator kind() const { return kind_; }
WasmInitExpr* operand() const { return operand_.get(); }
bool operator==(const WasmInitExpr& other) const {
if (kind() != other.kind()) return false;
switch (kind()) {
case kNone:
return true;
case kGlobalGet:
case kRefFuncConst:
return immediate().index == other.immediate().index;
case kI32Const:
return immediate().i32_const == other.immediate().i32_const;
case kI64Const:
return immediate().i64_const == other.immediate().i64_const;
case kF32Const:
return immediate().f32_const == other.immediate().f32_const;
case kF64Const:
return immediate().f64_const == other.immediate().f64_const;
case kRefNullConst:
case kRttCanon:
return immediate().heap_type == other.immediate().heap_type;
case kRttSub:
return immediate().heap_type == other.immediate().heap_type &&
*operand() == *other.operand();
}
}
V8_INLINE bool operator!=(const WasmInitExpr& other) {
return !(*this == other);
}
private:
Immediate immediate_;
Operator kind_;
std::unique_ptr<WasmInitExpr> operand_ = nullptr;
};
} // namespace wasm
......
......@@ -625,6 +625,137 @@ TEST_F(WasmModuleVerifyTest, RefNullGlobalInvalid2) {
"of type definitions supported by V8");
}
TEST_F(WasmModuleVerifyTest, RttCanonGlobalGeneric) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1),
WASM_RTT(1, kLocalFuncRef), 1,
WASM_RTT_CANON(kLocalFuncRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
}
TEST_F(WasmModuleVerifyTest, RttCanonGlobalStruct) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {
SECTION(Type, ENTRY_COUNT(1),
WASM_STRUCT_DEF(FIELD_COUNT(1), STRUCT_FIELD(kLocalI32, true))),
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(1, 0), 0, WASM_RTT_CANON(0),
kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_OK(result);
}
TEST_F(WasmModuleVerifyTest, RttCanonGlobalTypeError) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {SECTION(Global, ENTRY_COUNT(1),
WASM_RTT(1, kLocalExternRef), 1,
WASM_RTT_CANON(kLocalFuncRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result,
"type error in init expression, expected (rtt 1 extern), got "
"(rtt 1 func)");
}
TEST_F(WasmModuleVerifyTest, GlobalRttSubOfCanon) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {SECTION(
Global, ENTRY_COUNT(1), WASM_RTT(2, kLocalExternRef), 1,
WASM_RTT_CANON(kLocalEqRef), WASM_RTT_SUB(kLocalExternRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
WasmInitExpr expected = WasmInitExpr::RttSub(
HeapType::kExtern, WasmInitExpr::RttCanon(HeapType::kEq));
EXPECT_OK(result);
EXPECT_EQ(result.value()->globals.front().init, expected);
}
TEST_F(WasmModuleVerifyTest, GlobalRttSubOfSubOfCanon) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(3, kLocalExternRef), 1,
WASM_RTT_CANON(kLocalEqRef), WASM_RTT_SUB(kLocalExternRef),
WASM_RTT_SUB(kLocalExternRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
WasmInitExpr expected = WasmInitExpr::RttSub(
HeapType::kExtern,
WasmInitExpr::RttSub(HeapType::kExtern,
WasmInitExpr::RttCanon(HeapType::kEq)));
EXPECT_OK(result);
EXPECT_EQ(result.value()->globals.front().init, expected);
}
TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobal) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {
SECTION(Import, // section header
ENTRY_COUNT(1), // number of imports
ADD_COUNT('m'), // module name
ADD_COUNT('f'), // global name
kExternalGlobal, // import kind
WASM_RTT(1, kLocalEqRef), // type
0), // mutability
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, kLocalExternRef), 1,
WASM_GET_GLOBAL(0), WASM_RTT_SUB(kLocalExternRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
WasmInitExpr expected =
WasmInitExpr::RttSub(HeapType::kExtern, WasmInitExpr::GlobalGet(0));
EXPECT_OK(result);
EXPECT_EQ(result.value()->globals[1].init, expected);
}
TEST_F(WasmModuleVerifyTest, GlobalRttSubOfGlobalTypeError) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {
SECTION(Import, // section header
ENTRY_COUNT(1), // number of imports
ADD_COUNT('m'), // module name
ADD_COUNT('f'), // global name
kExternalGlobal, // import kind
kLocalI32, // type
0), // mutability
SECTION(Global, ENTRY_COUNT(1), WASM_RTT(2, kLocalExternRef), 1,
WASM_GET_GLOBAL(0), WASM_RTT_SUB(kLocalExternRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result, "rtt.sub requires a supertype rtt on stack");
}
TEST_F(WasmModuleVerifyTest, GlobalRttSubIllegalParent) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {SECTION(
Global, ENTRY_COUNT(1), WASM_RTT(2, kLocalEqRef), 1,
WASM_RTT_CANON(kLocalExternRef), WASM_RTT_SUB(kLocalEqRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result, "rtt.sub requires a supertype rtt on stack");
}
TEST_F(WasmModuleVerifyTest, RttSubGlobalTypeError) {
WASM_FEATURE_SCOPE(reftypes);
WASM_FEATURE_SCOPE(typed_funcref);
WASM_FEATURE_SCOPE(gc);
static const byte data[] = {SECTION(
Global, ENTRY_COUNT(1), WASM_RTT(1 /* Should be 2 */, kLocalExternRef), 1,
WASM_RTT_CANON(kLocalEqRef), WASM_RTT_SUB(kLocalExternRef), kExprEnd)};
ModuleResult result = DecodeModule(data, data + sizeof(data));
EXPECT_NOT_OK(result,
"type error in init expression, expected (rtt 1 extern), got "
"(rtt 2 extern)");
}
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