/* * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. * */ /** *
Provides low-level access to memory and functions outside the Java runtime. * *
* The main abstraction introduced to support foreign memory access is {@link java.lang.foreign.MemorySegment}, which * models a contiguous region of memory, residing either inside or outside the Java heap. The contents of a memory * segment can be described using a {@link java.lang.foreign.MemoryLayout memory layout}, which provides * basic operations to query sizes, offsets and alignment constraints. Memory layouts also provide * an alternate, more abstract way, to access memory segments * using {@linkplain java.lang.foreign.MemoryLayout#varHandle(java.lang.foreign.MemoryLayout.PathElement...) var handles}, * which can be computed using layout paths. * * For example, to allocate an off-heap region of memory big enough to hold 10 values of the primitive type {@code int}, * and fill it with values ranging from {@code 0} to {@code 9}, we can use the following code: * * {@snippet lang = java: * MemorySegment segment = MemorySegment.allocateNative(10 * 4, SegmentScope.auto()); * for (int i = 0 ; i < 10 ; i++) { * segment.setAtIndex(ValueLayout.JAVA_INT, i, i); * } *} * * This code creates a native memory segment, that is, a memory segment backed by * off-heap memory; the size of the segment is 40 bytes, enough to store 10 values of the primitive type {@code int}. * The segment is associated with an {@linkplain java.lang.foreign.SegmentScope#auto() automatic scope}. This * means that the off-heap region of memory backing the segment is managed, automatically, by the garbage collector. * As such, the off-heap memory backing the native segment will be released at some unspecified * point after the segment becomes unreachable. * This is similar to what happens with direct buffers created via {@link java.nio.ByteBuffer#allocateDirect(int)}. * It is also possible to manage the lifecycle of allocated native segments more directly, as shown in a later section. *
* Inside a loop, we then initialize the contents of the memory segment; note how the * {@linkplain java.lang.foreign.MemorySegment#setAtIndex(ValueLayout.OfInt, long, int) access method} * accepts a {@linkplain java.lang.foreign.ValueLayout value layout}, which specifies the size, alignment constraint, * byte order as well as the Java type ({@code int}, in this case) associated with the access operation. More specifically, * if we view the memory segment as a set of 10 adjacent slots, {@code s[i]}, where {@code 0 <= i < 10}, * where the size of each slot is exactly 4 bytes, the initialization logic above will set each slot * so that {@code s[i] = i}, again where {@code 0 <= i < 10}. * *
* Since memory segments created with an arena can become invalid (see above), segments are also validated (upon access) to make sure that * the scope associated with the segment being accessed is still alive. * We call this guarantee temporal safety. Together, spatial and temporal safety ensure that each memory access * operation either succeeds - and accesses a valid location within the region of memory backing the memory segment - or fails. * *
* For example, to compute the length of a string using the C standard library function {@code strlen} on a Linux x64 platform, * we can use the following code: * * {@snippet lang = java: * Linker linker = Linker.nativeLinker(); * SymbolLookup stdlib = linker.defaultLookup(); * MethodHandle strlen = linker.downcallHandle( * stdlib.find("strlen").get(), * FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS) * ); * * try (Arena arena = Arena.openConfined()) { * MemorySegment cString = arena.allocateUtf8String("Hello"); * long len = (long)strlen.invoke(cString); // 5 * } *} * * Here, we obtain a {@linkplain java.lang.foreign.Linker#nativeLinker() native linker} and we use it * to {@linkplain java.lang.foreign.SymbolLookup#find(java.lang.String) look up} the {@code strlen} symbol in the * standard C library; a downcall method handle targeting said symbol is subsequently * {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}. * To complete the linking successfully, we must provide a {@link java.lang.foreign.FunctionDescriptor} instance, * describing the signature of the {@code strlen} function. * From this information, the linker will uniquely determine the sequence of steps which will turn * the method handle invocation (here performed using {@link java.lang.invoke.MethodHandle#invoke(java.lang.Object...)}) * into a foreign function call, according to the rules specified by the ABI of the underlying platform. * The {@link java.lang.foreign.Arena} class also provides many useful methods for * interacting with foreign code, such as * {@linkplain java.lang.foreign.SegmentAllocator#allocateUtf8String(java.lang.String) converting} Java strings into * zero-terminated, UTF-8 strings, as demonstrated in the above example. * *
* Now that we have a method handle instance, we can turn it into a fresh function pointer, * using the {@link java.lang.foreign.Linker} interface, as follows: * * {@snippet lang = java: * SegmentScope scope = ... * MemorySegment comparFunc = Linker.nativeLinker().upcallStub( * intCompareHandle, intCompareDescriptor, scope); * ); *} * * The {@link java.lang.foreign.FunctionDescriptor} instance created in the previous step is then used to * {@linkplain java.lang.foreign.Linker#upcallStub(java.lang.invoke.MethodHandle, FunctionDescriptor, SegmentScope) create} * a new upcall stub; the layouts in the function descriptors allow the linker to determine the sequence of steps which * allow foreign code to call the stub for {@code intCompareHandle} according to the rules specified by the ABI of the * underlying platform. * The lifecycle of the upcall stub is tied to the {@linkplain java.lang.foreign.SegmentScope scope} * provided when the upcall stub is created. This same scope is made available by the {@link java.lang.foreign.MemorySegment} * instance returned by that method. * *
* Binding foreign data and/or functions is generally unsafe and, if done incorrectly, can result in VM crashes, * or memory corruption when the bound Java API element is accessed. For instance, in the case of * {@link java.lang.foreign.MemorySegment#ofAddress(long, long, SegmentScope)}, if the provided spatial bounds are * incorrect, a client of the segment returned by that method might crash the VM, or corrupt * memory when attempting to access said segment. For these reasons, it is crucial for code that calls a restricted method * to never pass arguments that might cause incorrect binding of foreign data and/or functions to a Java API. *
* Given the potential danger of restricted methods, the Java runtime issues a warning on the standard error stream * every time a restricted method is invoked. Such warnings can be disabled by granting access to restricted methods * to selected modules. This can be done either via implementation-specific command line options, or programmatically, e.g. by calling * {@link java.lang.ModuleLayer.Controller#enableNativeAccess(java.lang.Module)}. *
* For every class in this package, unless specified otherwise, any method arguments of reference * type must not be null, and any null argument will elicit a {@code NullPointerException}. This fact is not individually * documented for methods of this API. * * @apiNote Usual memory model guarantees, for example stated in {@jls 6.6} and {@jls 10.4}, do not apply * when accessing native memory segments as these segments are backed by off-heap regions of memory. * * @implNote * In the reference implementation, access to restricted methods can be granted to specific modules using the command line option * {@code --enable-native-access=M1,M2, ... Mn}, where {@code M1}, {@code M2}, {@code ... Mn} are module names * (for the unnamed module, the special value {@code ALL-UNNAMED} can be used). If this option is specified, access to * restricted methods is only granted to the modules listed by that option. If this option is not specified, * access to restricted methods is enabled for all modules, but access to restricted methods will result in runtime warnings. * * @spec jni/index.html Java Native Interface Specification */ package java.lang.foreign;