Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8330340

Add shortcut to SymbolLookup::find

XMLWordPrintable

    • Icon: CSR CSR
    • Resolution: Approved
    • Icon: P3 P3
    • 23
    • core-libs
    • None
    • source
    • minimal
    • Hide
      As the interface `SymbolLookup` is not sealed, anyone can create a custom implementation of it. Hence, it is possible, that some of these potential custom implementations already have a method `findOrThrow` defined.

      The new method is discoverable via reflection.
      Show
      As the interface `SymbolLookup` is not sealed, anyone can create a custom implementation of it. Hence, it is possible, that some of these potential custom implementations already have a method `findOrThrow` defined. The new method is discoverable via reflection.
    • Java API
    • SE

      Summary

      Add a default method SymbolLookup.findOrThrow(String name) that will throw an exception with a useful message if a symbol is not found.

      Problem

      It is a common pattern to call symbolLookup.find(name).orElseThrow() or symbolLookup.find(name).get() in order to obtain a symbol. In the case that a symbol cannot be found, the exception thrown above does not provide the given name in its description. Using symbolLookup.find(name).orElseThrow(() -> ... name ...) would incur a capturing lambda being created.

      Solution

      Add a method that will provide a relevant exception message, should a symbol not be found. The method does not incur lambda capturing internally.

      Specification

      
          diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
      index 9bfc7964322e1..3bc416b9c6272 100644
          --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
          +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java
      @@ -39,6 +39,7 @@
       import java.lang.invoke.MethodHandles;
       import java.nio.file.FileSystems;
       import java.nio.file.Path;
      +import java.util.NoSuchElementException;
       import java.util.Objects;
       import java.util.Optional;
       import java.util.function.BiFunction;
      @@ -79,7 +80,7 @@
        * {@snippet lang = java:
        * try (Arena arena = Arena.ofConfined()) {
        *     SymbolLookup libGL = SymbolLookup.libraryLookup("libGL.so", arena); // libGL.so loaded here
      - *     MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
      + *     MemorySegment glGetString = libGL.findOrThrow("glGetString");
        *     ...
        * } //  libGL.so unloaded here
        *}
      @@ -93,7 +94,7 @@
        * System.loadLibrary("GL"); // libGL.so loaded here
        * ...
        * SymbolLookup libGL = SymbolLookup.loaderLookup();
      - * MemorySegment glGetString = libGL.find("glGetString").orElseThrow();
      + * MemorySegment glGetString = libGL.findOrThrow("glGetString");
        * }
        *
        * This symbol lookup, which is known as a loader lookup, is dynamic with
      @@ -130,7 +131,7 @@
        * {@snippet lang = java:
        * Linker nativeLinker = Linker.nativeLinker();
        * SymbolLookup stdlib = nativeLinker.defaultLookup();
      - * MemorySegment malloc = stdlib.find("malloc").orElseThrow();
      + * MemorySegment malloc = stdlib.findOrThrow("malloc");
        *}
        *
        * @since 22
      @@ -144,9 +145,40 @@ public interface SymbolLookup {
            * @param name the symbol name
            * @return a zero-length memory segment whose address indicates the address of
            *         the symbol, if found
      +     * @see #findOrThrow(String)
            */
           Optional find(String name);
      
      +    /**
      +     * Returns the address of the symbol with the given name or throws an exception.
      +     *

      + * This is equivalent to the following code, but is more efficient: + * to: + * {@snippet lang= java : + * String name = ... + * MemorySegment address = lookup.find(name) + * .orElseThrow(() -> new NoSuchElementException("Symbol not found: " + name)); + * } + * + * @param name the symbol name + * @return a zero-length memory segment whose address indicates the address of + * the symbol + * @throws NoSuchElementException if no symbol address can be found for the + * given name + * @see #find(String) + * + * @since 23 + */ + default MemorySegment findOrThrow(String name) { + Objects.requireNonNull(name); + Optional address = find(name); + // Avoid lambda capturing + if (address.isPresent()) { + return address.get(); + } + throw new NoSuchElementException("Symbol not found: " + name); + } + /** * {@return a composed symbol lookup that returns the result of finding the symbol * with this lookup if found, otherwise returns the result of finding diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index b2a6a5f447440..6594826e40524 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -100,7 +100,7 @@ * Linker linker = Linker.nativeLinker(); * SymbolLookup stdlib = linker.defaultLookup(); * MethodHandle strlen = linker.downcallHandle( - * stdlib.find("strlen").orElseThrow(), + * stdlib.findOrThrow("strlen"), * FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS) * ); * @@ -111,7 +111,7 @@ *} * * 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} + * and we use it to {@linkplain java.lang.foreign.SymbolLookup#findOrThrow(java.lang.String) look up} * the {@code strlen} function in the standard C library; a downcall method handle * targeting said function is subsequently * {@linkplain java.lang.foreign.Linker#downcallHandle(FunctionDescriptor, Linker.Option...) obtained}.

            pminborg Per-Ake Minborg
            mcimadamore Maurizio Cimadamore
            Jorn Vernee
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: