mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-01 15:51:12 +00:00
Merge branch 'trunk' into update_zig_09
This commit is contained in:
commit
0124e4d4b1
486 changed files with 25920 additions and 11808 deletions
|
@ -750,7 +750,8 @@ pub fn dictWalk(
|
|||
const alignment_u32 = alignment.toU32();
|
||||
// allocate space to write the result of the stepper into
|
||||
// experimentally aliasing the accum and output pointers is not a good idea
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment_u32);
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment_u32) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
|
|
162
compiler/builtins/bitcode/src/expect.zig
Normal file
162
compiler/builtins/bitcode/src/expect.zig
Normal file
|
@ -0,0 +1,162 @@
|
|||
const std = @import("std");
|
||||
const utils = @import("utils.zig");
|
||||
const CSlice = utils.CSlice;
|
||||
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
|
||||
|
||||
const Failure = struct {
|
||||
start_line: u32,
|
||||
end_line: u32,
|
||||
start_col: u16,
|
||||
end_col: u16,
|
||||
};
|
||||
|
||||
// BEGIN FAILURES GLOBALS ///////////////////
|
||||
var failures_mutex = std.Thread.Mutex{};
|
||||
var failures: [*]Failure = undefined;
|
||||
var failure_length: usize = 0;
|
||||
var failure_capacity: usize = 0;
|
||||
// END FAILURES GLOBALS /////////////////////
|
||||
|
||||
pub fn expectFailed(
|
||||
start_line: u32,
|
||||
end_line: u32,
|
||||
start_col: u16,
|
||||
end_col: u16,
|
||||
) void {
|
||||
const new_failure = Failure{ .start_line = start_line, .end_line = end_line, .start_col = start_col, .end_col = end_col };
|
||||
|
||||
// Lock the failures mutex before reading from any of the failures globals,
|
||||
// and then release the lock once we're done modifying things.
|
||||
|
||||
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||
//
|
||||
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||
//
|
||||
// failures_mutex.lock();
|
||||
// defer failures_mutex.release();
|
||||
//
|
||||
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||
const held = failures_mutex.acquire();
|
||||
defer held.release();
|
||||
|
||||
// If we don't have enough capacity to add a failure, allocate a new failures pointer.
|
||||
if (failure_length >= failure_capacity) {
|
||||
if (failure_capacity > 0) {
|
||||
// We already had previous failures allocated, so try to realloc in order
|
||||
// to grow the size in-place without having to memcpy bytes over.
|
||||
const old_pointer = failures;
|
||||
const old_bytes = failure_capacity * @sizeOf(Failure);
|
||||
|
||||
failure_capacity *= 2;
|
||||
|
||||
const new_bytes = failure_capacity * @sizeOf(Failure);
|
||||
const failures_u8 = @ptrCast([*]u8, @alignCast(@alignOf(Failure), failures));
|
||||
const raw_pointer = utils.realloc(failures_u8, new_bytes, old_bytes, @alignOf(Failure));
|
||||
|
||||
failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer));
|
||||
|
||||
// If realloc wasn't able to expand in-place (that is, it returned a different pointer),
|
||||
// then copy the data into the new pointer and dealloc the old one.
|
||||
if (failures != old_pointer) {
|
||||
const old_pointer_u8 = @ptrCast([*]u8, old_pointer);
|
||||
utils.memcpy(@ptrCast([*]u8, failures), old_pointer_u8, old_bytes);
|
||||
utils.dealloc(old_pointer_u8, @alignOf(Failure));
|
||||
}
|
||||
} else {
|
||||
// We've never had any failures before, so allocate the failures for the first time.
|
||||
failure_capacity = 10;
|
||||
|
||||
const raw_pointer = utils.alloc(failure_capacity * @sizeOf(Failure), @alignOf(Failure));
|
||||
|
||||
failures = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_pointer));
|
||||
}
|
||||
}
|
||||
|
||||
failures[failure_length] = new_failure;
|
||||
failure_length += 1;
|
||||
}
|
||||
|
||||
pub fn expectFailedC(
|
||||
start_line: u32,
|
||||
end_line: u32,
|
||||
start_col: u16,
|
||||
end_col: u16,
|
||||
) callconv(.C) void {
|
||||
return @call(.{ .modifier = always_inline }, expectFailed, .{ start_line, end_line, start_col, end_col });
|
||||
}
|
||||
|
||||
pub fn getExpectFailures() []Failure {
|
||||
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||
//
|
||||
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||
//
|
||||
// failures_mutex.lock();
|
||||
// defer failures_mutex.release();
|
||||
//
|
||||
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||
const held = failures_mutex.acquire();
|
||||
defer held.release();
|
||||
|
||||
if (failure_length > 0) {
|
||||
// defensively clone failures, in case someone modifies the originals after the mutex has been released.
|
||||
const num_bytes = failure_length * @sizeOf(Failure);
|
||||
// TODO handle the possibility of alloc failing
|
||||
const raw_clones = utils.alloc(num_bytes, @alignOf(Failure)) orelse unreachable;
|
||||
|
||||
utils.memcpy(raw_clones, @ptrCast([*]u8, failures), num_bytes);
|
||||
|
||||
const clones = @ptrCast([*]Failure, @alignCast(@alignOf(Failure), raw_clones));
|
||||
|
||||
return clones[0..failure_length];
|
||||
} else {
|
||||
return failures[0..0];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getExpectFailuresC() callconv(.C) CSlice {
|
||||
var bytes = @ptrCast(*c_void, failures);
|
||||
|
||||
return .{ .pointer = bytes, .len = failure_length };
|
||||
}
|
||||
|
||||
pub fn deinitFailures() void {
|
||||
// TODO FOR ZIG 0.9: this API changed in https://github.com/ziglang/zig/commit/008b0ec5e58fc7e31f3b989868a7d1ea4df3f41d
|
||||
// to this: https://github.com/ziglang/zig/blob/c710d5eefe3f83226f1651947239730e77af43cb/lib/std/Thread/Mutex.zig
|
||||
//
|
||||
// ...so just use these two lines of code instead of the non-commented-out ones to make this work in Zig 0.9:
|
||||
//
|
||||
// failures_mutex.lock();
|
||||
// defer failures_mutex.release();
|
||||
//
|
||||
// 👆 👆 👆 IF UPGRADING TO ZIG 0.9, LOOK HERE! 👆 👆 👆
|
||||
const held = failures_mutex.acquire();
|
||||
defer held.release();
|
||||
|
||||
utils.dealloc(@ptrCast([*]u8, failures), @alignOf(Failure));
|
||||
failure_length = 0;
|
||||
}
|
||||
|
||||
pub fn deinitFailuresC() callconv(.C) void {
|
||||
return @call(.{ .modifier = always_inline }, deinitFailures, .{});
|
||||
}
|
||||
|
||||
test "expectFailure does something" {
|
||||
defer deinitFailures();
|
||||
|
||||
var fails = getExpectFailures();
|
||||
try std.testing.expectEqual(fails.len, 0);
|
||||
|
||||
expectFailed(1, 2, 3, 4);
|
||||
|
||||
fails = getExpectFailures();
|
||||
try std.testing.expectEqual(fails.len, 1);
|
||||
utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure));
|
||||
|
||||
const what_it_should_look_like = Failure{ .start_line = 1, .end_line = 2, .start_col = 3, .end_col = 4 };
|
||||
|
||||
fails = getExpectFailures();
|
||||
try std.testing.expectEqual(fails[0], what_it_should_look_like);
|
||||
utils.dealloc(@ptrCast([*]u8, fails.ptr), @alignOf([*]Failure));
|
||||
}
|
|
@ -550,7 +550,8 @@ pub fn listKeepResult(
|
|||
var output = RocList.allocate(alignment, list.len(), list.len() * after_width);
|
||||
const target_ptr = output.bytes orelse unreachable;
|
||||
|
||||
var temporary = @ptrCast([*]u8, utils.alloc(result_width, alignment));
|
||||
// TODO handle alloc failing!
|
||||
var temporary = utils.alloc(result_width, alignment) orelse unreachable;
|
||||
|
||||
if (data_is_owned) {
|
||||
inc_n_data(data, size);
|
||||
|
@ -614,7 +615,8 @@ pub fn listWalk(
|
|||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment);
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
|
@ -660,7 +662,8 @@ pub fn listWalkBackwards(
|
|||
inc_n_data(data, list.len());
|
||||
}
|
||||
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment);
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(accum_width, alignment) orelse unreachable;
|
||||
var b1 = output orelse unreachable;
|
||||
var b2 = bytes_ptr;
|
||||
|
||||
|
@ -708,7 +711,8 @@ pub fn listWalkUntil(
|
|||
return;
|
||||
}
|
||||
|
||||
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment);
|
||||
// TODO handle alloc failing!
|
||||
const bytes_ptr: [*]u8 = utils.alloc(continue_stop_width, alignment) orelse unreachable;
|
||||
|
||||
// NOTE: assumes data bytes are the first bytes in a tag
|
||||
@memcpy(bytes_ptr, accum orelse unreachable, accum_width);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const std = @import("std");
|
||||
const math = std.math;
|
||||
const utils = @import("utils.zig");
|
||||
const expect = @import("expect.zig");
|
||||
|
||||
const ROC_BUILTINS = "roc_builtins";
|
||||
const NUM = "num";
|
||||
|
@ -141,12 +142,14 @@ comptime {
|
|||
}
|
||||
|
||||
// Utils
|
||||
|
||||
comptime {
|
||||
exportUtilsFn(utils.test_panic, "test_panic");
|
||||
exportUtilsFn(utils.increfC, "incref");
|
||||
exportUtilsFn(utils.decrefC, "decref");
|
||||
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
|
||||
exportExpectFn(expect.expectFailedC, "expect_failed");
|
||||
exportExpectFn(expect.getExpectFailuresC, "get_expect_failures");
|
||||
exportExpectFn(expect.deinitFailuresC, "deinit_failures");
|
||||
|
||||
@export(utils.panic, .{ .name = "roc_builtins.utils." ++ "panic", .linkage = .Weak });
|
||||
}
|
||||
|
@ -175,6 +178,10 @@ fn exportUtilsFn(comptime func: anytype, comptime func_name: []const u8) void {
|
|||
exportBuiltinFn(func, "utils." ++ func_name);
|
||||
}
|
||||
|
||||
fn exportExpectFn(comptime func: anytype, comptime func_name: []const u8) void {
|
||||
exportBuiltinFn(func, "expect." ++ func_name);
|
||||
}
|
||||
|
||||
// Custom panic function, as builtin Zig version errors during LLVM verification
|
||||
pub fn panic(message: []const u8, stacktrace: ?*std.builtin.StackTrace) noreturn {
|
||||
const builtin = @import("builtin");
|
||||
|
|
|
@ -18,14 +18,18 @@ extern fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void;
|
|||
// Signals to the host that the program has panicked
|
||||
extern fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void;
|
||||
|
||||
// should work just like libc memcpy (we can't assume libc is present)
|
||||
extern fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
|
||||
comptime {
|
||||
const builtin = @import("builtin");
|
||||
// During tetsts, use the testing allocators to satisfy these functions.
|
||||
// During tests, use the testing allocators to satisfy these functions.
|
||||
if (builtin.is_test) {
|
||||
@export(testing_roc_alloc, .{ .name = "roc_alloc", .linkage = .Strong });
|
||||
@export(testing_roc_realloc, .{ .name = "roc_realloc", .linkage = .Strong });
|
||||
@export(testing_roc_dealloc, .{ .name = "roc_dealloc", .linkage = .Strong });
|
||||
@export(testing_roc_panic, .{ .name = "roc_panic", .linkage = .Strong });
|
||||
@export(testing_roc_memcpy, .{ .name = "roc_memcpy", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,8 +57,16 @@ fn testing_roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
|||
@panic("Roc panicked");
|
||||
}
|
||||
|
||||
pub fn alloc(size: usize, alignment: u32) [*]u8 {
|
||||
return @ptrCast([*]u8, @call(.{ .modifier = always_inline }, roc_alloc, .{ size, alignment }));
|
||||
fn testing_roc_memcpy(dest: *c_void, src: *c_void, bytes: usize) callconv(.C) ?*c_void {
|
||||
const zig_dest = @ptrCast([*]u8, dest);
|
||||
const zig_src = @ptrCast([*]u8, src);
|
||||
|
||||
@memcpy(zig_dest, zig_src, bytes);
|
||||
return dest;
|
||||
}
|
||||
|
||||
pub fn alloc(size: usize, alignment: u32) ?[*]u8 {
|
||||
return @ptrCast(?[*]u8, @call(.{ .modifier = always_inline }, roc_alloc, .{ size, alignment }));
|
||||
}
|
||||
|
||||
pub fn realloc(c_ptr: [*]u8, new_size: usize, old_size: usize, alignment: u32) [*]u8 {
|
||||
|
@ -70,6 +82,10 @@ pub fn panic(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
|||
return @call(.{ .modifier = always_inline }, roc_panic, .{ c_ptr, alignment });
|
||||
}
|
||||
|
||||
pub fn memcpy(dst: [*]u8, src: [*]u8, size: usize) void {
|
||||
@call(.{ .modifier = always_inline }, roc_memcpy, .{ dst, src, size });
|
||||
}
|
||||
|
||||
// indirection because otherwise zig creates an alias to the panic function which our LLVM code
|
||||
// does not know how to deal with
|
||||
pub fn test_panic(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||
|
@ -173,7 +189,8 @@ pub fn allocateWithRefcount(
|
|||
|
||||
switch (alignment) {
|
||||
16 => {
|
||||
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment));
|
||||
// TODO handle alloc failing!
|
||||
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment) orelse unreachable);
|
||||
|
||||
var as_usize_array = @ptrCast([*]usize, new_bytes);
|
||||
as_usize_array[0] = 0;
|
||||
|
@ -185,7 +202,8 @@ pub fn allocateWithRefcount(
|
|||
return first_slot;
|
||||
},
|
||||
8 => {
|
||||
var raw = alloc(length, alignment);
|
||||
// TODO handle alloc failing!
|
||||
var raw = alloc(length, alignment) orelse unreachable;
|
||||
var new_bytes: [*]align(8) u8 = @alignCast(8, raw);
|
||||
|
||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||
|
@ -197,7 +215,8 @@ pub fn allocateWithRefcount(
|
|||
return first_slot;
|
||||
},
|
||||
4 => {
|
||||
var raw = alloc(length, alignment);
|
||||
// TODO handle alloc failing!
|
||||
var raw = alloc(length, alignment) orelse unreachable;
|
||||
var new_bytes: [*]align(@alignOf(isize)) u8 = @alignCast(@alignOf(isize), raw);
|
||||
|
||||
var as_isize_array = @ptrCast([*]isize, new_bytes);
|
||||
|
@ -217,6 +236,11 @@ pub fn allocateWithRefcount(
|
|||
}
|
||||
}
|
||||
|
||||
pub const CSlice = extern struct {
|
||||
pointer: *c_void,
|
||||
len: usize,
|
||||
};
|
||||
|
||||
pub fn unsafeReallocate(
|
||||
source_ptr: [*]u8,
|
||||
alignment: u32,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue