Skip to content

Commit

Permalink
update to latest api
Browse files Browse the repository at this point in the history
  • Loading branch information
TimWhiting committed Dec 27, 2024
1 parent aa556a4 commit 14cadde
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 72 deletions.
130 changes: 69 additions & 61 deletions lib/std/core/cextern.kk
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ pub alias owned-c<t> = extern-owned<t>
pub alias borrowed-c<s::S,t> = extern-borrowed<t>

// A raw pointer to C memory
pub value struct c-pointer<t>
ptr: intptr_t
pub type c-pointer<t>

// An opaque type to designate c-array types in Koka
pub type c-array<t>
Expand All @@ -27,43 +26,78 @@ pub type c-array<t>
pub alias c-null<t> = c-pointer<t>

// The null pointer in C
pub inline fun cnull(): c-null<t>
C-pointer(0.intptr_t)
pub inline extern cnull(): c-null<t>
c inline "(intptr_t)0"

// A null callback pointer
pub val null-cb = 0.intptr_t

// Needs to be extern otherwise, the compiler will optimize out the function and not keep the reference alive
// Ensure that a reference is > 1 until after this point
pub extern owned/keepalive(^s: owned-c<a>): <> ()
""

// Release a reference (decref an owned reference)
pub fun owned/release(s: owned-c<a>): <> ()
()

// Retain a reference (incref an owned reference)
pub extern owned/retain(s: owned-c<a>): <> ()
""

pub inline extern int/ptr<t>(i: intptr_t): c-pointer<t>
c inline "(intptr_t)#1"

pub inline extern carray/intptr<t>(c: c-array<t>): intptr_t
c inline "#1"

pub inline extern carray/ptr<t>(c: c-array<t>): c-pointer<t>
c inline "#1"

pub inline extern intptr/carray<t>(c: intptr_t): c-array<t>
c inline "#1"

pub inline extern ptr/carray<t>(c: c-pointer<t>): c-array<t>
c inline "#1"

// Allow casting between different types of pointers
pub inline extern unsafe/cptr-cast<s>(c: c-pointer<t>): c-pointer<s>
c inline "#1"

// Allocate `n*size-of` bytes of memory using kk_malloc and return a pointer to the allocated memory
extern int/malloc<t>(n: int32, size-of: int32): intptr_t
inline extern int/malloc<t>(n: int32, size-of: int32): c-pointer<t>
c inline "(kk_addr_t)kk_malloc(#1*#2, kk_context())"

// Allocate `n*size-of` bytes of memory using C's malloc and return a pointer to the allocated memory
extern int/malloc-c<t>(n: int32, size-of: int32): intptr_t
inline extern int/malloc-c<t>(n: int32, size-of: int32): c-pointer<t>
c inline "(kk_addr_t)malloc(#1*#2)"

// Allocate a single element of type `t` using `kk_malloc` and return a managed pointer
// Type `t` should:
// - Be an opaque type in Koka corresponding to a C type (e.g. `pub type cstruct` with no members)
// - Have a `size-of` function that returns the size of the structure in bytes
pub fun single/malloc<t>(?size-of: (c-null<t>) -> int32): owned-c<t>
pub inline fun single/malloc<t>(?size-of: (c-null<t>) -> int32): owned-c<t>
int/malloc(1.int32, size-of(cnull())).c-own-extern

// Allocate `n` elements of type `t` using `kk_malloc` and return a managed pointer to the array
// Type `t` should:
// - Be an opaque type in Koka corresponding to a C type (e.g. `pub type cstruct` with no members)
// - Have a `size-of` function that returns the size of the structure in bytes
pub fun array/malloc<t>(n: int32, ?size-of: (c-null<t>) -> int32): owned-c<c-array<t>>
pub inline fun array/malloc<t>(n: int32, ?size-of: (c-null<t>) -> int32): owned-c<c-array<t>>
int/malloc(n, size-of(cnull())).c-own-extern

// Allocate a single element of type `t` using C's `malloc` and return a managed pointer
// Type `t` should:
// - Be an opaque type in Koka corresponding to a C type (e.g. `pub type cstruct` with no members)
// - Have a `size-of` function that returns the size of the structure in bytes
pub fun single/malloc-c<t>(?size-of: (c-null<t>) -> int32): owned-c<t>
pub inline fun single/malloc-c<t>(?size-of: (c-null<t>) -> int32): owned-c<t>
int/malloc-c(1.int32, size-of(cnull())).c-own-free-calloc-extern

