Merge pull request #1686 from rtfeldman/refcounting-cleanup

Refcounting cleanup
This commit is contained in:
Richard Feldman 2021-09-11 13:33:36 -04:00 committed by GitHub
commit 0dd1395331
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 120 additions and 160 deletions

View file

@ -3,15 +3,15 @@ use std::path::Path;
use crate::llvm::bitcode::{call_bitcode_fn, call_void_bitcode_fn};
use crate::llvm::build_dict::{
dict_contains, dict_difference, dict_empty, dict_get, dict_insert, dict_intersection,
self, dict_contains, dict_difference, dict_empty, dict_get, dict_insert, dict_intersection,
dict_keys, dict_len, dict_remove, dict_union, dict_values, dict_walk, set_from_list,
};
use crate::llvm::build_hash::generic_hash;
use crate::llvm::build_list::{
allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat, list_contains,
list_drop, list_get_unsafe, list_join, list_keep_errs, list_keep_if, list_keep_oks, list_len,
list_map, list_map2, list_map3, list_map_with_index, list_prepend, list_range, list_repeat,
list_reverse, list_set, list_single, list_sort_with, list_swap,
self, allocate_list, empty_list, empty_polymorphic_list, list_append, list_concat,
list_contains, list_drop, list_get_unsafe, list_join, list_keep_errs, list_keep_if,
list_keep_oks, list_len, list_map, list_map2, list_map3, list_map_with_index, list_prepend,
list_range, list_repeat, list_reverse, list_set, list_single, list_sort_with, list_swap,
};
use crate::llvm::build_str::{
empty_str, str_concat, str_count_graphemes, str_ends_with, str_from_float, str_from_int,
@ -2305,32 +2305,6 @@ fn list_literal<'a, 'ctx, 'env>(
}
}
fn decrement_with_size_check<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
parent: FunctionValue<'ctx>,
size: IntValue<'ctx>,
layout: Layout<'a>,
refcount_ptr: PointerToRefcount<'ctx>,
) {
let not_empty = env.context.append_basic_block(parent, "not_null");
let done = env.context.append_basic_block(parent, "done");
let is_empty =
env.builder
.build_int_compare(IntPredicate::EQ, size, size.get_type().const_zero(), "");
env.builder
.build_conditional_branch(is_empty, done, not_empty);
env.builder.position_at_end(not_empty);
refcount_ptr.decrement(env, &layout);
env.builder.build_unconditional_branch(done);
env.builder.position_at_end(done);
}
pub fn build_exp_stmt<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
layout_ids: &mut LayoutIds<'a>,
@ -2540,34 +2514,25 @@ pub fn build_exp_stmt<'a, 'ctx, 'env>(
let (value, layout) = load_symbol_and_layout(scope, symbol);
match layout {
Layout::Builtin(Builtin::List(_)) => {
Layout::Builtin(Builtin::List(element_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = element_layout.alignment_bytes(env.ptr_bytes);
// because of how we insert DECREF for lists, we can't guarantee that
// the list is non-empty. When the list is empty, the pointer to the
// elements is NULL, and trying to get to the RC address will
// underflow, causing a segfault. Therefore, in this case we must
// manually check that the list is non-empty
let refcount_ptr = PointerToRefcount::from_list_wrapper(
env,
value.into_struct_value(),
);
let length = list_len(env.builder, value.into_struct_value());
decrement_with_size_check(env, parent, length, *layout, refcount_ptr);
build_list::decref(env, value.into_struct_value(), alignment);
}
Layout::Builtin(Builtin::Dict(_, _)) | Layout::Builtin(Builtin::Set(_)) => {
Layout::Builtin(Builtin::Dict(key_layout, value_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = key_layout
.alignment_bytes(env.ptr_bytes)
.max(value_layout.alignment_bytes(env.ptr_bytes));
let refcount_ptr = PointerToRefcount::from_list_wrapper(
env,
value.into_struct_value(),
);
build_dict::decref(env, value.into_struct_value(), alignment);
}
Layout::Builtin(Builtin::Set(key_layout)) => {
debug_assert!(value.is_struct_value());
let alignment = key_layout.alignment_bytes(env.ptr_bytes);
let length = dict_len(env, scope, *symbol).into_int_value();
decrement_with_size_check(env, parent, length, *layout, refcount_ptr);
build_dict::decref(env, value.into_struct_value(), alignment);
}
_ if layout.is_refcounted() => {