Skip to content
Permalink
Browse files
8273905: Foreign API refresh
Reviewed-by: uschindler, psandoz
  • Loading branch information
mcimadamore committed Sep 22, 2021
1 parent b0283a4 commit 831e75bcb2eff79be1b2fb743aea9a2a2560cbd8
Show file tree
Hide file tree
Showing 162 changed files with 6,456 additions and 7,924 deletions.
@@ -28,6 +28,8 @@
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.VarHandle;
import java.lang.module.Configuration;
import java.lang.module.ModuleReference;
import java.lang.module.ModuleDescriptor;
@@ -68,6 +70,7 @@
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.Stable;
import sun.security.util.SecurityConstants;

/**
@@ -109,8 +112,10 @@ public final class Module implements AnnotatedElement {
// the module descriptor
private final ModuleDescriptor descriptor;

// true, if this module allows restricted native access
private volatile boolean enableNativeAccess;
// true, if this module allows restricted native access; @Stable makes sure that modules that allow native
// access capture this property as a constant.
@Stable
private boolean enableNativeAccess;

/**
* Creates a new named Module. The resulting Module will be defined to the
@@ -820,15 +820,16 @@ public MemorySegmentProxy bufferSegment(Buffer buffer) {
}

@Override
public Scope.Handle acquireScope(Buffer buffer, boolean async) {
public Runnable acquireScope(Buffer buffer, boolean async) {
var scope = buffer.scope();
if (scope == null) {
return null;
}
if (async && scope.ownerThread() != null) {
throw new IllegalStateException("Confined scope not supported");
}
return scope.acquire();
scope.acquire0();
return scope::release0;
}

@Override
@@ -92,7 +92,7 @@ public interface JavaNioAccess {
* scope handle. Null is returned if the buffer has no scope, or
* acquiring is not required to guarantee safety.
*/
Scope.Handle acquireScope(Buffer buffer, boolean async);
Runnable acquireScope(Buffer buffer, boolean async);

