mirror of
https://github.com/roc-lang/roc.git
synced 2025-12-23 08:48:03 +00:00
Use copyForward instead of memcpy
This commit is contained in:
parent
79a037cf8d
commit
57ef075f70
3 changed files with 36 additions and 22 deletions
|
|
@ -325,11 +325,13 @@ pub const RocList = extern struct {
|
|||
if (self.isUnique() and !self.isSeamlessSlice()) {
|
||||
const capacity = self.capacity_or_alloc_ptr;
|
||||
if (capacity >= new_length) {
|
||||
return RocList{ .bytes = self.bytes, .length = new_length, .capacity_or_alloc_ptr = capacity };
|
||||
const result = RocList{ .bytes = self.bytes, .length = new_length, .capacity_or_alloc_ptr = capacity };
|
||||
return result;
|
||||
} else {
|
||||
const new_capacity = utils.calculateCapacity(capacity, new_length, element_width);
|
||||
const new_source = utils.unsafeReallocate(source_ptr, alignment, capacity, new_capacity, element_width, elements_refcounted);
|
||||
return RocList{ .bytes = new_source, .length = new_length, .capacity_or_alloc_ptr = new_capacity };
|
||||
const result = RocList{ .bytes = new_source, .length = new_length, .capacity_or_alloc_ptr = new_capacity };
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return self.reallocateFresh(alignment, new_length, element_width, elements_refcounted, inc_context, inc, roc_ops);
|
||||
|
|
@ -1124,7 +1126,11 @@ pub fn listConcat(
|
|||
// These must exist, otherwise, the lists would have been empty.
|
||||
const source_a = resized_list_a.bytes orelse unreachable;
|
||||
const source_b = list_b.bytes orelse unreachable;
|
||||
@memcpy(source_a[(list_a.len() * element_width)..(total_length * element_width)], source_b[0..(list_b.len() * element_width)]);
|
||||
|
||||
// Use std.mem.copyForwards instead of @memcpy to handle potential aliasing
|
||||
const dest_slice = source_a[(list_a.len() * element_width)..(total_length * element_width)];
|
||||
const src_slice = source_b[0..(list_b.len() * element_width)];
|
||||
std.mem.copyForwards(u8, dest_slice, src_slice);
|
||||
|
||||
// Increment refcount of all cloned elements.
|
||||
if (elements_refcounted) {
|
||||
|
|
|
|||
|
|
@ -33,9 +33,10 @@ fn comptimeRocAlloc(alloc_args: *RocAlloc, env: *anyopaque) callconv(.c) void {
|
|||
const evaluator: *ComptimeEvaluator = @ptrCast(@alignCast(env));
|
||||
const align_enum = std.mem.Alignment.fromByteUnits(@as(usize, @intCast(alloc_args.alignment)));
|
||||
|
||||
// Allocate exactly what Roc requested - it already includes any header space it needs
|
||||
const result = evaluator.allocator.rawAlloc(alloc_args.length, align_enum, @returnAddress());
|
||||
const base_ptr = result orelse {
|
||||
// Use C allocator for Roc's allocations to bypass GPA canary checks
|
||||
const c_alloc = std.heap.c_allocator;
|
||||
const allocation = c_alloc.rawAlloc(alloc_args.length, align_enum, @returnAddress());
|
||||
const base_ptr = allocation orelse {
|
||||
const msg = "Out of memory during compile-time evaluation (alloc)";
|
||||
const crashed = RocCrashed{
|
||||
.utf8_bytes = @ptrCast(@constCast(msg.ptr)),
|
||||
|
|
@ -46,13 +47,12 @@ fn comptimeRocAlloc(alloc_args: *RocAlloc, env: *anyopaque) callconv(.c) void {
|
|||
return;
|
||||
};
|
||||
|
||||
// Track this allocation for later dealloc/realloc
|
||||
const ptr_addr = @intFromPtr(base_ptr);
|
||||
evaluator.roc_allocations.put(ptr_addr, alloc_args.length) catch {
|
||||
// If we can't track it, just continue - we'll leak memory but won't crash
|
||||
};
|
||||
|
||||
// Return the allocation start - Roc will manage its own header offsets
|
||||
// Track this allocation
|
||||
evaluator.roc_allocations.put(ptr_addr, alloc_args.length) catch {};
|
||||
|
||||
// Return the allocation start
|
||||
alloc_args.answer = @ptrFromInt(ptr_addr);
|
||||
}
|
||||
|
||||
|
|
@ -62,32 +62,29 @@ fn comptimeRocDealloc(dealloc_args: *RocDealloc, env: *anyopaque) callconv(.c) v
|
|||
const ptr_addr = @intFromPtr(dealloc_args.ptr);
|
||||
|
||||
// Look up the allocation size from our tracking map
|
||||
const size = evaluator.roc_allocations.get(ptr_addr) orelse {
|
||||
// Not found - might be a double-free or pointer we didn't allocate
|
||||
// Just ignore it to avoid crashing
|
||||
return;
|
||||
};
|
||||
const size = evaluator.roc_allocations.get(ptr_addr) orelse return;
|
||||
|
||||
// Remove from tracking map
|
||||
_ = evaluator.roc_allocations.remove(ptr_addr);
|
||||
|
||||
// Free the memory
|
||||
// Free the memory using c_allocator
|
||||
const c_alloc = std.heap.c_allocator;
|
||||
const align_enum = std.mem.Alignment.fromByteUnits(@as(usize, @intCast(dealloc_args.alignment)));
|
||||
const ptr: [*]u8 = @ptrFromInt(ptr_addr);
|
||||
const slice = ptr[0..size];
|
||||
evaluator.allocator.rawFree(slice, align_enum, @returnAddress());
|
||||
c_alloc.rawFree(slice, align_enum, @returnAddress());
|
||||
}
|
||||
|
||||
fn comptimeRocRealloc(realloc_args: *RocRealloc, env: *anyopaque) callconv(.c) void {
|
||||
const evaluator: *ComptimeEvaluator = @ptrCast(@alignCast(env));
|
||||
|
||||
const old_ptr_addr = @intFromPtr(realloc_args.answer);
|
||||
const c_alloc = std.heap.c_allocator;
|
||||
|
||||
// Look up the old allocation size
|
||||
const old_size = evaluator.roc_allocations.get(old_ptr_addr) orelse {
|
||||
// Not found - this shouldn't happen, but if it does, just allocate new memory
|
||||
const align_enum = std.mem.Alignment.fromByteUnits(@as(usize, @intCast(realloc_args.alignment)));
|
||||
const new_ptr = evaluator.allocator.rawAlloc(realloc_args.new_length, align_enum, @returnAddress()) orelse {
|
||||
const new_ptr = c_alloc.rawAlloc(realloc_args.new_length, align_enum, @returnAddress()) orelse {
|
||||
const msg = "Out of memory during compile-time evaluation (realloc)";
|
||||
const crashed = RocCrashed{
|
||||
.utf8_bytes = @ptrCast(@constCast(msg.ptr)),
|
||||
|
|
@ -103,10 +100,10 @@ fn comptimeRocRealloc(realloc_args: *RocRealloc, env: *anyopaque) callconv(.c) v
|
|||
return;
|
||||
};
|
||||
|
||||
// Try to use the allocator's realloc for efficiency
|
||||
// Realloc using c_allocator
|
||||
const old_ptr: [*]u8 = @ptrFromInt(old_ptr_addr);
|
||||
const old_slice = old_ptr[0..old_size];
|
||||
const new_slice = evaluator.allocator.realloc(old_slice, realloc_args.new_length) catch {
|
||||
const new_slice = c_alloc.realloc(old_slice, realloc_args.new_length) catch {
|
||||
const msg = "Out of memory during compile-time evaluation (realloc)";
|
||||
const crashed = RocCrashed{
|
||||
.utf8_bytes = @ptrCast(@constCast(msg.ptr)),
|
||||
|
|
|
|||
|
|
@ -251,6 +251,17 @@ test "e_low_level_lambda - List.concat with two empty lists" {
|
|||
try testing.expectEqual(@as(i128, 0), len_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.first on literal list" {
|
||||
const src =
|
||||
\\x = [10, 20, 30, 40, 50]
|
||||
\\first = List.first(x)
|
||||
;
|
||||
|
||||
const first_value = try evalModuleAndGetString(src, 1, test_allocator);
|
||||
defer test_allocator.free(first_value);
|
||||
try testing.expectEqualStrings("Ok 10", first_value);
|
||||
}
|
||||
|
||||
test "e_low_level_lambda - List.concat preserves order" {
|
||||
const src =
|
||||
\\x = List.concat([10, 20], [30, 40, 50])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue