WIP Update coffi.mem to JDK 21
This commit is contained in:
parent
36f1685718
commit
2325abf53b
1 changed files with 103 additions and 72 deletions
|
|
@ -23,11 +23,11 @@
|
||||||
[clojure.spec.alpha :as s])
|
[clojure.spec.alpha :as s])
|
||||||
(:import
|
(:import
|
||||||
(java.lang.foreign
|
(java.lang.foreign
|
||||||
Addressable
|
AddressLayout
|
||||||
MemoryAddress
|
Arena
|
||||||
MemoryLayout
|
MemoryLayout
|
||||||
MemorySegment
|
MemorySegment
|
||||||
MemorySession
|
MemorySegment$Scope
|
||||||
SegmentAllocator
|
SegmentAllocator
|
||||||
ValueLayout
|
ValueLayout
|
||||||
ValueLayout$OfByte
|
ValueLayout$OfByte
|
||||||
|
|
@ -36,50 +36,79 @@
|
||||||
ValueLayout$OfLong
|
ValueLayout$OfLong
|
||||||
ValueLayout$OfChar
|
ValueLayout$OfChar
|
||||||
ValueLayout$OfFloat
|
ValueLayout$OfFloat
|
||||||
ValueLayout$OfDouble
|
ValueLayout$OfDouble)
|
||||||
ValueLayout$OfAddress)
|
|
||||||
(java.lang.ref Cleaner)
|
(java.lang.ref Cleaner)
|
||||||
(java.nio ByteOrder)))
|
(java.nio ByteOrder)))
|
||||||
|
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(defn stack-session
|
(defn confined-arena
|
||||||
|
"Constructs a new arena for use only in this thread.
|
||||||
|
|
||||||
|
The memory allocated within this arena is cheap to allocate, like a native
|
||||||
|
stack.
|
||||||
|
|
||||||
|
The memory allocated within this arena will be cleared once it is closed, so
|
||||||
|
it is usually a good idea to create it in a [[with-open]] clause."
|
||||||
|
(^Arena []
|
||||||
|
(Arena/ofConfined)))
|
||||||
|
|
||||||
|
(defn ^:deprecated stack-session
|
||||||
"Constructs a new session for use only in this thread.
|
"Constructs a new session for use only in this thread.
|
||||||
|
|
||||||
The memory allocated within this session is cheap to allocate, like a native
|
The memory allocated within this session is cheap to allocate, like a native
|
||||||
stack."
|
stack."
|
||||||
(^MemorySession []
|
(^Arena []
|
||||||
(MemorySession/openConfined))
|
(confined-arena))
|
||||||
(^MemorySession [^Cleaner cleaner]
|
(^Arena [^Cleaner cleaner]
|
||||||
(MemorySession/openConfined cleaner)))
|
(assert false "Stack sessions with associated cleaners have been removed.")))
|
||||||
|
|
||||||
(defn ^:deprecated stack-scope
|
(defn ^:deprecated stack-scope
|
||||||
"Constructs a new scope for use only in this thread.
|
"Constructs a new scope for use only in this thread.
|
||||||
|
|
||||||
The memory allocated within this scope is cheap to allocate, like a native
|
The memory allocated within this scope is cheap to allocate, like a native
|
||||||
stack."
|
stack."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(stack-session))
|
(confined-arena))
|
||||||
|
|
||||||
(defn shared-session
|
(defn shared-arena
|
||||||
|
"Constructs a new shared memory arena.
|
||||||
|
|
||||||
|
This arena can be shared across threads and memory allocated in it will only
|
||||||
|
be cleaned up once any thread accessing the arena closes it."
|
||||||
|
(^Arena []
|
||||||
|
(Arena/ofShared)))
|
||||||
|
|
||||||
|
(defn ^:deprecated shared-session
|
||||||
"Constructs a new shared memory session.
|
"Constructs a new shared memory session.
|
||||||
|
|
||||||
This session can be shared across threads and memory allocated in it will only
|
This session can be shared across threads and memory allocated in it will only
|
||||||
be cleaned up once every thread accessing the session closes it."
|
be cleaned up once every thread accessing the session closes it."
|
||||||
(^MemorySession []
|
(^Arena []
|
||||||
(MemorySession/openShared))
|
(shared-arena))
|
||||||
(^MemorySession [^Cleaner cleaner]
|
(^Arena [^Cleaner cleaner]
|
||||||
(MemorySession/openShared cleaner)))
|
(assert false "Shared sessions with associated cleaners have been removed.")))
|
||||||
|
|
||||||
(defn ^:deprecated shared-scope
|
(defn ^:deprecated shared-scope
|
||||||
"Constructs a new shared scope.
|
"Constructs a new shared scope.
|
||||||
|
|
||||||
This scope can be shared across threads and memory allocated in it will only
|
This scope can be shared across threads and memory allocated in it will only
|
||||||
be cleaned up once every thread accessing the scope closes it."
|
be cleaned up once every thread accessing the scope closes it."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(shared-session))
|
(shared-arena))
|
||||||
|
|
||||||
(defn connected-session
|
(defn auto-arena
|
||||||
|
"Constructs a new memory arena that is managed by the garbage collector.
|
||||||
|
|
||||||
|
The arena may be shared across threads, and all resources created with it will
|
||||||
|
be cleaned up at the same time, when all references have been collected.
|
||||||
|
|
||||||
|
This type of arena cannot be closed, and therefore should not be created in
|
||||||
|
a [[with-open]] clause."
|
||||||
|
^Arena []
|
||||||
|
(Arena/ofAuto))
|
||||||
|
|
||||||
|
(defn ^:deprecated connected-session
|
||||||
"Constructs a new memory session to reclaim all connected resources at once.
|
"Constructs a new memory session to reclaim all connected resources at once.
|
||||||
|
|
||||||
The session may be shared across threads, and all resources created with it
|
The session may be shared across threads, and all resources created with it
|
||||||
|
|
@ -87,8 +116,8 @@
|
||||||
|
|
||||||
This type of session cannot be closed, and therefore should not be created in
|
This type of session cannot be closed, and therefore should not be created in
|
||||||
a [[with-open]] clause."
|
a [[with-open]] clause."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(MemorySession/openImplicit))
|
(auto-arena))
|
||||||
|
|
||||||
(defn ^:deprecated connected-scope
|
(defn ^:deprecated connected-scope
|
||||||
"Constructs a new scope to reclaim all connected resources at once.
|
"Constructs a new scope to reclaim all connected resources at once.
|
||||||
|
|
@ -98,18 +127,28 @@
|
||||||
|
|
||||||
This type of scope cannot be closed, and therefore should not be created in
|
This type of scope cannot be closed, and therefore should not be created in
|
||||||
a [[with-open]] clause."
|
a [[with-open]] clause."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(connected-session))
|
(auto-arena))
|
||||||
|
|
||||||
(defn global-session
|
(defn global-arena
|
||||||
|
"Constructs the global arena, which will never reclaim its resources.
|
||||||
|
|
||||||
|
This arena may be shared across threads, but is intended mainly in cases where
|
||||||
|
memory is allocated with [[alloc]] but is either never freed or whose
|
||||||
|
management is relinquished to a native library, such as when returned from a
|
||||||
|
callback."
|
||||||
|
^Arena []
|
||||||
|
(Arena/global))
|
||||||
|
|
||||||
|
(defn ^:deprecated global-session
|
||||||
"Constructs the global session, which will never reclaim its resources.
|
"Constructs the global session, which will never reclaim its resources.
|
||||||
|
|
||||||
This session may be shared across threads, but is intended mainly in cases
|
This session may be shared across threads, but is intended mainly in cases
|
||||||
where memory is allocated with [[alloc]] but is either never freed or whose
|
where memory is allocated with [[alloc]] but is either never freed or whose
|
||||||
management is relinquished to a native library, such as when returned from a
|
management is relinquished to a native library, such as when returned from a
|
||||||
callback."
|
callback."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(MemorySession/global))
|
(global-arena))
|
||||||
|
|
||||||
(defn ^:deprecated global-scope
|
(defn ^:deprecated global-scope
|
||||||
"Constructs the global scope, which will never reclaim its resources.
|
"Constructs the global scope, which will never reclaim its resources.
|
||||||
|
|
@ -118,17 +157,17 @@
|
||||||
memory is allocated with [[alloc]] but is either never freed or whose
|
memory is allocated with [[alloc]] but is either never freed or whose
|
||||||
management is relinquished to a native library, such as when returned from a
|
management is relinquished to a native library, such as when returned from a
|
||||||
callback."
|
callback."
|
||||||
^MemorySession []
|
^Arena []
|
||||||
(global-session))
|
(global-arena))
|
||||||
|
|
||||||
(defn session-allocator
|
(defn ^:deprecated session-allocator
|
||||||
"Constructs a segment allocator from the given `session`.
|
"Constructs a segment allocator from the given `session`.
|
||||||
|
|
||||||
This is primarily used when working with unwrapped downcall functions. When a
|
This is primarily used when working with unwrapped downcall functions. When a
|
||||||
downcall function returns a non-primitive type, it must be provided with an
|
downcall function returns a non-primitive type, it must be provided with an
|
||||||
allocator."
|
allocator."
|
||||||
^SegmentAllocator [^MemorySession session]
|
^SegmentAllocator [^Arena session]
|
||||||
(SegmentAllocator/newNativeArena session))
|
(assert false "Segment allocators can no longer be constructed from sessions."))
|
||||||
|
|
||||||
(defn ^:deprecated scope-allocator
|
(defn ^:deprecated scope-allocator
|
||||||
"Constructs a segment allocator from the given `scope`.
|
"Constructs a segment allocator from the given `scope`.
|
||||||
|
|
@ -136,26 +175,26 @@
|
||||||
This is primarily used when working with unwrapped downcall functions. When a
|
This is primarily used when working with unwrapped downcall functions. When a
|
||||||
downcall function returns a non-primitive type, it must be provided with an
|
downcall function returns a non-primitive type, it must be provided with an
|
||||||
allocator."
|
allocator."
|
||||||
^SegmentAllocator [^MemorySession scope]
|
^SegmentAllocator [^Arena scope]
|
||||||
(session-allocator scope))
|
(assert false "Segment allocators can no longer be constructed from scopes."))
|
||||||
|
|
||||||
(defn segment-session
|
(defn ^:deprecated segment-session
|
||||||
"Gets the memory session used to construct the `segment`."
|
"Gets the memory session used to construct the `segment`."
|
||||||
^MemorySession [segment]
|
^Arena [^MemorySegment segment]
|
||||||
(.session ^MemorySegment segment))
|
(assert false "Segment sessions no longer provide linkes to the arenas that allocated them."))
|
||||||
|
|
||||||
(defn ^:deprecated segment-scope
|
(defn segment-scope
|
||||||
"Gets the scope used to construct the `segment`."
|
"Gets the scope associated with the `segment`."
|
||||||
^MemorySession [segment]
|
^MemorySegment$Scope [segment]
|
||||||
(segment-session segment))
|
(.scope ^MemorySegment segment))
|
||||||
|
|
||||||
(defn alloc
|
(defn alloc
|
||||||
"Allocates `size` bytes.
|
"Allocates `size` bytes.
|
||||||
|
|
||||||
If a `session` is provided, the allocation will be reclaimed when it is closed."
|
If an `arena` is provided, the allocation will be reclaimed when it is closed."
|
||||||
(^MemorySegment [size] (alloc size (connected-session)))
|
(^MemorySegment [size] (alloc size (auto-arena)))
|
||||||
(^MemorySegment [size session] (MemorySegment/allocateNative (long size) ^MemorySession session))
|
(^MemorySegment [size arena] (.allocate ^Arena arena (long size)))
|
||||||
(^MemorySegment [size alignment session] (MemorySegment/allocateNative (long size) (long alignment) ^MemorySession session)))
|
(^MemorySegment [size alignment arena] (.allocate ^Arena arena (long size) (long alignment))))
|
||||||
|
|
||||||
(defn alloc-with
|
(defn alloc-with
|
||||||
"Allocates `size` bytes using the `allocator`."
|
"Allocates `size` bytes using the `allocator`."
|
||||||
|
|
@ -164,7 +203,7 @@
|
||||||
(^MemorySegment [allocator size alignment]
|
(^MemorySegment [allocator size alignment]
|
||||||
(.allocate ^SegmentAllocator allocator (long size) (long alignment))))
|
(.allocate ^SegmentAllocator allocator (long size) (long alignment))))
|
||||||
|
|
||||||
(defmacro with-acquired
|
(defmacro ^:deprecated with-acquired
|
||||||
"Acquires one or more `sessions` until the `body` completes.
|
"Acquires one or more `sessions` until the `body` completes.
|
||||||
|
|
||||||
This is only necessary to do on shared sessions, however if you are operating
|
This is only necessary to do on shared sessions, however if you are operating
|
||||||
|
|
@ -172,17 +211,7 @@
|
||||||
interacts with it wrapped in this."
|
interacts with it wrapped in this."
|
||||||
{:style/indent 1}
|
{:style/indent 1}
|
||||||
[sessions & body]
|
[sessions & body]
|
||||||
(if (seq sessions)
|
(assert false "Support was removed for keeping a shared arena open."))
|
||||||
`(let [session# ~(first sessions)
|
|
||||||
res# (volatile! ::invalid-value)]
|
|
||||||
(.whileAlive
|
|
||||||
^MemorySession session#
|
|
||||||
(^:once fn* []
|
|
||||||
(vreset! res#
|
|
||||||
(with-acquired [~@(rest sessions)]
|
|
||||||
~@body))))
|
|
||||||
@res#)
|
|
||||||
`(do ~@body)))
|
|
||||||
(s/fdef with-acquired
|
(s/fdef with-acquired
|
||||||
:args (s/cat :sessions any?
|
:args (s/cat :sessions any?
|
||||||
:body (s/* any?)))
|
:body (s/* any?)))
|
||||||
|
|
@ -191,20 +220,20 @@
|
||||||
"Gets the address of a given segment.
|
"Gets the address of a given segment.
|
||||||
|
|
||||||
This value can be used as an argument to functions which take a pointer."
|
This value can be used as an argument to functions which take a pointer."
|
||||||
^MemoryAddress [addressable]
|
^long [addressable]
|
||||||
(.address ^Addressable addressable))
|
(.address ^MemorySegment addressable))
|
||||||
|
|
||||||
(defn null?
|
(defn null?
|
||||||
"Checks if a memory address is null."
|
"Checks if a memory address is null."
|
||||||
[addr]
|
[addr]
|
||||||
(or (.equals (MemoryAddress/NULL) addr) (not addr)))
|
(or (.equals (MemorySegment/NULL) addr) (not addr)))
|
||||||
|
|
||||||
(defn address?
|
(defn address?
|
||||||
"Checks if an object is a memory address.
|
"Checks if an object is a memory address.
|
||||||
|
|
||||||
`nil` is considered an address."
|
`nil` is considered an address."
|
||||||
[addr]
|
[addr]
|
||||||
(or (nil? addr) (instance? MemoryAddress addr)))
|
(or (nil? addr) (instance? MemorySegment addr)))
|
||||||
|
|
||||||
(defn slice
|
(defn slice
|
||||||
"Get a slice over the `segment` with the given `offset`."
|
"Get a slice over the `segment` with the given `offset`."
|
||||||
|
|
@ -213,24 +242,28 @@
|
||||||
(^MemorySegment [segment offset size]
|
(^MemorySegment [segment offset size]
|
||||||
(.asSlice ^MemorySegment segment (long offset) (long size))))
|
(.asSlice ^MemorySegment segment (long offset) (long size))))
|
||||||
|
|
||||||
(defn slice-into
|
(defn ^:deprecated slice-into
|
||||||
"Get a slice into the `segment` starting at the `address`."
|
"Get a slice into the `segment` starting at the `address`."
|
||||||
(^MemorySegment [address segment]
|
(^MemorySegment [address segment]
|
||||||
(.asSlice ^MemorySegment segment ^MemoryAddress address))
|
(.asSlice ^MemorySegment segment (address-of address)))
|
||||||
(^MemorySegment [address segment size]
|
(^MemorySegment [address segment size]
|
||||||
(.asSlice ^MemorySegment segment ^MemoryAddress address (long size))))
|
(.asSlice ^MemorySegment segment (address-of address) (long size))))
|
||||||
|
|
||||||
(defn with-offset
|
(defn ^:deprecated with-offset
|
||||||
"Get a new address `offset` from the old `address`."
|
"Get a new address `offset` from the old `address`."
|
||||||
^MemoryAddress [address offset]
|
^MemorySegment [address offset]
|
||||||
(.addOffset ^MemoryAddress address (long offset)))
|
(slice address offset))
|
||||||
|
|
||||||
|
;; TODO(Joshua): Figure out if this can be replicated with [[Cleaner]]
|
||||||
|
#_
|
||||||
(defn add-close-action!
|
(defn add-close-action!
|
||||||
"Adds a 0-arity function to be run when the `session` closes."
|
"Adds a 0-arity function to be run when the `session` closes."
|
||||||
[^MemorySession session ^Runnable action]
|
[^MemorySession session ^Runnable action]
|
||||||
(.addCloseAction session action)
|
(.addCloseAction session action)
|
||||||
nil)
|
nil)
|
||||||
|
|
||||||
|
;; TODO(Joshua): Determine if this needs to exist at all
|
||||||
|
#_
|
||||||
(defn as-segment
|
(defn as-segment
|
||||||
"Dereferences an `address` into a memory segment associated with the `session`."
|
"Dereferences an `address` into a memory segment associated with the `session`."
|
||||||
(^MemorySegment [^MemoryAddress address size]
|
(^MemorySegment [^MemoryAddress address size]
|
||||||
|
|
@ -243,9 +276,7 @@
|
||||||
|
|
||||||
Returns `dest`."
|
Returns `dest`."
|
||||||
^MemorySegment [^MemorySegment dest ^MemorySegment src]
|
^MemorySegment [^MemorySegment dest ^MemorySegment src]
|
||||||
(with-acquired [(segment-session src) (segment-session dest)]
|
(.copyFrom dest src))
|
||||||
(.copyFrom dest src)
|
|
||||||
dest))
|
|
||||||
|
|
||||||
(defn clone-segment
|
(defn clone-segment
|
||||||
"Clones the content of `segment` into a new segment of the same size."
|
"Clones the content of `segment` into a new segment of the same size."
|
||||||
|
|
@ -721,12 +752,12 @@
|
||||||
([segment value]
|
([segment value]
|
||||||
`(let [segment# ~segment
|
`(let [segment# ~segment
|
||||||
value# ~value]
|
value# ~value]
|
||||||
(.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout 0 ^Addressable value#)))
|
(.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout 0 ^MemorySegment value#)))
|
||||||
([segment offset value]
|
([segment offset value]
|
||||||
`(let [segment# ~segment
|
`(let [segment# ~segment
|
||||||
offset# ~offset
|
offset# ~offset
|
||||||
value# ~value]
|
value# ~value]
|
||||||
(.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout offset# ^Addressable value#))))}
|
(.set ^MemorySegment segment# ^ValueLayout$OfAddress pointer-layout offset# ^MemorySegment value#))))}
|
||||||
(^MemoryAddress [^MemorySegment segment ^MemoryAddress value]
|
(^MemoryAddress [^MemorySegment segment ^MemoryAddress value]
|
||||||
(.set segment ^ValueLayout$OfAddress pointer-layout 0 value))
|
(.set segment ^ValueLayout$OfAddress pointer-layout 0 value))
|
||||||
(^MemoryAddress [^MemorySegment segment ^long offset ^MemoryAddress value]
|
(^MemoryAddress [^MemorySegment segment ^long offset ^MemoryAddress value]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue