From c43bce4768fd752a83b3ab63e83ac211beada0b0 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Mon, 10 Jun 2024 16:33:30 -0700 Subject: [PATCH 01/15] switch to java22 support --- build.clj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.clj b/build.clj index 90919c4..7d00c55 100644 --- a/build.clj +++ b/build.clj @@ -52,8 +52,8 @@ (b/process {:command-args ["javac" "--enable-preview" "src/java/coffi/ffi/Loader.java" "-d" class-dir - "-target" "21" - "-source" "21"]}) + "-target" "22" + "-source" "22"]}) opts) (defn- write-pom From a04fe7253f1b2bd9857b12ff2a23b74addfae157 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Wed, 12 Jun 2024 11:10:52 -0700 Subject: [PATCH 02/15] change String handling to match new FFI API --- src/clj/coffi/mem.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index fab0981..d9e620d 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -1247,15 +1247,15 @@ ::pointer) (defmethod serialize* ::c-string - [obj _type session] + [obj _type ^Arena session] (if obj - (address-of (.allocateUtf8String (arena-allocator session) ^String obj)) + (address-of (.allocateFrom session ^String obj)) (MemorySegment/NULL))) (defmethod deserialize* ::c-string [addr _type] (when-not (null? addr) - (.getUtf8String (.reinterpret ^MemorySegment addr Integer/MAX_VALUE) 0))) + (.getString (.reinterpret ^MemorySegment addr Integer/MAX_VALUE) 0))) ;;; Union types From c740745d49d0c0fba670c5b1d7bc12bfaa73f80c Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Wed, 12 Jun 2024 15:52:44 -0700 Subject: [PATCH 03/15] restructure build.clj functions to not need to accept options and return them, so that they may return useful data relevant to their task --- build.clj | 56 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/build.clj b/build.clj index 7d00c55..af7aee3 100644 --- a/build.clj +++ b/build.clj @@ -36,9 +36,8 @@ (defn clean "Deletes the `target/` directory." - [opts] - (b/delete {:path target-dir}) - opts) + [] + (b/delete {:path target-dir})) (defn- exists? "Checks if a file composed of the given path segments exists." @@ -47,18 +46,17 @@ (defn compile-java "Compiles java classes required for interop." - [opts] + [] (.mkdirs (io/file class-dir)) (b/process {:command-args ["javac" "--enable-preview" "src/java/coffi/ffi/Loader.java" "-d" class-dir "-target" "22" - "-source" "22"]}) - opts) + "-source" "22"]})) (defn- write-pom "Writes a pom file if one does not already exist." - [opts] + [] (when-not (exists? (b/pom-path {:lib lib-coord :class-dir class-dir})) (b/write-pom {:basis basis @@ -72,44 +70,40 @@ :src-dirs source-dirs}) (b/copy-file {:src (b/pom-path {:lib lib-coord :class-dir class-dir}) - :target (str target-dir "pom.xml")})) - opts) + :target (str target-dir "pom.xml")}))) (defn pom "Generates a `pom.xml` file in the `target/classes/META-INF` directory. If `:pom/output-path` is specified, copies the resulting pom file to it." [opts] - (write-pom opts) + (write-pom) (when-some [path (:output-path opts)] (b/copy-file {:src (b/pom-path {:lib lib-coord :class-dir class-dir}) - :target path})) - opts) + :target path}))) (defn- copy-resources "Copies the resources from the [[resource-dirs]] to the [[class-dir]]." - [opts] + [] (b/copy-dir {:target-dir class-dir - :src-dirs resource-dirs}) - opts) + :src-dirs resource-dirs})) (defn jar "Generates a `coffi.jar` file in the `target/` directory. This is a thin jar including only the sources." [opts] (write-pom opts) - (compile-java opts) - (copy-resources opts) + (compile-java) + (copy-resources) (when-not (exists? target-dir jar-file) (b/copy-dir {:target-dir class-dir :src-dirs source-dirs}) (b/jar {:class-dir class-dir - :jar-file jar-file})) - opts) + :jar-file jar-file}))) (defn compile-test-library "Compiles the C test code for running the tests." - [opts] + [] (let [c-files (->> c-test-dirs (map io/file) (mapcat file-seq) @@ -118,8 +112,20 @@ (.mkdirs (io/file target-dir)) (b/process {:command-args (concat ["clang" "-fpic" "-shared"] c-files - ["-o" test-c-library])})) - opts) + ["-o" test-c-library])}))) + +(defn- arities [fn-var] (:arglists (meta fn-var))) +(defn- niladic-only? [fn-var] + (let [ari (arities fn-var) + one-arity? (= 1 (count ari)) + niladic? (= 0 (count (first ari)))] + (and one-arity? niladic?))) +(defn- call-optionally [fn-sym arg] + (let [fn-var (resolve fn-sym)] + (if (niladic-only? fn-var) + (fn-var) + (fn-var arg)))) +(defn- call-optionally-with [arg] #(call-optionally % arg)) (defn run-tasks "Runs a series of tasks with a set of options. @@ -127,8 +133,4 @@ the option keys are passed unmodified." [opts] (binding [*ns* (find-ns 'build)] - (reduce - (fn [opts task] - ((resolve task) opts)) - opts - (:tasks opts)))) + (run! (call-optionally-with opts) (:tasks opts)))) From 4a7659cf2a345aecebc39df82872050b30403bfb Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Mon, 17 Jun 2024 10:57:15 -0700 Subject: [PATCH 04/15] add more upcall tests --- build.clj | 16 ++++++++++++++++ test/c/ffi_test.c | 8 ++++++++ test/clj/coffi/ffi_test.clj | 10 ++++++++++ 3 files changed, 34 insertions(+) diff --git a/build.clj b/build.clj index af7aee3..756cc2d 100644 --- a/build.clj +++ b/build.clj @@ -134,3 +134,19 @@ [opts] (binding [*ns* (find-ns 'build)] (run! (call-optionally-with opts) (:tasks opts)))) + + +(def prep-all ['compile-java 'compile-test-library]) + +(comment + + (compile-java) + + (compile-test-library) + + (run-tasks prep-all) + + (compile-test-library) + +) + diff --git a/test/c/ffi_test.c b/test/c/ffi_test.c index c689e87..d0d4c03 100644 --- a/test/c/ffi_test.c +++ b/test/c/ffi_test.c @@ -26,10 +26,18 @@ CString upcall_test(StringFactory fun) { return fun(); } +int upcall_test2(int (*f)(void)) { + return f(); +} + int counter = 0; static char* responses[] = { "Hello, world!", "Goodbye friend.", "co'oi prenu" }; +char* upcall_test_int_fn_string_ret(int (*f)(void)) { + return responses[f()]; +} + CString get_string1(void) { return responses[counter++ % 3]; } diff --git a/test/clj/coffi/ffi_test.clj b/test/clj/coffi/ffi_test.clj index 15cc4b6..45a724a 100644 --- a/test/clj/coffi/ffi_test.clj +++ b/test/clj/coffi/ffi_test.clj @@ -32,6 +32,16 @@ (fn [] "hello")) "hello"))) +(t/deftest can-make-upcall2 + (t/is (= ((ffi/cfn "upcall_test2" [[::ffi/fn [] ::mem/int]] ::mem/int) + (fn [] 6)) + 5))) + +(t/deftest can-make-upcall-int-fn-string-ret + (t/is (= ((ffi/cfn "upcall_test_int_fn_string_ret" [[::ffi/fn [] ::mem/int]] ::mem/c-string) + (fn [] 2)) + "co'oi prenu"))) + (mem/defalias ::alignment-test (layout/with-c-layout [::mem/struct From 85d52f64b7980839602a5de7de81eeb54a087761 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Wed, 26 Jun 2024 13:22:47 +0200 Subject: [PATCH 05/15] fix upcalls with strings --- deps.edn | 2 +- src/clj/coffi/ffi.clj | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/deps.edn b/deps.edn index d0e1469..a6c2599 100644 --- a/deps.edn +++ b/deps.edn @@ -1,6 +1,6 @@ {:paths ["src/clj" "target/classes" "resources"] :deps {org.clojure/clojure {:mvn/version "1.11.1"} - insn/insn {:mvn/version "0.2.1"}} + insn/insn {:mvn/version "0.5.4"}} :deps/prep-lib {:alias :build :fn build/compile-java diff --git a/src/clj/coffi/ffi.clj b/src/clj/coffi/ffi.clj index bff4e99..730908d 100644 --- a/src/clj/coffi/ffi.clj +++ b/src/clj/coffi/ffi.clj @@ -135,6 +135,7 @@ method handle without reflection, unboxing primitives when needed." [args ret] {:flags #{:public :final} + :version 8 :super clojure.lang.AFunction :fields [{:name "downcall_handle" :type MethodHandle @@ -466,6 +467,7 @@ boxes any primitives passed to it and calls a closed over [[IFn]]." [arg-types ret-type] {:flags #{:public :final} + :version 8 :fields [{:name "upcall_ifn" :type IFn :flags #{:final}}] @@ -497,6 +499,10 @@ inc))) acc)) [:invokeinterface IFn "invoke" (repeat (inc (count arg-types)) Object)] + (if (identical? ::mem/pointer (mem/primitive-type ret-type)) + [[:checkcast Long] + [:invokevirtual Long "longValue" [:long]] + [:invokestatic MemorySegment "ofAddress" [:long MemorySegment] true]]) (to-prim-asm ret-type) [(return-for-type ret-type :areturn)]]}]}) @@ -538,7 +544,6 @@ (defmethod mem/serialize* ::fn [f [_fn arg-types ret-type & {:keys [raw-fn?]}] arena] - (println "Attempting to serialize function of type" (str ret-type "(*)(" (clojure.string/join "," arg-types) ")")) (.upcallStub (Linker/nativeLinker) ^MethodHandle (cond-> f From ef1dcfb6d077daa396beeada3824ee5e7d73911d Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Wed, 26 Jun 2024 15:13:41 +0200 Subject: [PATCH 06/15] fix ill-defined test --- test/clj/coffi/ffi_test.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/clj/coffi/ffi_test.clj b/test/clj/coffi/ffi_test.clj index 45a724a..ac075e4 100644 --- a/test/clj/coffi/ffi_test.clj +++ b/test/clj/coffi/ffi_test.clj @@ -29,12 +29,12 @@ (t/deftest can-make-upcall (t/is (= ((ffi/cfn "upcall_test" [[::ffi/fn [] ::mem/c-string]] ::mem/c-string) - (fn [] "hello")) - "hello"))) + (fn [] "hello from clojure from c from clojure")) + "hello from clojure from c from clojure"))) (t/deftest can-make-upcall2 (t/is (= ((ffi/cfn "upcall_test2" [[::ffi/fn [] ::mem/int]] ::mem/int) - (fn [] 6)) + (fn [] 5)) 5))) (t/deftest can-make-upcall-int-fn-string-ret From 6fc010191492e5622dc7fcbea490235c45b68995 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Thu, 27 Jun 2024 14:40:28 +0200 Subject: [PATCH 07/15] fix build/jar to call write-pom without arguments --- build.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.clj b/build.clj index 756cc2d..a909708 100644 --- a/build.clj +++ b/build.clj @@ -92,7 +92,7 @@ "Generates a `coffi.jar` file in the `target/` directory. This is a thin jar including only the sources." [opts] - (write-pom opts) + (write-pom) (compile-java) (copy-resources) (when-not (exists? target-dir jar-file) From 854914350cd36feb33a222ae4e9f96c82cfe9df0 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Thu, 27 Jun 2024 15:17:14 +0200 Subject: [PATCH 08/15] rename reference to nonexistent MemoryAddress class to MemorySegment --- src/clj/coffi/ffi.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/clj/coffi/ffi.clj b/src/clj/coffi/ffi.clj index 730908d..3d35d01 100644 --- a/src/clj/coffi/ffi.clj +++ b/src/clj/coffi/ffi.clj @@ -292,7 +292,7 @@ ;; cast null pointers to something understood by panama (#{::mem/pointer} type) - `(or ~sym (MemoryAddress/NULL)) + `(or ~sym (MemorySegment/NULL)) (mem/primitive-type type) `(mem/serialize* ~sym ~type-sym ~session) From 56481ea9e3eba2369f83a7d0f43385a433e78822 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Thu, 27 Jun 2024 15:40:42 +0200 Subject: [PATCH 09/15] revert regression as it breaks user code (for now) --- src/clj/coffi/mem.clj | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index d9e620d..71fbd42 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -269,8 +269,6 @@ (.addCloseAction session action) nil) -;; TODO(Joshua): Determine if this needs to exist at all -#_ (defn as-segment "Dereferences an `address` into a memory segment associated with the `session`." (^MemorySegment [^MemoryAddress address size] From b68f8af5494219ef438d61f61f118e35d6265ded Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Thu, 27 Jun 2024 16:07:38 +0200 Subject: [PATCH 10/15] revert build.clj changes --- build.clj | 74 +++++++++++++++++++++---------------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/build.clj b/build.clj index a909708..1830d09 100644 --- a/build.clj +++ b/build.clj @@ -36,8 +36,9 @@ (defn clean "Deletes the `target/` directory." - [] - (b/delete {:path target-dir})) + [opts] + (b/delete {:path target-dir}) + opts) (defn- exists? "Checks if a file composed of the given path segments exists." @@ -46,17 +47,18 @@ (defn compile-java "Compiles java classes required for interop." - [] + [opts] (.mkdirs (io/file class-dir)) (b/process {:command-args ["javac" "--enable-preview" "src/java/coffi/ffi/Loader.java" "-d" class-dir "-target" "22" - "-source" "22"]})) + "-source" "22"]}) + opts) (defn- write-pom "Writes a pom file if one does not already exist." - [] + [opts] (when-not (exists? (b/pom-path {:lib lib-coord :class-dir class-dir})) (b/write-pom {:basis basis @@ -70,40 +72,44 @@ :src-dirs source-dirs}) (b/copy-file {:src (b/pom-path {:lib lib-coord :class-dir class-dir}) - :target (str target-dir "pom.xml")}))) + :target (str target-dir "pom.xml")}) + opts)) (defn pom "Generates a `pom.xml` file in the `target/classes/META-INF` directory. If `:pom/output-path` is specified, copies the resulting pom file to it." [opts] - (write-pom) + (write-pom opts) (when-some [path (:output-path opts)] (b/copy-file {:src (b/pom-path {:lib lib-coord :class-dir class-dir}) - :target path}))) + :target path})) + opts) (defn- copy-resources "Copies the resources from the [[resource-dirs]] to the [[class-dir]]." - [] + [opts] (b/copy-dir {:target-dir class-dir - :src-dirs resource-dirs})) + :src-dirs resource-dirs}) + opts) (defn jar "Generates a `coffi.jar` file in the `target/` directory. This is a thin jar including only the sources." [opts] - (write-pom) - (compile-java) - (copy-resources) + (write-pom opts) + (compile-java opts) + (copy-resources opts) (when-not (exists? target-dir jar-file) (b/copy-dir {:target-dir class-dir :src-dirs source-dirs}) (b/jar {:class-dir class-dir - :jar-file jar-file}))) + :jar-file jar-file})) + opts) (defn compile-test-library "Compiles the C test code for running the tests." - [] + [opts] (let [c-files (->> c-test-dirs (map io/file) (mapcat file-seq) @@ -112,20 +118,8 @@ (.mkdirs (io/file target-dir)) (b/process {:command-args (concat ["clang" "-fpic" "-shared"] c-files - ["-o" test-c-library])}))) - -(defn- arities [fn-var] (:arglists (meta fn-var))) -(defn- niladic-only? [fn-var] - (let [ari (arities fn-var) - one-arity? (= 1 (count ari)) - niladic? (= 0 (count (first ari)))] - (and one-arity? niladic?))) -(defn- call-optionally [fn-sym arg] - (let [fn-var (resolve fn-sym)] - (if (niladic-only? fn-var) - (fn-var) - (fn-var arg)))) -(defn- call-optionally-with [arg] #(call-optionally % arg)) + ["-o" test-c-library])}) + opts)) (defn run-tasks "Runs a series of tasks with a set of options. @@ -133,20 +127,8 @@ the option keys are passed unmodified." [opts] (binding [*ns* (find-ns 'build)] - (run! (call-optionally-with opts) (:tasks opts)))) - - -(def prep-all ['compile-java 'compile-test-library]) - -(comment - - (compile-java) - - (compile-test-library) - - (run-tasks prep-all) - - (compile-test-library) - -) - + (reduce + (fn [opts task] + ((resolve task) opts)) + opts + (:tasks opts)))) From 854d6ce850d15691d9b6f05986cbac3087e7adc3 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Thu, 27 Jun 2024 16:26:22 +0200 Subject: [PATCH 11/15] migrate as-segment to jdk22 API --- src/clj/coffi/mem.clj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index 71fbd42..972b12d 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -271,10 +271,10 @@ (defn as-segment "Dereferences an `address` into a memory segment associated with the `session`." - (^MemorySegment [^MemoryAddress address size] - (MemorySegment/ofAddress address (long size) (connected-session))) - (^MemorySegment [^MemoryAddress address size session] - (MemorySegment/ofAddress address (long size) session))) + (^MemorySegment [^MemorySegment address size] + (.reinterpret (MemorySegment/ofAddress address) (long size) (connected-session) nil)) + (^MemorySegment [^MemorySegment address size session] + (.reinterpret (MemorySegment/ofAddress address) (long size) session nil))) (defn copy-segment "Copies the content to `dest` from `src`. From b37b975b17bf00f3fc02a021ec794d6f1a95b3fa Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Fri, 28 Jun 2024 11:41:24 +0200 Subject: [PATCH 12/15] revert build.clj changes fully --- build.clj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.clj b/build.clj index 1830d09..7d00c55 100644 --- a/build.clj +++ b/build.clj @@ -72,8 +72,8 @@ :src-dirs source-dirs}) (b/copy-file {:src (b/pom-path {:lib lib-coord :class-dir class-dir}) - :target (str target-dir "pom.xml")}) - opts)) + :target (str target-dir "pom.xml")})) + opts) (defn pom "Generates a `pom.xml` file in the `target/classes/META-INF` directory. @@ -118,8 +118,8 @@ (.mkdirs (io/file target-dir)) (b/process {:command-args (concat ["clang" "-fpic" "-shared"] c-files - ["-o" test-c-library])}) - opts)) + ["-o" test-c-library])})) + opts) (defn run-tasks "Runs a series of tasks with a set of options. From 510763f68eed485c1884ea3946038f7c5121db20 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Tue, 23 Jul 2024 15:04:44 +0200 Subject: [PATCH 13/15] add new failing test case --- test/c/ffi_test.c | 42 +++++++++++++++++++++---------------- test/clj/coffi/ffi_test.clj | 9 ++++++++ 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/test/c/ffi_test.c b/test/c/ffi_test.c index d0d4c03..8c98f48 100644 --- a/test/c/ffi_test.c +++ b/test/c/ffi_test.c @@ -39,35 +39,41 @@ char* upcall_test_int_fn_string_ret(int (*f)(void)) { } CString get_string1(void) { - return responses[counter++ % 3]; + return responses[counter++ % 3]; } CString get_string2(void) { - return "Alternate string"; + return "Alternate string"; } StringFactory get_downcall(int whichString) { - switch (whichString % 2) { - case 0: - return get_string1; - case 1: - return get_string2; - default: - return 0; - } + switch (whichString % 2) { + case 0: + return get_string1; + case 1: + return get_string2; + default: + return 0; + } } typedef struct alignment_test { - char a; - double x; - float y; + char a; + double x; + float y; } AlignmentTest; AlignmentTest get_struct() { - AlignmentTest ret = {}; - ret.a = 'x'; - ret.x = 3.14; - ret.y = 42.0; + AlignmentTest ret = {}; + ret.a = 'x'; + ret.x = 3.14; + ret.y = 42.0; - return ret; + return ret; } + +void test_call_with_trailing_string_arg(int a, int b, char* text) { + printf("call of `test_call_with_trailing_string_arg` with a=%i b=%i text='%s'",a,b,text); + return; +} + diff --git a/test/clj/coffi/ffi_test.clj b/test/clj/coffi/ffi_test.clj index ac075e4..45c1930 100644 --- a/test/clj/coffi/ffi_test.clj +++ b/test/clj/coffi/ffi_test.clj @@ -59,3 +59,12 @@ (ffi/freset! (ffi/static-variable "counter" ::mem/int) 1) (t/is (= ((ffi/cfn "get_string1" [] ::mem/c-string)) "Goodbye friend."))) + +(t/deftest can-call-with-trailing-string-arg + (t/is + (= + ((ffi/cfn "test_call_with_trailing_string_arg" + [::mem/int ::mem/int ::mem/c-string] + ::mem/void) + 1 2 "third arg") + ))) From 0bf267e44ad0460f246caae7fdc6589fa4d4d1f4 Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Tue, 23 Jul 2024 15:35:21 +0200 Subject: [PATCH 14/15] add more failing test cases --- test/c/ffi_test.c | 3 ++- test/clj/coffi/ffi_test.clj | 4 ++-- test/clj/coffi/mem_test.clj | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 test/clj/coffi/mem_test.clj diff --git a/test/c/ffi_test.c b/test/c/ffi_test.c index 8c98f48..e38ff30 100644 --- a/test/c/ffi_test.c +++ b/test/c/ffi_test.c @@ -73,7 +73,8 @@ AlignmentTest get_struct() { } void test_call_with_trailing_string_arg(int a, int b, char* text) { - printf("call of `test_call_with_trailing_string_arg` with a=%i b=%i text='%s'",a,b,text); + printf("call of `test_call_with_trailing_string_arg` with a=%i b=%i text='%s'",1,2,text); + printf("\r "); return; } diff --git a/test/clj/coffi/ffi_test.clj b/test/clj/coffi/ffi_test.clj index 45c1930..d45e3ae 100644 --- a/test/clj/coffi/ffi_test.clj +++ b/test/clj/coffi/ffi_test.clj @@ -66,5 +66,5 @@ ((ffi/cfn "test_call_with_trailing_string_arg" [::mem/int ::mem/int ::mem/c-string] ::mem/void) - 1 2 "third arg") - ))) + 1 2 "third arg")))) + diff --git a/test/clj/coffi/mem_test.clj b/test/clj/coffi/mem_test.clj new file mode 100644 index 0000000..b52c1eb --- /dev/null +++ b/test/clj/coffi/mem_test.clj @@ -0,0 +1,32 @@ +(ns coffi.mem-test + (:require + [clojure.test :as t] + [coffi.ffi :as ffi] + [coffi.layout :as layout] + [coffi.mem :as mem]) + (:import + (java.lang.foreign + AddressLayout + Arena + MemoryLayout + MemorySegment + MemorySegment$Scope + SegmentAllocator + ValueLayout + ValueLayout$OfByte + ValueLayout$OfShort + ValueLayout$OfInt + ValueLayout$OfLong + ValueLayout$OfChar + ValueLayout$OfFloat + ValueLayout$OfDouble) + (java.lang.ref Cleaner) + (java.nio ByteOrder))) + +(ffi/load-library "target/ffi_test.so") + +(t/deftest can-serialize-string + (t/is + (instance? MemorySegment (mem/serialize "this is a string" ::mem/c-string)))) + + From 4160b1cb6861225c6b7e0d7ec0f45837a793d9ce Mon Sep 17 00:00:00 2001 From: Kristin Rutenkolk Date: Tue, 23 Jul 2024 15:39:58 +0200 Subject: [PATCH 15/15] consistently serialize strings to MemorySegment instead of addresses (Longs) and remove ad-hoc upcall-class Long to MemorySegment conversion --- src/clj/coffi/ffi.clj | 4 ---- src/clj/coffi/mem.clj | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/clj/coffi/ffi.clj b/src/clj/coffi/ffi.clj index 3d35d01..365fa10 100644 --- a/src/clj/coffi/ffi.clj +++ b/src/clj/coffi/ffi.clj @@ -499,10 +499,6 @@ inc))) acc)) [:invokeinterface IFn "invoke" (repeat (inc (count arg-types)) Object)] - (if (identical? ::mem/pointer (mem/primitive-type ret-type)) - [[:checkcast Long] - [:invokevirtual Long "longValue" [:long]] - [:invokestatic MemorySegment "ofAddress" [:long MemorySegment] true]]) (to-prim-asm ret-type) [(return-for-type ret-type :areturn)]]}]}) diff --git a/src/clj/coffi/mem.clj b/src/clj/coffi/mem.clj index 972b12d..23139c1 100644 --- a/src/clj/coffi/mem.clj +++ b/src/clj/coffi/mem.clj @@ -1247,7 +1247,7 @@ (defmethod serialize* ::c-string [obj _type ^Arena session] (if obj - (address-of (.allocateFrom session ^String obj)) + (.allocateFrom session ^String obj) (MemorySegment/NULL))) (defmethod deserialize* ::c-string