Commit 1646c9be authored by Manos Koukoutos's avatar Manos Koukoutos Committed by Commit Bot

[wasm-gc] Add mutability and packed types to arrays/structs

Bug: v8:7748
Change-Id: I4ae500548e7ab09f5bd037563af5c057751197bb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2215049Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67996}
parent 5058c397
......@@ -3223,10 +3223,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
case kExprStructGet: {
FieldIndexImmediate<validate> field(this, this->pc_ + len);
if (!this->Validate(this->pc_ + len, field)) break;
ValueType field_type =
field.struct_index.struct_type->field(field.index);
if (field_type.IsPacked()) {
this->error(this->pc_,
"struct.get used with a field of packed type. "
"Use struct.get_s or struct.get_u instead.");
break;
}
len += field.length;
Value struct_obj =
Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index));
Value* value = Push(field.struct_index.struct_type->field(field.index));
Value* value = Push(field_type);
CALL_INTERFACE_IF_REACHABLE(StructGet, struct_obj, field, value);
break;
}
......@@ -3234,8 +3242,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
FieldIndexImmediate<validate> field(this, this->pc_ + len);
if (!this->Validate(this->pc_ + len, field)) break;
len += field.length;
if (!field.struct_index.struct_type->mutability(field.index)) {
this->error(this->pc_, "setting immutable struct field");
break;
}
Value field_value = Pop(
0, ValueType(field.struct_index.struct_type->field(field.index)));
0,
ValueType(
field.struct_index.struct_type->field(field.index).Unpack()));
Value struct_obj =
Pop(0, ValueType(ValueType::kOptRef, field.struct_index.index));
CALL_INTERFACE_IF_REACHABLE(StructSet, struct_obj, field, field_value);
......@@ -3256,6 +3270,12 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ArrayIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
if (!this->Validate(this->pc_ + len, imm)) break;
if (imm.array_type->element_type().IsPacked()) {
this->error(this->pc_,
"array.get used with a field of packed type. "
"Use array.get_s or array.get_u instead.");
break;
}
Value index = Pop(0, kWasmI32);
Value array_obj = Pop(0, ValueType(ValueType::kOptRef, imm.index));
Value* value = Push(imm.array_type->element_type());
......@@ -3267,7 +3287,11 @@ class WasmFullDecoder : public WasmDecoder<validate> {
ArrayIndexImmediate<validate> imm(this, this->pc_ + len);
len += imm.length;
if (!this->Validate(this->pc_ + len, imm)) break;
Value value = Pop(0, imm.array_type->element_type());
if (!imm.array_type->mutability()) {
this->error(this->pc_, "setting element of immutable array");
break;
}
Value value = Pop(0, imm.array_type->element_type().Unpack());
Value index = Pop(0, kWasmI32);
Value array_obj = Pop(0, ValueType(ValueType::kOptRef, imm.index));
// TODO(7748): Optimize this when array_obj is non-nullable ref.
......
......@@ -1754,6 +1754,21 @@ class ModuleDecoderImpl : public Decoder {
return result;
}
ValueType consume_storage_type() {
uint8_t opcode = read_u8<kValidate>(this->pc());
switch (opcode) {
case kLocalI8:
consume_bytes(1);
return kWasmI8;
case kLocalI16:
consume_bytes(1);
return kWasmI16;
default:
// It is not a packed type, so it has to be a value type.
return consume_value_type();
}
}
// Reads a single 8-bit integer, interpreting it as a reference type.
ValueType consume_reference_type() {
byte val = consume_u8("reference type");
......@@ -1824,30 +1839,35 @@ class ModuleDecoderImpl : public Decoder {
// TODO(7748): Introduce a proper maximum.
uint32_t field_count = consume_count("field count", 999);
if (failed()) return nullptr;
std::vector<ValueType> fields;
ValueType* fields = zone->NewArray<ValueType>(field_count);
bool* mutabilities = zone->NewArray<bool>(field_count);
for (uint32_t i = 0; ok() && i < field_count; ++i) {
ValueType field = consume_value_type();
ValueType field = consume_storage_type();
if (field.has_immediate()) {
deferred_struct_field_type_offsets_.emplace(field.ref_index(),
pc_offset());
}
fields.push_back(field);
fields[i] = field;
bool mutability = consume_mutability();
mutabilities[i] = mutability;
}
if (failed()) return nullptr;
ValueType* buffer = zone->NewArray<ValueType>(field_count);
for (uint32_t i = 0; i < field_count; i++) buffer[i] = fields[i];
uint32_t* offsets = zone->NewArray<uint32_t>(field_count);
return new (zone) StructType(field_count, offsets, buffer);
return new (zone) StructType(field_count, offsets, fields, mutabilities);
}
const ArrayType* consume_array(Zone* zone) {
ValueType field = consume_value_type();
ValueType field = consume_storage_type();
if (failed()) return nullptr;
if (field.has_immediate()) {
deferred_struct_field_type_offsets_.emplace(field.ref_index(),
pc_offset());
}
return new (zone) ArrayType(field);
bool mutability = consume_mutability();
if (!mutability) {
error(this->pc() - 1, "immutable arrays are not supported yet");
}
return new (zone) ArrayType(field, mutability);
}
// Consume the attribute field of an exception.
......
......@@ -18,8 +18,11 @@ namespace wasm {
class StructType : public ZoneObject {
public:
StructType(uint32_t field_count, uint32_t* field_offsets,
const ValueType* reps)
: field_count_(field_count), field_offsets_(field_offsets), reps_(reps) {
const ValueType* reps, const bool* mutabilities)
: field_count_(field_count),
field_offsets_(field_offsets),
reps_(reps),
mutabilities_(mutabilities) {
InitializeOffsets();
}
......@@ -30,15 +33,26 @@ class StructType : public ZoneObject {
return reps_[index];
}
bool mutability(uint32_t index) const {
DCHECK_LT(index, field_count_);
return mutabilities_[index];
}
// Iteration support.
base::iterator_range<const ValueType*> fields() const {
return {reps_, reps_ + field_count_};
}
base::iterator_range<const bool*> mutabilities() const {
return {mutabilities_, mutabilities_ + field_count_};
}
bool operator==(const StructType& other) const {
if (this == &other) return true;
if (field_count() != other.field_count()) return false;
return std::equal(fields().begin(), fields().end(), other.fields().begin());
return std::equal(fields().begin(), fields().end(),
other.fields().begin()) &&
std::equal(mutabilities().begin(), mutabilities().end(),
other.mutabilities().begin());
}
bool operator!=(const StructType& other) const { return !(*this == other); }
......@@ -70,17 +84,20 @@ class StructType : public ZoneObject {
: field_count_(field_count),
zone_(zone),
cursor_(0),
buffer_(zone->NewArray<ValueType>(static_cast<int>(field_count))) {}
buffer_(zone->NewArray<ValueType>(static_cast<int>(field_count))),
mutabilities_(zone->NewArray<bool>(static_cast<int>(field_count))) {}
void AddField(ValueType type) {
void AddField(ValueType type, bool mutability) {
DCHECK_LT(cursor_, field_count_);
mutabilities_[cursor_] = mutability;
buffer_[cursor_++] = type;
}
StructType* Build() {
DCHECK_EQ(cursor_, field_count_);
uint32_t* offsets = zone_->NewArray<uint32_t>(field_count_);
return new (zone_) StructType(field_count_, offsets, buffer_);
return new (zone_)
StructType(field_count_, offsets, buffer_, mutabilities_);
}
private:
......@@ -88,25 +105,30 @@ class StructType : public ZoneObject {
Zone* zone_;
uint32_t cursor_;
ValueType* buffer_;
bool* mutabilities_;
};
private:
uint32_t field_count_;
uint32_t* field_offsets_;
const ValueType* reps_;
const bool* mutabilities_;
};
class ArrayType : public ZoneObject {
public:
constexpr explicit ArrayType(ValueType rep) : rep_(rep) {}
constexpr explicit ArrayType(ValueType rep, bool mutability)
: rep_(rep), mutability_(mutability) {}
ValueType element_type() const { return rep_; }
bool mutability() const { return mutability_; }
bool operator==(const ArrayType& other) const { return rep_ == other.rep_; }
bool operator!=(const ArrayType& other) const { return rep_ != other.rep_; }
private:
const ValueType rep_;
const bool mutability_;
};
} // namespace wasm
......
......@@ -450,8 +450,9 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
StructType* struct_type = type.struct_type;
buffer->write_u8(kWasmStructTypeCode);
buffer->write_size(struct_type->field_count());
for (auto field : struct_type->fields()) {
WriteValueType(buffer, field);
for (uint32_t i = 0; i < struct_type->field_count(); i++) {
WriteValueType(buffer, struct_type->field(i));
buffer->write_u8(struct_type->mutability(i) ? 1 : 0);
}
break;
}
......@@ -459,6 +460,7 @@ void WasmModuleBuilder::WriteTo(ZoneBuffer* buffer) const {
ArrayType* array_type = type.array_type;
buffer->write_u8(kWasmArrayTypeCode);
WriteValueType(buffer, array_type->element_type());
buffer->write_u8(array_type->mutability() ? 1 : 0);
break;
}
}
......
......@@ -37,8 +37,8 @@ WASM_EXEC_TEST(BasicStruct) {
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
StructType::Builder type_builder(&zone, 2);
type_builder.AddField(kWasmI32);
type_builder.AddField(kWasmI32);
type_builder.AddField(kWasmI32, true);
type_builder.AddField(kWasmI32, true);
int32_t type_index = builder->AddStructType(type_builder.Build());
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
ValueType kOptRefType = ValueType(ValueType::kOptRef, type_index);
......@@ -218,8 +218,8 @@ WASM_EXEC_TEST(LetInstruction) {
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
StructType::Builder type_builder(&zone, 2);
type_builder.AddField(kWasmI32);
type_builder.AddField(kWasmI32);
type_builder.AddField(kWasmI32, true);
type_builder.AddField(kWasmI32, true);
int32_t type_index = builder->AddStructType(type_builder.Build());
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
......@@ -316,7 +316,7 @@ WASM_EXEC_TEST(BasicArray) {
Zone zone(&allocator, ZONE_NAME);
WasmModuleBuilder* builder = new (&zone) WasmModuleBuilder(&zone);
ArrayType type(wasm::kWasmI32);
ArrayType type(wasm::kWasmI32, true);
int32_t type_index = builder->AddArrayType(&type);
ValueType kRefTypes[] = {ValueType(ValueType::kRef, type_index)};
FunctionSig sig_q_v(1, 0, kRefTypes);
......
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