1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 27 package jdk.internal.foreign; 28 29 import java.lang.foreign.MemorySegment; 30 import java.nio.ByteBuffer; 31 import java.util.Optional; 32 33 import jdk.internal.misc.Unsafe; 34 import jdk.internal.misc.VM; 35 import jdk.internal.vm.annotation.ForceInline; 36 37 /** 38 * Implementation for native memory segments. A native memory segment is essentially a wrapper around 39 * a native long address. 40 */ 41 public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl permits MappedMemorySegmentImpl { 42 43 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 44 45 // The maximum alignment supported by malloc - typically 16 bytes on 46 // 64-bit platforms and 8 bytes on 32-bit platforms. 47 private static final long MAX_MALLOC_ALIGN = Unsafe.ADDRESS_SIZE == 4 ? 8 : 16; 48 49 final long min; 50 51 @ForceInline 52 NativeMemorySegmentImpl(long min, long length, boolean readOnly, MemorySessionImpl scope) { 53 super(length, readOnly, scope); 54 this.min = (Unsafe.getUnsafe().addressSize() == 4) 55 // On 32-bit systems, normalize the upper unused 32-bits to zero 56 ? min & 0x0000_0000_FFFF_FFFFL 57 // On 64-bit systems, all the bits are used 58 : min; 59 } 60 61 /** 62 * This constructor should only be used when initializing {@link MemorySegment#NULL}. Note: because of the memory 63 * segment class hierarchy, it is possible to end up in a situation where this constructor is called 64 * when the static fields in this class are not yet initialized. 65 */ 66 @ForceInline 67 public NativeMemorySegmentImpl() { 68 super(0L, false, MemorySessionImpl.NATIVE_SESSION); 69 this.min = 0L; 70 } 71 72 @Override 73 public long address() { 74 return min; 75 } 76 77 @Override 78 public Optional<Object> heapBase() { 79 return Optional.empty(); 80 } 81 82 @ForceInline 83 @Override 84 NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { 85 return new NativeMemorySegmentImpl(min + offset, size, readOnly, scope); 86 } 87 88 @Override 89 ByteBuffer makeByteBuffer() { 90 return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, this); 91 } 92 93 @Override 94 public boolean isNative() { 95 return true; 96 } 97 98 @Override 99 public long unsafeGetOffset() { 100 return min; 101 } 102 103 @Override 104 public Object unsafeGetBase() { 105 return null; 106 } 107 108 @Override 109 public long maxAlignMask() { 110 return 0; 111 } 112 113 // factories 114 115 public static MemorySegment makeNativeSegment(long byteSize, long byteAlignment, MemorySessionImpl sessionImpl, 116 boolean shouldReserve) { 117 sessionImpl.checkValidState(); 118 if (VM.isDirectMemoryPageAligned()) { 119 byteAlignment = Math.max(byteAlignment, NIO_ACCESS.pageSize()); 120 } 121 long alignedSize = Math.max(1L, byteAlignment > MAX_MALLOC_ALIGN ? 122 byteSize + (byteAlignment - 1) : 123 byteSize); 124 125 if (shouldReserve) { 126 NIO_ACCESS.reserveMemory(alignedSize, byteSize); 127 } 128 129 long buf = allocateMemoryWrapper(alignedSize); 130 long alignedBuf = Utils.alignUp(buf, byteAlignment); 131 AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize, 132 false, sessionImpl); 133 sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() { 134 @Override 135 public void cleanup() { 136 UNSAFE.freeMemory(buf); 137 if (shouldReserve) { 138 NIO_ACCESS.unreserveMemory(alignedSize, byteSize); 139 } 140 } 141 }); 142 if (alignedSize != byteSize) { 143 long delta = alignedBuf - buf; 144 segment = segment.asSlice(delta, byteSize); 145 } 146 return segment; 147 } 148 149 private static long allocateMemoryWrapper(long size) { 150 try { 151 return UNSAFE.allocateMemory(size); 152 } catch (IllegalArgumentException ex) { 153 throw new OutOfMemoryError(); 154 } 155 } 156 157 // Unsafe native segment factories. These are used by the implementation code, to skip the sanity checks 158 // associated with MemorySegment::ofAddress. 159 160 @ForceInline 161 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl, Runnable action) { 162 if (action == null) { 163 sessionImpl.checkValidState(); 164 } else { 165 sessionImpl.addCloseAction(action); 166 } 167 return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); 168 } 169 170 @ForceInline 171 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl) { 172 sessionImpl.checkValidState(); 173 return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); 174 } 175 176 @ForceInline 177 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize) { 178 return new NativeMemorySegmentImpl(min, byteSize, false, MemorySessionImpl.NATIVE_SESSION); 179 } 180 }