diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d249e1..a35b1e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,19 @@ # Change Log All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/). +## [0.1.205] +### Added +- An `address?` predicate + +### Fixed +- Compound types caused problems in arglists meta on expansion of `defcfn` +- Compound types were not allowed as return types in `defcfn` +- `nil` was not considered a null pointer +- Primitive-serializing types fail to compile as arguments to downcall handles +- Primitive-serializing types fail to load as arguments to upcall functions +- Void return types on upcalls crash the JVM +- Invalid implementation of serialize-into for primitive types + ## [0.1.192] - 2021-09-30 ### Added - An `::ffi/address` key to wrapper functions' metadata @@ -28,6 +41,7 @@ All notable changes to this project will be documented in this file. This change - Support for serializing and deserializing arbitrary Clojure functions - Support for serializing and deserializing arbitrary Clojure data structures +[0.1.205]: https://github.com/IGJoshua/coffi/compare/v0.1.192...v0.1.205 [0.1.192]: https://github.com/IGJoshua/coffi/compare/v0.1.184...v0.1.192 [0.1.184]: https://github.com/IGJoshua/coffi/compare/v0.1.176...v0.1.184 [0.1.176]: https://github.com/IGJoshua/coffi/compare/v0.1.169...v0.1.176 diff --git a/README.md b/README.md index c5ac49a..49ff808 100644 --- a/README.md +++ b/README.md @@ -17,8 +17,8 @@ This library is available on Clojars. Add one of the following entries to the `:deps` key of your `deps.edn`: ```clojure -org.suskalo/coffi {:mvn/version "0.1.192"} -io.github.IGJoshua/coffi {:git/tag "v0.1.192" :git/sha "9d65f47"} +org.suskalo/coffi {:mvn/version "0.1.205"} +io.github.IGJoshua/coffi {:git/tag "v0.1.205" :git/sha "0149012"} ``` If you use this library as a git dependency, you will need to prepare the diff --git a/src/clj/coffi/ffi.clj b/src/clj/coffi/ffi.clj index 6fa1e32..bfb497f 100644 --- a/src/clj/coffi/ffi.clj +++ b/src/clj/coffi/ffi.clj @@ -108,9 +108,10 @@ (defn- insn-layout "Gets the type keyword or class for referring to the type in bytecode." [type] - (if (some-> (mem/primitive-type type) (not= ::mem/pointer)) - (keyword (name type)) - (mem/java-layout type))) + (when-some [prim (mem/primitive-type type)] + (if (not= prim ::mem/pointer) + (keyword (name prim)) + (mem/java-layout type)))) (def ^:private unbox-fn-for-type "Map from type name to the name of its unboxing function." @@ -320,7 +321,7 @@ [:getfield :this "upcall_ifn" IFn] (map-indexed (fn [idx arg] - [[(load-instructions arg :aload) (inc idx)] + [[(load-instructions (mem/primitive-type arg) :aload) (inc idx)] (to-object-asm arg)]) arg-types) [:invokeinterface IFn "invoke" (repeat (inc (count arg-types)) Object)] @@ -503,7 +504,7 @@ (s/or :string string? :symbol simple-symbol?)) :native-arglist (s/coll-of ::mem/type :kind vector?) - :return-type qualified-keyword? + :return-type ::mem/type :wrapper (s/? (s/cat :native-fn simple-symbol? @@ -581,7 +582,11 @@ (or old-list (seq arglists) (list - (mapv (comp symbol name) + (mapv (fn [type] + (-> (cond-> type + (vector? type) first) + name + symbol)) (:native-arglist args))))))) (assoc (:attr-map args) ::address address))) diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index 69118f6..a237442 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -128,7 +128,14 @@ (defn null? "Checks if a memory address is null." [addr] - (.equals (MemoryAddress/NULL) addr)) + (or (.equals (MemoryAddress/NULL) addr) (not addr))) + +(defn address? + "Checks if an object is a memory address. + + `nil` is considered an address." + [addr] + (or (nil? addr) (instance? MemoryAddress addr))) (defn slice-global "Gets a slice of the global address space. @@ -315,20 +322,22 @@ (defmethod serialize* :default [obj type _scope] (if-let [prim (primitive-type type)] - ((primitive-cast prim) obj) + (when-not (= ::void prim) + ((primitive-cast prim) obj)) (throw (ex-info "Attempted to serialize a non-primitive type with primitive methods" {:type type :object obj})))) (defmethod serialize* ::pointer [obj type scope] - (when-not (null? obj) + (if-not (null? obj) (if (sequential? type) (with-acquired [scope] (let [segment (alloc-instance (second type) scope)] (serialize-into obj (second type) segment scope) (address-of segment))) - obj))) + obj) + (MemoryAddress/NULL))) (defmulti serialize-into "Writes a serialized version of the `obj` to the given `segment`. @@ -352,7 +361,7 @@ (defmethod serialize-into :default [obj type segment scope] (if-some [prim-layout (primitive-type type)] - (with-acquired [(segment-scope scope) scope] + (with-acquired [(segment-scope segment) scope] (serialize-into (serialize* obj type scope) prim-layout segment scope)) (throw (ex-info "Attempted to serialize an object to a type that has not been overriden" {:type type