[wasm-gc] Add array.init constant expression
Bug: v8:7748 Change-Id: I3fa510b4dc35d3f58532ecbbeecd79d2826ff667 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2951722 Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#75115}
This commit is contained in:
parent
e4921a2ae4
commit
546929280e
@ -1457,6 +1457,29 @@ Handle<WasmCapiFunctionData> Factory::NewWasmCapiFunctionData(
|
||||
return handle(result, isolate());
|
||||
}
|
||||
|
||||
Handle<WasmArray> Factory::NewWasmArray(
|
||||
const wasm::ArrayType* type, const std::vector<wasm::WasmValue>& elements,
|
||||
Handle<Map> map) {
|
||||
uint32_t length = static_cast<uint32_t>(elements.size());
|
||||
HeapObject raw =
|
||||
AllocateRaw(WasmArray::SizeFor(*map, length), AllocationType::kYoung);
|
||||
raw.set_map_after_allocation(*map);
|
||||
WasmArray result = WasmArray::cast(raw);
|
||||
result.set_raw_properties_or_hash(*empty_fixed_array());
|
||||
result.set_length(length);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
Address address = result.ElementAddress(i);
|
||||
if (type->element_type().is_numeric()) {
|
||||
elements[i]
|
||||
.Packed(type->element_type())
|
||||
.CopyTo(reinterpret_cast<byte*>(address));
|
||||
} else {
|
||||
base::WriteUnalignedValue<Object>(address, *elements[i].to_ref());
|
||||
}
|
||||
}
|
||||
return handle(result, isolate());
|
||||
}
|
||||
|
||||
Handle<WasmStruct> Factory::NewWasmStruct(const wasm::StructType* type,
|
||||
wasm::WasmValue* args,
|
||||
Handle<Map> map) {
|
||||
|
@ -71,6 +71,7 @@ class WasmJSFunctionData;
|
||||
class WeakCell;
|
||||
#if V8_ENABLE_WEBASSEMBLY
|
||||
namespace wasm {
|
||||
class ArrayType;
|
||||
class StructType;
|
||||
class WasmValue;
|
||||
} // namespace wasm
|
||||
@ -578,6 +579,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
|
||||
Handle<Code> wrapper_code);
|
||||
Handle<WasmStruct> NewWasmStruct(const wasm::StructType* type,
|
||||
wasm::WasmValue* args, Handle<Map> map);
|
||||
Handle<WasmArray> NewWasmArray(const wasm::ArrayType* type,
|
||||
const std::vector<wasm::WasmValue>& elements,
|
||||
Handle<Map> map);
|
||||
|
||||
Handle<SharedFunctionInfo> NewSharedFunctionInfoForWasmExportedFunction(
|
||||
Handle<String> name, Handle<WasmExportedFunctionData> data);
|
||||
|
@ -1823,7 +1823,10 @@ class ModuleDecoderImpl : public Decoder {
|
||||
len += imm.length;
|
||||
const StructType* type = module->struct_type(imm.index);
|
||||
if (!V8_LIKELY(stack.size() >= type->field_count() + 1)) {
|
||||
error(pc(), "not enough arguments for struct.new");
|
||||
errorf(pc(),
|
||||
"not enough arguments on the stack for struct.new: "
|
||||
"expected %u, found %zu",
|
||||
type->field_count() + 1, stack.size());
|
||||
return {};
|
||||
}
|
||||
std::vector<WasmInitExpr> arguments(type->field_count() + 1);
|
||||
@ -1856,6 +1859,71 @@ class ModuleDecoderImpl : public Decoder {
|
||||
imm.index, std::move(arguments)));
|
||||
break;
|
||||
}
|
||||
case kExprArrayInit: {
|
||||
if (!V8_LIKELY(enabled_features_.has_gc_experiments())) {
|
||||
error(pc(),
|
||||
"invalid opcode array.init in init. expression, enable "
|
||||
"with --experimental-wasm-gc-experiments");
|
||||
return {};
|
||||
}
|
||||
IndexImmediate<validate> array_imm(this, pc() + len,
|
||||
"array index");
|
||||
if (!V8_LIKELY(module->has_array(array_imm.index))) {
|
||||
errorf(pc() + len, "invalid array type index #%u",
|
||||
array_imm.index);
|
||||
return {};
|
||||
}
|
||||
IndexImmediate<validate> length_imm(
|
||||
this, pc() + len + array_imm.length, "array.init length");
|
||||
uint32_t elem_count = length_imm.index;
|
||||
if (elem_count > kV8MaxWasmArrayInitLength) {
|
||||
errorf(pc() + len + array_imm.length,
|
||||
"Requested length %u for array.init too large, maximum "
|
||||
"is %zu",
|
||||
length_imm.index, kV8MaxWasmArrayInitLength);
|
||||
return {};
|
||||
}
|
||||
len += array_imm.length + length_imm.length;
|
||||
const ArrayType* array_type =
|
||||
module_->array_type(array_imm.index);
|
||||
if (stack.size() < elem_count + 1) {
|
||||
errorf(pc(),
|
||||
"not enough arguments on the stack for array.init: "
|
||||
"expected %u, found %zu",
|
||||
elem_count + 1, stack.size());
|
||||
return {};
|
||||
}
|
||||
std::vector<WasmInitExpr> arguments(elem_count + 1);
|
||||
WasmInitExpr* stack_args = &stack.back() - elem_count;
|
||||
for (uint32_t i = 0; i < elem_count; i++) {
|
||||
WasmInitExpr& argument = stack_args[i];
|
||||
if (!IsSubtypeOf(TypeOf(argument),
|
||||
array_type->element_type().Unpacked(),
|
||||
module)) {
|
||||
errorf(pc(), "array.init[%u]: expected %s, found %s instead",
|
||||
i, array_type->element_type().name().c_str(),
|
||||
TypeOf(argument).name().c_str());
|
||||
return {};
|
||||
}
|
||||
arguments[i] = std::move(argument);
|
||||
}
|
||||
WasmInitExpr& rtt = stack.back();
|
||||
if (!IsSubtypeOf(TypeOf(rtt), ValueType::Rtt(array_imm.index),
|
||||
module)) {
|
||||
errorf(pc(), "array.init[%u]: expected %s, found %s instead",
|
||||
elem_count,
|
||||
ValueType::Rtt(array_imm.index).name().c_str(),
|
||||
TypeOf(rtt).name().c_str());
|
||||
return {};
|
||||
}
|
||||
arguments[elem_count] = std::move(rtt);
|
||||
for (uint32_t i = 0; i <= elem_count; i++) {
|
||||
stack.pop_back();
|
||||
}
|
||||
stack.push_back(WasmInitExpr::ArrayInit(array_imm.index,
|
||||
std::move(arguments)));
|
||||
break;
|
||||
}
|
||||
case kExprRttCanon: {
|
||||
IndexImmediate<validate> imm(this, pc() + len, "type index");
|
||||
if (V8_UNLIKELY(!module_->has_type(imm.index))) {
|
||||
@ -2049,7 +2117,7 @@ class ModuleDecoderImpl : public Decoder {
|
||||
ValueType field = consume_storage_type();
|
||||
if (failed()) return nullptr;
|
||||
bool mutability = consume_mutability();
|
||||
if (!mutability) {
|
||||
if (!V8_LIKELY(mutability)) {
|
||||
error(this->pc() - 1, "immutable arrays are not supported yet");
|
||||
}
|
||||
return zone->New<ArrayType>(field, mutability);
|
||||
|
@ -1576,6 +1576,17 @@ WasmValue InstanceBuilder::EvaluateInitExpression(
|
||||
isolate_->factory()->NewWasmStruct(type, fields.data(), rtt),
|
||||
init.type(module_, enabled_));
|
||||
}
|
||||
case WasmInitExpr::kArrayInit: {
|
||||
const ArrayType* type = module_->array_type(init.immediate().index);
|
||||
std::vector<WasmValue> elements(init.operands().size() - 1);
|
||||
for (uint32_t i = 0; i < elements.size(); i++) {
|
||||
elements[i] = EvaluateInitExpression(init.operands()[i], instance);
|
||||
}
|
||||
auto rtt = Handle<Map>::cast(
|
||||
EvaluateInitExpression(init.operands().back(), instance).to_ref());
|
||||
return WasmValue(isolate_->factory()->NewWasmArray(type, elements, rtt),
|
||||
init.type(module_, enabled_));
|
||||
}
|
||||
case WasmInitExpr::kRttCanon: {
|
||||
int map_index = init.immediate().index;
|
||||
return WasmValue(
|
||||
|
@ -39,6 +39,7 @@ ValueType WasmInitExpr::type(const WasmModule* module,
|
||||
case kRefNullConst:
|
||||
return ValueType::Ref(immediate().heap_type, kNullable);
|
||||
case kStructNewWithRtt:
|
||||
case kArrayInit:
|
||||
return ValueType::Ref(immediate().index, kNonNullable);
|
||||
case kRttCanon:
|
||||
return ValueType::Rtt(immediate().heap_type, 0);
|
||||
|
@ -34,6 +34,7 @@ class WasmInitExpr {
|
||||
kRefNullConst,
|
||||
kRefFuncConst,
|
||||
kStructNewWithRtt,
|
||||
kArrayInit,
|
||||
kRttCanon,
|
||||
kRttSub,
|
||||
kRttFreshSub,
|
||||
@ -98,6 +99,15 @@ class WasmInitExpr {
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr ArrayInit(uint32_t index,
|
||||
std::vector<WasmInitExpr> elements) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kArrayInit;
|
||||
expr.immediate_.index = index;
|
||||
expr.operands_ = std::move(elements);
|
||||
return expr;
|
||||
}
|
||||
|
||||
static WasmInitExpr RttCanon(uint32_t index) {
|
||||
WasmInitExpr expr;
|
||||
expr.kind_ = kRttCanon;
|
||||
@ -153,6 +163,13 @@ class WasmInitExpr {
|
||||
if (operands()[i] != other.operands()[i]) return false;
|
||||
}
|
||||
return true;
|
||||
case kArrayInit:
|
||||
if (immediate().index != other.immediate().index) return false;
|
||||
if (operands().size() != other.operands().size()) return false;
|
||||
for (uint32_t i = 0; i < operands().size(); i++) {
|
||||
if (operands()[i] != other.operands()[i]) return false;
|
||||
}
|
||||
return true;
|
||||
case kRttSub:
|
||||
case kRttFreshSub:
|
||||
return immediate().index == other.immediate().index &&
|
||||
|
@ -61,6 +61,7 @@ constexpr uint32_t kV8MaxRttSubtypingDepth = 31;
|
||||
// Maximum supported by implementation: ((1<<27)-3).
|
||||
// Reason: total object size in bytes must fit into a Smi, for filler objects.
|
||||
constexpr size_t kV8MaxWasmArrayLength = 1u << 26;
|
||||
constexpr size_t kV8MaxWasmArrayInitLength = 999;
|
||||
|
||||
static_assert(kV8MaxWasmTableSize <= 4294967295, // 2^32 - 1
|
||||
"v8 should not exceed WebAssembly's non-web embedding limits");
|
||||
|
@ -526,6 +526,16 @@ void WriteInitializerExpression(ZoneBuffer* buffer, const WasmInitExpr& init,
|
||||
buffer->write_u8(static_cast<uint8_t>(kExprStructNewWithRtt));
|
||||
buffer->write_u32v(init.immediate().index);
|
||||
break;
|
||||
case WasmInitExpr::kArrayInit:
|
||||
STATIC_ASSERT((kExprArrayInit >> 8) == kGCPrefix);
|
||||
for (const WasmInitExpr& operand : init.operands()) {
|
||||
WriteInitializerExpression(buffer, operand, kWasmBottom);
|
||||
}
|
||||
buffer->write_u8(kGCPrefix);
|
||||
buffer->write_u8(static_cast<uint8_t>(kExprArrayInit));
|
||||
buffer->write_u32v(init.immediate().index);
|
||||
buffer->write_u32v(static_cast<uint32_t>(init.operands().size() - 1));
|
||||
break;
|
||||
case WasmInitExpr::kRttCanon:
|
||||
STATIC_ASSERT((kExprRttCanon >> 8) == kGCPrefix);
|
||||
buffer->write_u8(kGCPrefix);
|
||||
|
@ -1685,6 +1685,12 @@ ObjectSlot WasmArray::ElementSlot(uint32_t index) {
|
||||
return RawField(kHeaderSize + kTaggedSize * index);
|
||||
}
|
||||
|
||||
Address WasmArray::ElementAddress(uint32_t index) {
|
||||
DCHECK_LE(index, length());
|
||||
return ptr() + WasmArray::kHeaderSize +
|
||||
index * type()->element_type().element_size_bytes() - kHeapObjectTag;
|
||||
}
|
||||
|
||||
// static
|
||||
Handle<WasmExceptionObject> WasmExceptionObject::New(
|
||||
Isolate* isolate, const wasm::FunctionSig* sig,
|
||||
|
@ -1000,6 +1000,9 @@ class WasmArray : public TorqueGeneratedWasmArray<WasmArray, WasmObject> {
|
||||
Handle<WasmArray> array,
|
||||
uint32_t index);
|
||||
|
||||
// Returns the Address of the element at {index}.
|
||||
Address ElementAddress(uint32_t index);
|
||||
|
||||
DECL_CAST(WasmArray)
|
||||
DECL_PRINTER(WasmArray)
|
||||
|
||||
|
@ -396,6 +396,7 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
|
||||
CASE_OP(ArraySet, "array.set")
|
||||
CASE_OP(ArrayLen, "array.len")
|
||||
CASE_OP(ArrayCopy, "array.copy")
|
||||
CASE_OP(ArrayInit, "array.init")
|
||||
CASE_OP(I31New, "i31.new")
|
||||
CASE_OP(I31GetS, "i31.get_s")
|
||||
CASE_OP(I31GetU, "i31.get_u")
|
||||
|
@ -664,6 +664,7 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
|
||||
V(ArraySet, 0xfb16, _) \
|
||||
V(ArrayLen, 0xfb17, _) \
|
||||
V(ArrayCopy, 0xfb18, _) /* not standardized - V8 experimental */ \
|
||||
V(ArrayInit, 0xfb19, _) /* not standardized - V8 experimental */ \
|
||||
V(I31New, 0xfb20, _) \
|
||||
V(I31GetS, 0xfb21, _) \
|
||||
V(I31GetU, 0xfb22, _) \
|
||||
|
@ -560,6 +560,9 @@ inline WasmOpcode LoadStoreOpcodeOf(MachineType type, bool store) {
|
||||
dst_array, dst_index, src_array, src_index, length, \
|
||||
WASM_GC_OP(kExprArrayCopy), static_cast<byte>(dst_idx), \
|
||||
static_cast<byte>(src_idx)
|
||||
#define WASM_ARRAY_INIT(index, length, ...) \
|
||||
__VA_ARGS__, WASM_GC_OP(kExprArrayInit), static_cast<byte>(index), \
|
||||
static_cast<byte>(length)
|
||||
|
||||
#define WASM_RTT_WITH_DEPTH(depth, typeidx) \
|
||||
kRttWithDepthCode, U32V_1(depth), U32V_1(typeidx)
|
||||
|
@ -170,6 +170,7 @@ std::ostream& operator<<(std::ostream& os, const WasmInitExpr& expr) {
|
||||
case WasmInitExpr::kRttFreshSub:
|
||||
case WasmInitExpr::kRefNullConst:
|
||||
case WasmInitExpr::kStructNewWithRtt:
|
||||
case WasmInitExpr::kArrayInit:
|
||||
// TODO(manoskouk): Implement these.
|
||||
UNIMPLEMENTED();
|
||||
case WasmInitExpr::kGlobalGet:
|
||||
|
@ -7,6 +7,8 @@
|
||||
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
|
||||
(function TestReferenceGlobals() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
var exporting_instance = (function() {
|
||||
var builder = new WasmModuleBuilder();
|
||||
|
||||
@ -105,6 +107,8 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
})();
|
||||
|
||||
(function TestStructInitExpr() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
var builder = new WasmModuleBuilder();
|
||||
var struct_index = builder.addStruct([{type: kWasmI32, mutability: false}]);
|
||||
var composite_struct_index = builder.addStruct(
|
||||
@ -158,3 +162,96 @@ d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
assertEquals(field2_value, instance.exports.field_2());
|
||||
assertEquals((field3_value << 24) >> 24, instance.exports.field_3());
|
||||
})();
|
||||
|
||||
(function TestArrayInitExprNumeric() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
var builder = new WasmModuleBuilder();
|
||||
var array_index = builder.addArray(kWasmI16, true);
|
||||
|
||||
let element0_value = -44;
|
||||
let element1_value = 55;
|
||||
|
||||
var global0 = builder.addGlobal(
|
||||
kWasmI32, false,
|
||||
WasmInitExpr.I32Const(element0_value));
|
||||
|
||||
var global = builder.addGlobal(
|
||||
wasmRefType(array_index), false,
|
||||
WasmInitExpr.ArrayInit(
|
||||
array_index,
|
||||
[WasmInitExpr.GlobalGet(global0.index),
|
||||
WasmInitExpr.I32Const(element1_value),
|
||||
WasmInitExpr.RttCanon(array_index)]));
|
||||
|
||||
builder.addFunction("get_element", kSig_i_i)
|
||||
.addBody([
|
||||
kExprGlobalGet, global.index,
|
||||
kExprLocalGet, 0,
|
||||
kGCPrefix, kExprArrayGetS, array_index])
|
||||
.exportFunc();
|
||||
|
||||
var instance = builder.instantiate({});
|
||||
|
||||
assertEquals(element0_value, instance.exports.get_element(0));
|
||||
assertEquals(element1_value, instance.exports.get_element(1));
|
||||
})();
|
||||
|
||||
(function TestArrayInitExprRef() {
|
||||
print(arguments.callee.name);
|
||||
|
||||
var builder = new WasmModuleBuilder();
|
||||
var struct_index = builder.addStruct([{type: kWasmI32, mutability: false}]);
|
||||
var array_index = builder.addArray(wasmOptRefType(struct_index), true);
|
||||
|
||||
let element0_value = 44;
|
||||
let element2_value = 55;
|
||||
|
||||
var global0 = builder.addGlobal(
|
||||
wasmRefType(struct_index), false,
|
||||
WasmInitExpr.StructNewWithRtt(
|
||||
struct_index,
|
||||
[WasmInitExpr.I32Const(element0_value),
|
||||
WasmInitExpr.RttCanon(struct_index)]));
|
||||
|
||||
var global = builder.addGlobal(
|
||||
wasmRefType(array_index), false,
|
||||
WasmInitExpr.ArrayInit(
|
||||
array_index,
|
||||
[WasmInitExpr.GlobalGet(global0.index),
|
||||
WasmInitExpr.RefNull(struct_index),
|
||||
WasmInitExpr.StructNewWithRtt(
|
||||
struct_index,
|
||||
[WasmInitExpr.I32Const(element2_value),
|
||||
WasmInitExpr.RttCanon(struct_index)]),
|
||||
WasmInitExpr.RttCanon(array_index)]));
|
||||
|
||||
builder.addFunction("element0", kSig_i_v)
|
||||
.addBody([
|
||||
kExprGlobalGet, global.index,
|
||||
kExprI32Const, 0,
|
||||
kGCPrefix, kExprArrayGet, array_index,
|
||||
kGCPrefix, kExprStructGet, struct_index, 0])
|
||||
.exportFunc();
|
||||
|
||||
builder.addFunction("element1", makeSig([], [kWasmAnyRef]))
|
||||
.addBody([
|
||||
kExprGlobalGet, global.index,
|
||||
kExprI32Const, 1,
|
||||
kGCPrefix, kExprArrayGet, array_index])
|
||||
.exportFunc();
|
||||
|
||||
builder.addFunction("element2", kSig_i_v)
|
||||
.addBody([
|
||||
kExprGlobalGet, global.index,
|
||||
kExprI32Const, 2,
|
||||
kGCPrefix, kExprArrayGet, array_index,
|
||||
kGCPrefix, kExprStructGet, struct_index, 0])
|
||||
.exportFunc();
|
||||
|
||||
var instance = builder.instantiate({});
|
||||
|
||||
assertEquals(element0_value, instance.exports.element0());
|
||||
assertEquals(null, instance.exports.element1());
|
||||
assertEquals(element2_value, instance.exports.element2());
|
||||
})();
|
||||
|
@ -15,7 +15,7 @@ let instances = [];
|
||||
function createArray_i() {
|
||||
let builder = new WasmModuleBuilder();
|
||||
|
||||
const type_index = builder.addArray(kWasmI32);
|
||||
const type_index = builder.addArray(kWasmI32, true);
|
||||
|
||||
let sig_a_i = makeSig_r_x(kWasmDataRef, kWasmI32);
|
||||
let sig_i_ai = makeSig([kWasmDataRef, kWasmI32], [kWasmI32]);
|
||||
|
@ -458,6 +458,8 @@ let kExprArrayGetS = 0x14;
|
||||
let kExprArrayGetU = 0x15;
|
||||
let kExprArraySet = 0x16;
|
||||
let kExprArrayLen = 0x17;
|
||||
let kExprArrayCopy = 0x18;
|
||||
let kExprArrayInit = 0x19;
|
||||
let kExprI31New = 0x20;
|
||||
let kExprI31GetS = 0x21;
|
||||
let kExprI31GetU = 0x22;
|
||||
@ -982,6 +984,15 @@ class Binary {
|
||||
this.emit_u8(kExprStructNewWithRtt);
|
||||
this.emit_u32v(expr.value);
|
||||
break;
|
||||
case kExprArrayInit:
|
||||
for (let operand of expr.operands) {
|
||||
this.emit_init_expr_recursive(operand);
|
||||
}
|
||||
this.emit_u8(kGCPrefix);
|
||||
this.emit_u8(kExprArrayInit);
|
||||
this.emit_u32v(expr.value);
|
||||
this.emit_u32v(expr.operands.length - 1);
|
||||
break;
|
||||
case kExprRttCanon:
|
||||
this.emit_u8(kGCPrefix);
|
||||
this.emit_u8(kExprRttCanon);
|
||||
@ -992,11 +1003,13 @@ class Binary {
|
||||
this.emit_u8(kGcPrefix);
|
||||
this.emit_u8(kExprRttSub);
|
||||
this.emit_u32v(expr.value);
|
||||
break;
|
||||
case kExprRttFreshSub:
|
||||
this.emit_init_expr_recursive(expr.parent);
|
||||
this.emit_u8(kGcPrefix);
|
||||
this.emit_u8(kExprRttFreshSub);
|
||||
this.emit_u32v(expr.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1129,6 +1142,9 @@ class WasmInitExpr {
|
||||
static StructNewWithRtt(type, args) {
|
||||
return {kind: kExprStructNewWithRtt, value: type, operands: args};
|
||||
}
|
||||
static ArrayInit(type, args) {
|
||||
return {kind: kExprArrayInit, value: type, operands: args};
|
||||
}
|
||||
static RttCanon(type) {
|
||||
return {kind: kExprRttCanon, value: type};
|
||||
}
|
||||
@ -1212,8 +1228,10 @@ class WasmStruct {
|
||||
}
|
||||
|
||||
class WasmArray {
|
||||
constructor(type) {
|
||||
constructor(type, mutability) {
|
||||
this.type = type;
|
||||
if (!mutability) throw new Error("Immutable arrays are not supported yet");
|
||||
this.mutability = mutability;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1339,8 +1357,8 @@ class WasmModuleBuilder {
|
||||
return this.types.length - 1;
|
||||
}
|
||||
|
||||
addArray(type) {
|
||||
this.types.push(new WasmArray(type));
|
||||
addArray(type, mutability) {
|
||||
this.types.push(new WasmArray(type, mutability));
|
||||
return this.types.length - 1;
|
||||
}
|
||||
|
||||
@ -1581,7 +1599,7 @@ class WasmModuleBuilder {
|
||||
} else if (type instanceof WasmArray) {
|
||||
section.emit_u8(kWasmArrayTypeForm);
|
||||
section.emit_type(type.type);
|
||||
section.emit_u8(1); // Only mutable arrays supported currently.
|
||||
section.emit_u8(type.mutability ? 1 : 0);
|
||||
} else {
|
||||
section.emit_u8(kWasmFunctionTypeForm);
|
||||
section.emit_u32v(type.params.length);
|
||||
|
@ -37,6 +37,8 @@ namespace module_decoder_unittest {
|
||||
#define WASM_INIT_EXPR_GLOBAL(index) WASM_GLOBAL_GET(index), kExprEnd
|
||||
#define WASM_INIT_EXPR_STRUCT_NEW(index, ...) \
|
||||
WASM_STRUCT_NEW_WITH_RTT(index, __VA_ARGS__), kExprEnd
|
||||
#define WASM_INIT_EXPR_ARRAY_INIT(index, length, ...) \
|
||||
WASM_ARRAY_INIT(index, length, __VA_ARGS__), kExprEnd
|
||||
#define WASM_INIT_EXPR_RTT_CANON(index) WASM_RTT_CANON(index), kExprEnd
|
||||
|
||||
#define REF_NULL_ELEMENT kExprRefNull, kFuncRefCode, kExprEnd
|
||||
@ -1131,6 +1133,52 @@ TEST_F(WasmModuleVerifyTest, StructNewInitExpr) {
|
||||
"struct.new[1]: expected (rtt 0), found (rtt 0 1) instead");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, ArrayInitInitExpr) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
WASM_FEATURE_SCOPE(gc);
|
||||
WASM_FEATURE_SCOPE(gc_experiments);
|
||||
|
||||
static const byte basic[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(1), // --
|
||||
kRefCode, 0, 0, // type, mutability
|
||||
WASM_INIT_EXPR_ARRAY_INIT(0, 3, WASM_I32V(10), WASM_I32V(20),
|
||||
WASM_I32V(30), WASM_RTT_CANON(0)))};
|
||||
EXPECT_VERIFIES(basic);
|
||||
|
||||
static const byte type_error[] = {
|
||||
SECTION(Type, ENTRY_COUNT(2), // --
|
||||
WASM_ARRAY_DEF(kI32Code, true),
|
||||
WASM_ARRAY_DEF(WASM_SEQ(kRefCode, 0), true)),
|
||||
SECTION(
|
||||
Global, ENTRY_COUNT(1), // --
|
||||
kRefCode, 1, 0, // type, mutability
|
||||
WASM_INIT_EXPR_ARRAY_INIT(0, 1, WASM_I32V(42), WASM_RTT_CANON(0)))};
|
||||
EXPECT_FAILURE_WITH_MSG(
|
||||
type_error,
|
||||
"type error in init expression, expected (ref 1), got (ref 0)");
|
||||
|
||||
static const byte subexpr_type_error[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI64Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(1), // --
|
||||
kRefCode, 0, 0, // type, mutability
|
||||
WASM_INIT_EXPR_ARRAY_INIT(0, 2, WASM_I64V(42), WASM_I32V(142),
|
||||
WASM_RTT_CANON(0)))};
|
||||
EXPECT_FAILURE_WITH_MSG(subexpr_type_error,
|
||||
"array.init[1]: expected i64, found i32 instead");
|
||||
|
||||
static const byte length_error[] = {
|
||||
SECTION(Type, ENTRY_COUNT(1), WASM_ARRAY_DEF(kI16Code, true)),
|
||||
SECTION(Global, ENTRY_COUNT(1), // --
|
||||
kRefCode, 0, 0, // type, mutability
|
||||
WASM_INIT_EXPR_ARRAY_INIT(0, 10, WASM_I32V(10), WASM_I32V(20),
|
||||
WASM_I32V(30), WASM_RTT_CANON(0)))};
|
||||
EXPECT_FAILURE_WITH_MSG(
|
||||
length_error,
|
||||
"not enough arguments on the stack for array.init: expected 11, found 4");
|
||||
}
|
||||
|
||||
TEST_F(WasmModuleVerifyTest, EmptyStruct) {
|
||||
WASM_FEATURE_SCOPE(reftypes);
|
||||
WASM_FEATURE_SCOPE(typed_funcref);
|
||||
|
Loading…
Reference in New Issue
Block a user