/**
* Used by {@code jdk.internal.foreign.MappedMemorySegmentImpl} and byte buffer var handle views.
@@ -103,19 +103,13 @@ public class ScopedMemoryAccess {
*/
public interface Scope {

interface Handle {
Scope scope();
}

void checkValidState();

Thread ownerThread();

boolean isImplicit();

Handle acquire();
void acquire0();

void release(Handle handle);
void release0();

/**
* Error thrown when memory access fails because the memory has already been released.
@@ -32,6 +32,7 @@
import java.util.Set;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;

/** Common utility routines used by both java.lang and
@@ -106,6 +107,7 @@ public static void ensureMemberAccess(Class<?> currentClass,
}
}

@ForceInline
public static void ensureNativeAccess(Class<?> currentClass) {
Module module = currentClass.getModule();
if (!SharedSecrets.getJavaLangAccess().isEnableNativeAccess(module)) {
@@ -465,15 +465,15 @@ static long read(FileDescriptor fd, ByteBuffer[] bufs, int offset, int length,

private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();

static Scope.Handle acquireScope(ByteBuffer bb, boolean async) {
static Runnable acquireScope(ByteBuffer bb, boolean async) {
return NIO_ACCESS.acquireScope(bb, async);
}

private static void releaseScope(Scope.Handle handle) {
private static void releaseScope(Runnable handle) {
if (handle == null)
return;
try {
handle.scope().release(handle);
handle.run();
} catch (Exception e) {
throw new IllegalStateException(e);
}
@@ -525,11 +525,11 @@ static LinkedRunnable of(Runnable first, Runnable second) {
}
}

static record Releaser(Scope.Handle handle) implements Runnable {
static record Releaser(Runnable handle) implements Runnable {
Releaser { Objects.requireNonNull(handle) ; }
@Override public void run() { releaseScope(handle); }
static Runnable of(Scope.Handle handle) { return new Releaser(handle); }
static Runnable ofNullable(Scope.Handle handle) {
static Runnable of(Runnable handle) { return new Releaser(handle); }
static Runnable ofNullable(Runnable handle) {
if (handle == null)
return () -> { };
return new Releaser(handle);
@@ -25,23 +25,19 @@
*/
package jdk.incubator.foreign;

import jdk.internal.foreign.Utils;
import jdk.internal.vm.annotation.Stable;

import java.lang.constant.ClassDesc;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
import java.lang.constant.ConstantDescs;
import java.lang.constant.DirectMethodHandleDesc;
import java.lang.constant.DynamicConstantDesc;
import java.lang.constant.MethodHandleDesc;
import java.lang.constant.MethodTypeDesc;
import java.nio.ByteOrder;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.OptionalLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.lang.constant.ConstantDescs.BSM_GET_STATIC_FINAL;
import static java.lang.constant.ConstantDescs.BSM_INVOKE;
@@ -52,50 +48,33 @@

private final OptionalLong size;
final long alignment;
final Map<String, Constable> attributes;
private final Optional<String> name;
@Stable
long cachedSize;

public AbstractLayout(OptionalLong size, long alignment, Map<String, Constable> attributes) {
public AbstractLayout(OptionalLong size, long alignment, Optional<String> name) {
this.size = size;
this.alignment = alignment;
this.attributes = Collections.unmodifiableMap(attributes);
this.name = name;
}

@Override
public AbstractLayout withName(String name) {
Objects.requireNonNull(name);
return withAttribute(LAYOUT_NAME, name);
return dup(alignment, Optional.of(name));
}

@Override
public final Optional<String> name() {
return attribute(LAYOUT_NAME).map(String.class::cast);
}

@Override
public Optional<Constable> attribute(String name) {
Objects.requireNonNull(name);
return Optional.ofNullable(attributes.get(name));
}

@Override
public Stream<String> attributes() {
return attributes.keySet().stream();
}

@Override
public AbstractLayout withAttribute(String name, Constable value) {
Objects.requireNonNull(name);
Map<String, Constable> newAttributes = new HashMap<>(attributes);
newAttributes.put(name, value);
return dup(alignment, newAttributes);
return name;
}

abstract AbstractLayout dup(long alignment, Map<String, Constable> annos);
abstract AbstractLayout dup(long alignment, Optional<String> name);

@Override
public AbstractLayout withBitAlignment(long alignmentBits) {
checkAlignment(alignmentBits);
return dup(alignmentBits, attributes);
return dup(alignmentBits, name);
}

void checkAlignment(long alignmentBitCount) {
@@ -120,6 +99,15 @@ public final long bitAlignment() {
return alignment;
}

@Override
public long byteSize() {
if (cachedSize == 0) {
cachedSize = Utils.bitsToBytesOrThrow(bitSize(),
() -> new UnsupportedOperationException("Cannot compute byte size; bit size is not a multiple of 8"));
}
return cachedSize;
}

@Override
public boolean hasSize() {
return size.isPresent();
@@ -145,11 +133,6 @@ String decorateLayoutString(String s) {
if (!hasNaturalAlignment()) {
s = alignment + "%" + s;
}
if (!attributes.isEmpty()) {
s += attributes.entrySet().stream()
.map(e -> e.getKey() + "=" + e.getValue())
.collect(Collectors.joining(",", "[", "]"));
}
return s;
}

@@ -158,9 +141,9 @@ <T> DynamicConstantDesc<T> decorateLayoutConstant(DynamicConstantDesc<T> desc) {
desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withBitAlignment", desc.constantType(), MH_WITH_BIT_ALIGNMENT,
desc, bitAlignment());
}
for (var e : attributes.entrySet()) {
desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withAttribute", desc.constantType(), MH_WITH_ATTRIBUTE,
desc, e.getKey(), e.getValue().describeConstable().orElseThrow());
if (name().isPresent()) {
desc = DynamicConstantDesc.ofNamed(BSM_INVOKE, "withName", desc.constantType(), MH_WITH_NAME,
desc, name().get().describeConstable().orElseThrow());
}

return desc;
@@ -177,7 +160,7 @@ public boolean isPadding() {

@Override
public int hashCode() {
return attributes.hashCode() << Long.hashCode(alignment);
return name.hashCode() << Long.hashCode(alignment);
}

@Override
@@ -190,7 +173,7 @@ public boolean equals(Object other) {
return false;
}

return Objects.equals(attributes, ((AbstractLayout) other).attributes) &&
return Objects.equals(name, ((AbstractLayout) other).name) &&
Objects.equals(alignment, ((AbstractLayout) other).alignment);
}

@@ -208,18 +191,13 @@ public boolean equals(Object other) {

static final ClassDesc CD_FUNCTION_DESC = FunctionDescriptor.class.describeConstable().get();

static final ClassDesc CD_Constable = Constable.class.describeConstable().get();

static final ConstantDesc BIG_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "BIG_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);

static final ConstantDesc LITTLE_ENDIAN = DynamicConstantDesc.ofNamed(BSM_GET_STATIC_FINAL, "LITTLE_ENDIAN", CD_BYTEORDER, CD_BYTEORDER);

static final MethodHandleDesc MH_PADDING = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "paddingLayout",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));

static final MethodHandleDesc MH_VALUE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "valueLayout",
MethodTypeDesc.of(CD_VALUE_LAYOUT, CD_long, CD_BYTEORDER));

static final MethodHandleDesc MH_SIZED_SEQUENCE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_STATIC, CD_MEMORY_LAYOUT, "sequenceLayout",
MethodTypeDesc.of(CD_SEQUENCE_LAYOUT, CD_long, CD_MEMORY_LAYOUT));

@@ -241,6 +219,6 @@ public boolean equals(Object other) {
static final MethodHandleDesc MH_WITH_BIT_ALIGNMENT = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withBitAlignment",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_long));

static final MethodHandleDesc MH_WITH_ATTRIBUTE = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withAttribute",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_String, CD_Constable));
static final MethodHandleDesc MH_WITH_NAME = MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.INTERFACE_VIRTUAL, CD_MEMORY_LAYOUT, "withName",
MethodTypeDesc.of(CD_MEMORY_LAYOUT, CD_String));
}
@@ -27,16 +27,36 @@

/**
* Represents a type which is <em>addressable</em>. An addressable type is one which can be projected down to
* a memory address instance (see {@link #address()}). Examples of addressable types are {@link MemorySegment},
* {@link MemoryAddress} and {@link CLinker.VaList}.
* a {@linkplain #address() memory address}. Examples of addressable types are {@link MemorySegment},
* {@link MemoryAddress}, {@link VaList} and {@link CLinker.UpcallStub}.
* <p>
* An addressable instance is associated with a {@linkplain ResourceScope resource scope}; the resource scope determines the
* lifecycle of the addressable instance, as well as whether the instance can be used from multiple threads. Some
* addressable instances might not be associated with a lifecycle, in which case {@link #scope()} returns the
* {@linkplain ResourceScope#globalScope() global scope}. Attempting to obtain a memory address
* from an addressable instance whose backing scope has already been {@linkplain ResourceScope#isAlive() closed} always
* results in an exception.
* <p>
* The {@link Addressable} type is used by the {@link CLinker C linker} to model the types of
* {@link CLinker#downcallHandle(FunctionDescriptor) downcall handle} parameters that must be passed <em>by reference</em>
* (e.g. memory addresses, va lists and upcall stubs).
*
* @implSpec
* Implementations of this interface are <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
*/
public interface Addressable {

/**
* Map this object into a {@link MemoryAddress} instance.
* @return the {@link MemoryAddress} instance associated with this object.
* Returns the memory address associated with this addressable.
* @return The memory address associated with this addressable.
* @throws IllegalStateException if the scope associated with this addressable has been closed, or if access occurs from
* a thread other than the thread owning that scope.
*/
MemoryAddress address();

/**
* Obtains the resource scope associated with this addressable.
* @return the resource scope associated with this addressable.
*/
ResourceScope scope();
}

0 comments on commit 831e75b

Please sign in to comment.