// Allocate `n` elements of type `t` using C's `malloc` and return a managed pointer to the array
// Type `t` should:
// - Be an opaque type in Koka corresponding to a C type (e.g. `pub type cstruct` with no members)
// - Have a `size-of` function that returns the size of the structure in bytes
pub fun array/malloc-c<t>(n: int32, ?size-of: (c-null<t>) -> int32): owned-c<c-array<t>>
pub inline fun array/malloc-c<t>(n: int32, ?size-of: (c-null<t>) -> int32): owned-c<c-array<t>>
int/malloc-c(n, size-of(cnull())).c-own-free-calloc-extern

// !!!WARNING!!! UNSAFE API
Expand All @@ -77,8 +111,8 @@ pub fun array/malloc-c<t>(n: int32, ?size-of: (c-null<t>) -> int32): owned-c<c-a
// Raw `c-pointer<t>` should be used in low-level generated koka ffi functions since the pointer is unknown to be managed or not.
// Conversion routines for `owned-c<t>` and `borrowed-c<s,t>` then should be used to get the raw pointers to be used in the ffi functions
// Higher level apis to c libraries should then provide an interface using `owned-c<t>` and `borrowed-c<s,t>` instead of `c-pointer<t>`
pub fun ptr/unsafe-malloc<t>(n: int32, ?size-of: (c-null<t>) -> int32): c-pointer<t>
C-pointer(int/malloc(n, size-of(cnull())))
pub inline fun ptr/unsafe-malloc<t>(n: int32, ?size-of: (c-null<t>) -> int32): c-pointer<t>
int/malloc(n, size-of(cnull()))

// !!!WARNING!!! UNSAFE API
// Allocate `n` elements of type `t` using C's `malloc` and return a managed pointer to the array
Expand All @@ -91,69 +125,54 @@ pub fun ptr/unsafe-malloc<t>(n: int32, ?size-of: (c-null<t>) -> int32): c-pointe
// Raw `c-pointer<t>` should be used in low-level generated koka ffi functions since the pointer is unknown to be managed or not.
// Conversion routines for `owned-c<t>` and `borrowed-c<s,t>` then should be used to get the raw pointers to be used in the ffi functions
// Higher level apis to c libraries should then provide an interface using `owned-c<t>` and `borrowed-c<s,t>` instead of `c-pointer<t>`
pub fun ptr/unsafe-malloc-c<t>(n: int32, ?size-of: (c-null<t>) -> int32): c-pointer<t>
C-pointer(int/malloc-c(n, size-of(cnull())))
pub inline fun ptr/unsafe-malloc-c<t>(n: int32, ?size-of: (c-null<t>) -> int32): c-pointer<t>
int/malloc-c(n, size-of(cnull()))

// Transform a C ptr into a managed koka value, which will be freed by `kk_free` when koka's reference count reaches 0
extern c-own-extern(c: intptr_t): a
inline extern c-own-extern(c: c-pointer<a>): owned-c<a>
c inline "kk_cptr_raw_box(&kk_free_fun, (void *)#1, kk_context())"

// Transform a C ptr into a managed koka value, which will be freed by C's `free` when koka's reference count reaches 0
extern c-own-free-calloc-extern(c: intptr_t): a
inline extern c-own-free-calloc-extern(c: c-pointer<a>): owned-c<a>
c inline "kk_cptr_raw_box(&kk_free_calloc, (void *)#1, kk_context())"

// Transform a C ptr `c` into a koka value that holds the c reference without freeing it
// The pointer should be valid for the duration of the callback `f`.
extern c-borrow-extern(c: intptr_t, f: b -> e a): e a
inline extern c-borrow(c: c-pointer<t>, f: forall<s> borrowed-c<s,t> -> e a): e a
c "kk_borrow_ptr"

// !!!WARNING!!!: Extremely unsafe API (needed for `c-borrow`), get approval to use anywhere else.
extern unsafe-cast(b: b): a
inline extern unsafe-cast<s>(b: c-pointer<t>): borrowed-c<s,t>
c inline "#1"

// Transform an unmanaged C ptr into a managed koka reference to C memory
// Ensure the pointer is not going to be freed by C code, otherwise use `c-borrow` instead
// Also ensure the memory was allocated using `kk_malloc`
pub fun c-own<t>(t: c-pointer<t>): owned-c<t>
t.ptr.c-own-extern
pub inline fun c-own<t>(t: c-pointer<t>): owned-c<t>
t.c-own-extern

