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 }