mirror of
https://github.com/janet-lang/janet
synced 2025-01-10 23:50:26 +00:00
Add ffi jit example.
This commit is contained in:
parent
c731f01067
commit
aa60c1f36a
BIN
examples/jitfn/hello.bin
Normal file
BIN
examples/jitfn/hello.bin
Normal file
Binary file not shown.
17
examples/jitfn/hello.nasm
Normal file
17
examples/jitfn/hello.nasm
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
BITS 64
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Code
|
||||||
|
;;;
|
||||||
|
mov rax, 1 ; write(
|
||||||
|
mov rdi, 1 ; STDOUT_FILENO,
|
||||||
|
lea rsi, [rel msg] ; msg,
|
||||||
|
mov rdx, msglen ; sizeof(msg)
|
||||||
|
syscall ; );
|
||||||
|
ret ; return;
|
||||||
|
|
||||||
|
;;;
|
||||||
|
;;; Constants
|
||||||
|
;;;
|
||||||
|
msg: db "Hello, world!", 10
|
||||||
|
msglen: equ $ - msg
|
12
examples/jitfn/jitfn.janet
Normal file
12
examples/jitfn/jitfn.janet
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
###
|
||||||
|
### Relies on NASM being installed to assemble code.
|
||||||
|
### Only works on x86-64 Linux.
|
||||||
|
###
|
||||||
|
### Before running, compile hello.nasm to hello.bin with
|
||||||
|
### $ nasm hello.nasm -o hello.bin
|
||||||
|
|
||||||
|
(def bin (slurp "hello.bin"))
|
||||||
|
(def f (ffi/jitfn bin))
|
||||||
|
(def signature (ffi/signature :default :void))
|
||||||
|
(ffi/call f signature)
|
||||||
|
(print "called a jitted function with FFI!")
|
@ -1280,27 +1280,36 @@ static Janet janet_ffi_win64(JanetFFISignature *signature, void *function_pointe
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Allocate executable memory chunks in sizes of a page. Ideally we would keep
|
||||||
|
* an allocator around so that multiple JIT allocations would point to the same
|
||||||
|
* region but it isn't really worth it. */
|
||||||
|
#define FFI_PAGE_MASK 0xFFF
|
||||||
|
|
||||||
JANET_CORE_FN(cfun_ffi_jitfn,
|
JANET_CORE_FN(cfun_ffi_jitfn,
|
||||||
"(ffi/jitfn bytes)",
|
"(ffi/jitfn bytes)",
|
||||||
"Create an abstract type that can be used as the pointer argument to `ffi/call`. The content "
|
"Create an abstract type that can be used as the pointer argument to `ffi/call`. The content "
|
||||||
"of `bytes` is architecture specific machine code that will be copied into executable memory.") {
|
"of `bytes` is architecture specific machine code that will be copied into executable memory.") {
|
||||||
janet_fixarity(argc, 1);
|
janet_fixarity(argc, 1);
|
||||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||||
|
|
||||||
|
/* Quick hack to align to page boundary, we should query OS. FIXME */
|
||||||
|
size_t alloc_size = ((size_t) bytes.len + FFI_PAGE_MASK) & ~FFI_PAGE_MASK;
|
||||||
|
|
||||||
#ifdef JANET_FFI_JIT
|
#ifdef JANET_FFI_JIT
|
||||||
JanetFFIJittedFn *fn = janet_abstract_threaded(&janet_type_ffijit, sizeof(JanetFFIJittedFn));
|
JanetFFIJittedFn *fn = janet_abstract_threaded(&janet_type_ffijit, sizeof(JanetFFIJittedFn));
|
||||||
fn->function_pointer = NULL;
|
fn->function_pointer = NULL;
|
||||||
fn->size = 0;
|
fn->size = 0;
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
void *ptr = VirtualAlloc(NULL, bytes.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
void *ptr = VirtualAlloc(NULL, alloc_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
#elif defined(MAP_ANONYMOUS)
|
#elif defined(MAP_ANONYMOUS)
|
||||||
void *ptr = mmap(0, bytes.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
void *ptr = mmap(0, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
#elif defined(MAP_ANON)
|
#elif defined(MAP_ANON)
|
||||||
/* macos doesn't have MAP_ANONYMOUS */
|
/* macos doesn't have MAP_ANONYMOUS */
|
||||||
void *ptr = mmap(0, bytes.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
void *ptr = mmap(0, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||||
#else
|
#else
|
||||||
/* -std=c99 gets in the way */
|
/* -std=c99 gets in the way */
|
||||||
/* #define MAP_ANONYMOUS 0x20 should work, though. */
|
/* #define MAP_ANONYMOUS 0x20 should work, though. */
|
||||||
void *ptr = mmap(0, bytes.len, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
|
void *ptr = mmap(0, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
|
||||||
#endif
|
#endif
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
janet_panic("failed to memory map writable memory");
|
janet_panic("failed to memory map writable memory");
|
||||||
@ -1308,16 +1317,16 @@ JANET_CORE_FN(cfun_ffi_jitfn,
|
|||||||
memcpy(ptr, bytes.bytes, bytes.len);
|
memcpy(ptr, bytes.bytes, bytes.len);
|
||||||
#ifdef JANET_WINDOWS
|
#ifdef JANET_WINDOWS
|
||||||
DWORD old = 0;
|
DWORD old = 0;
|
||||||
if (!VirtualProtect(ptr, fn->size, PAGE_EXECUTE_READ, &old)) {
|
if (!VirtualProtect(ptr, alloc_size, PAGE_EXECUTE_READ, &old)) {
|
||||||
janet_panic("failed to make mapped memory executable");
|
janet_panic("failed to make mapped memory executable");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (mprotect(ptr, fn->size, PROT_READ | PROT_EXEC) == -1) {
|
if (mprotect(ptr, alloc_size, PROT_READ | PROT_EXEC) == -1) {
|
||||||
janet_panic("failed to make mapped memory executable");
|
janet_panic("failed to make mapped memory executable");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fn->size = (size_t) bytes.len;
|
fn->size = alloc_size;
|
||||||
fn->function_pointer = (JanetCFunction) ptr;
|
fn->function_pointer = ptr;
|
||||||
return janet_wrap_abstract(fn);
|
return janet_wrap_abstract(fn);
|
||||||
#else
|
#else
|
||||||
janet_panic("ffi/jitfn not available on this platform");
|
janet_panic("ffi/jitfn not available on this platform");
|
||||||
|
Loading…
Reference in New Issue
Block a user