From a2d2eefcc323cdde64e8b67324ad5e51812ba8eb Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 2 May 2025 21:05:24 +0800 Subject: [PATCH 1/2] Frame use record, use lambda replace CleanupAction --- .../jdk/internal/foreign/BufferStack.java | 105 ++++++++---------- 1 file changed, 44 insertions(+), 61 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java index dbf21601c53ac..a807c21ad8288 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java +++ b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java @@ -103,8 +103,9 @@ public String toString() { private record PerThread(ReentrantLock lock, Arena arena, SlicingAllocator stack, - CleanupAction cleanupAction) { + Consumer cleanupAction) { + @SuppressWarnings("restricted") @ForceInline public Arena pushFrame(long size, long byteAlignment) { boolean needsLock = Thread.currentThread().isVirtual() && !lock.isHeldByCurrentThread(); @@ -116,7 +117,16 @@ public Arena pushFrame(long size, long byteAlignment) { if (needsLock) lock.unlock(); return Arena.ofConfined(); } - return new Frame(needsLock, size, byteAlignment); + + long parentOffset = stack.currentOffset(); + final MemorySegment frameSegment = stack.allocate(size, byteAlignment); + long topOfStack = stack.currentOffset(); + Arena confinedArena = Arena.ofConfined(); + // return new Frame(needsLock, size, byte + // The cleanup action will keep the original automatic `arena` (from which + // the reusable segment is first allocated) alive even if this Frame + // becomes unreachable but there are reachable segments still alive. + return new Frame(this, needsLock, parentOffset, topOfStack, confinedArena, new SlicingAllocator(frameSegment.reinterpret(confinedArena, cleanupAction))); } static PerThread of(long byteSize, long byteAlignment) { @@ -124,71 +134,44 @@ static PerThread of(long byteSize, long byteAlignment) { return new PerThread(new ReentrantLock(), arena, new SlicingAllocator(arena.allocate(byteSize, byteAlignment)), - new CleanupAction(arena)); - } - - private record CleanupAction(Arena arena) implements Consumer { - @Override - public void accept(MemorySegment memorySegment) { - Reference.reachabilityFence(arena); - } + (MemorySegment _) -> Reference.reachabilityFence(arena)); } + } - private final class Frame implements Arena { - - private final boolean locked; - private final long parentOffset; - private final long topOfStack; - private final Arena confinedArena; - private final SegmentAllocator frame; - - @SuppressWarnings("restricted") - @ForceInline - public Frame(boolean locked, long byteSize, long byteAlignment) { - this.locked = locked; - this.parentOffset = stack.currentOffset(); - final MemorySegment frameSegment = stack.allocate(byteSize, byteAlignment); - this.topOfStack = stack.currentOffset(); - this.confinedArena = Arena.ofConfined(); - // The cleanup action will keep the original automatic `arena` (from which - // the reusable segment is first allocated) alive even if this Frame - // becomes unreachable but there are reachable segments still alive. - this.frame = new SlicingAllocator(frameSegment.reinterpret(confinedArena, cleanupAction)); - } + private record Frame(PerThread thead, boolean locked, long parentOffset, long topOfStack, Arena confinedArena, SegmentAllocator frame) implements Arena { - @ForceInline - private void assertOrder() { - if (topOfStack != stack.currentOffset()) - throw new IllegalStateException("Out of order access: frame not top-of-stack"); - } + @ForceInline + private void assertOrder() { + if (topOfStack != thead.stack.currentOffset()) + throw new IllegalStateException("Out of order access: frame not top-of-stack"); + } - @ForceInline - @Override - @SuppressWarnings("restricted") - public MemorySegment allocate(long byteSize, long byteAlignment) { - // Make sure we are on the right thread and not closed - MemorySessionImpl.toMemorySession(confinedArena).checkValidState(); - return frame.allocate(byteSize, byteAlignment); - } + @ForceInline + @Override + @SuppressWarnings("restricted") + public MemorySegment allocate(long byteSize, long byteAlignment) { + // Make sure we are on the right thread and not closed + MemorySessionImpl.toMemorySession(confinedArena).checkValidState(); + return frame.allocate(byteSize, byteAlignment); + } - @ForceInline - @Override - public MemorySegment.Scope scope() { - return confinedArena.scope(); - } + @ForceInline + @Override + public MemorySegment.Scope scope() { + return confinedArena.scope(); + } - @ForceInline - @Override - public void close() { - assertOrder(); - // the Arena::close method is called "early" as it checks thread - // confinement and crucially before any mutation of the internal - // state takes place. - confinedArena.close(); - stack.resetTo(parentOffset); - if (locked) { - lock.unlock(); - } + @ForceInline + @Override + public void close() { + assertOrder(); + // the Arena::close method is called "early" as it checks thread + // confinement and crucially before any mutation of the internal + // state takes place. + confinedArena.close(); + thead.stack.resetTo(parentOffset); + if (locked) { + thead.lock.unlock(); } } } From aaf71dbc927b20f57a60be582220fa73d77920b9 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 3 May 2025 00:05:47 +0800 Subject: [PATCH 2/2] Use anonymous class --- .../share/classes/jdk/internal/foreign/BufferStack.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java index a807c21ad8288..79e239971f55d 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java +++ b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java @@ -134,7 +134,11 @@ static PerThread of(long byteSize, long byteAlignment) { return new PerThread(new ReentrantLock(), arena, new SlicingAllocator(arena.allocate(byteSize, byteAlignment)), - (MemorySegment _) -> Reference.reachabilityFence(arena)); + new Consumer() { + @Override + public void accept(MemorySegment memorySegment) { + Reference.reachabilityFence(arena); + }}); } }