8350118: Simplify the layout access VarHandle

Reviewed-by: mcimadamore, jvernee, erikj
This commit is contained in:
Chen Liang 2025-02-28 20:01:17 +00:00
parent fb659eba02
commit c7fa499bf5
18 changed files with 1977 additions and 1140 deletions

View file

@ -42,6 +42,17 @@ define GenerateScopedOp
$1_Type := $2 $1_Type := $2
ifeq ($$($1_Type), Boolean)
$1_type := boolean
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
endif
ifeq ($$($1_Type), Byte) ifeq ($$($1_Type), Byte)
$1_type := byte $1_type := byte
$1_BoxType := $$($1_Type) $1_BoxType := $$($1_Type)
@ -50,6 +61,7 @@ define GenerateScopedOp
$1_RawType := $$($1_Type) $1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -Kbyte $1_ARGS += -Kbyte
endif endif
@ -60,6 +72,8 @@ define GenerateScopedOp
$1_rawType := $$($1_type) $1_rawType := $$($1_type)
$1_RawType := $$($1_Type) $1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned $1_ARGS += -KUnaligned
endif endif
@ -70,6 +84,8 @@ define GenerateScopedOp
$1_rawType := $$($1_type) $1_rawType := $$($1_type)
$1_RawType := $$($1_Type) $1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS
$1_ARGS += -KUnaligned $1_ARGS += -KUnaligned
endif endif
@ -82,8 +98,6 @@ define GenerateScopedOp
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS $1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
$1_ARGS += -KUnaligned $1_ARGS += -KUnaligned
endif endif
@ -96,8 +110,6 @@ define GenerateScopedOp
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KCAS $1_ARGS += -KCAS
$1_ARGS += -KAtomicAdd
$1_ARGS += -KBitwise
$1_ARGS += -KUnaligned $1_ARGS += -KUnaligned
endif endif
@ -133,7 +145,7 @@ define GenerateScopedOp
$1_ARGS += -KBitwise $1_ARGS += -KBitwise
endif endif
ifneq ($$(findstring $$($1_Type), Byte Short Char), ) ifneq ($$(findstring $$($1_Type), Boolean Byte Short Char), )
$1_ARGS += -KShorterThanInt $1_ARGS += -KShorterThanInt
endif endif
endef endef
@ -141,7 +153,7 @@ endef
################################################################################ ################################################################################
# Setup a rule for generating the ScopedMemoryAccess java class # Setup a rule for generating the ScopedMemoryAccess java class
SCOPE_MEMORY_ACCESS_TYPES := Byte Short Char Int Long Float Double SCOPE_MEMORY_ACCESS_TYPES := Boolean Byte Short Char Int Long Float Double
$(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \ $(foreach t, $(SCOPE_MEMORY_ACCESS_TYPES), \
$(eval $(call GenerateScopedOp,BIN_$t,$t))) $(eval $(call GenerateScopedOp,BIN_$t,$t)))

View file

@ -174,6 +174,18 @@ define GenerateVarHandleMemorySegment
$1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java $1_FILENAME := $(VARHANDLES_GENSRC_DIR)/VarHandleSegmentAs$$($1_Type)s.java
ifeq ($$($1_Type), Boolean)
$1_type := boolean
$1_BoxType := $$($1_Type)
$1_rawType := $$($1_type)
$1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType)
$1_ARGS += -Kbyte
$1_ARGS += -KShorterThanInt
endif
ifeq ($$($1_Type), Byte) ifeq ($$($1_Type), Byte)
$1_type := byte $1_type := byte
$1_BoxType := $$($1_Type) $1_BoxType := $$($1_Type)
@ -183,6 +195,7 @@ define GenerateVarHandleMemorySegment
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -Kbyte $1_ARGS += -Kbyte
$1_ARGS += -KShorterThanInt
endif endif
ifeq ($$($1_Type), Short) ifeq ($$($1_Type), Short)
@ -192,6 +205,8 @@ define GenerateVarHandleMemorySegment
$1_rawType := $$($1_type) $1_rawType := $$($1_type)
$1_RawType := $$($1_Type) $1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KShorterThanInt
endif endif
ifeq ($$($1_Type), Char) ifeq ($$($1_Type), Char)
@ -201,6 +216,8 @@ define GenerateVarHandleMemorySegment
$1_rawType := $$($1_type) $1_rawType := $$($1_type)
$1_RawType := $$($1_Type) $1_RawType := $$($1_Type)
$1_RawBoxType := $$($1_BoxType) $1_RawBoxType := $$($1_BoxType)
$1_ARGS += -KShorterThanInt
endif endif
ifeq ($$($1_Type), Int) ifeq ($$($1_Type), Int)
@ -277,7 +294,7 @@ $(foreach t, $(VARHANDLES_BYTE_ARRAY_TYPES), \
$(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t))) $(eval $(call GenerateVarHandleByteArray,VAR_HANDLE_BYTE_ARRAY_$t,$t)))
# List the types to generate source for, with capitalized first letter # List the types to generate source for, with capitalized first letter
VARHANDLES_MEMORY_SEGMENT_TYPES := Byte Short Char Int Long Float Double VARHANDLES_MEMORY_SEGMENT_TYPES := Boolean Byte Short Char Int Long Float Double
$(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \ $(foreach t, $(VARHANDLES_MEMORY_SEGMENT_TYPES), \
$(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t))) $(eval $(call GenerateVarHandleMemorySegment,VAR_HANDLE_MEMORY_SEGMENT_$t,$t)))

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,6 +43,7 @@ import sun.invoke.util.Wrapper;
import java.lang.classfile.ClassFile; import java.lang.classfile.ClassFile;
import java.lang.constant.ClassDesc; import java.lang.constant.ClassDesc;
import java.lang.foreign.MemoryLayout;
import java.lang.invoke.MethodHandles.Lookup; import java.lang.invoke.MethodHandles.Lookup;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -1552,8 +1553,8 @@ abstract class MethodHandleImpl {
} }
@Override @Override
public VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask, ByteOrder order) { public VarHandle memorySegmentViewHandle(Class<?> carrier, MemoryLayout enclosing, long alignmentMask, ByteOrder order, boolean constantOffset, long offset) {
return VarHandles.memorySegmentViewHandle(carrier, alignmentMask, order); return VarHandles.memorySegmentViewHandle(carrier, enclosing, alignmentMask, constantOffset, offset, order);
} }
@Override @Override

View file

