Commit c108d7a0 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Implement array.new_with_rtt

Also remove traces of array.new_sub

Bug: v8:7748
Change-Id: I96a922a16406960a80af0788e9cad5aa5692000a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2307237
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68956}
parent 0ed43683
......@@ -820,6 +820,7 @@ namespace internal {
TFC(WasmFloat32ToNumber, WasmFloat32ToNumber) \
TFC(WasmFloat64ToNumber, WasmFloat64ToNumber) \
TFS(WasmAllocateArray, kMapIndex, kLength, kElementSize) \
TFS(WasmAllocateArrayWithRtt, kMap, kLength, kElementSize) \
TFC(WasmI32AtomicWait32, WasmI32AtomicWait32) \
TFC(WasmI64AtomicWait32, WasmI64AtomicWait32) \
\
......
......@@ -138,5 +138,25 @@ TF_BUILTIN(WasmAllocateArray, WasmBuiltinsAssembler) {
Return(result);
}
TF_BUILTIN(WasmAllocateArrayWithRtt, WasmBuiltinsAssembler) {
TNode<Map> map = CAST(Parameter(Descriptor::kMap));
TNode<Smi> length = CAST(Parameter(Descriptor::kLength));
TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
TNode<IntPtrT> untagged_length = SmiUntag(length);
// instance_size = WasmArray::kHeaderSize
// + RoundUp(element_size * length, kObjectAlignment)
TNode<IntPtrT> raw_size = IntPtrMul(SmiUntag(element_size), untagged_length);
TNode<IntPtrT> rounded_size =
WordAnd(IntPtrAdd(raw_size, IntPtrConstant(kObjectAlignmentMask)),
IntPtrConstant(~kObjectAlignmentMask));
TNode<IntPtrT> instance_size =
IntPtrAdd(IntPtrConstant(WasmArray::kHeaderSize), rounded_size);
TNode<WasmArray> result = UncheckedCast<WasmArray>(Allocate(instance_size));
StoreMap(result, map);
StoreObjectFieldNoWriteBarrier(result, WasmArray::kLengthOffset,
TruncateIntPtrToInt32(untagged_length));
Return(result);
}
} // namespace internal
} // namespace v8
......@@ -5335,6 +5335,44 @@ Node* WasmGraphBuilder::ArrayNew(uint32_t array_index,
return a;
}
Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index,
const wasm::ArrayType* type,
Node* length, Node* initial_value,
Node* rtt) {
wasm::ValueType element_type = type->element_type();
Node* a = CALL_BUILTIN(
WasmAllocateArrayWithRtt, rtt, BuildChangeUint31ToSmi(length),
graph()->NewNode(mcgraph()->common()->NumberConstant(
element_type.element_size_bytes())),
LOAD_INSTANCE_FIELD(NativeContext, MachineType::TaggedPointer()));
auto loop = gasm_->MakeLoopLabel(MachineRepresentation::kWord32);
auto done = gasm_->MakeLabel();
Node* start_offset =
gasm_->Int32Constant(WasmArray::kHeaderSize - kHeapObjectTag);
Node* element_size = gasm_->Int32Constant(element_type.element_size_bytes());
Node* end_offset =
gasm_->Int32Add(start_offset, gasm_->Int32Mul(element_size, length));
// "Goto" requires the graph's end to have been set up.
// TODO(jkummerow): Figure out if there's a more elegant solution.
Graph* g = mcgraph()->graph();
if (!g->end()) {
g->SetEnd(g->NewNode(mcgraph()->common()->End(0)));
}
gasm_->Goto(&loop, start_offset);
gasm_->Bind(&loop);
{
Node* offset = loop.PhiAt(0);
Node* check = gasm_->Uint32LessThan(offset, end_offset);
gasm_->GotoIfNot(check, &done);
StoreWithTaggedAlignment(gasm_.get(), a, offset, initial_value,
type->element_type());
offset = gasm_->Int32Add(offset, element_size);
gasm_->Goto(&loop, offset);
}
gasm_->Bind(&done);
return a;
}
Node* WasmGraphBuilder::RttCanon(wasm::HeapType type) {
if (type.is_generic()) {
switch (type.representation()) {
......
......@@ -402,6 +402,8 @@ class WasmGraphBuilder {
wasm::WasmCodePosition position);
Node* ArrayNew(uint32_t array_index, const wasm::ArrayType* type,
Node* length, Node* initial_value);
Node* ArrayNewWithRtt(uint32_t array_index, const wasm::ArrayType* type,
Node* length, Node* initial_value, Node* rtt);
void BoundsCheck(Node* array, Node* index, wasm::WasmCodePosition position);
Node* ArrayGet(Node* array_object, const wasm::ArrayType* type, Node* index,
CheckForNull null_check, bool is_signed,
......
......@@ -3618,6 +3618,13 @@ class LiftoffCompiler {
// TODO(7748): Implement.
unsupported(decoder, kGC, "array.new");
}
void ArrayNewWithRtt(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& initial_value,
const Value& rtt, Value* result) {
// TODO(7748): Implement.
unsupported(decoder, kGC, "array.new_with_rtt");
}
void ArrayGet(FullDecoder* decoder, const Value& array_obj,
const ArrayIndexImmediate<validate>& imm, const Value& index,
bool is_signed, Value* result) {
......
......@@ -954,6 +954,9 @@ struct ControlBase {
const FieldIndexImmediate<validate>& field, const Value& field_value) \
F(ArrayNew, const ArrayIndexImmediate<validate>& imm, const Value& length, \
const Value& initial_value, Value* result) \
F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& initial_value, const Value& rtt, \
Value* result) \
F(ArrayGet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \
bool is_signed, Value* result) \
......@@ -1681,7 +1684,7 @@ class WasmDecoder : public Decoder {
return 2 + imm.length;
}
case kExprArrayNew:
case kExprArrayNewSub:
case kExprArrayNewWithRtt:
case kExprArrayNewDefault:
case kExprArrayGet:
case kExprArrayGetS:
......@@ -1854,7 +1857,7 @@ class WasmDecoder : public Decoder {
return {3, 0};
case kExprRttCanon:
return {0, 1};
case kExprArrayNewSub:
case kExprArrayNewWithRtt:
return {3, 1};
case kExprStructNew: {
StructIndexImmediate<validate> imm(this, this->pc_ + 2);
......@@ -3473,6 +3476,33 @@ class WasmFullDecoder : public WasmDecoder<validate> {
value);
return 2 + imm.length;
}
case kExprArrayNewWithRtt: {
ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
if (!this->Validate(this->pc_ + 2, imm)) return 0;
Value rtt = Pop(2);
if (!VALIDATE(rtt.type.kind() == ValueType::kRtt)) {
this->errorf(
this->pc_ + 2,
"array.new_with_rtt expected type rtt, found %s of type %s",
SafeOpcodeNameAt(rtt.pc), rtt.type.type_name().c_str());
return 0;
}
// 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_representation() == imm.index)) {
this->errorf(this->pc_ + 2,
"array.new_with_rtt expected rtt for type %d, found "
"rtt for type %s",
imm.index, rtt.type.heap_type().name().c_str());
return 0;
}
Value length = Pop(1, kWasmI32);
Value initial_value = Pop(0, imm.array_type->element_type().Unpacked());
Value* value = Push(ValueType::Ref(imm.index, kNonNullable));
CALL_INTERFACE_IF_REACHABLE(ArrayNewWithRtt, imm, length, initial_value,
rtt, value);
return 2 + imm.length;
}
case kExprArrayGetS:
case kExprArrayGetU: {
ArrayIndexImmediate<validate> imm(this, this->pc_ + 2);
......
......@@ -700,6 +700,14 @@ class WasmGraphBuildingInterface {
initial_value.node);
}
void ArrayNewWithRtt(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& initial_value,
const Value& rtt, Value* result) {
result->node = BUILD(ArrayNewWithRtt, imm.index, imm.array_type,
length.node, initial_value.node, rtt.node);
}
void ArrayGet(FullDecoder* decoder, const Value& array_obj,
const ArrayIndexImmediate<validate>& imm, const Value& index,
bool is_signed, Value* result) {
......
......@@ -363,7 +363,7 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_OP(StructGetU, "struct.get_u")
CASE_OP(StructSet, "struct.set")
CASE_OP(ArrayNew, "array.new")
CASE_OP(ArrayNewSub, "array.new_sub")
CASE_OP(ArrayNewWithRtt, "array.new_with_rtt")
CASE_OP(ArrayNewDefault, "array.new_default")
CASE_OP(ArrayGet, "array.get")
CASE_OP(ArrayGetS, "array.get_s")
......
......@@ -609,7 +609,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(StructGetU, 0xfb05, _) \
V(StructSet, 0xfb06, _) \
V(ArrayNew, 0xfb10, _) \
V(ArrayNewSub, 0xfb11, _) \
V(ArrayNewWithRtt, 0xfb11, _) \
V(ArrayNewDefault, 0xfb12, _) \
V(ArrayGet, 0xfb13, _) \
V(ArrayGetS, 0xfb14, _) \
......
......@@ -649,6 +649,33 @@ TEST(BasicRTT) {
tester.CheckResult(kRefCast, 43);
}
TEST(ArrayNewWithRtt) {
WasmGCTester tester;
uint32_t type_index = tester.DefineArray(kWasmI32, true);
ValueType array_type = ValueType::Ref(type_index, kNonNullable);
FunctionSig sig(1, 0, &array_type);
const uint32_t array_new_with_rtt = tester.DefineFunction(
&sig, {},
{WASM_ARRAY_NEW_WITH_RTT(type_index, WASM_I32V(10), WASM_I32V(42),
WASM_RTT_CANON(type_index)),
kExprEnd});
ValueType rtt_type = ValueType::Rtt(type_index, 1);
FunctionSig rtt_canon_sig(1, 0, &rtt_type);
const uint32_t kRttCanon = tester.DefineFunction(
&rtt_canon_sig, {}, {WASM_RTT_CANON(type_index), kExprEnd});
tester.CompileModule();
Handle<Object> map = tester.GetResultObject(kRttCanon).ToHandleChecked();
Handle<Object> result =
tester.GetResultObject(array_new_with_rtt).ToHandleChecked();
CHECK(result->IsWasmArray());
CHECK_EQ(Handle<WasmArray>::cast(result)->map(), *map);
}
TEST(RefTestCastNull) {
WasmGCTester tester;
uint8_t type_index =
......
......@@ -458,6 +458,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
#define WASM_ARRAY_NEW(index, default_value, length) \
default_value, length, WASM_GC_OP(kExprArrayNew), static_cast<byte>(index)
#define WASM_ARRAY_NEW_WITH_RTT(index, default_value, length, rtt) \
default_value, length, rtt, WASM_GC_OP(kExprArrayNewWithRtt), \
static_cast<byte>(index)
#define WASM_ARRAY_GET(typeidx, array, index) \
array, index, WASM_GC_OP(kExprArrayGet), static_cast<byte>(typeidx)
#define WASM_ARRAY_GET_U(typeidx, array, index) \
......
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