Skip to content

Commit

Permalink
FFI accepts arguments and returns values
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaz87 committed Oct 30, 2019
1 parent dad0ab3 commit 7043e45
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 30 deletions.
3 changes: 0 additions & 3 deletions src/aurolib.nim
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,6 @@ template createFunctor (name: string, body: untyped): Module =
template globalFunctor (name: string, body: untyped) =
machine_modules.add(createFunctor(name.replace('.', '\x1f'), body))

proc hash(t: Type): Hash = t.id.hash
proc hash(sig: Signature): Hash = !$(sig.ins.hash !& sig.outs.hash)

let boolT*: Type = newType("bool")
globalModule("auro.bool"):
self["bool"] = boolT
Expand Down
4 changes: 1 addition & 3 deletions src/compile.nim
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ proc getModule (self: State, index: int): Module =
kind: machine.mItem,
m: self.getModule(item.index)
)
else: raise newException(UnsupportedError, "Non function/type items not supported")
#else: raise newException(UnsupportedError, "Non function/type items not supported")
promises[i] = some(result)
return result
return Item(kind: machine.nilItem)
Expand All @@ -112,8 +112,6 @@ proc getModule (self: State, index: int): Module =
let msg = "Module " & data.name & " not found in " & base.name
raise newException(ModuleNotFoundError, msg)
result = item.m
else:
raise newException(UnsupportedError, "Module kind " & $data.kind & " not yet supported")

self.modules[index] = result

Expand Down
107 changes: 89 additions & 18 deletions src/ffi.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ var ffi_modules = initTable[string, Module](32)
var self = SimpleModule("auro\x1fffi", [])

type Type = machine.Type
type FfiType = libffi.Type

