Commit b584f273 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Allow array.init in function bodies

Bug: v8:7748
Change-Id: Ic25e7be11cb1a06b160c1abe6d004a4c74b88b49
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3167493
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76912}
parent 6f5f8e6c
...@@ -5579,6 +5579,7 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index, ...@@ -5579,6 +5579,7 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index,
length, gasm_->Uint32Constant(WasmArray::MaxLength(type))), length, gasm_->Uint32Constant(WasmArray::MaxLength(type))),
position); position);
wasm::ValueType element_type = type->element_type(); wasm::ValueType element_type = type->element_type();
// TODO(7748): Consider using gasm_->Allocate().
Builtin stub = ChooseArrayAllocationBuiltin(element_type, initial_value); Builtin stub = ChooseArrayAllocationBuiltin(element_type, initial_value);
// Do NOT mark this as Operator::kEliminatable, because that would cause the // Do NOT mark this as Operator::kEliminatable, because that would cause the
// Call node to have no control inputs, which means it could get scheduled // Call node to have no control inputs, which means it could get scheduled
...@@ -5613,6 +5614,25 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index, ...@@ -5613,6 +5614,25 @@ Node* WasmGraphBuilder::ArrayNewWithRtt(uint32_t array_index,
return a; return a;
} }
Node* WasmGraphBuilder::ArrayInit(uint32_t array_index,
const wasm::ArrayType* type, Node* rtt,
base::Vector<Node*> elements) {
wasm::ValueType element_type = type->element_type();
// TODO(7748): Consider using gasm_->Allocate().
Node* array =
gasm_->CallBuiltin(Builtin::kWasmAllocateArray_Uninitialized,
Operator::kNoDeopt | Operator::kNoThrow, rtt,
Int32Constant(static_cast<int32_t>(elements.size())),
Int32Constant(element_type.element_size_bytes()));
for (int i = 0; i < static_cast<int>(elements.size()); i++) {
Node* offset =
gasm_->WasmArrayElementOffset(Int32Constant(i), element_type);
gasm_->StoreToObject(ObjectAccessForGCStores(element_type), array, offset,
elements[i]);
}
return array;
}
Node* WasmGraphBuilder::RttCanon(uint32_t type_index) { Node* WasmGraphBuilder::RttCanon(uint32_t type_index) {
Node* maps_list = Node* maps_list =
LOAD_INSTANCE_FIELD(ManagedObjectMaps, MachineType::TaggedPointer()); LOAD_INSTANCE_FIELD(ManagedObjectMaps, MachineType::TaggedPointer());
......
...@@ -477,6 +477,8 @@ class WasmGraphBuilder { ...@@ -477,6 +477,8 @@ class WasmGraphBuilder {
void ArrayCopy(Node* dst_array, Node* dst_index, CheckForNull dst_null_check, void ArrayCopy(Node* dst_array, Node* dst_index, CheckForNull dst_null_check,
Node* src_array, Node* src_index, CheckForNull src_null_check, Node* src_array, Node* src_index, CheckForNull src_null_check,
Node* length, wasm::WasmCodePosition position); Node* length, wasm::WasmCodePosition position);
Node* ArrayInit(uint32_t array_index, const wasm::ArrayType* type, Node* rtt,
base::Vector<Node*> elements);
Node* I31New(Node* input); Node* I31New(Node* input);
Node* I31GetS(Node* input); Node* I31GetS(Node* input);
Node* I31GetU(Node* input); Node* I31GetU(Node* input);
......
...@@ -5168,7 +5168,50 @@ class LiftoffCompiler { ...@@ -5168,7 +5168,50 @@ class LiftoffCompiler {
void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm, void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements, const Value& rtt, const base::Vector<Value>& elements, const Value& rtt,
Value* result) { Value* result) {
UNREACHABLE(); ValueKind rtt_kind = rtt.type.kind();
ValueKind elem_kind = imm.array_type->element_type().kind();
// Allocate the array.
{
LiftoffAssembler::VarState rtt_var =
__ cache_state()->stack_state.end()[-1];
LiftoffRegList pinned;
LiftoffRegister elem_size_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
__ LoadConstant(elem_size_reg, WasmValue(element_size_bytes(elem_kind)));
LiftoffAssembler::VarState elem_size_var(kI32, elem_size_reg, 0);
LiftoffRegister length_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
__ LoadConstant(length_reg,
WasmValue(static_cast<int32_t>(elements.size())));
LiftoffAssembler::VarState length_var(kI32, length_reg, 0);
CallRuntimeStub(WasmCode::kWasmAllocateArray_Uninitialized,
MakeSig::Returns(kRef).Params(rtt_kind, kI32, kI32),
{rtt_var, length_var, elem_size_var},
decoder->position());
// Drop the RTT.
__ DropValues(1);
}
// Initialize the array with stack arguments.
LiftoffRegister array(kReturnRegister0);
if (!CheckSupportedType(decoder, elem_kind, "array.init")) return;
for (int i = static_cast<int>(elements.size()) - 1; i >= 0; i--) {
LiftoffRegList pinned = LiftoffRegList::ForRegs(array);
LiftoffRegister element = pinned.set(__ PopToRegister(pinned));
LiftoffRegister offset_reg =
pinned.set(__ GetUnusedRegister(kGpReg, pinned));
__ LoadConstant(offset_reg, WasmValue(i << element_size_log2(elem_kind)));
StoreObjectField(array.gp(), offset_reg.gp(),
wasm::ObjectAccess::ToTagged(WasmArray::kHeaderSize),
element, pinned, elem_kind);
}
// Push the array onto the stack.
__ PushRegister(kRef, array);
} }
// 1 bit Smi tag, 31 bits Smi shift, 1 bit i31ref high-bit truncation. // 1 bit Smi tag, 31 bits Smi shift, 1 bit i31ref high-bit truncation.
......
...@@ -1877,6 +1877,13 @@ class WasmDecoder : public Decoder { ...@@ -1877,6 +1877,13 @@ class WasmDecoder : public Decoder {
ArrayIndexImmediate<validate> imm(decoder, pc + length); ArrayIndexImmediate<validate> imm(decoder, pc + length);
return length + imm.length; return length + imm.length;
} }
case kExprArrayInit:
case kExprArrayInitStatic: {
ArrayIndexImmediate<validate> array_imm(decoder, pc + length);
IndexImmediate<validate> length_imm(
decoder, pc + length + array_imm.length, "array length");
return length + array_imm.length + length_imm.length;
}
case kExprArrayCopy: { case kExprArrayCopy: {
ArrayIndexImmediate<validate> dst_imm(decoder, pc + length); ArrayIndexImmediate<validate> dst_imm(decoder, pc + length);
ArrayIndexImmediate<validate> src_imm(decoder, ArrayIndexImmediate<validate> src_imm(decoder,
...@@ -2098,6 +2105,13 @@ class WasmDecoder : public Decoder { ...@@ -2098,6 +2105,13 @@ class WasmDecoder : public Decoder {
CHECK(Validate(pc + 2, imm)); CHECK(Validate(pc + 2, imm));
return {imm.struct_type->field_count(), 1}; return {imm.struct_type->field_count(), 1};
} }
case kExprArrayInit:
case kExprArrayInitStatic: {
ArrayIndexImmediate<validate> array_imm(this, pc + 2);
IndexImmediate<validate> length_imm(this, pc + 2 + array_imm.length,
"array length");
return {length_imm.index + (opcode == kExprArrayInit ? 1 : 0), 1};
}
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -4355,10 +4369,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> { ...@@ -4355,10 +4369,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
} }
case kExprArrayInit: case kExprArrayInit:
case kExprArrayInitStatic: { case kExprArrayInitStatic: {
if (decoding_mode != kInitExpression) {
this->DecodeError("array.init is only allowed in init. expressions");
return 0;
}
ArrayIndexImmediate<validate> array_imm(this, ArrayIndexImmediate<validate> array_imm(this,
this->pc_ + opcode_length); this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0; if (!this->Validate(this->pc_ + opcode_length, array_imm)) return 0;
......
...@@ -1074,7 +1074,12 @@ class WasmGraphBuildingInterface { ...@@ -1074,7 +1074,12 @@ class WasmGraphBuildingInterface {
void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm, void ArrayInit(FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements, const Value& rtt, const base::Vector<Value>& elements, const Value& rtt,
Value* result) { Value* result) {
UNREACHABLE(); NodeVector element_nodes(elements.size());
for (uint32_t i = 0; i < elements.size(); i++) {
element_nodes[i] = elements[i].node;
}
result->node = builder_->ArrayInit(imm.index, imm.array_type, rtt.node,
VectorOf(element_nodes));
} }
void I31New(FullDecoder* decoder, const Value& input, Value* result) { void I31New(FullDecoder* decoder, const Value& input, Value* result) {
......
...@@ -937,7 +937,7 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> { ...@@ -937,7 +937,7 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
// Get the {ObjectSlot} corresponding to the element at {index}. Requires that // Get the {ObjectSlot} corresponding to the element at {index}. Requires that
// this is a reference array. // this is a reference array.
ObjectSlot ElementSlot(uint32_t index); ObjectSlot ElementSlot(uint32_t index);
wasm::WasmValue GetElement(uint32_t index); V8_EXPORT_PRIVATE wasm::WasmValue GetElement(uint32_t index);
static inline int SizeFor(Map map, int length); static inline int SizeFor(Map map, int length);
......
...@@ -832,6 +832,12 @@ WASM_COMPILED_EXEC_TEST(WasmBasicArray) { ...@@ -832,6 +832,12 @@ WASM_COMPILED_EXEC_TEST(WasmBasicArray) {
{WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(2)), WASM_DROP, {WASM_ARRAY_NEW_DEFAULT(type_index, WASM_I32V(2)), WASM_DROP,
WASM_ARRAY_NEW(type_index, WASM_I32V(42), WASM_I32V(2)), kExprEnd}); WASM_ARRAY_NEW(type_index, WASM_I32V(42), WASM_I32V(2)), kExprEnd});
const byte kInit = tester.DefineFunction(
&sig_q_v, {},
{WASM_ARRAY_INIT(type_index, 3, WASM_I32V(10), WASM_I32V(20),
WASM_I32V(30), WASM_RTT_CANON(type_index)),
kExprEnd});
const uint32_t kLongLength = 1u << 16; const uint32_t kLongLength = 1u << 16;
const byte kAllocateLarge = tester.DefineFunction( const byte kAllocateLarge = tester.DefineFunction(
&sig_q_v, {}, &sig_q_v, {},
...@@ -879,6 +885,13 @@ WASM_COMPILED_EXEC_TEST(WasmBasicArray) { ...@@ -879,6 +885,13 @@ WASM_COMPILED_EXEC_TEST(WasmBasicArray) {
CHECK(h_result->IsWasmArray()); CHECK(h_result->IsWasmArray());
CHECK_EQ(2, Handle<WasmArray>::cast(h_result)->length()); CHECK_EQ(2, Handle<WasmArray>::cast(h_result)->length());
Handle<Object> init_result = tester.GetResultObject(kInit).ToHandleChecked();
CHECK(init_result->IsWasmArray());
CHECK_EQ(3, Handle<WasmArray>::cast(init_result)->length());
CHECK_EQ(10, Handle<WasmArray>::cast(init_result)->GetElement(0).to_i32());
CHECK_EQ(20, Handle<WasmArray>::cast(init_result)->GetElement(1).to_i32());
CHECK_EQ(30, Handle<WasmArray>::cast(init_result)->GetElement(2).to_i32());
MaybeHandle<Object> maybe_large_result = MaybeHandle<Object> maybe_large_result =
tester.GetResultObject(kAllocateLarge); tester.GetResultObject(kAllocateLarge);
Handle<Object> large_result = maybe_large_result.ToHandleChecked(); Handle<Object> large_result = maybe_large_result.ToHandleChecked();
......
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