///|
fn gen_valid_descriptor_branches_config() -> GenValidConfig {
let base = gen_valid_array_memory_config()
GenValidConfig::{
..base,
max_type_defs: 3,
max_params: 2,
max_locals: 1,
max_globals: 1,
max_body_statements: 464,
}
}
///|
fn gen_valid_descriptor_branches_module(ctx : GenValidContext) -> Module {
let seed = if ctx.use_named_streams {
ctx.root_seed
} else {
ctx.rnd.next_uint64()
}
let fail_branch = (seed & 1UL) != 0UL
let exact = (seed & 2UL) != 0UL
let nullable = (seed & 4UL) != 0UL
let null_descriptor = (seed & 8UL) != 0UL
let unreachable_source = (seed & 16UL) != 0UL
let refine_local = (seed & 32UL) != 0UL
let nested_target = (seed & 64UL) != 0UL
let object_index = TypeIdx::new(0U)
let descriptor_index = TypeIdx::new(1U)
let source = RefType::new(true, HeapType::new(object_index))
let target = RefType::new(
if refine_local {
!fail_branch
} else {
nullable
},
HeapType::new(object_index),
exact~,
)
let descriptor = RefType::new(true, HeapType::new(descriptor_index), exact~)
let label = LabelIdx::new(if nested_target { 1U } else { 0U })
let branch = if fail_branch {
Instruction::br_on_cast_desc_eq_fail(label, source, target)
} else {
Instruction::br_on_cast_desc_eq(label, source, target)
}
let body = [
if unreachable_source {
Instruction::unreachable_()
} else {
Instruction::local_get(LocalIdx::new(0U))
},
if refine_local {
Instruction::block(
BlockType::val_type(
ValType::ref_type(
RefType::new(false, HeapType::new(descriptor_index), exact~),
),
),
Expr::new([
Instruction::ref_null(HeapType::abs(AbsHeapType::none())),
Instruction::ref_as_non_null(),
]),
)
} else if null_descriptor {
Instruction::ref_null(HeapType::abs(AbsHeapType::none()))
} else {
Instruction::local_get(LocalIdx::new(1U))
},
branch,
]
if refine_local {
body.push(Instruction::local_set(LocalIdx::new(2U)))
body.push(Instruction::unreachable_())
}
let block_type = BlockType::val_type(ValType::ref_type(source))
let increment = fn(amount : Int32) {
[
Instruction::global_get(GlobalIdx::new(0U)),
Instruction::i32_const(I32(amount)),
Instruction::i32_add(),
Instruction::global_set(GlobalIdx::new(0U)),
]
}
let outer_body = if nested_target {
let inner = [Instruction::block(block_type, Expr::new(body))]
inner.append(increment(1))
inner
} else {
body
}
let roots = [Instruction::block(block_type, Expr::new(outer_body))]
if nested_target {
// A wrong label can skip either write. Preserve the reference stack value
// across both updates so label remapping and lifetime capture are exercised.
roots.append(increment(10))
}
let mod_ = Module::new()
.with_type_sec(
TypeSec::new([
RecType::group([
SubType::new(
false,
[],
CompType::struct_([]),
metadata=TypeMetadata::new(descriptor=Some(descriptor_index)),
),
SubType::new(
false,
[],
CompType::struct_([]),
metadata=TypeMetadata::new(describes=Some(object_index)),
),
]),
RecType::new(
SubType::comp_type(
CompType::func(
[ValType::ref_type(source), ValType::ref_type(descriptor)],
[ValType::ref_type(source)],
),
),
),
]),
)
.with_func_sec(FuncSec::new([TypeIdx::new(2U)]))
.with_code_sec(
CodeSec::new([
Func::new(
if refine_local {
Locals::from_types([
ValType::ref_type(
RefType::new(false, HeapType::new(object_index)),
),
])
} else {
Locals::empty()
},
Expr::new(roots),
),
]),
)
.with_export_sec(
ExportSec::new([
Export::new(Name::from_string("run"), ExternIdx::func(FuncIdx::new(0U))),
]),
)
if nested_target {
mod_
.with_global_sec(
GlobalSec::new([
Global::new(
GlobalType::new(ValType::i32(), true),
Expr::new([Instruction::i32_const(I32(0))]),
),
]),
)
.with_export_sec(
ExportSec::new([
Export::new(Name::from_string("run"), ExternIdx::func(FuncIdx::new(0U))),
Export::new(
Name::from_string("branch-effects"),
ExternIdx::global(GlobalIdx::new(0U)),
),
]),
)
} else {
mod_
}
}