@ -0,0 +1,95 @@
/*
* Copyright (c) 2019, 2025, 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.
*/
package java.lang.invoke;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.util.Objects;
import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline;
/**
* A var handle that accesses primitive values in a memory segment.
*/
final class SegmentVarHandle extends VarHandle {
// Common implementation fields for the VarForms
static final boolean BE = MethodHandleStatics.UNSAFE.isBigEndian();
static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
/** endianness **/
final boolean be;
/** The layout the accessed segment must be compatible with. */
final MemoryLayout enclosing;
/** The offset value, if is constant. vform decides if offset is constant or variable. */
final long offset;
SegmentVarHandle(VarForm form, boolean be, MemoryLayout enclosing, long offset, boolean exact) {
super(form, exact);
this.be = be;
this.enclosing = enclosing;
this.offset = offset;
}
@Override
final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) {
var getType = vform.methodType_table[0]; // erased, but our value type is erase-compatible
return getType.parameterCount() == 2
? accessType.accessModeType(MemorySegment.class, getType.returnType(), long.class)
: accessType.accessModeType(MemorySegment.class, getType.returnType(), long.class, long.class);
}
@Override
public SegmentVarHandle withInvokeExactBehavior() {
return hasInvokeExactBehavior() ?
this :
new SegmentVarHandle(vform, be, enclosing, offset, true);
}
@Override
public SegmentVarHandle withInvokeBehavior() {
return !hasInvokeExactBehavior() ?
this :
new SegmentVarHandle(vform, be, enclosing, offset, false);
}
// Common implementation methods for the VarForms
@ForceInline
static long offset(AbstractMemorySegmentImpl bb, long base, long offset) {
long segment_base = bb.unsafeGetOffset();
return segment_base + base + offset;
}
@ForceInline
AbstractMemorySegmentImpl checkSegment(Object obb, long base, boolean ro) {
AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl) Objects.requireNonNull(obb);
oo.checkEnclosingLayout(base, this.enclosing, ro);
return oo;
}
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic; import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
/** /**
* A var handle form containing a set of member name, one for each operation. * A var handle form containing a set of member name, one for each operation.
@ -43,6 +44,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
*/ */
final class VarForm { final class VarForm {
// implClass must be initialized when the member names are accessed!
final Class<?> implClass; final Class<?> implClass;
final @Stable MethodType[] methodType_table; final @Stable MethodType[] methodType_table;
@ -63,6 +65,15 @@ final class VarForm {
} }
} }
VarForm(Class<?> implClass, VarForm methodTypeSource) {
this.implClass = implClass;
// reuse initMethodTypes result from methodTypeSource
this.methodType_table = methodTypeSource.methodType_table;
this.methodType_V_table = methodTypeSource.methodType_V_table;
this.memberName_table = new MemberName[VarHandle.AccessMode.COUNT];
assert assertMethodTypeTableInitialized() : implClass;
}
// Used by IndirectVarHandle // Used by IndirectVarHandle
VarForm(Class<?> value, Class<?>[] coordinates) { VarForm(Class<?> value, Class<?>[] coordinates) {
this.methodType_table = new MethodType[VarHandle.AccessType.COUNT]; this.methodType_table = new MethodType[VarHandle.AccessType.COUNT];
@ -103,6 +114,15 @@ final class VarForm {
type.changeReturnType(boolean.class); type.changeReturnType(boolean.class);
} }
private boolean assertMethodTypeTableInitialized() {
if (methodType_table == null)
return false;
for (int i = 0; i < VarHandle.AccessType.COUNT; i++) {
assert methodType_table[i] != null : implClass + " " + VarHandle.AccessType.values()[i];
}
return true;
}
@ForceInline @ForceInline
final MethodType getMethodType(int type) { final MethodType getMethodType(int type) {
return methodType_table[type]; return methodType_table[type];
@ -137,6 +157,7 @@ final class VarForm {
AccessMode value = AccessMode.valueFromOrdinal(mode); AccessMode value = AccessMode.valueFromOrdinal(mode);
String methodName = value.methodName(); String methodName = value.methodName();
MethodType type = methodType_table[value.at.ordinal()].insertParameterTypes(0, VarHandle.class); MethodType type = methodType_table[value.at.ordinal()].insertParameterTypes(0, VarHandle.class);
assert !UNSAFE.shouldBeInitialized(implClass) : implClass;
return memberName_table[mode] = MethodHandles.Lookup.IMPL_LOOKUP return memberName_table[mode] = MethodHandles.Lookup.IMPL_LOOKUP
.resolveOrNull(REF_invokeStatic, implClass, methodName, type); .resolveOrNull(REF_invokeStatic, implClass, methodName, type);
} }

View file

@ -472,8 +472,7 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
* @since 9 * @since 9
*/ */
public abstract sealed class VarHandle implements Constable public abstract sealed class VarHandle implements Constable
permits IndirectVarHandle, LazyInitializingVarHandle, permits IndirectVarHandle, LazyInitializingVarHandle, SegmentVarHandle,
VarHandleSegmentViewBase,
VarHandleByteArrayAsChars.ByteArrayViewVarHandle, VarHandleByteArrayAsChars.ByteArrayViewVarHandle,
VarHandleByteArrayAsDoubles.ByteArrayViewVarHandle, VarHandleByteArrayAsDoubles.ByteArrayViewVarHandle,
VarHandleByteArrayAsFloats.ByteArrayViewVarHandle, VarHandleByteArrayAsFloats.ByteArrayViewVarHandle,

View file

@ -1,55 +0,0 @@
/*
* Copyright (c) 2019, 2024, 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.
*/
package java.lang.invoke;
/**
* Base class for memory segment var handle view implementations.
*/
abstract sealed class VarHandleSegmentViewBase extends VarHandle permits
VarHandleSegmentAsBytes,
VarHandleSegmentAsChars,
VarHandleSegmentAsDoubles,
VarHandleSegmentAsFloats,
VarHandleSegmentAsInts,
VarHandleSegmentAsLongs,
VarHandleSegmentAsShorts {
/** endianness **/
final boolean be;
/** alignment constraint (in bytes, expressed as a bit mask) **/
final long alignmentMask;
VarHandleSegmentViewBase(VarForm form, boolean be, long alignmentMask, boolean exact) {
super(form, exact);
this.be = be;
this.alignmentMask = alignmentMask;
}
static UnsupportedOperationException newUnsupportedAccessModeForAlignment(long alignment) {
return new UnsupportedOperationException("Unsupported access mode for alignment: " + alignment);
}
}

View file

@ -27,6 +27,7 @@ package java.lang.invoke;
import sun.invoke.util.Wrapper; import sun.invoke.util.Wrapper;
import java.lang.foreign.MemoryLayout;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -291,44 +292,55 @@ final class VarHandles {
} }
/** /**
* Creates a memory segment view var handle. * Creates a memory segment view var handle accessing a {@code carrier} element. It has access coordinates
* * {@code (MS, long)} if {@code constantOffset}, {@code (MS, long, (validated) long)} otherwise.
* <p>
* The resulting var handle will take a memory segment as first argument (the segment to be dereferenced), * The resulting var handle will take a memory segment as first argument (the segment to be dereferenced),
* and a {@code long} as second argument (the offset into the segment). * and a {@code long} as second argument (the offset into the segment). Both arguments are checked.
* <p>
* If {@code constantOffset == false}, the resulting var handle will take a third pre-validated additional
* offset instead of the given fixed {@code offset}, and caller must ensure that passed additional offset,
* either to the handle (such as computing through method handles) or as fixed {@code offset} here, is valid.
* *
* Note: the returned var handle does not perform any size or alignment check. It is up to clients * @param carrier the Java carrier type of the element
* to adapt the returned var handle and insert the appropriate checks. * @param enclosing the enclosing layout to perform bound and alignment checks against
* * @param alignmentMask alignment of this accessed element in the enclosing layout
* @param carrier the Java carrier type. * @param constantOffset if access path has a constant offset value, i.e. it has no strides
* @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask. * @param offset the offset value, if the offset is constant
* @param byteOrder the byte order. * @param byteOrder the byte order
* @return the created VarHandle. * @return the created var handle
*/ */
static VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask, static VarHandle memorySegmentViewHandle(Class<?> carrier, MemoryLayout enclosing, long alignmentMask,
ByteOrder byteOrder) { boolean constantOffset, long offset, ByteOrder byteOrder) {
if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) { if (!carrier.isPrimitive() || carrier == void.class) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName()); throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
} }
boolean be = byteOrder == ByteOrder.BIG_ENDIAN; boolean be = byteOrder == ByteOrder.BIG_ENDIAN;
boolean exact = VAR_HANDLE_SEGMENT_FORCE_EXACT; boolean exact = VAR_HANDLE_SEGMENT_FORCE_EXACT;
// All carrier types must persist across MethodType erasure
VarForm form;
if (carrier == byte.class) { if (carrier == byte.class) {
return maybeAdapt(new VarHandleSegmentAsBytes(be, alignmentMask, exact)); form = VarHandleSegmentAsBytes.selectForm(alignmentMask, constantOffset);
} else if (carrier == char.class) { } else if (carrier == char.class) {
return maybeAdapt(new VarHandleSegmentAsChars(be, alignmentMask, exact)); form = VarHandleSegmentAsChars.selectForm(alignmentMask, constantOffset);
} else if (carrier == short.class) { } else if (carrier == short.class) {
return maybeAdapt(new VarHandleSegmentAsShorts(be, alignmentMask, exact)); form = VarHandleSegmentAsShorts.selectForm(alignmentMask, constantOffset);
} else if (carrier == int.class) { } else if (carrier == int.class) {
return maybeAdapt(new VarHandleSegmentAsInts(be, alignmentMask, exact)); form = VarHandleSegmentAsInts.selectForm(alignmentMask, constantOffset);
} else if (carrier == float.class) { } else if (carrier == float.class) {
return maybeAdapt(new VarHandleSegmentAsFloats(be, alignmentMask, exact)); form = VarHandleSegmentAsFloats.selectForm(alignmentMask, constantOffset);
} else if (carrier == long.class) { } else if (carrier == long.class) {
return maybeAdapt(new VarHandleSegmentAsLongs(be, alignmentMask, exact)); form = VarHandleSegmentAsLongs.selectForm(alignmentMask, constantOffset);
} else if (carrier == double.class) { } else if (carrier == double.class) {
return maybeAdapt(new VarHandleSegmentAsDoubles(be, alignmentMask, exact)); form = VarHandleSegmentAsDoubles.selectForm(alignmentMask, constantOffset);
} else if (carrier == boolean.class) {
form = VarHandleSegmentAsBooleans.selectForm(alignmentMask, constantOffset);
} else { } else {
throw new IllegalStateException("Cannot get here"); throw new IllegalStateException("Cannot get here");
} }
return maybeAdapt(new SegmentVarHandle(form, be, enclosing, offset, exact));
} }
private static VarHandle maybeAdapt(VarHandle target) { private static VarHandle maybeAdapt(VarHandle target) {
@ -724,7 +736,7 @@ final class VarHandles {
// Object getAndUpdate(Object value); // Object getAndUpdate(Object value);
// } // }
// //
// record HandleType(Class<?> receiver, Class<?> value, Class<?>... intermediates) { // record HandleType(Class<?> receiver, Class<?>... intermediates) {
// } // }
// //
// /** // /**
@ -744,48 +756,31 @@ final class VarHandles {
// System.out.println(); // System.out.println();
// //
// // Declare the stream of shapes // // Declare the stream of shapes
// Stream<HandleType> hts = Stream.of( // List<HandleType> hts = List.of(
// // Object->Object // // Object->T
// new HandleType(Object.class, Object.class), // new HandleType(Object.class),
// // Object->int //
// // <static>->T
// new HandleType(null),
//
// // Array[index]->T
// new HandleType(Object.class, int.class), // new HandleType(Object.class, int.class),
// // Object->long //
// // MS[base]->T
// new HandleType(Object.class, long.class), // new HandleType(Object.class, long.class),
// // Object->float
// new HandleType(Object.class, float.class),
// // Object->double
// new HandleType(Object.class, double.class),
// //
// // <static>->Object // // MS[base][offset]->T
// new HandleType(null, Object.class),
// // <static>->int
// new HandleType(null, int.class),
// // <static>->long
// new HandleType(null, long.class),
// // <static>->float
// new HandleType(null, float.class),
// // <static>->double
// new HandleType(null, double.class),
//
// // Array[int]->Object
// new HandleType(Object.class, Object.class, int.class),
// // Array[int]->int
// new HandleType(Object.class, int.class, int.class),
// // Array[int]->long
// new HandleType(Object.class, long.class, int.class),
// // Array[int]->float
// new HandleType(Object.class, float.class, int.class),
// // Array[int]->double
// new HandleType(Object.class, double.class, int.class),
//
// // Array[long]->int
// new HandleType(Object.class, int.class, long.class),
// // Array[long]->long
// new HandleType(Object.class, long.class, long.class) // new HandleType(Object.class, long.class, long.class)
// ); // );
// //
// hts.flatMap(ht -> Stream.of(VarHandleTemplate.class.getMethods()). // Stream.of(VarHandleTemplate.class.getMethods()).<MethodType>
// map(m -> generateMethodType(m, ht.receiver, ht.value, ht.intermediates))). // mapMulti((m, sink) -> {
// for (var ht : hts) {
// for (var bt : LambdaForm.BasicType.ARG_TYPES) {
// sink.accept(generateMethodType(m, ht.receiver, bt.btClass, ht.intermediates));
// }
// }
// }).
// distinct(). // distinct().
// map(GuardMethodGenerator::generateMethod). // map(GuardMethodGenerator::generateMethod).
// forEach(System.out::println); // forEach(System.out::println);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,53 +25,106 @@
package java.lang.invoke; package java.lang.invoke;
import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.AbstractMemorySegmentImpl;
import jdk.internal.foreign.Utils;
import jdk.internal.misc.ScopedMemoryAccess;
import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.ForceInline;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySegment;
import java.lang.ref.Reference;
import java.util.Objects; import static java.lang.invoke.SegmentVarHandle.*;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
#warn #warn
final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase { {#if[byte]?final:sealed} class VarHandleSegmentAs$Type$s {
static final boolean BE = UNSAFE.isBigEndian();
static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
#if[!byte]
static final int NON_PLAIN_ACCESS_MIN_ALIGN_MASK = $BoxType$.BYTES - 1; static final int NON_PLAIN_ACCESS_MIN_ALIGN_MASK = $BoxType$.BYTES - 1;
static final VarForm FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class); #end[byte]
static VarForm selectForm(long alignmentMask, boolean constantOffset) {
VarHandleSegmentAs$Type$s(boolean be, long alignmentMask, boolean exact) { #if[byte]
super(FORM, be, alignmentMask, exact); return constantOffset ? CONSTANT_OFFSET_FORM : VARIABLE_OFFSET_FORM;
#else[byte]
return (alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK ?
(constantOffset ? CONSTANT_OFFSET_FORM : VARIABLE_OFFSET_FORM) :
(constantOffset ? VarHandleSegmentAs$Type$sAligned.CONSTANT_OFFSET_FORM : VarHandleSegmentAs$Type$sAligned.VARIABLE_OFFSET_FORM);
#end[byte]
} }
@Override static final VarForm CONSTANT_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class);
final MethodType accessModeTypeUncached(VarHandle.AccessType accessType) { static final VarForm VARIABLE_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$s.class, MemorySegment.class, $type$.class, long.class, long.class);
return accessType.accessModeType(MemorySegment.class, $type$.class, MemoryLayout.class, long.class, long.class);
VarHandleSegmentAs$Type$s() { throw new AssertionError(); }
@ForceInline
static $type$ get(VarHandle ob, Object obb, long base) {
return get(ob, obb, base, ((SegmentVarHandle) ob).offset);
} }
@Override @ForceInline
public VarHandleSegmentAs$Type$s withInvokeExactBehavior() { static $type$ get(VarHandle ob, Object obb, long base, long offset) {
return hasInvokeExactBehavior() ? SegmentVarHandle handle = (SegmentVarHandle)ob;
this : AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true);
new VarHandleSegmentAs$Type$s(be, alignmentMask, true); #if[floatingPoint]
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset));
#else[byte]
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset),
handle.be);
#end[byte]
#end[floatingPoint]
} }
@Override @ForceInline
public VarHandleSegmentAs$Type$s withInvokeBehavior() { static void set(VarHandle ob, Object obb, long base, $type$ value) {
return !hasInvokeExactBehavior() ? set(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
this :
new VarHandleSegmentAs$Type$s(be, alignmentMask, false);
} }
@ForceInline
static void set(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[floatingPoint]
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset),
value);
#else[byte]
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset),
value,
handle.be);
#end[byte]
#end[floatingPoint]
}
#if[!byte]
}
// This class must be accessed through non-aligned VarHandleSegmentAs$Type$s
final class VarHandleSegmentAs$Type$sAligned extends VarHandleSegmentAs$Type$s {
static final VarForm CONSTANT_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$sAligned.class, VarHandleSegmentAs$Type$s.CONSTANT_OFFSET_FORM);
static final VarForm VARIABLE_OFFSET_FORM = new VarForm(VarHandleSegmentAs$Type$sAligned.class, VarHandleSegmentAs$Type$s.VARIABLE_OFFSET_FORM);
VarHandleSegmentAs$Type$sAligned() { throw new AssertionError(); }
#end[byte]
#if[floatingPoint] #if[floatingPoint]
@ForceInline @ForceInline
static $rawType$ convEndian(boolean big, $type$ v) { static $rawType$ convEndian(boolean big, $type$ v) {
@ -99,296 +152,338 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
#end[floatingPoint] #end[floatingPoint]
@ForceInline @ForceInline
static AbstractMemorySegmentImpl checkSegment(Object obb, Object encl, long base, boolean ro) { static $type$ getVolatile(VarHandle ob, Object obb, long base) {
AbstractMemorySegmentImpl oo = (AbstractMemorySegmentImpl)Objects.requireNonNull(obb); return getVolatile(ob, obb, base, ((SegmentVarHandle) ob).offset);
oo.checkEnclosingLayout(base, (MemoryLayout)encl, ro);
return oo;
} }
@ForceInline @ForceInline
static long offsetNonPlain(AbstractMemorySegmentImpl bb, long base, long offset, long alignmentMask) { static $type$ getVolatile(VarHandle ob, Object obb, long base, long offset) {
if ((alignmentMask & NON_PLAIN_ACCESS_MIN_ALIGN_MASK) != NON_PLAIN_ACCESS_MIN_ALIGN_MASK) { SegmentVarHandle handle = (SegmentVarHandle)ob;
throw VarHandleSegmentViewBase.newUnsupportedAccessModeForAlignment(alignmentMask + 1); AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true);
}
return offsetPlain(bb, base, offset);
}
@ForceInline
static long offsetPlain(AbstractMemorySegmentImpl bb, long base, long offset) {
long segment_base = bb.unsafeGetOffset();
return segment_base + base + offset;
}
@ForceInline
static $type$ get(VarHandle ob, Object obb, Object encl, long base, long offset) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true);
#if[floatingPoint]
$rawType$ rawValue = SCOPED_MEMORY_ACCESS.get$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
return SCOPED_MEMORY_ACCESS.get$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset));
#else[byte]
return SCOPED_MEMORY_ACCESS.get$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset),
handle.be);
#end[byte]
#end[floatingPoint]
}
@ForceInline
static void set(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false);
#if[floatingPoint]
SCOPED_MEMORY_ACCESS.put$RawType$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
SCOPED_MEMORY_ACCESS.put$Type$(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset),
value);
#else[byte]
SCOPED_MEMORY_ACCESS.put$Type$Unaligned(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetPlain(bb, base, offset),
value,
handle.be);
#end[byte]
#end[floatingPoint]
}
@ForceInline
static $type$ getVolatile(VarHandle ob, Object obb, Object encl, long base, long offset) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob;
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask))); offset(bb, base, offset)));
} }
@ForceInline @ForceInline
static void setVolatile(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static void setVolatile(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; setVolatile(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static void setVolatile(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.put$RawType$Volatile(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value)); convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static $type$ getAcquire(VarHandle ob, Object obb, Object encl, long base, long offset) { static $type$ getAcquire(VarHandle ob, Object obb, long base) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true); }
@ForceInline
static $type$ getAcquire(VarHandle ob, Object obb, long base, long offset) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.get$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask))); offset(bb, base, offset)));
} }
@ForceInline @ForceInline
static void setRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static void setRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; setRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static void setRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.put$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value)); convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static $type$ getOpaque(VarHandle ob, Object obb, Object encl, long base, long offset) { static $type$ getOpaque(VarHandle ob, Object obb, long base) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getOpaque(ob, obb, base, ((SegmentVarHandle) ob).offset);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, true);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask)));
} }
@ForceInline @ForceInline
static void setOpaque(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getOpaque(VarHandle ob, Object obb, long base, long offset) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, true);
return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.get$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(),
offset(bb, base, offset)));
}
@ForceInline
static void setOpaque(VarHandle ob, Object obb, long base, $type$ value) {
setOpaque(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
}
@ForceInline
static void setOpaque(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.put$RawType$Opaque(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value)); convEndian(handle.be, value));
} }
#if[CAS] #if[CAS]
@ForceInline @ForceInline
static boolean compareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static boolean compareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return compareAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static boolean compareAndSet(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.compareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static $type$ compareAndExchange(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static $type$ compareAndExchange(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return compareAndExchange(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ compareAndExchange(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value))); convEndian(handle.be, expected), convEndian(handle.be, value)));
} }
@ForceInline @ForceInline
static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return compareAndExchangeAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ compareAndExchangeAcquire(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value))); convEndian(handle.be, expected), convEndian(handle.be, value)));
} }
@ForceInline @ForceInline
static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return compareAndExchangeRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ compareAndExchangeRelease(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.compareAndExchange$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value))); convEndian(handle.be, expected), convEndian(handle.be, value)));
} }
@ForceInline @ForceInline
static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return weakCompareAndSetPlain(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static boolean weakCompareAndSetPlain(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Plain(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static boolean weakCompareAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return weakCompareAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static boolean weakCompareAndSet(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return weakCompareAndSetAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static boolean weakCompareAndSetAcquire(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ expected, $type$ value) { static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, $type$ expected, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return weakCompareAndSetRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, expected, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static boolean weakCompareAndSetRelease(VarHandle ob, Object obb, long base, long offset, $type$ expected, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, expected), convEndian(handle.be, value)); convEndian(handle.be, expected), convEndian(handle.be, value));
} }
@ForceInline @ForceInline
static $type$ getAndSet(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndSet(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndSet(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndSet(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.getAndSet$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value))); convEndian(handle.be, value)));
} }
@ForceInline @ForceInline
static $type$ getAndSetAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndSetAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndSetAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.getAndSet$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value))); convEndian(handle.be, value)));
} }
@ForceInline @ForceInline
static $type$ getAndSetRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndSetRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndSetRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
return convEndian(handle.be, return convEndian(handle.be,
SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(), SCOPED_MEMORY_ACCESS.getAndSet$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
convEndian(handle.be, value))); convEndian(handle.be, value)));
} }
#end[CAS] #end[CAS]
#if[AtomicAdd] #if[AtomicAdd]
@ForceInline @ForceInline
static $type$ getAndAdd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { static $type$ getAndAdd(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndAdd(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndAdd(VarHandle ob, Object obb, long base, long offset, $type$ delta) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
delta); delta);
#if[!byte]
} else { } else {
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndAddAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndAddAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndAddAcquire(VarHandle ob, Object obb, long base, long offset, $type$ delta) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
delta); delta);
#if[!byte]
} else { } else {
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndAddRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ delta) { static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndAddRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndAddRelease(VarHandle ob, Object obb, long base, long offset, $type$ delta) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndAdd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
delta); delta);
#if[!byte]
} else { } else {
return getAndAddConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), delta); return getAndAddConvEndianWithCAS(bb, offset(bb, base, offset), delta);
} }
#end[byte]
} }
#if[!byte]
@ForceInline @ForceInline
static $type$ getAndAddConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ delta) { static $type$ getAndAddConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ delta) {
@ -398,53 +493,82 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta))); nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue + delta))));
return expectedValue; return expectedValue;
} }
#end[byte]
#end[AtomicAdd] #end[AtomicAdd]
#if[Bitwise] #if[Bitwise]
@ForceInline @ForceInline
static $type$ getAndBitwiseOr(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseOr(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseOr(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseOrRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseOrRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseOrAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseOrAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseOr$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseOrConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
#if[!byte]
@ForceInline @ForceInline
static $type$ getAndBitwiseOrConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { static $type$ getAndBitwiseOrConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
@ -454,51 +578,81 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value))); nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue | value))));
return expectedValue; return expectedValue;
} }
#end[byte]
@ForceInline @ForceInline
static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseAnd(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseAnd(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseAndRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseAndRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseAndAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseAndAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseAnd$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseAndConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
#if[!byte]
@ForceInline @ForceInline
static $type$ getAndBitwiseAndConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { static $type$ getAndBitwiseAndConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
@ -508,52 +662,80 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value))); nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue & value))));
return expectedValue; return expectedValue;
} }
#end[byte]
@ForceInline @ForceInline
static $type$ getAndBitwiseXor(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseXor(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseXor(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseXorRelease(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseXorRelease(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Release(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
@ForceInline @ForceInline
static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, Object encl, long base, long offset, $type$ value) { static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, $type$ value) {
VarHandleSegmentViewBase handle = (VarHandleSegmentViewBase)ob; return getAndBitwiseXorAcquire(ob, obb, base, ((SegmentVarHandle) ob).offset, value);
AbstractMemorySegmentImpl bb = checkSegment(obb, encl, base, false); }
@ForceInline
static $type$ getAndBitwiseXorAcquire(VarHandle ob, Object obb, long base, long offset, $type$ value) {
SegmentVarHandle handle = (SegmentVarHandle)ob;
AbstractMemorySegmentImpl bb = handle.checkSegment(obb, base, false);
#if[!byte]
if (handle.be == BE) { if (handle.be == BE) {
#end[byte]
return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(), return SCOPED_MEMORY_ACCESS.getAndBitwiseXor$RawType$Acquire(bb.sessionImpl(),
bb.unsafeGetBase(), bb.unsafeGetBase(),
offsetNonPlain(bb, base, offset, handle.alignmentMask), offset(bb, base, offset),
value); value);
#if[!byte]
} else { } else {
return getAndBitwiseXorConvEndianWithCAS(bb, offsetNonPlain(bb, base, offset, handle.alignmentMask), value); return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, offset), value);
} }
#end[byte]
} }
#if[!byte]
@ForceInline @ForceInline
static $type$ getAndBitwiseXorConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) { static $type$ getAndBitwiseXorConvEndianWithCAS(AbstractMemorySegmentImpl bb, long offset, $type$ value) {
@ -563,8 +745,9 @@ final class VarHandleSegmentAs$Type$s extends VarHandleSegmentViewBase {
nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset); nativeExpectedValue = SCOPED_MEMORY_ACCESS.get$RawType$Volatile(bb.sessionImpl(),base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue); expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset, } while (!SCOPED_MEMORY_ACCESS.weakCompareAndSet$RawType$(bb.sessionImpl(),base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value))); nativeExpectedValue, $RawBoxType$.reverseBytes({#if[ShorterThanInt]?($type$) }(expectedValue ^ value))));
return expectedValue; return expectedValue;
} }
#end[byte]
#end[Bitwise] #end[Bitwise]
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,8 +27,8 @@ package jdk.internal.access;
import jdk.internal.foreign.abi.NativeEntryPoint; import jdk.internal.foreign.abi.NativeEntryPoint;
import java.lang.foreign.MemoryLayout;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType; import java.lang.invoke.MethodType;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -75,7 +75,7 @@ public interface JavaLangInvokeAccess {
* Used by {@code jdk.internal.foreign.LayoutPath} and * Used by {@code jdk.internal.foreign.LayoutPath} and
* {@code java.lang.invoke.MethodHandles}. * {@code java.lang.invoke.MethodHandles}.
*/ */
VarHandle memorySegmentViewHandle(Class<?> carrier, long alignmentMask, ByteOrder order); VarHandle memorySegmentViewHandle(Class<?> carrier, MemoryLayout enclosing, long alignmentMask, ByteOrder order, boolean constantOffset, long offset);
/** /**
* Var handle carrier combinator. * Var handle carrier combinator.

View file

@ -59,6 +59,7 @@ public class LayoutPath {
private static final long[] EMPTY_STRIDES = new long[0]; private static final long[] EMPTY_STRIDES = new long[0];
private static final long[] EMPTY_BOUNDS = new long[0]; private static final long[] EMPTY_BOUNDS = new long[0];
private static final MethodHandle[] EMPTY_DEREF_HANDLES = new MethodHandle[0]; private static final MethodHandle[] EMPTY_DEREF_HANDLES = new MethodHandle[0];
public static final MemoryLayout.PathElement[] EMPTY_PATH_ELEMENTS = new MemoryLayout.PathElement[0];
private static final MethodHandle MH_ADD_SCALED_OFFSET; private static final MethodHandle MH_ADD_SCALED_OFFSET;
private static final MethodHandle MH_SLICE; private static final MethodHandle MH_SLICE;
@ -205,15 +206,13 @@ public class LayoutPath {
String.format("Path does not select a value layout: %s", breadcrumbs())); String.format("Path does not select a value layout: %s", breadcrumbs()));
} }
VarHandle handle = Utils.makeRawSegmentViewVarHandle(valueLayout); // (MS, ML, long, long) boolean constantOffset = strides.length == 0;
handle = MethodHandles.insertCoordinates(handle, 1, rootLayout()); // (MS, long, long) // (MS, long, long) if variable offset, (MS, long) if constant offset
if (strides.length > 0) { VarHandle handle = Utils.makeRawSegmentViewVarHandle(rootLayout(), valueLayout, constantOffset, offset);
MethodHandle offsetAdapter = offsetHandle(); if (!constantOffset) {
MethodHandle offsetAdapter = offsetHandle(); // Adapter performs the bound checks
offsetAdapter = MethodHandles.insertArguments(offsetAdapter, 0, 0L); offsetAdapter = MethodHandles.insertArguments(offsetAdapter, 0, 0L);
handle = MethodHandles.collectCoordinates(handle, 2, offsetAdapter); // (MS, long) handle = MethodHandles.collectCoordinates(handle, 2, offsetAdapter); // (MS, long)
} else {
// simpler adaptation
handle = MethodHandles.insertCoordinates(handle, 2, offset); // (MS, long)
} }
if (adapt) { if (adapt) {

View file

@ -1,27 +1,26 @@
/* /*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 * under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this * published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided * particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code. * by Oracle in the LICENSE file that accompanied this code.
* *
* This code is distributed in the hope that it will be useful, but WITHOUT * This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * 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 * version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code). * accompanied this code).
* *
* You should have received a copy of the GNU General Public License version * 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, * 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * 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.
* *
* 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.
*/ */
package jdk.internal.foreign; package jdk.internal.foreign;
@ -34,7 +33,6 @@ import sun.invoke.util.Wrapper;
import java.lang.foreign.AddressLayout; import java.lang.foreign.AddressLayout;
import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemoryLayout.PathElement;
import java.lang.foreign.MemorySegment; import java.lang.foreign.MemorySegment;
import java.lang.foreign.StructLayout; import java.lang.foreign.StructLayout;
import java.lang.foreign.ValueLayout; import java.lang.foreign.ValueLayout;
@ -46,6 +44,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@ -56,25 +55,31 @@ public final class Utils {
// Suppresses default constructor, ensuring non-instantiability. // Suppresses default constructor, ensuring non-instantiability.
private Utils() {} private Utils() {}
private static final MethodHandle BYTE_TO_BOOL; private static final Class<?> ADDRESS_CARRIER_TYPE;
private static final MethodHandle BOOL_TO_BYTE; private static final MethodHandle LONG_TO_CARRIER;
private static final MethodHandle ADDRESS_TO_LONG;
private static final MethodHandle LONG_TO_ADDRESS_TARGET; private static final MethodHandle LONG_TO_ADDRESS_TARGET;
private static final MethodHandle LONG_TO_ADDRESS_NO_TARGET; private static final MethodHandle LONG_TO_ADDRESS_NO_TARGET;
static { static {
MethodHandles.Lookup lookup = MethodHandles.lookup();
String unboxSegmentName;
Class<?> rawAddressType;
if (Unsafe.getUnsafe().addressSize() == 8) {
unboxSegmentName = "unboxSegment";
rawAddressType = long.class;
} else {
assert Unsafe.getUnsafe().addressSize() == 4 : Unsafe.getUnsafe().addressSize();
unboxSegmentName = "unboxSegment32";
rawAddressType = int.class;
}
ADDRESS_CARRIER_TYPE = rawAddressType;
try { try {
MethodHandles.Lookup lookup = MethodHandles.lookup(); LONG_TO_CARRIER = lookup.findStatic(SharedUtils.class, unboxSegmentName,
BYTE_TO_BOOL = lookup.findStatic(Utils.class, "byteToBoolean", MethodType.methodType(rawAddressType, MemorySegment.class));
MethodType.methodType(boolean.class, byte.class));
BOOL_TO_BYTE = lookup.findStatic(Utils.class, "booleanToByte",
MethodType.methodType(byte.class, boolean.class));
ADDRESS_TO_LONG = lookup.findStatic(SharedUtils.class, "unboxSegment",
MethodType.methodType(long.class, MemorySegment.class));
LONG_TO_ADDRESS_TARGET = lookup.findStatic(Utils.class, "longToAddress", LONG_TO_ADDRESS_TARGET = lookup.findStatic(Utils.class, "longToAddress",
MethodType.methodType(MemorySegment.class, long.class, AddressLayout.class)); MethodType.methodType(MemorySegment.class, rawAddressType, AddressLayout.class));
LONG_TO_ADDRESS_NO_TARGET = lookup.findStatic(Utils.class, "longToAddress", LONG_TO_ADDRESS_NO_TARGET = lookup.findStatic(Utils.class, "longToAddress",
MethodType.methodType(MemorySegment.class, long.class)); MethodType.methodType(MemorySegment.class, rawAddressType));
} catch (Throwable ex) { } catch (Throwable ex) {
throw new ExceptionInInitializerError(ex); throw new ExceptionInInitializerError(ex);
} }
@ -90,48 +95,57 @@ public final class Utils {
} }
/** /**
* This method returns a <em>raw var handle</em>, that is, a var handle that does not perform any size * This method returns a var handle that accesses a target layout in an enclosing layout, taking the memory offset
* or alignment checks. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}. * and the base offset of the enclosing layout in the segment.
* <p>
* If the offset of the target layout in the enclosing layout is constant, the coordinates are (MS, long).
* If the offset of the target layout in the enclosing layout is variable, the coordinates are (MS, long, long).
* The trailing long is a pre-validated, variable extra offset, which the var handle does not perform any size or
* alignment checks against. Such checks are added (using adaptation) by {@link LayoutPath#dereferenceHandle()}.
* <p> * <p>
* We provide two level of caching of the generated var handles. First, the var handle associated * We provide two level of caching of the generated var handles. First, the var handle associated
* with a {@link ValueLayout#varHandle()} call is cached inside a stable field of the value layout implementation. * with a {@link ValueLayout#varHandle()} call is cached inside a stable field of the value layout implementation.
* This optimizes common code idioms like {@code JAVA_INT.varHandle().getInt(...)}. A second layer of caching * This optimizes common code idioms like {@code JAVA_INT.varHandle().getInt(...)}. A second layer of caching
* is then provided by this method: after all, var handles constructed by {@link MemoryLayout#varHandle(PathElement...)} * is then provided by this method, so different value layouts with same effects can reuse var handle instances.
* will be obtained by adapting some raw var handle generated by this method. * (The 2nd layer may be redundant in the long run)
* *
* @param layout the value layout for which a raw memory segment var handle is to be created. * @param enclosing the enclosing context of the value layout
* @return a raw memory segment var handle. * @param layout the value layout for which a raw memory segment var handle is to be created
* @param constantOffset if the VH carries a constant offset instead of taking a variable offset
* @param offset the offset if it is a constant
* @return a raw memory segment var handle
*/ */
public static VarHandle makeRawSegmentViewVarHandle(ValueLayout layout) { public static VarHandle makeRawSegmentViewVarHandle(MemoryLayout enclosing, ValueLayout layout, boolean constantOffset, long offset) {
final class VarHandleCache { if (enclosing instanceof ValueLayout direct) {
private static final Map<ValueLayout, VarHandle> HANDLE_MAP = new ConcurrentHashMap<>(); assert direct.equals(layout) && constantOffset && offset == 0;
record VarHandleCache() implements Function<ValueLayout, VarHandle> {
private static final Map<ValueLayout, VarHandle> HANDLE_MAP = new ConcurrentHashMap<>();
private static final VarHandleCache INSTANCE = new VarHandleCache();
@Override
public VarHandle apply(ValueLayout valueLayout) {
return Utils.makeRawSegmentViewVarHandleInternal(valueLayout, valueLayout, true, 0);
}
}
return VarHandleCache.HANDLE_MAP.computeIfAbsent(direct.withoutName(), VarHandleCache.INSTANCE);
} }
return VarHandleCache.HANDLE_MAP return makeRawSegmentViewVarHandleInternal(enclosing, layout, constantOffset, offset);
.computeIfAbsent(layout.withoutName(), Utils::makeRawSegmentViewVarHandleInternal);
} }
private static VarHandle makeRawSegmentViewVarHandleInternal(ValueLayout layout) { private static VarHandle makeRawSegmentViewVarHandleInternal(MemoryLayout enclosing, ValueLayout layout, boolean constantOffset, long offset) {
Class<?> baseCarrier = layout.carrier(); Class<?> baseCarrier = layout.carrier();
if (layout.carrier() == MemorySegment.class) { if (layout.carrier() == MemorySegment.class) {
baseCarrier = switch ((int) ValueLayout.ADDRESS.byteSize()) { baseCarrier = ADDRESS_CARRIER_TYPE;
case Long.BYTES -> long.class;
case Integer.BYTES -> int.class;
default -> throw new UnsupportedOperationException("Unsupported address layout");
};
} else if (layout.carrier() == boolean.class) {
baseCarrier = byte.class;
} }
VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier, VarHandle handle = SharedSecrets.getJavaLangInvokeAccess().memorySegmentViewHandle(baseCarrier,
layout.byteAlignment() - 1, layout.order()); enclosing, layout.byteAlignment() - 1, layout.order(), constantOffset, offset);
if (layout.carrier() == boolean.class) { if (layout instanceof AddressLayout addressLayout) {
handle = MethodHandles.filterValue(handle, BOOL_TO_BYTE, BYTE_TO_BOOL);
} else if (layout instanceof AddressLayout addressLayout) {
MethodHandle longToAddressAdapter = addressLayout.targetLayout().isPresent() ? MethodHandle longToAddressAdapter = addressLayout.targetLayout().isPresent() ?
MethodHandles.insertArguments(LONG_TO_ADDRESS_TARGET, 1, addressLayout) : MethodHandles.insertArguments(LONG_TO_ADDRESS_TARGET, 1, addressLayout) :
LONG_TO_ADDRESS_NO_TARGET; LONG_TO_ADDRESS_NO_TARGET;
handle = MethodHandles.filterValue(handle, ADDRESS_TO_LONG, longToAddressAdapter); handle = MethodHandles.filterValue(handle, LONG_TO_CARRIER, longToAddressAdapter);
} }
return handle; return handle;
} }
@ -149,11 +163,23 @@ public final class Utils {
return longToAddress(addr, 0, 1); return longToAddress(addr, 0, 1);
} }
// 32 bit
@ForceInline
public static MemorySegment longToAddress(int addr) {
return longToAddress(addr, 0, 1);
}
@ForceInline @ForceInline
public static MemorySegment longToAddress(long addr, AddressLayout layout) { public static MemorySegment longToAddress(long addr, AddressLayout layout) {
return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout)); return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout));
} }
// 32 bit
@ForceInline
public static MemorySegment longToAddress(int addr, AddressLayout layout) {
return longToAddress(addr, pointeeByteSize(layout), pointeeByteAlign(layout));
}
@ForceInline @ForceInline
public static MemorySegment longToAddress(long addr, long size, long align) { public static MemorySegment longToAddress(long addr, long size, long align) {
if (!isAligned(addr, align)) { if (!isAligned(addr, align)) {

View file

@ -321,11 +321,20 @@ public final class SharedUtils {
} }
} }
@ForceInline
public static long unboxSegment(MemorySegment segment) { public static long unboxSegment(MemorySegment segment) {
checkNative(segment); checkNative(segment);
return segment.address(); return segment.address();
} }
@ForceInline
public static int unboxSegment32(MemorySegment segment) {
// This cast to 'int' is safe, because we only call this method on 32-bit
// platforms, where we know the address of a segment is truncated to 32-bits.
// There's a similar cast for 4-byte addresses in Unsafe.putAddress.
return (int) unboxSegment(segment);
}
public static void checkExceptions(MethodHandle target) { public static void checkExceptions(MethodHandle target) {
Class<?>[] exceptions = JLIA.exceptionTypes(target); Class<?>[] exceptions = JLIA.exceptionTypes(target);
if (exceptions != null && exceptions.length != 0) { if (exceptions != null && exceptions.length != 0) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
*/ */
package jdk.internal.foreign.layout; package jdk.internal.foreign.layout;
import jdk.internal.foreign.LayoutPath;
import jdk.internal.foreign.Utils; import jdk.internal.foreign.Utils;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.CallerSensitive;
@ -38,10 +39,8 @@ import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout; import java.lang.foreign.ValueLayout;
import java.lang.invoke.VarHandle; import java.lang.invoke.VarHandle;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as <em>integral</em> types * A value layout. A value layout is used to model the memory layout associated with values of basic data types, such as <em>integral</em> types
@ -159,19 +158,13 @@ public final class ValueLayouts {
@ForceInline @ForceInline
public final VarHandle varHandle() { public final VarHandle varHandle() {
final class VarHandleCache { var vh = handle;
private static final Map<ValueLayout, VarHandle> HANDLE_MAP = new ConcurrentHashMap<>(); if (vh == null) {
vh = varHandleInternal(LayoutPath.EMPTY_PATH_ELEMENTS);
// benign race stable field store is safe because VarHandle is thread safe
handle = vh;
} }
if (handle == null) { return vh;
// this store to stable field is safe, because return value of 'makeMemoryAccessVarHandle' has stable identity
handle = VarHandleCache.HANDLE_MAP.computeIfAbsent(self().withoutName(), _ -> varHandleInternal());
}
return handle;
}
@SuppressWarnings("unchecked")
final V self() {
return (V) this;
} }
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -33,6 +33,9 @@ import java.lang.invoke.VarHandle;
/** /**
* Static factories for certain VarHandle/MethodHandle variants. * Static factories for certain VarHandle/MethodHandle variants.
* <p> * <p>
* Some methods take no receiver argument. In these cases, the receiver is the
* lookup class.
* <p>
* The methods will throw an {@link InternalError} if the lookup fails. * The methods will throw an {@link InternalError} if the lookup fails.
* <p> * <p>
* Here is an example of how one of these methods could be used: * Here is an example of how one of these methods could be used:
@ -63,6 +66,11 @@ public final class MhUtil {
} }
} }
public static MethodHandle findVirtual(MethodHandles.Lookup lookup,
String name,
MethodType type) {
return findVirtual(lookup, lookup.lookupClass(), name, type);
}
public static MethodHandle findVirtual(MethodHandles.Lookup lookup, public static MethodHandle findVirtual(MethodHandles.Lookup lookup,
Class<?> refc, Class<?> refc,
@ -75,4 +83,21 @@ public final class MhUtil {
} }
} }
public static MethodHandle findStatic(MethodHandles.Lookup lookup,
String name,
MethodType type) {
return findStatic(lookup, lookup.lookupClass(), name, type);
}
public static MethodHandle findStatic(MethodHandles.Lookup lookup,
Class<?> refc,
String name,
MethodType type) {
try {
return lookup.findStatic(refc, name, type);
} catch (ReflectiveOperationException e) {
throw new InternalError(e);
}
}
} }

View file

@ -75,7 +75,7 @@ import jdk.internal.vm.vector.VectorSupport;
* which might be deemed to expensive; in other words, this approach prioritizes the performance of memory access over * which might be deemed to expensive; in other words, this approach prioritizes the performance of memory access over
* that of releasing a shared memory resource. * that of releasing a shared memory resource.
*/ */
public class ScopedMemoryAccess { public final class ScopedMemoryAccess {
private static final Unsafe UNSAFE = Unsafe.getUnsafe(); private static final Unsafe UNSAFE = Unsafe.getUnsafe();

View file

@ -61,6 +61,7 @@ public class TestAccessModes {
// access is unaligned // access is unaligned
assertTrue(segment.maxByteAlignment() < layout.byteAlignment()); assertTrue(segment.maxByteAlignment() < layout.byteAlignment());
} }
assertEquals(varHandle.isAccessModeSupported(mode), compatible);
} }
static ValueLayout accessLayout(MemoryLayout layout) { static ValueLayout accessLayout(MemoryLayout layout) {