Commit 603910ff authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[wasm-gc][ic] Support more Wasm field types in LoadIC

Bug: v8:11804
Change-Id: Ief0ade232c4f120b62a6d83f75ed0095abbe797a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2966388Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75212}
parent 2dfe4236
......@@ -340,12 +340,11 @@ void AccessorAssembler::HandleLoadWasmField(
Label* rebox_double, ExitPoint* exit_point) {
Label type_I8(this), type_I16(this), type_I32(this), type_U32(this),
type_I64(this), type_U64(this), type_F32(this), type_F64(this),
unsupported_type(this, Label::kDeferred),
type_Ref(this), unsupported_type(this, Label::kDeferred),
unexpected_type(this, Label::kDeferred);
Label* wasm_value_type_labels[] = {
&type_I8, &type_I16, &type_I32, &type_U32,
&type_I64, &type_F32, &type_F64, &unsupported_type,
&unsupported_type, &unsupported_type};
&type_I8, &type_I16, &type_I32, &type_U32, &type_I64,
&type_F32, &type_F64, &type_Ref, &type_Ref, &unsupported_type};
int32_t wasm_value_types[] = {
static_cast<int32_t>(WasmValueType::kI8),
static_cast<int32_t>(WasmValueType::kI16),
......@@ -354,10 +353,10 @@ void AccessorAssembler::HandleLoadWasmField(
static_cast<int32_t>(WasmValueType::kI64),
static_cast<int32_t>(WasmValueType::kF32),
static_cast<int32_t>(WasmValueType::kF64),
// TODO(ishell): support the following value types.
static_cast<int32_t>(WasmValueType::kS128),
static_cast<int32_t>(WasmValueType::kRef),
static_cast<int32_t>(WasmValueType::kOptRef)};
static_cast<int32_t>(WasmValueType::kOptRef),
// TODO(v8:11804): support the following value types.
static_cast<int32_t>(WasmValueType::kS128)};
const size_t kWasmValueTypeCount =
static_cast<size_t>(WasmValueType::kNumTypes);
DCHECK_EQ(kWasmValueTypeCount, arraysize(wasm_value_types));
......@@ -392,7 +391,12 @@ void AccessorAssembler::HandleLoadWasmField(
BIND(&type_I64);
{
Comment("type_I64");
Unreachable();
TNode<RawPtrT> data_pointer =
ReinterpretCast<RawPtrT>(BitcastTaggedToWord(holder));
TNode<BigInt> value = LoadFixedBigInt64ArrayElementAsTagged(
data_pointer,
Signed(IntPtrSub(field_offset, IntPtrConstant(kHeapObjectTag))));
exit_point->Return(value);
}
BIND(&type_F32);
{
......@@ -408,6 +412,12 @@ void AccessorAssembler::HandleLoadWasmField(
*var_double_value = value;
Goto(rebox_double);
}
BIND(&type_Ref);
{
Comment("type_Ref");
TNode<Object> value = LoadObjectField(holder, field_offset);
exit_point->Return(value);
}
BIND(&unsupported_type);
{
Print("Not supported Wasm field type");
......
......@@ -1229,13 +1229,18 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
// monomorphic. If this optimistic assumption is not true, the IC will
// miss again and it will become polymorphic and support both the
// untransitioned and transitioned maps.
if (state() == MONOMORPHIC && !receiver->IsString() &&
!receiver->IsJSProxy() &&
IsMoreGeneralElementsKindTransition(
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) {
Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
if (state() == MONOMORPHIC) {
if ((receiver->IsJSObject() &&
IsMoreGeneralElementsKindTransition(
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind()))
#ifdef V8_ENABLE_WEBASSEMBLY
|| receiver->IsWasmObject()
#endif
) {
Handle<Object> handler = LoadElementHandler(receiver_map, load_mode);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
}
DCHECK(state() != GENERIC);
......
......@@ -432,11 +432,20 @@ Handle<Object> WasmObject::ReadValueAt(Isolate* isolate, Handle<HeapObject> obj,
int32_t value = base::Memory<int32_t>(field_address);
return isolate->factory()->NewNumberFromInt(value);
}
case wasm::kI64:
case wasm::kF32:
case wasm::kF64:
case wasm::kI64: {
int64_t value = base::ReadUnalignedValue<int64_t>(field_address);
return BigInt::FromInt64(isolate, value);
}
case wasm::kF32: {
float value = base::Memory<float>(field_address);
return isolate->factory()->NewNumber(value);
}
case wasm::kF64: {
double value = base::ReadUnalignedValue<double>(field_address);
return isolate->factory()->NewNumber(value);
}
case wasm::kS128:
// TODO(ishell): implement
// TODO(v8:11804): implement
UNREACHABLE();
case wasm::kRef:
......
......@@ -12,33 +12,37 @@ const kIterationsCountForICProgression = 20;
// TODO(ishell): remove once leaked maps could keep NativeModule alive.
let instances = [];
function createStruct_i() {
let builder = new WasmModuleBuilder();
function createSimpleStruct(field_type, value1, value2) {
const builder = new WasmModuleBuilder();
const is_small_int = (field_type == kWasmI8) || (field_type == kWasmI16);
const parameter_type = is_small_int ? kWasmI32 : field_type;
const struct_get_opcode = is_small_int ? kExprStructGetS : kExprStructGet;
const type_index = builder.addStruct([
{type: kWasmI32, mutability: true},
{type: field_type, mutability: true},
]);
let sig_a_i = makeSig_r_x(kWasmDataRef, kWasmI32);
let sig_i_a = makeSig_r_x(kWasmI32, kWasmDataRef);
let sig_v_ai = makeSig([kWasmDataRef, kWasmI32], []);
let sig_a_t = makeSig_r_x(kWasmDataRef, parameter_type);
let sig_t_a = makeSig_r_x(parameter_type, kWasmDataRef);
let sig_v_at = makeSig([kWasmDataRef, parameter_type], []);
builder.addFunction("new_struct", sig_a_i)
builder.addFunction("new_struct", sig_a_t)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRttCanon, type_index, // --
kGCPrefix, kExprStructNewWithRtt, type_index]) // --
.exportAs("new_struct");
builder.addFunction("get_field", sig_i_a)
builder.addFunction("get_field", sig_t_a)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRttCanon, type_index, // --
kGCPrefix, kExprRefCast, // --
kGCPrefix, kExprStructGet, type_index, 0]) // --
kExprLocalGet, 0, // --
kGCPrefix, kExprRttCanon, type_index, // --
kGCPrefix, kExprRefCast, // --
kGCPrefix, struct_get_opcode, type_index, 0]) // --
.exportAs("get_field");
builder.addFunction("set_field", sig_v_ai)
builder.addFunction("set_field", sig_v_at)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRttCanon, type_index, // --
......@@ -53,34 +57,144 @@ function createStruct_i() {
let get_field = instance.exports.get_field;
let set_field = instance.exports.set_field;
let value = 42;
let o = new_struct(value);
%DebugPrint(o);
// Check that ctor, getter and setter work.
let o = new_struct(value1);
let res;
res = get_field(o);
assertEquals(value, res);
assertEquals(value1, res);
set_field(o, 153);
set_field(o, value2);
res = get_field(o);
assertEquals(153, res);
assertEquals(value2, res);
return o;
return {new_struct, get_field, set_field};
}
(function TestSimpleStructInterop() {
function SimpleStructInterop(field_type, value_generator,
value1 = 42, value2 = 111) {
const { new_struct, get_field, set_field } =
createSimpleStruct(field_type, value1, value2);
function f(o) {
for (let i = 0; i < kIterationsCountForICProgression; i++) {
let v = o.$field0;
assertEquals(153, v);
let expected = get_field(o);
assertEquals(expected, v);
v = o[i];
assertEquals(undefined, v);
}
}
// Start collecting feedback from scratch.
%ClearFunctionFeedback(f);
let o = createStruct_i();
%DebugPrint(o);
let o = new_struct(value1);
f(o);
for (const value of value_generator()) {
print("value: " + value);
set_field(o, value);
f(o);
}
gc();
}
(function TestSimpleStructsInteropI8() {
SimpleStructInterop(kWasmI8, function*() {
const max = 0x7f;
const min = -max - 1;
yield min;
yield max;
yield 0;
for (let i = 0; i < 10; i++) {
yield Math.floor((Math.random() - 0.5) * max);
}
});
})();
(function TestSimpleStructsInteropI16() {
SimpleStructInterop(kWasmI16, function*() {
const max = 0x7fff;
const min = -max - 1;
yield min;
yield max;
yield 0;
for (let i = 0; i < 10; i++) {
yield Math.floor((Math.random() - 0.5) * max);
}
});
})();
(function TestSimpleStructsInteropI32() {
SimpleStructInterop(kWasmI32, function*() {
const max = 0x7fffffff;
const min = -max - 1;
yield min;
yield max;
yield 0;
for (let i = 0; i < 10; i++) {
yield Math.floor((Math.random() - 0.5) * max);
}
});
})();
(function TestSimpleStructsInteropI64() {
SimpleStructInterop(kWasmI64, function*() {
const max = 0x7fffffffffffffn;
const min = -max - 1n;
yield min;
yield max;
yield 0n;
for (let i = 0; i < 10; i++) {
yield BigInt(Math.floor((Math.random() - 0.5) * Number(max)));
}
}, 42n, 153n);
})();
(function TestSimpleStructsInteropF32() {
SimpleStructInterop(kWasmF32, function*() {
const max_safe_integer = 2**23 - 1;
const max = 3.4028234664e+38;
yield -max;
yield max;
yield max_safe_integer;
yield -max_safe_integer;
yield 0.0;
yield -0.0;
for (let i = 0; i < 10; i++) {
yield Math.floor((Math.random() - 0.5) * max);
}
});
})();
(function TestSimpleStructsInteropF64() {
SimpleStructInterop(kWasmF64, function*() {
const max = 1.7976931348623157e+308
yield -max;
yield max;
yield Number.MAX_SAFE_INTEGER;;
yield Number.MIN_SAFE_INTEGER;
yield 0.0;
yield -0.0;
for (let i = 0; i < 10; i++) {
yield Math.floor((Math.random() - 0.5) * max);
}
});
})();
(function TestSimpleStructsInteropRef() {
SimpleStructInterop(kWasmAnyRef, function*() {
yield "foo";
yield null;
yield {x:1};
yield {x:1.4, y:2.3};
yield Number(13);
yield this;
}, null, undefined);
})();
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