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 import sun.security.action.GetBooleanAction; 37 38 /** 39 * Implementation for native memory segments. A native memory segment is essentially a wrapper around 40 * a native long address. 41 */ 42 public sealed class NativeMemorySegmentImpl extends AbstractMemorySegmentImpl permits MappedMemorySegmentImpl { 43 44 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 45 46 // The maximum alignment supported by malloc - typically 16 bytes on 47 // 64-bit platforms and 8 bytes on 32-bit platforms. 48 private static final long MAX_MALLOC_ALIGN = Unsafe.ADDRESS_SIZE == 4 ? 8 : 16; 49 private static final boolean SKIP_ZERO_MEMORY = GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.skipZeroMemory"); 50 51 final long min; 52 53 @ForceInline 54 NativeMemorySegmentImpl(long min, long length, boolean readOnly, MemorySessionImpl scope) { 55 super(length, readOnly, scope); 56 this.min = (Unsafe.getUnsafe().addressSize() == 4) 57 // On 32-bit systems, normalize the upper unused 32-bits to zero 58 ? min & 0x0000_0000_FFFF_FFFFL 59 // On 64-bit systems, all the bits are used 60 : min; 61 } 62 63 /** 64 * This constructor should only be used when initializing {@link MemorySegment#NULL}. Note: because of the memory 65 * segment class hierarchy, it is possible to end up in a situation where this constructor is called 66 * when the static fields in this class are not yet initialized. 67 */ 68 @ForceInline 69 public NativeMemorySegmentImpl() { 70 super(0L, false, new GlobalSession(null)); 71 this.min = 0L; 72 } 73 74 @Override 75 public long address() { 76 return min; 77 } 78 79 @Override 80 public Optional<Object> heapBase() { 81 return Optional.empty(); 82 } 83 84 @ForceInline 85 @Override 86 NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySessionImpl scope) { 87 return new NativeMemorySegmentImpl(min + offset, size, readOnly, scope); 88 } 89 90 @Override 91 ByteBuffer makeByteBuffer() { 92 return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, 93 scope == MemorySessionImpl.GLOBAL ? null : this); 94 } 95 96 @Override 97 public boolean isNative() { 98 return true; 99 } 100 101 @Override 102 public long unsafeGetOffset() { 103 return min; 104 } 105 106 @Override 107 public Object unsafeGetBase() { 108 return null; 109 } 110 111 @Override 112 public long maxAlignMask() { 113 return 0; 114 } 115 116 // factories 117 118 public static MemorySegment makeNativeSegment(long byteSize, long byteAlignment, MemorySessionImpl sessionImpl) { 119 sessionImpl.checkValidState(); 120 if (VM.isDirectMemoryPageAligned()) { 121 byteAlignment = Math.max(byteAlignment, NIO_ACCESS.pageSize()); 122 } 123 long alignedSize = Math.max(1L, byteAlignment > MAX_MALLOC_ALIGN ? 124 byteSize + (byteAlignment - 1) : 125 byteSize); 126 127 NIO_ACCESS.reserveMemory(alignedSize, byteSize); 128 129 long buf = UNSAFE.allocateMemory(alignedSize); 130 if (!SKIP_ZERO_MEMORY) { 131 UNSAFE.setMemory(buf, alignedSize, (byte)0); 132 } 133 long alignedBuf = Utils.alignUp(buf, byteAlignment); 134 AbstractMemorySegmentImpl segment = new NativeMemorySegmentImpl(buf, alignedSize, 135 false, sessionImpl); 136 sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() { 137 @Override 138 public void cleanup() { 139 UNSAFE.freeMemory(buf); 140 NIO_ACCESS.unreserveMemory(alignedSize, byteSize); 141 } 142 }); 143 if (alignedSize != byteSize) { 144 long delta = alignedBuf - buf; 145 segment = segment.asSlice(delta, byteSize); 146 } 147 return segment; 148 } 149 150 // Unsafe native segment factories. These are used by the implementation code, to skip the sanity checks 151 // associated with MemorySegment::ofAddress. 152 153 @ForceInline 154 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl, Runnable action) { 155 if (action == null) { 156 sessionImpl.checkValidState(); 157 } else { 158 sessionImpl.addCloseAction(action); 159 } 160 return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); 161 } 162 163 @ForceInline 164 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, MemorySessionImpl sessionImpl) { 165 sessionImpl.checkValidState(); 166 return new NativeMemorySegmentImpl(min, byteSize, false, sessionImpl); 167 } 168 169 @ForceInline 170 public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize) { 171 return new NativeMemorySegmentImpl(min, byteSize, false, new GlobalSession(null)); 172 } 173 }