diff --git a/crates/compiler/gen_wasm/src/backend.rs b/crates/compiler/gen_wasm/src/backend.rs index 2a9d17c6df..d191dda315 100644 --- a/crates/compiler/gen_wasm/src/backend.rs +++ b/crates/compiler/gen_wasm/src/backend.rs @@ -2102,6 +2102,17 @@ impl<'a, 'r> WasmBackend<'a, 'r> { self.register_helper_proc(spec_sym, spec_layout, ProcSource::Helper); } + self.get_existing_refcount_fn_index(proc_symbol, layout, op) + } + + /// return a pointer (table index) to a refcount helper procedure. + /// This allows it to be indirectly called from Zig code + pub fn get_existing_refcount_fn_index( + &mut self, + proc_symbol: Symbol, + layout: InLayout<'a>, + op: HelperOp, + ) -> u32 { let layout_repr = if op.is_indirect() { LayoutRepr::Ptr(layout) } else { diff --git a/crates/compiler/gen_wasm/src/low_level.rs b/crates/compiler/gen_wasm/src/low_level.rs index db5a47b10f..f55d8e76e6 100644 --- a/crates/compiler/gen_wasm/src/low_level.rs +++ b/crates/compiler/gen_wasm/src/low_level.rs @@ -341,6 +341,8 @@ impl<'a> LowLevelCall<'a> { ListDecref => { let input_list: Symbol = self.arguments[0]; + let dec_fn_sym = self.arguments[1]; + let list_layout = backend .layout_interner .get_repr(backend.storage.symbol_layouts[&input_list]); @@ -350,8 +352,12 @@ impl<'a> LowLevelCall<'a> { elem_layout.stack_size_and_alignment(backend.layout_interner); let elem_refcounted = backend.layout_interner.contains_refcounted(elem_in_layout); - let dec_fn_ptr = - build_refcount_element_fn(backend, elem_in_layout, HelperOp::IndirectDec); + let dec_fn = backend.get_existing_refcount_fn_index( + dec_fn_sym, + elem_in_layout, + HelperOp::IndirectDec, + ); + let dec_fn_ptr = backend.get_fn_ptr(dec_fn); // Zig arguments Wasm types // input_list: &RocList i32 @@ -2998,11 +3004,6 @@ fn build_refcount_element_fn<'a>( elem_layout: InLayout<'a>, rc_op: HelperOp, ) -> i32 { - // The refcount function receives a pointer to an element in the list - // This is the same as a Struct containing the element - let in_memory_layout = backend - .layout_interner - .insert_direct_no_semantic(LayoutRepr::Struct(backend.env.arena.alloc([elem_layout]))); - let rc_fn = backend.get_refcount_fn_index(in_memory_layout, rc_op); + let rc_fn = backend.get_refcount_fn_index(elem_layout, rc_op); backend.get_fn_ptr(rc_fn) } diff --git a/crates/compiler/mono/src/code_gen_help/refcount.rs b/crates/compiler/mono/src/code_gen_help/refcount.rs index 420bb95ac4..2f49af553d 100644 --- a/crates/compiler/mono/src/code_gen_help/refcount.rs +++ b/crates/compiler/mono/src/code_gen_help/refcount.rs @@ -196,7 +196,14 @@ pub fn refcount_generic<'a>( rc_return_stmt(root, ident_ids, ctx) } LayoutRepr::Builtin(Builtin::Str) => refcount_str(root, ident_ids, ctx), - LayoutRepr::Builtin(Builtin::List(_)) => refcount_list(root, ident_ids, ctx, structure), + LayoutRepr::Builtin(Builtin::List(element_layout)) => refcount_list( + root, + ident_ids, + ctx, + layout_interner, + element_layout, + structure, + ), LayoutRepr::Struct(field_layouts) => refcount_struct( root, ident_ids, @@ -945,6 +952,8 @@ fn refcount_list<'a>( root: &mut CodeGenHelp<'a>, ident_ids: &mut IdentIds, ctx: &mut Context<'a>, + layout_interner: &mut STLayoutInterner<'a>, + element_layout: InLayout<'a>, _structure: Symbol, ) -> Stmt<'a> { let arena = root.arena; @@ -964,13 +973,19 @@ fn refcount_list<'a>( }) } HelperOp::DecRef(_) | HelperOp::Dec => { - let rc_list_args = refcount_args(root, ctx, list); + let (rc_sym, linker_data) = root.gen_refcount_proc( + ident_ids, + layout_interner, + element_layout, + HelperOp::IndirectDec, + ); + ctx.new_linker_data.extend_from_slice(&linker_data); Expr::Call(Call { call_type: CallType::LowLevel { op: LowLevel::ListDecref, update_mode: UpdateModeId::BACKEND_DUMMY, }, - arguments: rc_list_args, + arguments: root.arena.alloc([list, rc_sym]), }) } _ => unreachable!(),