[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/+/3743483 Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#81518}
This commit is contained in:
parent
2cd4710142
commit
5e2174fbbc
@ -1675,6 +1675,36 @@ Handle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData(
|
||||
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(
|
||||
const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements,
|
||||
Handle<Map> map) {
|
||||
@ -1695,8 +1725,7 @@ Handle<WasmArray> Factory::NewWasmArrayFromElements(
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
int offset = result.element_offset(i);
|
||||
TaggedField<Object>::store(result, offset, *elements[i].to_ref());
|
||||
result.SetTaggedElement(i, elements[i].to_ref());
|
||||
}
|
||||
}
|
||||
return handle(result, isolate());
|
||||
|
@ -648,6 +648,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<WasmSuspenderObject> suspender, wasm::OnResume on_resume);
|
||||
Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type,
|
||||
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(
|
||||
const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements,
|
||||
Handle<Map> map);
|
||||
|
@ -191,7 +191,35 @@ void ConstantExpressionInterface::StructNewDefault(
|
||||
WasmValue(isolate_->factory()->NewWasmStruct(
|
||||
imm.struct_type, field_values.data(),
|
||||
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(
|
||||
|
@ -978,6 +978,11 @@ struct ControlBase : public PcForErrors<validate> {
|
||||
const Value& rtt, const Value args[], Value* result) \
|
||||
F(StructNewDefault, const StructIndexImmediate<validate>& imm, \
|
||||
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, \
|
||||
const base::Vector<Value>& elements, const Value& rtt, Value* result) \
|
||||
F(ArrayNewSegment, const ArrayIndexImmediate<validate>& array_imm, \
|
||||
@ -1084,11 +1089,6 @@ struct ControlBase : public PcForErrors<validate> {
|
||||
const FieldImmediate<validate>& field, bool is_signed, Value* result) \
|
||||
F(StructSet, const Value& struct_object, \
|
||||
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, \
|
||||
const ArrayIndexImmediate<validate>& imm, const Value& index, \
|
||||
bool is_signed, Value* result) \
|
||||
@ -4316,7 +4316,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
|
||||
}
|
||||
case kExprArrayNew:
|
||||
case kExprArrayNewWithRtt: {
|
||||
NON_CONST_ONLY
|
||||
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
ValueType rtt_type = ValueType::Rtt(imm.index);
|
||||
@ -4338,7 +4337,6 @@ class WasmFullDecoder : public WasmDecoder<validate, decoding_mode> {
|
||||
}
|
||||
case kExprArrayNewDefault:
|
||||
case kExprArrayNewDefaultWithRtt: {
|
||||
NON_CONST_ONLY
|
||||
ArrayIndexImmediate<validate> imm(this, this->pc_ + opcode_length);
|
||||
if (!this->Validate(this->pc_ + opcode_length, imm)) return 0;
|
||||
if (!VALIDATE(imm.array_type->element_type().is_defaultable())) {
|
||||
|
@ -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:
|
||||
ValueType type_;
|
||||
uint8_t bit_pattern_[16];
|
||||
|
@ -393,7 +393,7 @@ class InitExprInterface {
|
||||
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,
|
||||
const StructIndexImmediate<validate>& imm,
|
||||
const Value& rtt, const Value args[], Value* result) {
|
||||
@ -406,6 +406,19 @@ class InitExprInterface {
|
||||
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,
|
||||
const ArrayIndexImmediate<validate>& imm,
|
||||
const base::Vector<Value>& elements, const Value& rtt,
|
||||
|
@ -273,6 +273,72 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
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() {
|
||||
print(arguments.callee.name);
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
@ -182,6 +182,7 @@ let kSig_i_l = makeSig([kWasmI64], [kWasmI32]);
|
||||
let kSig_i_ii = makeSig([kWasmI32, kWasmI32], [kWasmI32]);
|
||||
let kSig_i_iii = 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_d_dd = makeSig([kWasmF64, kWasmF64], [kWasmF64]);
|
||||
let kSig_l_ll = makeSig([kWasmI64, kWasmI64], [kWasmI64]);
|
||||
@ -939,7 +940,7 @@ let kTrapMsgs = [
|
||||
|
||||
// This requires test/mjsunit/mjsunit.js.
|
||||
function assertTraps(trap, code) {
|
||||
assertThrows(code, WebAssembly.RuntimeError, kTrapMsgs[trap]);
|
||||
assertThrows(code, WebAssembly.RuntimeError, new RegExp(kTrapMsgs[trap]));
|
||||
}
|
||||
|
||||
function assertTrapsOneOf(traps, code) {
|
||||
|
Loading…
Reference in New Issue
Block a user