1 /*
  2  *  Copyright (c) 2019, 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.incubator.foreign;
 28 
 29 import jdk.internal.foreign.MemoryAddressImpl;
 30 import jdk.internal.ref.CleanerFactory;
 31 import jdk.internal.reflect.CallerSensitive;
 32 
 33 import java.lang.ref.Cleaner;
 34 
 35 /**
 36  * A memory address models a reference into a memory location. Memory addresses are typically obtained using the
 37  * {@link MemorySegment#address()} method, and can refer to either off-heap or on-heap memory. Off-heap memory
 38  * addresses are referred to as <em>native</em> memory addresses (see {@link #isNative()}). Native memory addresses
 39  * allow clients to obtain a raw memory address (expressed as a long value) which can then be used e.g. when interacting
 40  * with native code.
 41  * <p>
 42  * Given an address, it is possible to compute its offset relative to a given segment, which can be useful
 43  * when performing memory dereference operations using a memory access var handle (see {@link MemoryHandles}).
 44  * <p>
 45  * A memory address is associated with a {@linkplain ResourceScope resource scope}; the resource scope determines the
 46  * lifecycle of the memory address, and whether the address can be used from multiple threads. Memory addresses
 47  * obtained from {@linkplain #ofLong(long) numeric values}, or from native code, are associated with the
 48  * {@linkplain ResourceScope#globalScope() global resource scope}. Memory addresses obtained from segments
 49  * are associated with the same scope as the segment from which they have been obtained.
 50  * <p>
 51  * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
 52  * programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
 53  * use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
 54  * synchronization may fail. The {@code equals} method should be used for comparisons.
 55  * <p>
 56  * Non-platform classes should not implement {@linkplain MemoryAddress} directly.
 57  *
 58  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 59  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 60  *
 61  * @implSpec
 62  * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
 63  */
 64 public sealed interface MemoryAddress extends Addressable permits MemoryAddressImpl {
 65 
 66     @Override
 67     default MemoryAddress address() {
 68         return this;
 69     }
 70 
 71     /**
 72      * Creates a new memory address with given offset (in bytes), which might be negative, from current one.
 73      * @param offset specified offset (in bytes), relative to this address, which should be used to create the new address.
 74      * @return a new memory address with given offset from current one.
 75      */
 76     MemoryAddress addOffset(long offset);
 77 
 78     /**
 79      * Returns the resource scope associated with this memory address.
 80      * @return the resource scope associated with this memory address.
 81      */
 82     ResourceScope scope();
 83 
 84     /**
 85      * Returns the offset of this memory address into the given segment. More specifically, if both the segment's
 86      * base address and this address are native addresses, the result is computed as
 87      * {@code this.toRawLongValue() - segment.address().toRawLongValue()}. Otherwise, if both addresses in the form
 88      * {@code (B, O1)}, {@code (B, O2)}, where {@code B} is the same base heap object and {@code O1}, {@code O2}
 89      * are byte offsets (relative to the base object) associated with this address and the segment's base address,
 90      * the result is computed as {@code O1 - O2}.
 91      * <p>
 92      * If the segment's base address and this address are both heap addresses, but with different base objects, the result is undefined
 93      * and an exception is thrown. Similarly, if the segment's base address is an heap address (resp. off-heap) and
 94      * this address is an off-heap (resp. heap) address, the result is undefined and an exception is thrown.
 95      * Otherwise, the result is a byte offset {@code SO}. If this address falls within the
 96      * spatial bounds of the given segment, then {@code 0 <= SO < segment.byteSize()}; otherwise, {@code SO < 0 || SO > segment.byteSize()}.
 97      * @return the offset of this memory address into the given segment.
 98      * @param segment the segment relative to which this address offset should be computed
 99      * @throws IllegalArgumentException if {@code segment} is not compatible with this address; this can happen, for instance,
100      * when {@code segment} models an heap memory region, while this address is a {@linkplain #isNative() native} address.
101      */
102     long segmentOffset(MemorySegment segment);
103 
104     /**
105      Returns a new native memory segment with given size and resource scope (replacing the scope already associated
106      * with this address), and whose base address is this address. This method can be useful when interacting with custom
107      * native memory sources (e.g. custom allocators), where an address to some
108      * underlying memory region is typically obtained from native code (often as a plain {@code long} value).
109      * The returned segment is not read-only (see {@link MemorySegment#isReadOnly()}), and is associated with the
110      * provided resource scope.
111      * <p>
112      * Clients should ensure that the address and bounds refers to a valid region of memory that is accessible for reading and,
113      * if appropriate, writing; an attempt to access an invalid memory location from Java code will either return an arbitrary value,
114      * have no visible effect, or cause an unspecified exception to be thrown.
115      * <p>
116      * This method is equivalent to the following code:
117      * <pre>{@code
118     asSegment(byteSize, null, scope);
119      * }</pre>
120      * <p>
121      * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
122      * Restricted methods are unsafe, and, if used incorrectly, their use might crash
123      * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
124      * restricted methods, and use safe and supported functionalities, where possible.
125      *
126      * @param bytesSize the desired size.
127      * @param scope the native segment scope.
128      * @return a new native memory segment with given base address, size and scope.
129      * @throws IllegalArgumentException if {@code bytesSize <= 0}.
130      * @throws IllegalStateException if either the scope associated with this address or the provided scope
131      * have been already closed, or if access occurs from a thread other than the thread owning either
132      * scopes.
133      * @throws UnsupportedOperationException if this address is not a {@linkplain #isNative() native} address.
134      * @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
135      * {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
136      * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
137      */
138     @CallerSensitive
139     MemorySegment asSegment(long bytesSize, ResourceScope scope);
140 
141     /**
142      * Returns a new native memory segment with given size and resource scope (replacing the scope already associated
143      * with this address), and whose base address is this address. This method can be useful when interacting with custom
144      * native memory sources (e.g. custom allocators), where an address to some
145      * underlying memory region is typically obtained from native code (often as a plain {@code long} value).
146      * The returned segment is associated with the provided resource scope.
147      * <p>
148      * Clients should ensure that the address and bounds refers to a valid region of memory that is accessible for reading and,
149      * if appropriate, writing; an attempt to access an invalid memory location from Java code will either return an arbitrary value,
150      * have no visible effect, or cause an unspecified exception to be thrown.
151      * <p>
152      * Calling {@link ResourceScope#close()} on the scope associated with the returned segment will result in calling
153      * the provided cleanup action (if any).
154      * <p>
155      * This method is <a href="package-summary.html#restricted"><em>restricted</em></a>.
156      * Restricted methods are unsafe, and, if used incorrectly, their use might crash
157      * the JVM or, worse, silently result in memory corruption. Thus, clients should refrain from depending on
158      * restricted methods, and use safe and supported functionalities, where possible.
159      *
160      * @param bytesSize the desired size.
161      * @param cleanupAction the cleanup action; can be {@code null}.
162      * @param scope the native segment scope.
163      * @return a new native memory segment with given base address, size and scope.
164      * @throws IllegalArgumentException if {@code bytesSize <= 0}.
165      * @throws IllegalStateException if either the scope associated with this address or the provided scope
166      * have been already closed, or if access occurs from a thread other than the thread owning either
167      * scopes.
168      * @throws UnsupportedOperationException if this address is not a {@linkplain #isNative() native} address.
169      * @throws IllegalCallerException if access to this method occurs from a module {@code M} and the command line option
170      * {@code --enable-native-access} is either absent, or does not mention the module name {@code M}, or
171      * {@code ALL-UNNAMED} in case {@code M} is an unnamed module.
172      */
173     @CallerSensitive
174     MemorySegment asSegment(long bytesSize, Runnable cleanupAction, ResourceScope scope);
175 
176     /**
177      * Is this an off-heap memory address?
178      * @return true, if this is an off-heap memory address.
179      */
180     boolean isNative();
181 
182     /**
183      * Returns the raw long value associated with this native memory address.
184      * @return The raw long value associated with this native memory address.
185      * @throws UnsupportedOperationException if this memory address is not a {@linkplain #isNative() native} address.
186      * @throws IllegalStateException if the scope associated with this segment has been already closed,
187      * or if access occurs from a thread other than the thread owning either segment.
188      */
189     long toRawLongValue();
190 
191     /**
192      * Compares the specified object with this address for equality. Returns {@code true} if and only if the specified
193      * object is also an address, and it refers to the same memory location as this address.
194      *
195      * @apiNote two addresses might be considered equal despite their associated resource scopes differ. This
196      * can happen, for instance, if the same memory address is used to create memory segments with different
197      * scopes (using {@link #asSegment(long, ResourceScope)}), and the base address of the resulting segments is
198      * then compared.
199      *
200      * @param that the object to be compared for equality with this address.
201      * @return {@code true} if the specified object is equal to this address.
202      */
203     @Override
204     boolean equals(Object that);
205 
206     /**
207      * Returns the hash code value for this address.
208      * @return the hash code value for this address.
209      */
210     @Override
211     int hashCode();
212 
213     /**
214      * The native memory address instance modelling the {@code NULL} address, associated
215      * with the {@linkplain ResourceScope#globalScope() global} resource scope.
216      */
217     MemoryAddress NULL = new MemoryAddressImpl(null, 0L);
218 
219     /**
220      * Obtain a native memory address instance from given long address. The returned address is associated
221      * with the {@linkplain ResourceScope#globalScope() global} resource scope.
222      * @param value the long address.
223      * @return the new memory address instance.
224      */
225     static MemoryAddress ofLong(long value) {
226         return value == 0 ?
227                 NULL :
228                 new MemoryAddressImpl(null, value);
229     }
230 }