// Transform an unmanaged C ptr into a managed koka reference to C memory
// Ensure the pointer is not going to be freed by C code, otherwise use `c-borrow` instead
// Also ensure the memory was allocated using C's `malloc`
pub fun c-own-free-calloc<t>(t: c-pointer<t>): owned-c<t>
t.ptr.c-own-free-calloc-extern

// Transform an unmanaged C ptr into a borrowed koka reference to C memory
// The pointer must be guaranteed to be valid for the duration of the callback `f`
pub fun c-borrow<t>(c: c-pointer<t>, f: forall<s> borrowed-c<s,t> -> e a): e a
c-borrow-extern(c.ptr, fn(p) f(p.unsafe-cast()))
t.c-own-free-calloc-extern

// Transform a koka `owned-c` managed pointer into a C ptr
// Keeps the koka reference alive during the scope of the callback `f`
extern owned/with-ptr-extern(^t: b, f: intptr_t -> e a): e a
pub inline extern owned/with-ptr(^t: owned-c<t>, f: c-pointer<t> -> e a): e a
c "kk_owned_with_ptr"

// Transform a koka `owned-c` managed pointer into a C ptr
// Keeps the koka reference alive during the scope of the callback `f`
pub fun owned/with-ptr(t: owned-c<t>, f: c-pointer<t> -> e a): e a
owned/with-ptr-extern(t, fn(p) f(C-pointer(p)))

// Transform a koka `borrowed-c` managed pointer into a C ptr
// Keeps the koka reference alive during the scope of the callback `f`
extern borrowed/with-ptr-extern(^t: b, f: intptr_t -> e a): e a
pub inline extern borrowed/with-ptr(^t: borrowed-c<s,t>, f: c-pointer<t> -> e a): e a
c "kk_borrowed_with_ptr"

// Transform a koka `borrowed-c` managed pointer into a C ptr
// Keeps the koka reference alive during the scope of the callback `f`
pub fun borrowed/with-ptr(t: borrowed-c<s,t>, f: c-pointer<t> -> e a): e a
borrowed/with-ptr-extern(t, fn(i) f(C-pointer(i)))

// !!!WARNING!!! Extremely UNSAFE API
// Get the raw C pointer from a `borrowed-c` managed pointer to use immediately in an ffi function
// This doesn't return a typed pointer, and accepts any boxed type as input, so it is very dangerous
// Use `borrowed/with-ptr` most of the time and
// `borrow/use-ffi-ptr` if directly passing to an safe ffi call
pub extern unsafe-borrowed-ffi-ptr-extern<t>(c: b): intptr_t
pub inline extern unsafe-borrowed-ffi-ptr-extern<t>(c: borrowed-c<s,t>): c-pointer<t>
c inline "(kk_addr_t)kk_cptr_unbox_borrowed(#1, kk_context())"

// !!!WARNING!!! UNSAFE API
Expand All @@ -163,46 +182,35 @@ pub extern unsafe-borrowed-ffi-ptr-extern<t>(c: b): intptr_t
// This is due borrowed pointers being guaranteed to be valid during their whole scope (the lambda enclosing the call to this method)
// A similar api for `owned-c` is not possible since converting an owned pointer to a raw pointer could allow the owned pointer to be freed if this was its last use
// For owned pointers use `owned/with-ptr` instead
pub fun borrow/use-ffi-ptr<t>(c: borrowed-c<s,t>): c-pointer<t>
C-pointer(c.unsafe-borrowed-ffi-ptr-extern)
pub inline fun borrow/use-ffi-ptr<t>(c: borrowed-c<s,t>): c-pointer<t>
c.unsafe-borrowed-ffi-ptr-extern

// Transform a koka `owned-c` managed pointer to an array into a C ptr pointing to the element at index `idx` of type `t` and size `size-of(cnull())`
// Keeps the koka reference alive during the scope of the callback `f`
// This is guaranteed due to be this being an external function (`f` is not inlineable), and `t` being borrowed
extern offset/with-ptr(^t: b, idx: ssize_t, f: intptr_t -> e a, size-of: int32): e a
pub inline extern offset/with-ptr(^t: owned-c<c-array<t>>, idx: ssize_t, f: c-pointer<t> -> e a, size-of: int32): e a
c "kk_owned_with_ptr_idx"

