[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());
|
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(
|
|||||||
}
|
}
|
||||||
} 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> {
|
|||||||
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(
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
}
|
}
|
||||||
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> {
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
|||||||
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 {
|
|||||||
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");
|
|||||||
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]);
|
|||||||
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 = [
|
|||||||
|
|
||||||
// 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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user