template addfn* (
mymod: Module,
Expand All @@ -37,7 +38,10 @@ let ptrT = newType("pointer")

self["pointer"] = ptrT

proc make_type (name: string, base_type: Type) =
var ffi_type_table = initTable[Type, ptr libffi.Type](16)
var base_types_table = initTable[Type, Type](16)

proc make_type (name: string, base_type: Type, ffi_type: ptr FfiType) =
let tp = newType(name)
self[name] = tp

Expand All @@ -47,11 +51,26 @@ proc make_type (name: string, base_type: Type) =
self.addfn(name & "\x1dget", [tp], [base_type]):
discard

for name in ["u8", "u16", "u32", "u64", "i8", "i16", "i32", "i64"]:
make_type(name, intT)
ffi_type_table[tp] = ffi_type
base_types_table[tp] = base_type

let tpps = {
"u8": type_uint8.addr,
"u16": type_uint16.addr,
"u32": type_uint32.addr,
"u64": type_uint64.addr,
"i8": type_sint8.addr,
"i16": type_sint16.addr,
"i32": type_sint32.addr,
"i64": type_sint64.addr,
}

make_type("f32", fltT)
make_type("f64", fltT)
for pair in tpps:
let (name, tpp) = pair
make_type(name, intT, tpp)

make_type("f32", fltT, type_float.addr)
make_type("f64", fltT, type_double.addr)



Expand All @@ -78,10 +97,13 @@ proc import_proc (argument: Module): Module =

result = SimpleModule(basename, [])

proc get_type_ptr (item: Item): ptr libffi.Type =
proc get_type_ptr (item: Item): ptr FfiType =
if item.kind != tItem:
raise newException(Exception, "module argument " & item.name.main & " is not a type")
raise newException(Exception, "get_type_ptr not yet implemented")
if not ffi_type_table.has_key(item.t):
raise newException(Exception, "module argument " & item.name.main & " is not a valid ffi type")
ffi_type_table[item.t]


proc get_builder (argument: Module): Module =
let fnameitem = argument["name"]
Expand All @@ -100,35 +122,84 @@ proc import_proc (argument: Module): Module =
raise newException(Exception, "function " & fname & " not found in " & lib_name)

var cif: Tcif
var params: ParamList

# params has to be allocated manually.
# If handled by the gc, the compiler doesn't know the value is not used
# again after this function, so it gets freed before it's used

let params: ptr ParamList = cast[ptr ParamList](alloc0(sizeof(ParamList)))

var param_count: cuint = 0

var out_type: ptr libffi.Type

var sig_in = newSeq[Type]()
var sig_out = newSeq[Type]()

let out_item = argument["out"]
if out_item.kind == nilItem:
out_type = type_void.addr
else:
out_type = get_type_ptr(out_item)
sig_out.add(out_item.t)


var in_item = argument["in" & $param_count]
while in_item.kind != nilItem:
params[param_count] = get_type_ptr(in_item)
params[][param_count] = get_type_ptr(in_item)

sig_in.add(in_item.t)

param_count += 1
in_item = argument["in" & $param_count]

if cif.prep_cif(DEFAULT_ABI, param_count, out_type, params) != Ok:
if cif.prep_cif(DEFAULT_ABI, param_count, out_type, params[]) != Ok:
raise newException(Exception, "could not prepare function " & libname & "." & fname)


# To call:
# cif.call(proc_sym, out_var.addr, args)

result = SimpleModule(libname & "." & fname, [])
result.addfn("", [], []):
var out_var = 0
var some_args: ArgList
cif.call(proc_sym, out_var.addr, some_args)
result.addfn("", sig_in, sig_out):
var out_value: Value = Value(kind: intV)
var out_addr: pointer

if sig_out.len > 0:
let base_type = base_types_table[sig_out[0]]
if base_type == intT:
out_value = Value(kind: intV)
out_addr = out_value.i.addr
elif base_type == fltT:
out_value = Value(kind: fltV)
out_addr = out_value.f.addr
else:
raise newException(Exception, "Unsupported base type: " & $base_type)

var raw_vals: array[0..20, uint64]
var raw_val: uint64

var ffi_args: ArgList

for i in 0 .. sig_in.high:

template assign (m_t: untyped, m_v: untyped):untyped =
(cast[ptr m_t](raw_val.addr))[] = cast[m_t](m_v)

var val = args[i]
let ffi_type = ffi_type_table[sig_in[i]]

if ffi_type == type_sint8.addr:
assign(int8, val.i)
elif ffi_type == type_sint16.addr:
assign(int16, val.i)
elif ffi_type == type_sint32.addr:
assign(int32, val.i)
elif ffi_type == type_sint64.addr:
assign(int64, val.i)
else:
raise newException(Exception, "Unsupported type: " & $sig_in[i])

ffi_args[i] = raw_val.addr

cif.call(proc_sym, out_addr, ffi_args)
args[0] = out_value

let get_functor = CustomModule(libname & ".get", nil, get_builder)
result.items.add(ModuleItem("get", get_functor))
Expand Down
8 changes: 6 additions & 2 deletions src/machine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ proc `[]`* (m: Module, key: Name): Item =
of customM:
if not m.getter.isNil:
return m.getter(key)
else: discard
return Item(kind: nilItem)
proc `[]`* (m: Module, key: string): Item = m[parseName(key)]

Expand Down Expand Up @@ -412,4 +411,9 @@ proc `==`* (a: Value, b: Value): bool =
of binV: a.bytes == b.bytes
of functionV: a.fn == b.fn
of objV: a.obj == b.obj
of ptrV: a.pt == b.pt
of ptrV: a.pt == b.pt


import hashes
proc hash*(t: Type): Hash = t.id.hash
proc hash*(sig: Signature): Hash = !$(sig.ins.hash !& sig.outs.hash)
16 changes: 13 additions & 3 deletions test/ffi/main.au
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
module ffi = import auro.ffi;
module mylib = (ffi.`import`)({ `0` = mylib_name; });
module foo_mod = (mylib.get)({ name = foo_name; });

void foo () = foo_mod.``;
type i8 = ffi.i8;
i8 to_i8 (int) = ffi.i8$`new`;
int from_i8 (i8) = ffi.i8$get;

module foo_mod = (mylib.get)({
name = foo_name;
in0 = i8;
out = i8;
});

i8 foo (i8) = foo_mod.``;

string mylib_name () { return "./mylib"; }
string foo_name () { return "foo"; }

void main () {
foo();
int n = from_i8(foo(to_i8(42)));
println("This is auro: " + itos(n));
}
7 changes: 6 additions & 1 deletion test/ffi/mylib.c
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
void foo () { printf("This is C"); }
#include <stdio.h>

char foo (char n) {
printf("This is C: %d\n", n);
return n + 10;
}
Binary file modified test/ffi/out
Binary file not shown.

0 comments on commit 7043e45

Please sign in to comment.