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

[wasm-gc] Allow array.new(_default) as constant expressions

Additional change: Allow regular expressions in assertTraps.

Bug: v8:7748
Change-Id: I3bf99faec3d4f25fcf3caa4ed310f02f03196d4d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3743483Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81518}
parent 2cd47101
...@@ -1675,6 +1675,36 @@ Handle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData( ...@@ -1675,6 +1675,36 @@ Handle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData(
return handle(result, isolate()); return handle(result, isolate());
} }
Handle<WasmArray> Factory::NewWasmArray(const wasm::ArrayType* type,
uint32_t length,
wasm::WasmValue initial_value,
Handle<Map> map) {
HeapObject raw =
AllocateRaw(WasmArray::SizeFor(*map, length), AllocationType::kYoung);
DisallowGarbageCollection no_gc;
raw.set_map_after_allocation(*map);
WasmArray result = WasmArray::cast(raw);
result.set_raw_properties_or_hash(*empty_fixed_array(), kRelaxedStore);
result.set_length(length);
if (type->element_type().is_numeric()) {
if (initial_value.zero_byte_representation()) {
memset(reinterpret_cast<void*>(result.ElementAddress(0)), 0,
length * type->element_type().value_kind_size());
} else {
wasm::WasmValue packed = initial_value.Packed(type->element_type());
for (uint32_t i = 0; i < length; i++) {
Address address = result.ElementAddress(i);
packed.CopyTo(reinterpret_cast<byte*>(address));
}
}
} else {
for (uint32_t i = 0; i < length; i++) {
result.SetTaggedElement(i, initial_value.to_ref());
}
}
return handle(result, isolate());
}
Handle<WasmArray> Factory::NewWasmArrayFromElements( Handle<WasmArray> Factory::NewWasmArrayFromElements(
const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements, const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements,
Handle<Map> map) { Handle<Map> map) {
...@@ -1695,8 +1725,7 @@ Handle<WasmArray> Factory::NewWasmArrayFromElements( ...@@ -1695,8 +1725,7 @@ Handle<WasmArray> Factory::NewWasmArrayFromElements(
} }
} else { } else {
for (uint32_t i = 0; i < length; i++) { for (uint32_t i = 0; i < length; i++) {
int offset = result.element_offset(i); result.SetTaggedElement(i, elements[i].to_ref());
TaggedField<Object>::store(result, offset, *elements[i].to_ref());
} }
} }
return handle(result, isolate()); return handle(result, isolate());
......
...@@ -648,6 +648,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> { ...@@ -648,6 +648,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<WasmSuspenderObject> suspender, wasm::OnResume on_resume); Handle<WasmSuspenderObject> suspender, wasm::OnResume on_resume);
Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type, Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type,
wasm::WasmValue* args, Handle<Map> map); wasm::WasmValue* args, Handle<Map> map);
Handle<WasmArray> NewWasmArray(const wasm::ArrayType* type, uint32_t length,
wasm::WasmValue initial_value,
Handle<Map> map);
Handle<WasmArray> NewWasmArrayFromElements( Handle<WasmArray> NewWasmArrayFromElements(
const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements, const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements,
Handle<Map> map); Handle<Map> map);
......
...@@ -191,7 +191,35 @@ void ConstantExpressionInterface::StructNewDefault( ...@@ -191,7 +191,35 @@ void ConstantExpressionInterface::StructNewDefault(
WasmValue(isolate_->factory()->NewWasmStruct( WasmValue(isolate_->factory()->NewWasmStruct(
imm.struct_type, field_values.data(), imm.struct_type, field_values.data(),
Handle<Map>::cast(rtt.runtime_value.to_ref())), Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(HeapType(imm.index))); ValueType::Ref(imm.index));
}
void ConstantExpressionInterface::ArrayNewWithRtt(
FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& initial_value, const Value& rtt,
Value* result) {
if (!generate_value()) return;
if (length.runtime_value.to_u32() >
static_cast<uint32_t>(WasmArray::MaxLength(imm.array_type))) {
error_ = MessageTemplate::kWasmTrapArrayTooLarge;
return;
}
result->runtime_value =
WasmValue(isolate_->factory()->NewWasmArray(
imm.array_type, length.runtime_value.to_u32(),
initial_value.runtime_value,
Handle<Map>::cast(rtt.runtime_value.to_ref())),
ValueType::Ref(imm.index));
}
void ConstantExpressionInterface::ArrayNewDefault(
FullDecoder* decoder, const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& rtt, Value* result) {
if (!generate_value()) return;
Value initial_value(decoder->pc(), imm.array_type->element_type());
initial_value.runtime_value =
DefaultValueForType(imm.array_type->element_type(), isolate_);
return ArrayNewWithRtt(decoder, imm, length, initial_value, rtt, result);
} }
void ConstantExpressionInterface::ArrayNewFixed( void ConstantExpressionInterface::ArrayNewFixed(
......
...@@ -978,6 +978,11 @@ struct ControlBase : public PcForErrors<validate> { ...@@ -978,6 +978,11 @@ struct ControlBase : public PcForErrors<validate> {
const Value& rtt, const Value args[], Value* result) \ const Value& rtt, const Value args[], Value* result) \
F(StructNewDefault, const StructIndexImmediate<validate>& imm, \ F(StructNewDefault, const StructIndexImmediate<validate>& imm, \
const Value& rtt, Value* result) \ const Value& rtt, Value* result) \
F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& initial_value, const Value& rtt, \
Value* result) \
F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& rtt, Value* result) \
F(ArrayNewFixed, const ArrayIndexImmediate<validate>& imm, \ F(ArrayNewFixed, const ArrayIndexImmediate<validate>& imm, \
const base::Vector<Value>& elements, const Value& rtt, Value* result) \ const base::Vector<Value>& elements, const Value& rtt, Value* result) \
F(ArrayNewSegment, const ArrayIndexImmediate<validate>& array_imm, \ F(ArrayNewSegment, const ArrayIndexImmediate<validate>& array_imm, \
...@@ -1084,11 +1089,6 @@ struct ControlBase : public PcForErrors<validate> { ...@@ -1084,11 +1089,6 @@ struct ControlBase : public PcForErrors<validate> {
const FieldImmediate<validate>& field, bool is_signed, Value* result) \ const FieldImmediate<validate>& field, bool is_signed, Value* result) \
F(StructSet, const Value& struct_object, \ F(StructSet, const Value& struct_object, \
const FieldImmediate<validate>& field, const Value& field_value) \ const FieldImmediate<validate>& field, const Value& field_value) \
F(ArrayNewWithRtt, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& initial_value, const Value& rtt, \
Value* result) \
F(ArrayNewDefault, const ArrayIndexImmediate<validate>& imm, \
const Value& length, const Value& rtt, Value* result) \
F(ArrayGet, const Value& array_obj, \ F(ArrayGet, const Value& array_obj, \
const ArrayIndexImmediate<validate>& imm, const Value& index, \ const ArrayIndexImmediate<validate>& imm, const Value& index, \
bool is_signed, Value* result) \ bool is_signed, Value* result) \
...@@ -4316,7 +4316,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> { ...@@ -4316,7 +4316,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
} }
case kExprArrayNew: case kExprArrayNew:
case kExprArrayNewWithRtt: { case kExprArrayNewWithRtt: {
NON_CONST_ONLY
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
ValueType rtt_type = ValueType::Rtt(imm.index); ValueType rtt_type = ValueType::Rtt(imm.index);
...@@ -4338,7 +4337,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> { ...@@ -4338,7 +4337,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
} }
case kExprArrayNewDefault: case kExprArrayNewDefault:
case kExprArrayNewDefaultWithRtt: { case kExprArrayNewDefaultWithRtt: {
NON_CONST_ONLY
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length); ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0; if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
if (!VALIDATE(imm.array_type->element_type().is_defaultable())) { if (!VALIDATE(imm.array_type->element_type().is_defaultable())) {
......
...@@ -209,6 +209,13 @@ class WasmValue { ...@@ -209,6 +209,13 @@ class WasmValue {
} }
} }
bool zero_byte_representation() {
DCHECK(type().is_numeric());
uint32_t byte_count = type().value_kind_size();
return static_cast<uint32_t>(std::count(
bit_pattern_, bit_pattern_ + byte_count, 0)) == byte_count;
}
private: private:
ValueType type_; ValueType type_;
uint8_t bit_pattern_[16]; uint8_t bit_pattern_[16];
......
...@@ -393,7 +393,7 @@ class InitExprInterface { ...@@ -393,7 +393,7 @@ class InitExprInterface {
os_ << "kWasmGlobalGet, " << index(imm.index); os_ << "kWasmGlobalGet, " << index(imm.index);
} }
// The following three operations assume non-rtt versions of the instructions. // The following operations assume non-rtt versions of the instructions.
void StructNewWithRtt(FullDecoder* decoder, void StructNewWithRtt(FullDecoder* decoder,
const StructIndexImmediate<validate>& imm, const StructIndexImmediate<validate>& imm,
const Value& rtt, const Value args[], Value* result) { const Value& rtt, const Value args[], Value* result) {
...@@ -406,6 +406,19 @@ class InitExprInterface { ...@@ -406,6 +406,19 @@ class InitExprInterface {
os_ << "kGCPrefix, kExprStructNewDefault, " << index(imm.index); os_ << "kGCPrefix, kExprStructNewDefault, " << index(imm.index);
} }
void ArrayNewWithRtt(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& initial_value,
const Value& rtt, Value* result) {
os_ << "kGCPrefix, kExprArrayNew, " << index(imm.index);
}
void ArrayNewDefault(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm,
const Value& length, const Value& rtt, Value* result) {
os_ << "kGCPrefix, kExprArrayNewDefault, " << index(imm.index);
}
void ArrayNewFixed(FullDecoder* decoder, void ArrayNewFixed(FullDecoder* decoder,
const ArrayIndexImmediate<validate>& imm, const ArrayIndexImmediate<validate>& imm,
const base::Vector<Value>& elements, const Value& rtt, const base::Vector<Value>& elements, const Value& rtt,
......
...@@ -273,6 +273,72 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js"); ...@@ -273,6 +273,72 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
assertEquals(element2_value, instance.exports.element2()); assertEquals(element2_value, instance.exports.element2());
})(); })();
(function TestArrayNew() {
print(arguments.callee.name);
var builder = new WasmModuleBuilder();
var struct_index = builder.addStruct([makeField(kWasmI64, true)]);
var array_num_index = builder.addArray(kWasmI64, true);
var array_ref_index = builder.addArray(wasmRefNullType(struct_index), true);
let elem1 = -44;
let elem2 = 15;
let length = 20;
let global_elem_1 = builder.addGlobal(kWasmI64, false, wasmI64Const(elem1));
let global_elem_2 = builder.addGlobal(kWasmI64, false, wasmI64Const(elem2));
let global_length = builder.addGlobal(kWasmI32, false, wasmI32Const(length));
var global_array_1 = builder.addGlobal(
wasmRefType(array_num_index), false,
[kExprGlobalGet, global_elem_1.index,
kExprGlobalGet, global_length.index,
kGCPrefix, kExprArrayNew, array_num_index]);
var global_array_2 = builder.addGlobal(
wasmRefType(array_ref_index), false,
[kExprGlobalGet, global_elem_2.index,
kGCPrefix, kExprStructNew, struct_index,
kExprGlobalGet, global_length.index,
kGCPrefix, kExprArrayNew, array_ref_index]);
builder.addFunction("get_elements", kSig_l_i)
.addBody([
kExprGlobalGet, global_array_1.index,
kExprLocalGet, 0,
kGCPrefix, kExprArrayGet, array_num_index,
kExprGlobalGet, global_array_2.index,
kExprLocalGet, 0,
kGCPrefix, kExprArrayGet, array_ref_index,
kGCPrefix, kExprStructGet, struct_index, 0,
kExprI64Add])
.exportFunc();
var instance = builder.instantiate({});
let result = BigInt(elem1 + elem2);
assertEquals(result, instance.exports.get_elements(0));
assertEquals(result, instance.exports.get_elements(length / 2));
assertEquals(result, instance.exports.get_elements(length - 1));
assertTraps(kTrapArrayOutOfBounds,
() => instance.exports.get_elements(length));
})();
(function TestArrayNewArrayTooLarge() {
print(arguments.callee.name);
var builder = new WasmModuleBuilder();
var array_num_index = builder.addArray(kWasmI64, true);
builder.addGlobal(
wasmRefType(array_num_index), false,
[...wasmI32Const(0x8ffffff),
kGCPrefix, kExprArrayNewDefault, array_num_index]);
assertTraps(kTrapArrayTooLarge, () => builder.instantiate({}));
})();
(function TestI31RefConstantExpr() { (function TestI31RefConstantExpr() {
print(arguments.callee.name); print(arguments.callee.name);
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
......
...@@ -182,6 +182,7 @@ let kSig_i_l = makeSig([kWasmI64], [kWasmI32]); ...@@ -182,6 +182,7 @@ let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]); let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]); let kSig_i_iii = makeSig([kWasmI32, kWasmI32, kWasmI32], [kWasmI32]);
let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []); let kSig_v_iiii = makeSig([kWasmI32, kWasmI32, kWasmI32, kWasmI32], []);
let kSig_l_i = makeSig([kWasmI32], [kWasmI64]);
let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]); let kSig_f_ff = makeSig([kWasmF32, kWasmF32], [kWasmF32]);
let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]); let kSig_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]); let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
...@@ -939,7 +940,7 @@ let kTrapMsgs = [ ...@@ -939,7 +940,7 @@ let kTrapMsgs = [
// This requires test/mjsunit/mjsunit.js. // This requires test/mjsunit/mjsunit.js.
function assertTraps(trap, code) { function assertTraps(trap, code) {
assertThrows(code, WebAssembly.RuntimeError, kTrapMsgs[trap]); assertThrows(code, WebAssembly.RuntimeError, new RegExp(kTrapMsgs[trap]));
} }
function assertTrapsOneOf(traps, code) { function assertTrapsOneOf(traps, code) {
......
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