Commit 26626f87 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[wasm-gc] Implement struct.new_with_rtt

Bug: v8:7748
Change-Id: I6bbb73ceb397b102783ecfcc553264d83e926df2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2273126
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68620}
parent 8e54afbe
......@@ -242,6 +242,15 @@ builtin WasmAllocateRtt(implicit context: Context)(
tail runtime::WasmAllocateRtt(context, typeIndex, parent);
}
builtin WasmAllocateStructWithRtt(implicit context: Context)(rtt: Map):
HeapObject {
const instanceSize: intptr =
unsafe::TimesTaggedSize(Convert<intptr>(rtt.instance_size_in_words));
const result: HeapObject = unsafe::Allocate(instanceSize);
* UnsafeConstCast(& result.map) = rtt;
return result;
}
builtin WasmInt32ToNumber(value: int32): Number {
return ChangeInt32ToTagged(value);
}
......
......@@ -5287,6 +5287,18 @@ Node* WasmGraphBuilder::StructNew(uint32_t struct_index,
return s;
}
Node* WasmGraphBuilder::StructNewWithRtt(uint32_t struct_index,
const wasm::StructType* type,
Node* rtt, Vector<Node*> fields) {
Node* s = CALL_BUILTIN(
WasmAllocateStructWithRtt, rtt,
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()));
for (uint32_t i = 0; i < type->field_count(); i++) {
StoreStructFieldUnchecked(mcgraph(), gasm_.get(), s, type, i, fields[i]);
}
return s;
}
Node* WasmGraphBuilder::ArrayNew(uint32_t array_index,
const wasm::ArrayType* type, Node* length,
Node* initial_value) {
......
......@@ -383,6 +383,8 @@ class WasmGraphBuilder {
Node* StructNew(uint32_t struct_index, const wasm::StructType* type,
Vector<Node*> fields);
Node* StructNewWithRtt(uint32_t struct_index, const wasm::StructType* type,
Node* rtt, Vector<Node*> fields);
Node* StructGet(Node* struct_object, const wasm::StructType* struct_type,
uint32_t field_index, CheckForNull null_check, bool is_signed,
wasm::WasmCodePosition position);
......
......@@ -3576,6 +3576,12 @@ class LiftoffCompiler {
// TODO(7748): Implement.
unsupported(decoder, kGC, "struct.new");
}
void StructNewWithRtt(FullDecoder* decoder,
const StructIndexImmediate<validate>& imm,
const Value& rtt, const Value args[], Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "struct.new_with_rtt");
}
void StructGet(FullDecoder* decoder, const Value& struct_obj,
const FieldIndexImmediate<validate>& field, bool is_signed,
Value* result) {
......
......@@ -953,6 +953,8 @@ struct ControlBase {
const Value& value, const Value& count) \
F(StructNew, const StructIndexImmediate<validate>& imm, const Value args[], \
Value* result) \
F(StructNewWithRtt, const StructIndexImmediate<validate>& imm, \
const Value& rtt, const Value args[], Value* result) \
F(StructGet, const Value& struct_object, \
const FieldIndexImmediate<validate>& field, bool is_signed, Value* result) \
F(StructSet, const Value& struct_object, \
......@@ -1667,7 +1669,7 @@ class WasmDecoder : public Decoder {
WasmOpcode opcode = static_cast<WasmOpcode>(kGCPrefix << 8 | gc_index);
switch (opcode) {
case kExprStructNew:
case kExprStructNewSub:
case kExprStructNewWithRtt:
case kExprStructNewDefault: {
StructIndexImmediate<validate> imm(decoder, pc + 2);
return 2 + imm.length;
......@@ -3334,6 +3336,33 @@ class WasmFullDecoder : public WasmDecoder<validate> {
CALL_INTERFACE_IF_REACHABLE(StructNew, imm, args.begin(), value);
break;
}
case kExprStructNewWithRtt: {
StructIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
if (!this->Validate(this->pc_, imm)) break;
Value rtt = Pop();
if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
this->errorf(
this->pc_ + len,
"struct.new_with_rtt expected type rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc), rtt.type.type_name().c_str());
break;
}
// TODO(7748): Drop this check if {imm} is dropped from the proposal
// à la https://github.com/WebAssembly/function-references/pull/31.
if (!VALIDATE(rtt.type.heap() == imm.index)) {
this->errorf(this->pc_ + len,
"struct.new_with_rtt expected rtt for type %d, found "
"rtt for type %s",
imm.index, rtt.type.heap_type().name().c_str());
break;
}
ArgVector args = PopArgs(imm.struct_type);
Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
CALL_INTERFACE_IF_REACHABLE(StructNewWithRtt, imm, rtt, args.begin(),
value);
break;
}
case kExprStructGet: {
FieldIndexImmediate<validate> field(this, this->pc_ + 2);
len += field.length;
......
......@@ -653,6 +653,18 @@ class WasmGraphBuildingInterface {
BUILD(StructNew, imm.index, imm.struct_type, VectorOf(arg_nodes));
}
void StructNewWithRtt(FullDecoder* decoder,
const StructIndexImmediate<validate>& imm,
const Value& rtt, const Value args[], Value* result) {
uint32_t field_count = imm.struct_type->field_count();
base::SmallVector<TFNode*, 16> arg_nodes(field_count);
for (uint32_t i = 0; i < field_count; i++) {
arg_nodes[i] = args[i].node;
}
result->node = BUILD(StructNewWithRtt, imm.index, imm.struct_type, rtt.node,
VectorOf(arg_nodes));
}
void StructGet(FullDecoder* decoder, const Value& struct_object,
const FieldIndexImmediate<validate>& field, bool is_signed,
Value* result) {
......
......@@ -355,7 +355,7 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
// GC operations.
CASE_OP(StructNew, "struct.new")
CASE_OP(StructNewSub, "struct.new_sub")
CASE_OP(StructNewWithRtt, "struct.new_with_rtt")
CASE_OP(StructNewDefault, "struct.new_default")
CASE_OP(StructGet, "struct.get")
CASE_OP(StructGetS, "struct.get_s")
......
......@@ -598,7 +598,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
#define FOREACH_GC_OPCODE(V) \
V(StructNew, 0xfb00, _) \
V(StructNewSub, 0xfb01, _) \
V(StructNewWithRtt, 0xfb01, _) \
V(StructNewDefault, 0xfb02, _) \
V(StructGet, 0xfb03, _) \
V(StructGetS, 0xfb04, _) \
......
......@@ -555,12 +555,19 @@ TEST(BasicRTT) {
ValueType kRttSubtypes[] = {
ValueType::Rtt(static_cast<HeapType>(subtype_index), 2)};
FunctionSig sig_t2_v(1, 0, kRttSubtypes);
ValueType kRefTypes[] = {
ValueType::Ref(static_cast<HeapType>(type_index), kNonNullable)};
FunctionSig sig_q_v(1, 0, kRefTypes);
tester.DefineFunction("f", &sig_t_v, {},
{WASM_RTT_CANON(type_index), kExprEnd});
tester.DefineFunction(
"g", &sig_t2_v, {},
{WASM_RTT_CANON(type_index), WASM_RTT_SUB(subtype_index), kExprEnd});
tester.DefineFunction("h", &sig_q_v, {},
{WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(42),
WASM_RTT_CANON(type_index)),
kExprEnd});
tester.CompileModule();
......@@ -580,6 +587,10 @@ TEST(BasicRTT) {
CHECK_EQ(reinterpret_cast<Address>(
tester.instance()->module()->struct_type(subtype_index)),
submap->wasm_type_info().foreign_address());
Handle<Object> s = tester.GetJSResult("h", {}).ToHandleChecked();
CHECK(s->IsWasmStruct());
CHECK_EQ(Handle<WasmStruct>::cast(s)->map(), *map);
}
TEST(BasicI31) {
......
......@@ -426,6 +426,8 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_GC_OP(op) kGCPrefix, static_cast<byte>(op)
#define WASM_STRUCT_NEW(index, ...) \
__VA_ARGS__, WASM_GC_OP(kExprStructNew), static_cast<byte>(index)
#define WASM_STRUCT_NEW_WITH_RTT(index, ...) \
__VA_ARGS__, WASM_GC_OP(kExprStructNewWithRtt), static_cast<byte>(index)
#define WASM_STRUCT_GET(typeidx, fieldidx, struct_obj) \
struct_obj, WASM_GC_OP(kExprStructGet), static_cast<byte>(typeidx), \
static_cast<byte>(fieldidx)
......
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