mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-18 20:15:05 +00:00
change zig bitcode refcounting to require whether or not an element is refcounted
This also requires zig bitcode to have access to the dec functions for elements. This is needed so that zig will be able to free elements in lists.
This commit is contained in:
parent
070d14a5d6
commit
255cc31ad9
3 changed files with 232 additions and 83 deletions
|
@ -219,6 +219,7 @@ pub fn increfRcPtrC(ptr_to_refcount: *isize, amount: isize) callconv(.C) void {
|
|||
pub fn decrefRcPtrC(
|
||||
bytes_or_null: ?[*]isize,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) void {
|
||||
// IMPORTANT: bytes_or_null is this case is expected to be a pointer to the refcount
|
||||
// (NOT the start of the data, or the start of the allocation)
|
||||
|
@ -226,22 +227,24 @@ pub fn decrefRcPtrC(
|
|||
// this is of course unsafe, but we trust what we get from the llvm side
|
||||
var bytes = @as([*]isize, @ptrCast(bytes_or_null));
|
||||
|
||||
return @call(.always_inline, decref_ptr_to_refcount, .{ bytes, alignment });
|
||||
return @call(.always_inline, decref_ptr_to_refcount, .{ bytes, alignment, elements_refcounted });
|
||||
}
|
||||
|
||||
pub fn decrefCheckNullC(
|
||||
bytes_or_null: ?[*]u8,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) void {
|
||||
if (bytes_or_null) |bytes| {
|
||||
const isizes: [*]isize = @as([*]isize, @ptrCast(@alignCast(bytes)));
|
||||
return @call(.always_inline, decref_ptr_to_refcount, .{ isizes - 1, alignment });
|
||||
return @call(.always_inline, decref_ptr_to_refcount, .{ isizes - 1, alignment, elements_refcounted });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn decrefDataPtrC(
|
||||
bytes_or_null: ?[*]u8,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) void {
|
||||
var bytes = bytes_or_null orelse return;
|
||||
|
||||
|
@ -252,7 +255,7 @@ pub fn decrefDataPtrC(
|
|||
const isizes: [*]isize = @as([*]isize, @ptrFromInt(unmasked_ptr));
|
||||
const rc_ptr = isizes - 1;
|
||||
|
||||
return decrefRcPtrC(rc_ptr, alignment);
|
||||
return decrefRcPtrC(rc_ptr, alignment, elements_refcounted);
|
||||
}
|
||||
|
||||
pub fn increfDataPtrC(
|
||||
|
@ -273,6 +276,7 @@ pub fn increfDataPtrC(
|
|||
pub fn freeDataPtrC(
|
||||
bytes_or_null: ?[*]u8,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) void {
|
||||
var bytes = bytes_or_null orelse return;
|
||||
|
||||
|
@ -283,21 +287,23 @@ pub fn freeDataPtrC(
|
|||
const isizes: [*]isize = @as([*]isize, @ptrFromInt(masked_ptr));
|
||||
|
||||
// we always store the refcount right before the data
|
||||
return freeRcPtrC(isizes - 1, alignment);
|
||||
return freeRcPtrC(isizes - 1, alignment, elements_refcounted);
|
||||
}
|
||||
|
||||
pub fn freeRcPtrC(
|
||||
bytes_or_null: ?[*]isize,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) void {
|
||||
var bytes = bytes_or_null orelse return;
|
||||
return free_ptr_to_refcount(bytes, alignment);
|
||||
return free_ptr_to_refcount(bytes, alignment, elements_refcounted);
|
||||
}
|
||||
|
||||
pub fn decref(
|
||||
bytes_or_null: ?[*]u8,
|
||||
data_bytes: usize,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) void {
|
||||
if (data_bytes == 0) {
|
||||
return;
|
||||
|
@ -307,15 +313,18 @@ pub fn decref(
|
|||
|
||||
const isizes: [*]isize = @as([*]isize, @ptrCast(@alignCast(bytes)));
|
||||
|
||||
decref_ptr_to_refcount(isizes - 1, alignment);
|
||||
decref_ptr_to_refcount(isizes - 1, alignment, elements_refcounted);
|
||||
}
|
||||
|
||||
inline fn free_ptr_to_refcount(
|
||||
refcount_ptr: [*]isize,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) void {
|
||||
if (RC_TYPE == Refcount.none) return;
|
||||
const extra_bytes = @max(alignment, @sizeOf(usize));
|
||||
const ptr_width = @sizeOf(usize);
|
||||
const required_space: usize = if (elements_refcounted) (2 * ptr_width) else ptr_width;
|
||||
const extra_bytes = @max(required_space, alignment);
|
||||
const allocation_ptr = @as([*]u8, @ptrCast(refcount_ptr)) - (extra_bytes - @sizeOf(usize));
|
||||
|
||||
// NOTE: we don't even check whether the refcount is "infinity" here!
|
||||
|
@ -329,6 +338,7 @@ inline fn free_ptr_to_refcount(
|
|||
inline fn decref_ptr_to_refcount(
|
||||
refcount_ptr: [*]isize,
|
||||
alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) void {
|
||||
if (RC_TYPE == Refcount.none) return;
|
||||
|
||||
|
@ -353,13 +363,13 @@ inline fn decref_ptr_to_refcount(
|
|||
}
|
||||
|
||||
if (refcount == REFCOUNT_ONE_ISIZE) {
|
||||
free_ptr_to_refcount(refcount_ptr, alignment);
|
||||
free_ptr_to_refcount(refcount_ptr, alignment, elements_refcounted);
|
||||
}
|
||||
},
|
||||
Refcount.atomic => {
|
||||
var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic);
|
||||
if (last == REFCOUNT_ONE_ISIZE) {
|
||||
free_ptr_to_refcount(refcount_ptr, alignment);
|
||||
free_ptr_to_refcount(refcount_ptr, alignment, elements_refcounted);
|
||||
}
|
||||
},
|
||||
Refcount.none => unreachable,
|
||||
|
@ -438,17 +448,23 @@ pub inline fn calculateCapacity(
|
|||
pub fn allocateWithRefcountC(
|
||||
data_bytes: usize,
|
||||
element_alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) callconv(.C) [*]u8 {
|
||||
return allocateWithRefcount(data_bytes, element_alignment);
|
||||
return allocateWithRefcount(data_bytes, element_alignment, elements_refcounted);
|
||||
}
|
||||
|
||||
pub fn allocateWithRefcount(
|
||||
data_bytes: usize,
|
||||
element_alignment: u32,
|
||||
elements_refcounted: bool,
|
||||
) [*]u8 {
|
||||
// If the element type is refcounted, we need to also allocate space to store the element count on the heap.
|
||||
// This is used so that a seamless slice can de-allocate the underlying list type.
|
||||
const ptr_width = @sizeOf(usize);
|
||||
const alignment = @max(ptr_width, element_alignment);
|
||||
const length = alignment + data_bytes;
|
||||
const required_space: usize = if (elements_refcounted) (2 * ptr_width) else ptr_width;
|
||||
const extra_bytes = @max(required_space, element_alignment);
|
||||
const length = extra_bytes + data_bytes;
|
||||
|
||||
var new_bytes: [*]u8 = alloc(length, alignment) orelse unreachable;
|
||||
|
||||
|
@ -456,7 +472,7 @@ pub fn allocateWithRefcount(
|
|||
std.debug.print("+ allocated {*} ({} bytes with alignment {})\n", .{ new_bytes, data_bytes, alignment });
|
||||
}
|
||||
|
||||
const data_ptr = new_bytes + alignment;
|
||||
const data_ptr = new_bytes + extra_bytes;
|
||||
const refcount_ptr = @as([*]usize, @ptrCast(@as([*]align(ptr_width) u8, @alignCast(data_ptr)) - ptr_width));
|
||||
refcount_ptr[0] = if (RC_TYPE == Refcount.none) REFCOUNT_MAX_ISIZE else REFCOUNT_ONE;
|
||||
|
||||
|
@ -474,11 +490,14 @@ pub fn unsafeReallocate(
|
|||
old_length: usize,
|
||||
new_length: usize,
|
||||
element_width: usize,
|
||||
elements_refcounted: bool,
|
||||
) [*]u8 {
|
||||
const align_width: usize = @max(alignment, @sizeOf(usize));
|
||||
const ptr_width: usize = @sizeOf(usize);
|
||||
const required_space: usize = if (elements_refcounted) (2 * ptr_width) else ptr_width;
|
||||
const extra_bytes = @max(required_space, alignment);
|
||||
|
||||
const old_width = align_width + old_length * element_width;
|
||||
const new_width = align_width + new_length * element_width;
|
||||
const old_width = extra_bytes + old_length * element_width;
|
||||
const new_width = extra_bytes + new_length * element_width;
|
||||
|
||||
if (old_width >= new_width) {
|
||||
return source_ptr;
|
||||
|
@ -486,10 +505,10 @@ pub fn unsafeReallocate(
|
|||
|
||||
// TODO handle out of memory
|
||||
// NOTE realloc will dealloc the original allocation
|
||||
const old_allocation = source_ptr - align_width;
|
||||
const old_allocation = source_ptr - extra_bytes;
|
||||
const new_allocation = realloc(old_allocation, new_width, old_width, alignment);
|
||||
|
||||
const new_source = @as([*]u8, @ptrCast(new_allocation)) + align_width;
|
||||
const new_source = @as([*]u8, @ptrCast(new_allocation)) + extra_bytes;
|
||||
return new_source;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue