diff --git a/deps.edn b/deps.edn index 9177419..947628a 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,6 @@ {:paths ["src"] - :deps {org.clojure/clojure {:mvn/version "1.10.3"}} + :deps {org.clojure/clojure {:mvn/version "1.10.3"} + insn/insn {:mvn/version "0.2.1"}} :aliases {:dev {:extra-paths ["."] :extra-deps {io.github.clojure/tools.build {:git/tag "v0.3.0" :git/sha "e418fc9"} diff --git a/src/coffi/ffi.clj b/src/coffi/ffi.clj index 026c2cb..1a9ff6d 100644 --- a/src/coffi/ffi.clj +++ b/src/coffi/ffi.clj @@ -2,7 +2,8 @@ (:refer-clojure :exclude [defstruct]) (:require [clojure.java.io :as io] - [clojure.spec.alpha :as s]) + [clojure.spec.alpha :as s] + [insn.core :as insn]) (:import (java.lang.invoke VarHandle @@ -503,15 +504,52 @@ (find-symbol "strlen") (method-type args-types ret-type) (function-descriptor args-types ret-type)) + invoke (insn/new-instance + {:flags #{:public :final} + :super clojure.lang.AFunction + :fields [{:name "downcall_handle" + :type MethodHandle + :flags #{:final}}] + :methods [{:name :init + :flags #{:public} + :desc [MethodHandle :void] + :emit [[:aload 0] + [:dup] + [:invokespecial :super :init [:void]] + [:aload 1] + [:putfield :this "downcall_handle" MethodHandle] + [:return]]} + {:name :invoke + :flags #{:public} + :desc [Object Object] + :emit [ + ;; load the handle + [:aload 0] + [:getfield :this "downcall_handle" MethodHandle] + ;; load the arguments + [:aload 1] + ;; invokeExact + [:invokevirtual MethodHandle "invokeExact" [MemoryAddress :int]] + ;; convert to object + [:istore 2] + [:new Integer] + [:dup] + [:iload 2] + [:invokespecial Integer :init [:int :void]] + ;; return + [:areturn] + ]}]} + downcall) strlen (fn [str] (with-open [scope (stack-scope)] (let [arg1 (serialize (nth args-types 0) str scope)] - (deserialize* (.invoke downcall arg1) ret-type))))] + (deserialize* (invoke arg1) ret-type)))) + fun strlen] (def ^{:arglists '([str])} strlen "Counts the number of bytes in a C string." - strlen)) + fun)) )