Skip to content

Commit

Permalink
8317837: Leftover FFM implementation-only changes
Browse files Browse the repository at this point in the history
Co-authored-by: Maurizio Cimadamore <mcimadamore@openjdk.org>
Co-authored-by: Per Minborg <pminborg@openjdk.org>
Reviewed-by: mcimadamore
  • Loading branch information
3 people committed Oct 13, 2023
1 parent 605c976 commit b12c471
Show file tree
Hide file tree
Showing 22 changed files with 1,428 additions and 111 deletions.
1 change: 1 addition & 0 deletions make/test/BuildMicrobenchmark.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
--add-exports java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \
--add-exports java.base/jdk.internal.vm=ALL-UNNAMED \
--add-exports java.base/jdk.internal.event=ALL-UNNAMED \
--add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \
--enable-preview \
-processor org.openjdk.jmh.generators.BenchmarkProcessor, \
JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management \
Expand Down
17 changes: 17 additions & 0 deletions src/java.base/share/classes/java/lang/String.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.io.ObjectStreamField;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Native;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.lang.invoke.MethodHandles;
import java.lang.constant.Constable;
import java.lang.constant.ConstantDesc;
Expand Down Expand Up @@ -1836,6 +1838,21 @@ public byte[] getBytes() {
return encode(Charset.defaultCharset(), coder(), value);
}

boolean bytesCompatible(Charset charset) {
if (isLatin1()) {
if (charset == ISO_8859_1.INSTANCE) {
return true; // ok, same encoding
} else if (charset == UTF_8.INSTANCE || charset == US_ASCII.INSTANCE) {
return !StringCoding.hasNegatives(value, 0, value.length); // ok, if ASCII-compatible
}
}
return false;
}

void copyToSegmentRaw(MemorySegment segment, long offset) {
MemorySegment.copy(value, 0, segment, ValueLayout.JAVA_BYTE, offset, value.length);
}

