WIP Update coffi.mem to JDK 21

This commit is contained in:
Joshua Suskalo 2023-12-27 09:14:44 -06:00
parent 36f1685718
commit 2325abf53b
No known key found for this signature in database
GPG key ID: 9B6BA586EFF1B9F0

View file

@ -23,11 +23,11 @@
[clojure.spec.alpha :as s])
(:import
(java.lang.foreign
Addressable
MemoryAddress
AddressLayout
Arena
MemoryLayout
MemorySegment
MemorySession
MemorySegment$Scope
SegmentAllocator
ValueLayout
ValueLayout$OfByte
@ -36,50 +36,79 @@
ValueLayout$OfLong
ValueLayout$OfChar
ValueLayout$OfFloat
ValueLayout$OfDouble
ValueLayout$OfAddress)
ValueLayout$OfDouble)
(java.lang.ref Cleaner)
(java.nio ByteOrder)))
(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.
The memory allocated within this session is cheap to allocate, like a native
stack."
(^MemorySession []
(MemorySession/openConfined))
(^MemorySession [^Cleaner cleaner]
(MemorySession/openConfined cleaner)))
(^Arena []
(confined-arena))
(^Arena [^Cleaner cleaner]
(assert false "Stack sessions with associated cleaners have been removed.")))
(defn ^:deprecated stack-scope
"Constructs a new scope for use only in this thread.
The memory allocated within this scope is cheap to allocate, like a native
stack."
^MemorySession []
(stack-session))
^Arena []
(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.
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."
(^MemorySession []
(MemorySession/openShared))
(^MemorySession [^Cleaner cleaner]
(MemorySession/openShared cleaner)))
(^Arena []
(shared-arena))
(^Arena [^Cleaner cleaner]
(assert false "Shared sessions with associated cleaners have been removed.")))
(defn ^:deprecated shared-scope
"Constructs a new shared scope.
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."
^MemorySession []
(shared-session))
^Arena []
(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.
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
a [[with-open]] clause."
^MemorySession []
(MemorySession/openImplicit))
^Arena []
(auto-arena))
(defn ^:deprecated connected-scope
"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
a [[with-open]] clause."
^MemorySession []
(connected-session))
^Arena []
(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.
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
management is relinquished to a native library, such as when returned from a
callback."
^MemorySession []
(MemorySession/global))
^Arena []
(global-arena))
(defn ^:deprecated global-scope
"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
management is relinquished to a native library, such as when returned from a
callback."
^MemorySession []
(global-session))
^Arena []
(global-arena))
(defn session-allocator
(defn ^:deprecated session-allocator
"Constructs a segment allocator from the given `session`.
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
allocator."
^SegmentAllocator [^MemorySession session]
(SegmentAllocator/newNativeArena session))
^SegmentAllocator [^Arena session]
(assert false "Segment allocators can no longer be constructed from sessions."))
(defn ^:deprecated scope-allocator
"Constructs a segment allocator from the given `scope`.
@ -136,26 +175,26 @@
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
allocator."
^SegmentAllocator [^MemorySession scope]
(session-allocator scope))
^SegmentAllocator [^Arena 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`."
^MemorySession [segment]
(.session ^MemorySegment segment))
^Arena [^MemorySegment segment]
(assert false "Segment sessions no longer provide linkes to the arenas that allocated them."))
(defn ^:deprecated segment-scope
"Gets the scope used to construct the `segment`."
^MemorySession [segment]
(segment-session segment))
(defn segment-scope
"Gets the scope associated with the `segment`."
^MemorySegment$Scope [segment]
(.scope ^MemorySegment segment))
(defn alloc
"Allocates `size` bytes.
If a `session` is provided, the allocation will be reclaimed when it is closed."
(^MemorySegment [size] (alloc size (connected-session)))
(^MemorySegment [size session] (MemorySegment/allocateNative (long size) ^MemorySession session))
(^MemorySegment [size alignment session] (MemorySegment/allocateNative (long size) (long alignment) ^MemorySession session)))
If an `arena` is provided, the allocation will be reclaimed when it is closed."
(^MemorySegment [size] (alloc size (auto-arena)))
(^MemorySegment [size arena] (.allocate ^Arena arena (long size)))
(^MemorySegment [size alignment arena] (.allocate ^Arena arena (long size) (long alignment))))
(defn alloc-with
"Allocates `size` bytes using the `allocator`."
@ -164,7 +203,7 @@
(^MemorySegment [allocator size alignment]
(.allocate ^SegmentAllocator allocator (long size) (long alignment))))
(defmacro with-acquired
(defmacro ^:deprecated with-acquired
"Acquires one or more `sessions` until the `body` completes.
This is only necessary to do on shared sessions, however if you are operating
@ -172,17 +211,7 @@
interacts with it wrapped in this."
{:style/indent 1}
[sessions & body]
(if (seq sessions)
`(let [session# ~(first sessions)
res# (volatile! ::invalid-value)]
(.whileAlive
^MemorySession session#
(^:once fn* []
(vreset! res#
(with-acquired [~@(rest sessions)]
~@body))))
@res#)
`(do ~@body)))
(assert false "Support was removed for keeping a shared arena open."))
(s/fdef with-acquired
:args (s/cat :sessions any?
:body (s/* any?)))
@ -191,20 +220,20 @@
"Gets the address of a given segment.
This value can be used as an argument to functions which take a pointer."
^MemoryAddress [addressable]
(.address ^Addressable addressable))
^long [addressable]
(.address ^MemorySegment addressable))
(defn null?
"Checks if a memory address is null."
[addr]
(or (.equals (MemoryAddress/NULL) addr) (not addr)))
(or (.equals (MemorySegment/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)))
(or (nil? addr) (instance? MemorySegment addr)))
(defn slice
"Get a slice over the `segment` with the given `offset`."
@ -213,24 +242,28 @@
(^MemorySegment [segment offset 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`."
(^MemorySegment [address segment]
(.asSlice ^MemorySegment segment ^MemoryAddress address))
(.asSlice ^MemorySegment segment (address-of address)))
(^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`."
^MemoryAddress [address offset]
(.addOffset ^MemoryAddress address (long offset)))
^MemorySegment [address offset]
(slice address offset))
;; TODO(Joshua): Figure out if this can be replicated with [[Cleaner]]
#_
(defn add-close-action!
"Adds a 0-arity function to be run when the `session` closes."
[^MemorySession session ^Runnable action]
(.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]
@ -243,9 +276,7 @@
Returns `dest`."
^MemorySegment [^MemorySegment dest ^MemorySegment src]
(with-acquired [(segment-session src) (segment-session dest)]
(.copyFrom dest src)
dest))
(.copyFrom dest src))
(defn clone-segment
"Clones the content of `segment` into a new segment of the same size."
@ -721,12 +752,12 @@
([segment value]
`(let [segment# ~segment
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]
`(let [segment# ~segment
offset# ~offset
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]
(.set segment ^ValueLayout$OfAddress pointer-layout 0 value))
(^MemoryAddress [^MemorySegment segment ^long offset ^MemoryAddress value]