// Transform a koka `owned-c` managed pointer to an array into a C ptr pointing to the element at index `idx` of type `t` and size `size-of(cnull())`
// Keeps the koka reference alive during the scope of the callback `f`
pub fun c-array/with-ptr(t: owned-c<c-array<t>>, idx: ssize_t, f: forall<s> borrowed-c<s,t> -> e a, ?size-of: (c-null<t>) -> int32): e a
offset/with-ptr(t, idx, fn(p) c-borrow(C-pointer(p), f), size-of(cnull()))
pub inline fun c-array/with-ptr(t: owned-c<c-array<t>>, idx: ssize_t, f: forall<s> borrowed-c<s,t> -> e a, ?size-of: (c-null<t>) -> int32): e a
offset/with-ptr(t, idx, fn(p) c-borrow(p, f), size-of(cnull()))

// Transform an assumed pointer to a C string into a Koka string
// Copies the memory
extern ptr/to-string(ptr: intptr_t): string
pub inline extern ptr/to-string(ptr: c-pointer<int8>): string
c inline "kk_string_alloc_raw((const char *)#1, false, kk_context())"

// Transform an unmanaged `c-pointer<int8>` into a Koka string
// Copies the memory
pub fun cptr/to-string(c: c-pointer<int8>): string
ptr/to-string(c.ptr)

// Transform an assumed pointer to a C string of length len into a Koka string
// Copies the memory
// Assume the array is non-null terminated and adds the terminating character
extern strlen-ptr/to-string(ptr: intptr_t, len: int64): string
c inline "kk_string_alloc_raw_buff(#2, (const char *)#1, false, kk_context())"

// Transform an unmanaged `c-pointer<int8>` into a Koka string of length len
// Copies the memory
// Assume the array is non-null terminated and adds the terminating character
pub fun cptr-len/to-string(c: c-pointer<int8>, len: int64): string
strlen-ptr/to-string(c.ptr, len)
pub inline extern strlen-ptr/to-string(ptr: c-pointer<int8>, len: int64): string
c inline "kk_string_alloc_raw_buff(#2, (char *)#1, false, kk_context())"

// Borrows the c pointer to a koka managed string for the duration of the callback `f`
extern ptr/with-c-string(^s: string, f: intptr_t -> e a): e a
inline extern ptr/with-c-string(^s: string, f: c-pointer<int8> -> e a): e a
c "kk_with_c_string"

// Borrows the c pointer to a koka managed string for the duration of the callback `f`
pub fun cptr/with-c-string(^s: string, f: forall<s> borrowed-c<s,int8> -> e a): e a
with-c-string(s, fn(p) c-borrow(C-pointer(p), f))
pub inline fun cptr/with-c-string(^s: string, f: forall<s> borrowed-c<s,int8> -> e a): e a
with-c-string(s, fn(p) c-borrow(p, f))
14 changes: 7 additions & 7 deletions lib/std/core/inline/cextern.h
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
// free memory using default C allocator
void kk_free_calloc(void* p, kk_block_t* b, kk_context_t* _ctx) {
static void kk_free_calloc(void* p, kk_block_t* b, kk_context_t* _ctx) {
kk_unused(b);
kk_unused(_ctx);
free(p);
}

kk_box_t kk_owned_with_ptr(kk_box_t owned, kk_function_t f, kk_context_t* _ctx) {
static kk_box_t kk_owned_with_ptr(kk_box_t owned, kk_function_t f, kk_context_t* _ctx) {
kk_addr_t cptr = (kk_addr_t)kk_cptr_raw_unbox_borrowed(owned, kk_context());
return kk_function_call(kk_box_t,(kk_function_t,kk_addr_t,kk_context_t*), f, (f, cptr, kk_context()), kk_context());
}

kk_box_t kk_borrowed_with_ptr(kk_box_t borrowed, kk_function_t f, kk_context_t* _ctx) {
static kk_box_t kk_borrowed_with_ptr(kk_box_t borrowed, kk_function_t f, kk_context_t* _ctx) {
kk_addr_t cptr = (kk_addr_t)kk_cptr_unbox_borrowed(borrowed, kk_context());
return kk_function_call(kk_box_t,(kk_function_t,kk_addr_t,kk_context_t*), f, (f, cptr, kk_context()), kk_context());
}

kk_box_t kk_borrow_ptr(kk_addr_t cptr, kk_function_t f, kk_context_t* _ctx) {
static kk_box_t kk_borrow_ptr(kk_addr_t cptr, kk_function_t f, kk_context_t* _ctx) {
kk_box_t ptr = kk_cptr_box((void *)cptr, kk_context());
return kk_function_call(kk_box_t,(kk_function_t,kk_box_t,kk_context_t*), f, (f, ptr, kk_context()), kk_context());
}

kk_box_t kk_owned_with_ptr_idx(kk_box_t owned, kk_ssize_t idx, kk_function_t f, int32_t size, kk_context_t* _ctx) {
static kk_box_t kk_owned_with_ptr_idx(kk_box_t owned, kk_ssize_t idx, kk_function_t f, int32_t size, kk_context_t* _ctx) {
uint8_t* cptr = (uint8_t*)kk_cptr_raw_unbox_borrowed(owned, kk_context());
kk_addr_t cptr_idx = (kk_addr_t)(cptr + (idx*size));
return kk_function_call(kk_box_t,(kk_function_t,kk_addr_t,kk_context_t*), f, (f, cptr_idx, kk_context()), kk_context());
}

kk_string_t kk_string_alloc_raw_buff(kk_ssize_t len, char* s, bool free, kk_context_t* ctx){
static kk_string_t kk_string_alloc_raw_buff(kk_ssize_t len, char* s, bool free, kk_context_t* ctx){
s[len] = 0;
return kk_string_alloc_raw_len(len, s, free, ctx);
}

kk_box_t kk_with_c_string(kk_string_t s, kk_function_t f, kk_context_t* _ctx){
static kk_box_t kk_with_c_string(kk_string_t s, kk_function_t f, kk_context_t* _ctx){
kk_addr_t cptr = (kk_addr_t)kk_string_cbuf_borrow(s, NULL, kk_context());
return kk_function_call(kk_box_t,(kk_function_t,kk_addr_t,kk_context_t*), f, (f, cptr, kk_context()), kk_context());
}
4 changes: 4 additions & 0 deletions src/Backend/C/FromCore.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1336,6 +1336,10 @@ cTypeCon c
then CPrim "kk_ssize_t"
else if (name == nameTpIntPtrT)
then CPrim "intptr_t"
else if (name == nameTpCPointer)
then CPrim "intptr_t"
else if (name == nameTpCArray)
then CPrim "intptr_t"
else if (name == nameTpFloat)
then CPrim "double"
else if (name == nameTpBool)
Expand Down
4 changes: 3 additions & 1 deletion src/Common/NamePrim.hs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ module Common.NamePrim
, makeTpHandled
, nameTpHandled, nameTpHandled1, nameTpNHandled, nameTpNHandled1
, nameTpMarker
, nameTpExternOwned, nameTpExternBorrowed
, nameTpExternOwned, nameTpExternBorrowed, nameTpCPointer, nameTpCArray
{-
, nameTpOperation, nameYieldOp
, nameTpCps, nameTpYld, nameTpCont
Expand Down Expand Up @@ -404,6 +404,8 @@ nameByref = coreTypesName "@byref"
namePredHeapDiv = coreTypesName "hdiv"
namePredEffDiv = coreTypesName "ediv"

nameTpCPointer = qualify (newModuleName "std/core/cextern") (newName "c-pointer")
nameTpCArray = qualify (newModuleName "std/core/cextern") (newName "c-array")
nameTpExternOwned = coreTypesName "extern-owned"
nameTpExternBorrowed = coreTypesName "extern-borrowed"

Expand Down
6 changes: 3 additions & 3 deletions test/cgen/extern.kk
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ pub alias kstructb<s> = borrowed-c<s,c-struct>;
pub extern size-of(c: c-null<c-struct>): int32
c inline "sizeof(c_struct_t)"

inline extern ptr/xint(s: intptr_t): int32
inline extern ptr/xint(s: c-pointer<c-struct>): int32
c inline "((c_struct_t*)#1)->xint"

inline extern ptr/set-xint(s: intptr_t, x: int32): ()
inline extern ptr/set-xint(s: c-pointer<c-struct>, x: int32): ()
c inline "((c_struct_t*)#1)->xint = #2"

pub fun kstructo(): kstructo
Expand All @@ -33,7 +33,7 @@ pub inline fun kstruct/xint(^s: kstructo): int32
pub inline fun kstructb/xint(^s: kstructb<s>): int32
s.with-ptr(xint)

pub fun set-xintf(x: int32): ((intptr_t) -> ())
pub fun set-xintf(x: int32): ((c-pointer<c-struct>) -> ())
fn(p) set-xint(p, x)

pub inline fun kstruct/set-xint(^s: kstructo, x: int32): ()
Expand Down

0 comments on commit 14cadde

Please sign in to comment.