/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
Expand Down
12 changes: 11 additions & 1 deletion src/java.base/share/classes/java/lang/System.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.annotation.Annotation;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.invoke.StringConcatFactory;
Expand Down Expand Up @@ -88,7 +89,6 @@
import jdk.internal.vm.ContinuationScope;
import jdk.internal.vm.StackableScope;
import jdk.internal.vm.ThreadContainer;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.IntrinsicCandidate;
import jdk.internal.vm.annotation.Stable;
import sun.nio.fs.DefaultFileSystemProvider;
Expand Down Expand Up @@ -2669,6 +2669,16 @@ public StackWalker newStackWalkerInstance(Set<StackWalker.Option> options,
public String getLoaderNameID(ClassLoader loader) {
return loader.nameAndId();
}

@Override
public void copyToSegmentRaw(String string, MemorySegment segment, long offset) {
string.copyToSegmentRaw(segment, offset);
}

@Override
public boolean bytesCompatible(String string, Charset charset) {
return string.bytesCompatible(charset);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1076,7 +1076,7 @@ default long mismatch(MemorySegment other) {
* such that {@code isAccessibleBy(T) == false}.
*/
default String getString(long offset) {
return getString(offset, StandardCharsets.UTF_8);
return getString(offset, sun.nio.cs.UTF_8.INSTANCE);
}

/**
Expand Down Expand Up @@ -1132,7 +1132,7 @@ default String getString(long offset, Charset charset) {
*/
default void setString(long offset, String str) {
Objects.requireNonNull(str);
setString(offset, str, StandardCharsets.UTF_8);
setString(offset, str, sun.nio.cs.UTF_8.INSTANCE);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public interface SegmentAllocator {
@ForceInline
default MemorySegment allocateFrom(String str) {
Objects.requireNonNull(str);
return allocateFrom(str, StandardCharsets.UTF_8);
return allocateFrom(str, sun.nio.cs.UTF_8.INSTANCE);
}

/**
Expand Down Expand Up @@ -124,11 +124,20 @@ default MemorySegment allocateFrom(String str, Charset charset) {
Objects.requireNonNull(charset);
Objects.requireNonNull(str);
int termCharSize = StringSupport.CharsetKind.of(charset).terminatorCharSize();
byte[] bytes = str.getBytes(charset);
MemorySegment segment = allocateNoInit(bytes.length + termCharSize);
MemorySegment.copy(bytes, 0, segment, ValueLayout.JAVA_BYTE, 0, bytes.length);
MemorySegment segment;
int length;
if (StringSupport.bytesCompatible(str, charset)) {
length = str.length();
segment = allocateNoInit((long) length + termCharSize);
StringSupport.copyToSegmentRaw(str, segment, 0);
} else {
byte[] bytes = str.getBytes(charset);
length = bytes.length;
segment = allocateNoInit((long) bytes.length + termCharSize);
MemorySegment.copy(bytes, 0, segment, ValueLayout.JAVA_BYTE, 0, bytes.length);
}
for (int i = 0 ; i < termCharSize ; i++) {
segment.set(ValueLayout.JAVA_BYTE, bytes.length + i, (byte)0);
segment.set(ValueLayout.JAVA_BYTE, length + i, (byte)0);
}
return segment;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

package java.lang.invoke;

import jdk.internal.foreign.Utils;

/**
* Base class for memory segment var handle view implementations.
*/
Expand Down Expand Up @@ -54,7 +56,7 @@ abstract sealed class VarHandleSegmentViewBase extends VarHandle permits
}

static IllegalArgumentException newIllegalArgumentExceptionForMisalignedAccess(long address) {
return new IllegalArgumentException("Misaligned access at address: " + address);
return new IllegalArgumentException("Misaligned access at address: " + Utils.toHexString(address));
}

static UnsupportedOperationException newUnsupportedAccessModeForAlignment(long alignment) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.foreign.MemorySegment;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.lang.module.ModuleDescriptor;
Expand Down Expand Up @@ -574,4 +575,14 @@ StackWalker newStackWalkerInstance(Set<StackWalker.Option> options,
* explicitly set otherwise <qualified-class-name> @<id>
*/
String getLoaderNameID(ClassLoader loader);

/**
* Copy the string bytes to an existing segment, avoiding intermediate copies.
*/
void copyToSegmentRaw(String string, MemorySegment segment, long offset);

/**
* Are the string bytes compatible with the given charset?
*/
boolean bytesCompatible(String string, Charset charset);
}
66 changes: 45 additions & 21 deletions src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
package jdk.internal.foreign;

import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Stable;

import java.lang.foreign.AddressLayout;
import java.lang.foreign.GroupLayout;
Expand All @@ -40,9 +41,13 @@
import java.lang.invoke.VarHandle;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.UnaryOperator;
import java.util.stream.IntStream;
import java.util.stream.Stream;

import static java.util.stream.Collectors.joining;

/**
* This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)},
Expand Down Expand Up @@ -89,7 +94,6 @@ public class LayoutPath {
private final long offset;
private final LayoutPath enclosing;
private final long[] strides;

private final long[] bounds;
private final MethodHandle[] derefAdapters;

Expand All @@ -105,15 +109,13 @@ private LayoutPath(MemoryLayout layout, long offset, long[] strides, long[] boun
// Layout path selector methods

public LayoutPath sequenceElement() {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
SequenceLayout seq = requireSequenceLayout();
MemoryLayout elem = seq.elementLayout();
return LayoutPath.nestedPath(elem, offset, addStride(elem.byteSize()), addBound(seq.elementCount()), derefAdapters, this);
}

public LayoutPath sequenceElement(long start, long step) {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
SequenceLayout seq = requireSequenceLayout();
checkSequenceBounds(seq, start);
MemoryLayout elem = seq.elementLayout();
long elemSize = elem.byteSize();
Expand All @@ -122,21 +124,19 @@ public LayoutPath sequenceElement(long start, long step) {
start + 1;
long maxIndex = Math.ceilDiv(nelems, Math.abs(step));
return LayoutPath.nestedPath(elem, offset + (start * elemSize),
addStride(elemSize * step), addBound(maxIndex), derefAdapters, this);
addStride(elemSize * step), addBound(maxIndex), derefAdapters, this);
}

public LayoutPath sequenceElement(long index) {
check(SequenceLayout.class, "attempting to select a sequence element from a non-sequence layout");
SequenceLayout seq = (SequenceLayout)layout;
SequenceLayout seq = requireSequenceLayout();
checkSequenceBounds(seq, index);
long elemSize = seq.elementLayout().byteSize();
long elemOffset = elemSize * index;
return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, bounds, derefAdapters,this);
return LayoutPath.nestedPath(seq.elementLayout(), offset + elemOffset, strides, bounds, derefAdapters, this);
}

public LayoutPath groupElement(String name) {
check(GroupLayout.class, "attempting to select a group element from a non-group layout");
GroupLayout g = (GroupLayout)layout;
GroupLayout g = requireGroupLayout();
long offset = 0;
MemoryLayout elem = null;
for (int i = 0; i < g.memberLayouts().size(); i++) {
Expand All @@ -150,20 +150,21 @@ public LayoutPath groupElement(String name) {
}
}
if (elem == null) {
throw badLayoutPath("cannot resolve '" + name + "' in layout " + layout);
throw badLayoutPath(
String.format("cannot resolve '%s' in layout %s", name, breadcrumbs()));
}
return LayoutPath.nestedPath(elem, this.offset + offset, strides, bounds, derefAdapters, this);
}

public LayoutPath groupElement(long index) {
check(GroupLayout.class, "attempting to select a group element from a non-group layout");
GroupLayout g = (GroupLayout)layout;
GroupLayout g = requireGroupLayout();
long elemSize = g.memberLayouts().size();
long offset = 0;
MemoryLayout elem = null;
for (int i = 0; i <= index; i++) {
if (i == elemSize) {
throw badLayoutPath("cannot resolve element " + index + " in layout " + layout);
throw badLayoutPath(
String.format("cannot resolve element %d in layout: %s", index, breadcrumbs()));
}
elem = g.memberLayouts().get(i);
if (g instanceof StructLayout && i < index) {
Expand All @@ -176,7 +177,8 @@ public LayoutPath groupElement(long index) {
public LayoutPath derefElement() {
if (!(layout instanceof AddressLayout addressLayout) ||
addressLayout.targetLayout().isEmpty()) {
throw badLayoutPath("Cannot dereference layout: " + layout);
throw badLayoutPath(
String.format("Cannot dereference layout: %s", breadcrumbs()));
}
MemoryLayout derefLayout = addressLayout.targetLayout().get();
MethodHandle handle = dereferenceHandle(false).toMethodHandle(VarHandle.AccessMode.GET);
Expand All @@ -201,7 +203,8 @@ public VarHandle dereferenceHandle() {

public VarHandle dereferenceHandle(boolean adapt) {
if (!(layout instanceof ValueLayout valueLayout)) {
throw new IllegalArgumentException("Path does not select a value layout");
throw new IllegalArgumentException(
String.format("Path does not select a value layout: %s", breadcrumbs()));
}

// If we have an enclosing layout, drop the alignment check for the accessed element,
Expand Down Expand Up @@ -288,7 +291,9 @@ public MethodHandle sliceHandle() {

private static void checkAlign(MemorySegment segment, long offset, MemoryLayout constraint) {
if (!((AbstractMemorySegmentImpl) segment).isAlignedForElement(offset, constraint)) {
throw new IllegalArgumentException("Target offset incompatible with alignment constraints: " + constraint.byteAlignment());
throw new IllegalArgumentException(String.format(
"Target offset %d is incompatible with alignment constraint %d (of %s) for segment %s"
, offset, constraint.byteAlignment(), constraint, segment));
}
}

Expand All @@ -314,15 +319,27 @@ private static LayoutPath derefPath(MemoryLayout layout, MethodHandle handle, La

// Helper methods

private void check(Class<?> layoutClass, String msg) {
private SequenceLayout requireSequenceLayout() {
return requireLayoutType(SequenceLayout.class, "sequence");
}

private GroupLayout requireGroupLayout() {
return requireLayoutType(GroupLayout.class, "group");
}

private <T extends MemoryLayout> T requireLayoutType(Class<T> layoutClass, String name) {
if (!layoutClass.isAssignableFrom(layout.getClass())) {
throw badLayoutPath(msg);
throw badLayoutPath(
String.format("attempting to select a %s element from a non-%s layout: %s",
name, name, breadcrumbs()));
}
return layoutClass.cast(layout);
}

private void checkSequenceBounds(SequenceLayout seq, long index) {
if (index >= seq.elementCount()) {
throw badLayoutPath(String.format("Sequence index out of bound; found: %d, size: %d", index, seq.elementCount()));
throw badLayoutPath(String.format("sequence index out of bounds; index: %d, elementCount is %d for layout %s",
index, seq.elementCount(), breadcrumbs()));
}
}

Expand All @@ -342,6 +359,13 @@ private long[] addBound(long maxIndex) {
return newBounds;
}

private String breadcrumbs() {
return Stream.iterate(this, Objects::nonNull, lp -> lp.enclosing)
.map(LayoutPath::layout)
.map(Object::toString)
.collect(joining(", selected from: "));
}

/**
* This class provides an immutable implementation for the {@code PathElement} interface. A path element implementation
* is simply a pointer to one of the selector methods provided by the {@code LayoutPath} class.
Expand Down
Loading

1 comment on commit b12c471

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.