Implement memoization of upcall and downcall classes
This commit is contained in:
parent
bd7216a06e
commit
cce6c823f6
2 changed files with 120 additions and 81 deletions
|
|
@ -5,6 +5,9 @@ All notable changes to this project will be documented in this file. This change
|
|||
### Added
|
||||
- New `coffi.mem/null` var for implementing custom types
|
||||
|
||||
### Performance
|
||||
- Upcall and downcall classes have been changed to be memoized, meaning ASM is no longer invoked every time a function is serialized, which should drastically improve performance where functions are serialized in a hot loop
|
||||
|
||||
### Fixed
|
||||
- Usage of deprecated `(Class/STATIC_FIELD)` access pattern
|
||||
|
||||
|
|
|
|||
|
|
@ -130,10 +130,13 @@
|
|||
[:invokevirtual (prim-classes prim-type) (unbox-fn-for-type prim-type) [prim]]]
|
||||
[]))))
|
||||
|
||||
(defn- downcall-class
|
||||
"Class definition for an implementation of [[IFn]] which calls a closed over
|
||||
(defn- downcall-class-ctor*
|
||||
"Returns a function to construct a downcall class for the given `args` and `ret` types.
|
||||
|
||||
A downcall class is an implementation of [[IFn]] which calls a closed over
|
||||
method handle without reflection, unboxing primitives when needed."
|
||||
[args ret]
|
||||
(let [klass (insn/define
|
||||
{:flags #{:public :final}
|
||||
:version 8
|
||||
:super clojure.lang.AFunction
|
||||
|
|
@ -172,11 +175,25 @@
|
|||
(not (mem/primitive-type ret)) (cons SegmentAllocator))]
|
||||
(to-object-asm ret)
|
||||
[:areturn]]}]})
|
||||
ctor (.getConstructor klass
|
||||
(doto ^"[Ljava.lang.Class;" (make-array Class 1)
|
||||
(aset 0 MethodHandle)))]
|
||||
(fn [^MethodHandle h]
|
||||
(.newInstance ctor
|
||||
(doto (object-array 1)
|
||||
(aset 0 h))))))
|
||||
|
||||
(def ^:private downcall-class-ctor
|
||||
"Returns a function to construct a downcall class for the given memoized `args` and `ret` types.
|
||||
|
||||
A downcall class is an implementation of [[IFn]] which calls a closed over
|
||||
method handle without reflection, unboxing primitives when needed."
|
||||
(memoize downcall-class-ctor*))
|
||||
|
||||
(defn- downcall-fn
|
||||
"Creates a function to call `handle` without reflection."
|
||||
[handle args ret]
|
||||
(insn/new-instance (downcall-class args ret) ^MethodHandle handle))
|
||||
((downcall-class-ctor args ret) ^MethodHandle handle))
|
||||
|
||||
(defn ensure-symbol
|
||||
"Returns the argument if it is a [[MemorySegment]], otherwise
|
||||
|
|
@ -462,10 +479,13 @@
|
|||
"Set of primitive types which require 2 indices in the constant pool."
|
||||
#{::mem/double ::mem/long})
|
||||
|
||||
(defn- upcall-class
|
||||
"Constructs a class definition for a class with a single method, `upcall`, which
|
||||
boxes any primitives passed to it and calls a closed over [[IFn]]."
|
||||
(defn- upcall-class-ctor*
|
||||
"Returns a function to construct an upcall class for the given `arg-types` and `ret-types`.
|
||||
|
||||
An upcall class is a class with a single method, `upcall`, which boxes any
|
||||
primitives passed to it and calls a closed over [[IFn]]."
|
||||
[arg-types ret-type]
|
||||
(let [klass (insn/define
|
||||
{:flags #{:public :final}
|
||||
:version 8
|
||||
:fields [{:name "upcall_ifn"
|
||||
|
|
@ -501,11 +521,27 @@
|
|||
[:invokeinterface IFn "invoke" (repeat (inc (count arg-types)) Object)]
|
||||
(to-prim-asm ret-type)
|
||||
[(return-for-type ret-type :areturn)]]}]})
|
||||
ctor (.getConstructor klass
|
||||
(doto ^"[Ljava.lang.Class;" (make-array Class 1)
|
||||
(aset 0 IFn)))]
|
||||
(fn [^IFn f]
|
||||
(.newInstance ctor
|
||||
(doto (object-array 1)
|
||||
(aset 0 f))))))
|
||||
|
||||
(def ^:private upcall-class-ctor
|
||||
"Returns a function to construct an upcall class for the given memoized `arg-types` and `ret-types`.
|
||||
|
||||
An upcall class is a class with a single method, `upcall`, which boxes any
|
||||
primitives passed to it and calls a closed over [[IFn]]."
|
||||
(memoize upcall-class-ctor*))
|
||||
|
||||
(defn- upcall
|
||||
"Constructs an instance of [[upcall-class]], closing over `f`."
|
||||
"Constructs an instance of an upcall class, closing over `f`.
|
||||
|
||||
See [[upcall-class-ctor]]."
|
||||
[f arg-types ret-type]
|
||||
(insn/new-instance (upcall-class arg-types ret-type) ^IFn f))
|
||||
((upcall-class-ctor arg-types ret-type) ^IFn f))
|
||||
|
||||
(defn- method-type
|
||||
"Gets the [[MethodType]] for a set of `args` and `ret` types."
|
||||
|
|
|
|||
Loading…
Reference in a new issue