8234049: Implementation of Memory Access API (Incubator)

Co-authored-by: Vlaidmir Ivanov <vladimir.x.ivanov@oracle.com>
Reviewed-by: alanb, psandoz, chegar, rriggs, plevart, briangoetz, jrose, adinn, vlivanov
This commit is contained in:
Jorn Vernee 2019-12-12 22:59:57 +00:00 committed by Maurizio Cimadamore
parent 7cdecd8981
commit 8f4f088a12
59 changed files with 7849 additions and 147 deletions

View file

@ -0,0 +1,494 @@
/*
* Copyright (c) 2019, 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 jdk.internal.access.foreign.MemoryAddressProxy;
import jdk.internal.misc.Unsafe;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.util.TraceClassVisitor;
import jdk.internal.vm.annotation.ForceInline;
import sun.security.action.GetBooleanAction;
import sun.security.action.GetPropertyAction;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_FINAL;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PRIVATE;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.ACC_SUPER;
import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH;
import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST;
import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_1;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_2;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_3;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_4;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_5;
import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_M1;
import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static jdk.internal.org.objectweb.asm.Opcodes.LADD;
import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD;
import static jdk.internal.org.objectweb.asm.Opcodes.LMUL;
import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD;
import static jdk.internal.org.objectweb.asm.Opcodes.RETURN;
import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH;
import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
class AddressVarHandleGenerator {
private static final String DEBUG_DUMP_CLASSES_DIR_PROPERTY = "jdk.internal.foreign.ClassGenerator.DEBUG_DUMP_CLASSES_DIR";
private static final boolean DEBUG =
GetBooleanAction.privilegedGetProperty("jdk.internal.foreign.ClassGenerator.DEBUG");
private static final Class<?> BASE_CLASS = VarHandleMemoryAddressBase.class;
private static final HashMap<Class<?>, Class<?>> helperClassCache;
static {
helperClassCache = new HashMap<>();
helperClassCache.put(byte.class, VarHandleMemoryAddressAsBytes.class);
helperClassCache.put(short.class, VarHandleMemoryAddressAsShorts.class);
helperClassCache.put(char.class, VarHandleMemoryAddressAsChars.class);
helperClassCache.put(int.class, VarHandleMemoryAddressAsInts.class);
helperClassCache.put(long.class, VarHandleMemoryAddressAsLongs.class);
helperClassCache.put(float.class, VarHandleMemoryAddressAsFloats.class);
helperClassCache.put(double.class, VarHandleMemoryAddressAsDoubles.class);
}
private static final File DEBUG_DUMP_CLASSES_DIR;
static {
String path = GetPropertyAction.privilegedGetProperty(DEBUG_DUMP_CLASSES_DIR_PROPERTY);
if (path == null) {
DEBUG_DUMP_CLASSES_DIR = null;
} else {
DEBUG_DUMP_CLASSES_DIR = new File(path);
}
}
private static final Unsafe U = Unsafe.getUnsafe();
private final String implClassName;
private final int dimensions;
private final Class<?> carrier;
private final Class<?> helperClass;
private final VarForm form;
AddressVarHandleGenerator(Class<?> carrier, int dims) {
this.dimensions = dims;
this.carrier = carrier;
Class<?>[] components = new Class<?>[dimensions];
Arrays.fill(components, long.class);
this.form = new VarForm(BASE_CLASS, MemoryAddressProxy.class, carrier, components);
this.helperClass = helperClassCache.get(carrier);
this.implClassName = helperClass.getName().replace('.', '/') + dimensions;
}
/*
* Generate a VarHandle memory access factory.
* The factory has type (ZJJ[J)VarHandle.
*/
MethodHandle generateHandleFactory() {
Class<?> implCls = generateClass();
try {
Class<?>[] components = new Class<?>[dimensions];
Arrays.fill(components, long.class);
VarForm form = new VarForm(implCls, MemoryAddressProxy.class, carrier, components);
MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
MethodHandle constr = MethodHandles.Lookup.IMPL_LOOKUP.findConstructor(implCls, constrType);
constr = MethodHandles.insertArguments(constr, 0, form);
return constr;
} catch (Throwable ex) {
throw new AssertionError(ex);
}
}
/*
* Generate a specialized VarHandle class for given carrier
* and access coordinates.
*/
Class<?> generateClass() {
BinderClassWriter cw = new BinderClassWriter();
if (DEBUG) {
System.out.println("Generating header implementation class");
}
cw.visit(52, ACC_PUBLIC | ACC_SUPER, implClassName, null, Type.getInternalName(BASE_CLASS), null);
//add dimension fields
for (int i = 0; i < dimensions; i++) {
cw.visitField(ACC_PRIVATE | ACC_FINAL, "dim" + i, "J", null, null);
}
addConstructor(cw);
addAccessModeTypeMethod(cw);
addStridesAccessor(cw);
addCarrierAccessor(cw);
for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) {
addAccessModeMethodIfNeeded(mode, cw);
}
cw.visitEnd();
byte[] classBytes = cw.toByteArray();
return defineClass(cw, classBytes);
}
void addConstructor(BinderClassWriter cw) {
MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class);
MethodVisitor mv = cw.visitMethod(0, "<init>", constrType.toMethodDescriptorString(), null, null);
mv.visitCode();
//super call
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VarForm.class));
mv.visitVarInsn(ILOAD, 2);
mv.visitVarInsn(LLOAD, 3);
mv.visitVarInsn(LLOAD, 5);
mv.visitVarInsn(LLOAD, 7);
mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(BASE_CLASS), "<init>",
MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class).toMethodDescriptorString(), false);
//init dimensions
for (int i = 0 ; i < dimensions ; i++) {
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 9);
mv.visitLdcInsn(i);
mv.visitInsn(LALOAD);
mv.visitFieldInsn(PUTFIELD, implClassName, "dim" + i, "J");
}
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
void addAccessModeTypeMethod(BinderClassWriter cw) {
MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessMode.class);
MethodVisitor mv = cw.visitMethod(ACC_FINAL, "accessModeTypeUncached", modeMethType.toMethodDescriptorString(), null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(GETFIELD, Type.getInternalName(VarHandle.AccessMode.class), "at", Type.getDescriptor(VarHandle.AccessType.class));
mv.visitLdcInsn(cw.makeConstantPoolPatch(MemoryAddressProxy.class));
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
mv.visitLdcInsn(cw.makeConstantPoolPatch(carrier));
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
Class<?>[] dims = new Class<?>[dimensions];
Arrays.fill(dims, long.class);
mv.visitLdcInsn(cw.makeConstantPoolPatch(dims));
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class[].class));
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(VarHandle.AccessType.class),
"accessModeType", MethodType.methodType(MethodType.class, Class.class, Class.class, Class[].class).toMethodDescriptorString(), false);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
void addAccessModeMethodIfNeeded(VarHandle.AccessMode mode, BinderClassWriter cw) {
String methName = mode.methodName();
MethodType methType = form.getMethodType(mode.at.ordinal())
.insertParameterTypes(0, BASE_CLASS);
try {
MethodType helperType = methType.insertParameterTypes(2, long.class);
if (dimensions > 0) {
helperType = helperType.dropParameterTypes(3, 3 + dimensions);
}
//try to resolve...
String helperMethodName = methName + "0";
MethodHandles.Lookup.IMPL_LOOKUP
.findStatic(helperClass,
helperMethodName,
helperType);
MethodVisitor mv = cw.visitMethod(ACC_STATIC, methName, methType.toMethodDescriptorString(), null, null);
mv.visitAnnotation(Type.getDescriptor(ForceInline.class), true);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0); // handle impl
mv.visitVarInsn(ALOAD, 1); // receiver
// offset calculation
int slot = 2;
mv.visitVarInsn(ALOAD, 0); // load recv
mv.visitFieldInsn(GETFIELD, Type.getInternalName(BASE_CLASS), "offset", "J");
for (int i = 0 ; i < dimensions ; i++) {
mv.visitVarInsn(ALOAD, 0); // load recv
mv.visitTypeInsn(CHECKCAST, implClassName);
mv.visitFieldInsn(GETFIELD, implClassName, "dim" + i, "J");
mv.visitVarInsn(LLOAD, slot);
mv.visitInsn(LMUL);
mv.visitInsn(LADD);
slot += 2;
}
for (int i = 2 + dimensions; i < methType.parameterCount() ; i++) {
Class<?> param = methType.parameterType(i);
mv.visitVarInsn(loadInsn(param), slot); // load index
slot += getSlotsForType(param);
}
//call helper
mv.visitMethodInsn(INVOKESTATIC, Type.getInternalName(helperClass), helperMethodName,
helperType.toMethodDescriptorString(), false);
mv.visitInsn(returnInsn(helperType.returnType()));
mv.visitMaxs(0, 0);
mv.visitEnd();
} catch (ReflectiveOperationException ex) {
//not found, skip
}
}
void addStridesAccessor(BinderClassWriter cw) {
MethodVisitor mv = cw.visitMethod(ACC_FINAL, "strides", "()[J", null, null);
mv.visitCode();
iConstInsn(mv, dimensions);
mv.visitIntInsn(NEWARRAY, T_LONG);
for (int i = 0 ; i < dimensions ; i++) {
mv.visitInsn(DUP);
iConstInsn(mv, i);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, implClassName, "dim" + i, "J");
mv.visitInsn(LASTORE);
}
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
void addCarrierAccessor(BinderClassWriter cw) {
MethodVisitor mv = cw.visitMethod(ACC_FINAL, "carrier", "()Ljava/lang/Class;", null, null);
mv.visitCode();
mv.visitLdcInsn(cw.makeConstantPoolPatch(carrier));
mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class));
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
//where
private Class<?> defineClass(BinderClassWriter cw, byte[] classBytes) {
try {
if (DEBUG_DUMP_CLASSES_DIR != null) {
debugWriteClassToFile(classBytes);
}
Object[] patches = cw.resolvePatches(classBytes);
Class<?> c = U.defineAnonymousClass(BASE_CLASS, classBytes, patches);
return c;
} catch (Throwable e) {
debugPrintClass(classBytes);
throw e;
}
}
// shared code generation helpers
private static int getSlotsForType(Class<?> c) {
if (c == long.class || c == double.class) {
return 2;
}
return 1;
}
/**
* Emits an actual return instruction conforming to the given return type.
*/
private int returnInsn(Class<?> type) {
return switch (LambdaForm.BasicType.basicType(type)) {
case I_TYPE -> Opcodes.IRETURN;
case J_TYPE -> Opcodes.LRETURN;
case F_TYPE -> Opcodes.FRETURN;
case D_TYPE -> Opcodes.DRETURN;
case L_TYPE -> Opcodes.ARETURN;
case V_TYPE -> RETURN;
};
}
private int loadInsn(Class<?> type) {
return switch (LambdaForm.BasicType.basicType(type)) {
case I_TYPE -> Opcodes.ILOAD;
case J_TYPE -> LLOAD;
case F_TYPE -> Opcodes.FLOAD;
case D_TYPE -> Opcodes.DLOAD;
case L_TYPE -> Opcodes.ALOAD;
case V_TYPE -> throw new IllegalStateException("Cannot load void");
};
}
private static void iConstInsn(MethodVisitor mv, int i) {
switch (i) {
case -1, 0, 1, 2, 3, 4, 5:
mv.visitInsn(ICONST_0 + i);
break;
default:
if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
mv.visitIntInsn(BIPUSH, i);
} else if (i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
mv.visitIntInsn(SIPUSH, i);
} else {
mv.visitLdcInsn(i);
}
}
}
// debug helpers
private static String debugPrintClass(byte[] classFile) {
ClassReader cr = new ClassReader(classFile);
StringWriter sw = new StringWriter();
cr.accept(new TraceClassVisitor(new PrintWriter(sw)), 0);
return sw.toString();
}
private void debugWriteClassToFile(byte[] classFile) {
File file = new File(DEBUG_DUMP_CLASSES_DIR, implClassName + ".class");
if (DEBUG) {
System.err.println("Dumping class " + implClassName + " to " + file);
}
try {
debugWriteDataToFile(classFile, file);
} catch (Exception e) {
throw new RuntimeException("Failed to write class " + implClassName + " to file " + file);
}
}
private void debugWriteDataToFile(byte[] data, File file) {
if (file.exists()) {
file.delete();
}
if (file.exists()) {
throw new RuntimeException("Failed to remove pre-existing file " + file);
}
File parent = file.getParentFile();
if (!parent.exists()) {
parent.mkdirs();
}
if (!parent.exists()) {
throw new RuntimeException("Failed to create " + parent);
}
if (!parent.isDirectory()) {
throw new RuntimeException(parent + " is not a directory");
}
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(data);
} catch (IOException e) {
throw new RuntimeException("Failed to write class " + implClassName + " to file " + file);
}
}
static class BinderClassWriter extends ClassWriter {
private final ArrayList<ConstantPoolPatch> cpPatches = new ArrayList<>();
private int curUniquePatchIndex = 0;
BinderClassWriter() {
super(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
}
public String makeConstantPoolPatch(Object o) {
int myUniqueIndex = curUniquePatchIndex++;
String cpPlaceholder = "CONSTANT_PLACEHOLDER_" + myUniqueIndex;
int index = newConst(cpPlaceholder);
cpPatches.add(new ConstantPoolPatch(index, cpPlaceholder, o));
return cpPlaceholder;
}
public Object[] resolvePatches(byte[] classFile) {
if (cpPatches.isEmpty()) {
return null;
}
int size = ((classFile[8] & 0xFF) << 8) | (classFile[9] & 0xFF);
Object[] patches = new Object[size];
for (ConstantPoolPatch p : cpPatches) {
if (p.index >= size) {
throw new InternalError("Failed to resolve constant pool patch entries");
}
patches[p.index] = p.value;
}
return patches;
}
static class ConstantPoolPatch {
final int index;
final String placeholder;
final Object value;
ConstantPoolPatch(int index, String placeholder, Object value) {
this.index = index;
this.placeholder = placeholder;
this.value = value;
}
@Override
public String toString() {
return "CpPatch/index="+index+",placeholder="+placeholder+",value="+value;
}
}
}
}

View file

@ -41,6 +41,7 @@ import sun.invoke.util.VerifyType;
import sun.invoke.util.Wrapper;
import java.lang.reflect.Array;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@ -1790,6 +1791,44 @@ abstract class MethodHandleImpl {
invokerMethodTypes, callSiteMethodTypes);
}
@Override
public VarHandle memoryAddressViewVarHandle(Class<?> carrier, long alignmentMask,
ByteOrder order, long offset, long[] strides) {
return VarHandles.makeMemoryAddressViewHandle(carrier, alignmentMask, order, offset, strides);
}
@Override
public Class<?> memoryAddressCarrier(VarHandle handle) {
return checkMemAccessHandle(handle).carrier();
}
@Override
public long memoryAddressAlignmentMask(VarHandle handle) {
return checkMemAccessHandle(handle).alignmentMask;
}
@Override
public ByteOrder memoryAddressByteOrder(VarHandle handle) {
return checkMemAccessHandle(handle).be ?
ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
}
@Override
public long memoryAddressOffset(VarHandle handle) {
return checkMemAccessHandle(handle).offset;
}
@Override
public long[] memoryAddressStrides(VarHandle handle) {
return checkMemAccessHandle(handle).strides();
}
private VarHandleMemoryAddressBase checkMemAccessHandle(VarHandle handle) {
if (!(handle instanceof VarHandleMemoryAddressBase)) {
throw new IllegalArgumentException("Not a memory access varhandle: " + handle);
}
return (VarHandleMemoryAddressBase) handle;
}
});
}

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2019, 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 access var handle implementations.
*/
abstract class VarHandleMemoryAddressBase extends VarHandle {
/** endianness **/
final boolean be;
/** access size (in bytes, computed from var handle carrier type) **/
final long length;
/** access offset (in bytes); must be compatible with {@code alignmentMask} **/
final long offset;
/** alignment constraint (in bytes, expressed as a bit mask) **/
final long alignmentMask;
VarHandleMemoryAddressBase(VarForm form, boolean be, long length, long offset, long alignmentMask) {
super(form);
this.be = be;
this.length = length;
this.offset = offset;
this.alignmentMask = alignmentMask;
}
static IllegalStateException newIllegalStateExceptionForMisalignedAccess(long address) {
return new IllegalStateException("Misaligned access at address: " + address);
}
/**
* Strides used for multi-dimensional access; each stride must be compatible with {@code alignmentMask}.
*/
abstract long[] strides();
abstract Class<?> carrier();
}

View file

@ -25,13 +25,26 @@
package java.lang.invoke;
import sun.invoke.util.Wrapper;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.ByteOrder;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
final class VarHandles {
static ClassValue<ConcurrentMap<Integer, MethodHandle>> ADDRESS_FACTORIES = new ClassValue<>() {
@Override
protected ConcurrentMap<Integer, MethodHandle> computeValue(Class<?> type) {
return new ConcurrentHashMap<>();
}
};
static VarHandle makeFieldHandle(MemberName f, Class<?> refc, Class<?> type, boolean isWriteAllowedOnFinalFields) {
if (!f.isStatic()) {
long foffset = MethodHandleNatives.objectFieldOffset(f);
@ -279,6 +292,43 @@ final class VarHandles {
throw new UnsupportedOperationException();
}
/**
* Creates a memory access VarHandle.
*
* Resulting VarHandle will take a memory address as first argument,
* and a certain number of coordinate {@code long} parameters, depending on the length
* of the {@code strides} argument array.
*
* Coordinates are multiplied with corresponding scale factors ({@code strides}) and added
* to a single fixed offset to compute an effective offset from the given MemoryAddress for the access.
*
* @param carrier the Java carrier type.
* @param alignmentMask alignment requirement to be checked upon access. In bytes. Expressed as a mask.
* @param byteOrder the byte order.
* @param offset a constant offset for the access.
* @param strides the scale factors with which to multiply given access coordinates.
* @return the created VarHandle.
*/
static VarHandle makeMemoryAddressViewHandle(Class<?> carrier, long alignmentMask,
ByteOrder byteOrder, long offset, long[] strides) {
if (!carrier.isPrimitive() || carrier == void.class || carrier == boolean.class) {
throw new IllegalArgumentException("Invalid carrier: " + carrier.getName());
}
long size = Wrapper.forPrimitiveType(carrier).bitWidth() / 8;
boolean be = byteOrder == ByteOrder.BIG_ENDIAN;
Map<Integer, MethodHandle> carrierFactory = ADDRESS_FACTORIES.get(carrier);
MethodHandle fac = carrierFactory.computeIfAbsent(strides.length,
dims -> new AddressVarHandleGenerator(carrier, dims)
.generateHandleFactory());
try {
return (VarHandle)fac.invoke(be, size, offset, alignmentMask, strides);
} catch (Throwable ex) {
throw new IllegalStateException(ex);
}
}
// /**
// * A helper program to generate the VarHandleGuards class with a set of
// * static guard methods each of which corresponds to a particular shape and

View file

@ -24,6 +24,8 @@
*/
package java.lang.invoke;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.Unsafe;
import jdk.internal.util.Preconditions;
import jdk.internal.vm.annotation.ForceInline;
@ -38,6 +40,8 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE;
final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess();
static final int ALIGN = $BoxType$.BYTES - 1;
#if[floatingPoint]
@ -529,6 +533,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
@ForceInline
static int index(ByteBuffer bb, int index) {
nioAccess.checkSegment(bb);
return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null);
}
@ -536,7 +541,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
static int indexRO(ByteBuffer bb, int index) {
if (UNSAFE.getBoolean(bb, BYTE_BUFFER_IS_READ_ONLY))
throw new ReadOnlyBufferException();
return Preconditions.checkIndex(index, UNSAFE.getInt(bb, BUFFER_LIMIT) - ALIGN, null);
return index(bb, index);
}
@ForceInline

View file

@ -0,0 +1,512 @@
/*
* Copyright (c) 2019, 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 jdk.internal.access.foreign.MemoryAddressProxy;
import jdk.internal.vm.annotation.ForceInline;
import java.util.Objects;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
#warn
final class VarHandleMemoryAddressAs$Type$s {
static final boolean BE = UNSAFE.isBigEndian();
static final int VM_ALIGN = $BoxType$.BYTES - 1;
#if[floatingPoint]
@ForceInline
static $rawType$ convEndian(boolean big, $type$ v) {
$rawType$ rv = $Type$.$type$ToRaw$RawType$Bits(v);
return big == BE ? rv : $RawBoxType$.reverseBytes(rv);
}
@ForceInline
static $type$ convEndian(boolean big, $rawType$ rv) {
rv = big == BE ? rv : $RawBoxType$.reverseBytes(rv);
return $Type$.$rawType$BitsTo$Type$(rv);
}
#else[floatingPoint]
#if[byte]
@ForceInline
static $type$ convEndian(boolean big, $type$ n) {
return n;
}
#else[byte]
@ForceInline
static $type$ convEndian(boolean big, $type$ n) {
return big == BE ? n : $BoxType$.reverseBytes(n);
}
#end[byte]
#end[floatingPoint]
@ForceInline
static MemoryAddressProxy checkAddress(Object obb, long offset, long length, boolean ro) {
MemoryAddressProxy oo = (MemoryAddressProxy)Objects.requireNonNull(obb);
oo.checkAccess(offset, length, ro);
return oo;
}
@ForceInline
static long offset(MemoryAddressProxy bb, long offset, long alignmentMask) {
long address = offsetNoVMAlignCheck(bb, offset, alignmentMask);
if ((address & VM_ALIGN) != 0) {
throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
static long offsetNoVMAlignCheck(MemoryAddressProxy bb, long offset, long alignmentMask) {
long base = bb.unsafeGetOffset();
long address = base + offset;
//note: the offset portion has already been aligned-checked, by construction
if ((base & alignmentMask) != 0) {
throw VarHandleMemoryAddressBase.newIllegalStateExceptionForMisalignedAccess(address);
}
return address;
}
@ForceInline
static $type$ get0(VarHandleMemoryAddressBase handle, Object obb, long base) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
#if[floatingPoint]
$rawType$ rawValue = UNSAFE.get$RawType$Unaligned(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
return $Type$.$rawType$BitsTo$Type$(rawValue);
#else[floatingPoint]
#if[byte]
return UNSAFE.get$Type$(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask));
#else[byte]
return UNSAFE.get$Type$Unaligned(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
handle.be);
#end[byte]
#end[floatingPoint]
}
@ForceInline
static void set0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
#if[floatingPoint]
UNSAFE.put$RawType$Unaligned(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
$Type$.$type$ToRaw$RawType$Bits(value),
handle.be);
#else[floatingPoint]
#if[byte]
UNSAFE.put$Type$(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value);
#else[byte]
UNSAFE.put$Type$Unaligned(
bb.unsafeGetBase(),
offsetNoVMAlignCheck(bb, base, handle.alignmentMask),
value,
handle.be);
#end[byte]
#end[floatingPoint]
}
@ForceInline
static $type$ getVolatile0(VarHandleMemoryAddressBase handle, Object obb, long base) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
UNSAFE.get$RawType$Volatile(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setVolatile0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
UNSAFE.put$RawType$Volatile(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
UNSAFE.get$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
UNSAFE.put$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
@ForceInline
static $type$ getOpaque0(VarHandleMemoryAddressBase handle, Object obb, long base) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, true);
return convEndian(handle.be,
UNSAFE.get$RawType$Opaque(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask)));
}
@ForceInline
static void setOpaque0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
UNSAFE.put$RawType$Opaque(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value));
}
#if[CAS]
@ForceInline
static boolean compareAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return UNSAFE.compareAndSet$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ compareAndExchange0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.compareAndExchange$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.compareAndExchange$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static $type$ compareAndExchangeRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.compareAndExchange$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value)));
}
@ForceInline
static boolean weakCompareAndSetPlain0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return UNSAFE.weakCompareAndSet$RawType$Plain(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return UNSAFE.weakCompareAndSet$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return UNSAFE.weakCompareAndSet$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static boolean weakCompareAndSetRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ expected, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return UNSAFE.weakCompareAndSet$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, expected), convEndian(handle.be, value));
}
@ForceInline
static $type$ getAndSet0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.getAndSet$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.getAndSet$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
@ForceInline
static $type$ getAndSetRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
return convEndian(handle.be,
UNSAFE.getAndSet$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
convEndian(handle.be, value)));
}
#end[CAS]
#if[AtomicAdd]
@ForceInline
static $type$ getAndAdd0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndAdd$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndAdd$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ delta) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndAdd$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
delta);
} else {
return getAndAddConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), delta);
}
}
@ForceInline
static $type$ getAndAddConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ delta) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue + delta)));
return expectedValue;
}
#end[AtomicAdd]
#if[Bitwise]
@ForceInline
static $type$ getAndBitwiseOr0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseOr$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseOr$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseOr$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseOrConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseOrConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue | value)));
return expectedValue;
}
@ForceInline
static $type$ getAndBitwiseAnd0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseAnd$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseAnd$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseAnd$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseAndConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseAndConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue & value)));
return expectedValue;
}
@ForceInline
static $type$ getAndBitwiseXor0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseXor$RawType$(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorRelease0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseXor$RawType$Release(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorAcquire0(VarHandleMemoryAddressBase handle, Object obb, long base, $type$ value) {
MemoryAddressProxy bb = checkAddress(obb, base, handle.length, false);
if (handle.be == BE) {
return UNSAFE.getAndBitwiseXor$RawType$Acquire(
bb.unsafeGetBase(),
offset(bb, base, handle.alignmentMask),
value);
} else {
return getAndBitwiseXorConvEndianWithCAS(bb, offset(bb, base, handle.alignmentMask), value);
}
}
@ForceInline
static $type$ getAndBitwiseXorConvEndianWithCAS(MemoryAddressProxy bb, long offset, $type$ value) {
$type$ nativeExpectedValue, expectedValue;
Object base = bb.unsafeGetBase();
do {
nativeExpectedValue = UNSAFE.get$RawType$Volatile(base, offset);
expectedValue = $RawBoxType$.reverseBytes(nativeExpectedValue);
} while (!UNSAFE.weakCompareAndSet$RawType$(base, offset,
nativeExpectedValue, $RawBoxType$.reverseBytes(expectedValue ^ value)));
return expectedValue;
}
#end[Bitwise]
}

View file

@ -28,7 +28,9 @@ package java.nio;
import jdk.internal.HotSpotIntrinsicCandidate;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.Unsafe;
import jdk.internal.vm.annotation.ForceInline;
import java.util.Spliterator;
@ -213,13 +215,26 @@ public abstract class Buffer {
// NOTE: hoisted here for speed in JNI GetDirectBufferAddress
long address;
// Used by buffers generated by the memory access API (JEP-370)
final MemorySegmentProxy segment;
// Creates a new buffer with given address and capacity.
//
Buffer(long addr, int cap, MemorySegmentProxy segment) {
this.address = addr;
this.capacity = cap;
this.segment = segment;
}
// Creates a new buffer with the given mark, position, limit, and capacity,
// after checking invariants.
//
Buffer(int mark, int pos, int lim, int cap) { // package-private
Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
if (cap < 0)
throw createCapacityException(cap);
this.capacity = cap;
this.segment = segment;
limit(lim);
position(pos);
if (mark >= 0) {
@ -731,6 +746,13 @@ public abstract class Buffer {
mark = -1;
}
@ForceInline
final void checkSegment() {
if (segment != null) {
segment.checkValidState();
}
}
static {
// setup access to this package in SharedSecrets
SharedSecrets.setJavaNioAccess(
@ -739,6 +761,31 @@ public abstract class Buffer {
public JavaNioAccess.BufferPool getDirectBufferPool() {
return Bits.BUFFER_POOL;
}
@Override
public ByteBuffer newDirectByteBuffer(long addr, int cap, Object obj, MemorySegmentProxy segment) {
return new DirectByteBuffer(addr, cap, obj, segment);
}
@Override
public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegmentProxy segment) {
return new HeapByteBuffer(hb, offset, capacity, segment);
}
@Override
public Object getBufferBase(ByteBuffer bb) {
return bb.base();
}
@Override
public long getBufferAddress(ByteBuffer bb) {
return bb.address;
}
@Override
public void checkSegment(Buffer buffer) {
buffer.checkSegment();
}
});
}

View file

@ -28,6 +28,7 @@
package java.nio;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.Unsafe;
class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
@ -40,11 +41,11 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
#end[rw]
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb) { // package-private
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb, MemorySegmentProxy segment) { // package-private
#if[rw]
super(-1, 0,
bb.remaining() >> $LG_BYTES_PER_VALUE$,
bb.remaining() >> $LG_BYTES_PER_VALUE$);
bb.remaining() >> $LG_BYTES_PER_VALUE$, segment);
this.bb = bb;
// enforce limit == capacity
int cap = this.capacity();
@ -53,21 +54,21 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
assert (pos <= cap);
address = bb.address;
#else[rw]
super(bb);
super(bb, segment);
#end[rw]
}
ByteBufferAs$Type$Buffer$RW$$BO$(ByteBuffer bb,
int mark, int pos, int lim, int cap,
long addr)
long addr, MemorySegmentProxy segment)
{
#if[rw]
super(mark, pos, lim, cap);
super(mark, pos, lim, cap, segment);
this.bb = bb;
address = addr;
assert address >= bb.address;
#else[rw]
super(bb, mark, pos, lim, cap, addr);
super(bb, mark, pos, lim, cap, addr, segment);
#end[rw]
}
@ -82,7 +83,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
long addr = byteOffset(pos);
return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr);
return new ByteBufferAs$Type$Buffer$RW$$BO$(bb, -1, 0, rem, rem, addr, segment);
}
@Override
@ -93,7 +94,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
0,
length,
length,
byteOffset(index));
byteOffset(index), segment);
}
public $Type$Buffer duplicate() {
@ -102,7 +103,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
this.position(),
this.limit(),
this.capacity(),
address);
address, segment);
}
public $Type$Buffer asReadOnlyBuffer() {
@ -112,7 +113,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
this.position(),
this.limit(),
this.capacity(),
address);
address, segment);
#else[rw]
return duplicate();
#end[rw]
@ -130,12 +131,14 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
}
public $type$ get() {
checkSegment();
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(nextGetIndex()),
{#if[boB]?true:false});
return $fromBits$(x);
}
public $type$ get(int i) {
checkSegment();
$memtype$ x = UNSAFE.get$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)),
{#if[boB]?true:false});
return $fromBits$(x);
@ -153,6 +156,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put($type$ x) {
#if[rw]
checkSegment();
$memtype$ y = $toBits$(x);
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(nextPutIndex()), y,
{#if[boB]?true:false});
@ -164,6 +168,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
checkSegment();
$memtype$ y = $toBits$(x);
UNSAFE.put$Memtype$Unaligned(bb.hb, byteOffset(checkIndex(i)), y,
{#if[boB]?true:false});
@ -237,7 +242,7 @@ class ByteBufferAs$Type$Buffer$RW$$BO$ // package-private
pos + start,
pos + end,
capacity(),
address);
address, segment);
}
#end[char]

View file

@ -33,6 +33,7 @@ class XXX {
private $type$ get$Type$(long a) {
try {
checkSegment();
$memtype$ x = UNSAFE.get$Memtype$Unaligned(null, a, bigEndian);
return $fromBits$(x);
} finally {
@ -61,6 +62,7 @@ class XXX {
private ByteBuffer put$Type$(long a, $type$ x) {
#if[rw]
try {
checkSegment();
$memtype$ y = $toBits$(x);
UNSAFE.put$Memtype$Unaligned(null, a, y, bigEndian);
} finally {
@ -104,13 +106,13 @@ class XXX {
0,
size,
size,
address + off))
address + off, segment))
: ($Type$Buffer)(new ByteBufferAs$Type$Buffer$RW$L(this,
-1,
0,
size,
size,
address + off)));
address + off, segment)));
} else {
return (nativeByteOrder
? ($Type$Buffer)(new Direct$Type$Buffer$RW$U(this,
@ -118,13 +120,13 @@ class XXX {
0,
size,
size,
off))
off, segment))
: ($Type$Buffer)(new Direct$Type$Buffer$RW$S(this,
-1,
0,
size,
size,
off)));
off, segment)));
}
}

View file

@ -30,6 +30,7 @@ package java.nio;
import java.io.FileDescriptor;
import java.lang.ref.Reference;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.VM;
import jdk.internal.ref.Cleaner;
import sun.nio.ch.DirectBuffer;
@ -112,7 +113,7 @@ class Direct$Type$Buffer$RW$$BO$
//
Direct$Type$Buffer$RW$(int cap) { // package-private
#if[rw]
super(-1, 0, cap, cap);
super(-1, 0, cap, cap, null);
boolean pa = VM.isDirectMemoryPageAligned();
int ps = Bits.pageSize();
long size = Math.max(1L, (long)cap + (pa ? ps : 0));
@ -145,8 +146,8 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked to construct a direct ByteBuffer referring to the block of
// memory. A given arbitrary object may also be attached to the buffer.
//
Direct$Type$Buffer(long addr, int cap, Object ob) {
super(-1, 0, cap, cap);
Direct$Type$Buffer(long addr, int cap, Object ob, MemorySegmentProxy segment) {
super(-1, 0, cap, cap, segment);
address = addr;
cleaner = null;
att = ob;
@ -156,7 +157,7 @@ class Direct$Type$Buffer$RW$$BO$
// Invoked only by JNI: NewDirectByteBuffer(void*, long)
//
private Direct$Type$Buffer(long addr, int cap) {
super(-1, 0, cap, cap);
super(-1, 0, cap, cap, null);
address = addr;
cleaner = null;
att = null;
@ -169,15 +170,15 @@ class Direct$Type$Buffer$RW$$BO$
protected Direct$Type$Buffer$RW$(int cap, long addr,
FileDescriptor fd,
Runnable unmapper,
boolean isSync)
boolean isSync, MemorySegmentProxy segment)
{
#if[rw]
super(-1, 0, cap, cap, fd, isSync);
super(-1, 0, cap, cap, fd, isSync, segment);
address = addr;
cleaner = Cleaner.create(this, unmapper);
att = null;
#else[rw]
super(cap, addr, fd, unmapper, isSync);
super(cap, addr, fd, unmapper, isSync, segment);
this.isReadOnly = true;
#end[rw]
}
@ -188,10 +189,10 @@ class Direct$Type$Buffer$RW$$BO$
//
Direct$Type$Buffer$RW$$BO$(DirectBuffer db, // package-private
int mark, int pos, int lim, int cap,
int off)
int off, MemorySegmentProxy segment)
{
#if[rw]
super(mark, pos, lim, cap);
super(mark, pos, lim, cap, segment);
address = db.address() + off;
#if[byte]
cleaner = null;
@ -199,7 +200,7 @@ class Direct$Type$Buffer$RW$$BO$
Object attachment = db.attachment();
att = (attachment == null ? db : attachment);
#else[rw]
super(db, mark, pos, lim, cap, off);
super(db, mark, pos, lim, cap, off, segment);
this.isReadOnly = true;
#end[rw]
}
@ -216,7 +217,7 @@ class Direct$Type$Buffer$RW$$BO$
int rem = (pos <= lim ? lim - pos : 0);
int off = (pos << $LG_BYTES_PER_VALUE$);
assert (off >= 0);
return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off, segment);
}
@Override
@ -227,7 +228,7 @@ class Direct$Type$Buffer$RW$$BO$
0,
length,
length,
index);
index, segment);
}
public $Type$Buffer duplicate() {
@ -236,7 +237,7 @@ class Direct$Type$Buffer$RW$$BO$
this.position(),
this.limit(),
this.capacity(),
0);
0, segment);
}
public $Type$Buffer asReadOnlyBuffer() {
@ -246,7 +247,7 @@ class Direct$Type$Buffer$RW$$BO$
this.position(),
this.limit(),
this.capacity(),
0);
0, segment);
#else[rw]
return duplicate();
#end[rw]
@ -264,6 +265,7 @@ class Direct$Type$Buffer$RW$$BO$
public $type$ get() {
try {
checkSegment();
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(nextGetIndex()))));
} finally {
Reference.reachabilityFence(this);
@ -272,6 +274,7 @@ class Direct$Type$Buffer$RW$$BO$
public $type$ get(int i) {
try {
checkSegment();
return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(checkIndex(i)))));
} finally {
Reference.reachabilityFence(this);
@ -290,6 +293,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer get($type$[] dst, int offset, int length) {
#if[rw]
checkSegment();
if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
Objects.checkFromIndexSize(offset, length, dst.length);
int pos = position();
@ -331,6 +335,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer get(int index, $type$[] dst, int offset, int length) {
#if[rw]
checkSegment();
if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, dst.length);
@ -368,6 +373,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put($type$ x) {
#if[rw]
try {
checkSegment();
UNSAFE.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
} finally {
Reference.reachabilityFence(this);
@ -381,6 +387,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
try {
checkSegment();
UNSAFE.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
} finally {
Reference.reachabilityFence(this);
@ -393,6 +400,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put($Type$Buffer src) {
#if[rw]
checkSegment();
if (src instanceof Direct$Type$Buffer$BO$) {
if (src == this)
throw createSameBufferException();
@ -439,6 +447,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put($type$[] src, int offset, int length) {
#if[rw]
checkSegment();
if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
Objects.checkFromIndexSize(offset, length, src.length);
int pos = position();
@ -480,6 +489,7 @@ class Direct$Type$Buffer$RW$$BO$
public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
#if[rw]
checkSegment();
if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, src.length);
@ -577,7 +587,7 @@ class Direct$Type$Buffer$RW$$BO$
pos + start,
pos + end,
capacity(),
offset);
offset, segment);
}
#end[char]

View file

@ -28,6 +28,7 @@
package java.nio;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
/**
#if[rw]
@ -58,47 +59,47 @@ class Heap$Type$Buffer$RW$
#end[rw]
*/
Heap$Type$Buffer$RW$(int cap, int lim) { // package-private
Heap$Type$Buffer$RW$(int cap, int lim, MemorySegmentProxy segment) { // package-private
#if[rw]
super(-1, 0, lim, cap, new $type$[cap], 0);
super(-1, 0, lim, cap, new $type$[cap], 0, segment);
/*
hb = new $type$[cap];
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
super(cap, lim);
super(cap, lim, segment);
this.isReadOnly = true;
#end[rw]
}
Heap$Type$Buffer$RW$($type$[] buf, int off, int len) { // package-private
Heap$Type$Buffer$RW$($type$[] buf, int off, int len, MemorySegmentProxy segment) { // package-private
#if[rw]
super(-1, off, off + len, buf.length, buf, 0);
super(-1, off, off + len, buf.length, buf, 0, segment);
/*
hb = buf;
offset = 0;
*/
this.address = ARRAY_BASE_OFFSET;
#else[rw]
super(buf, off, len);
super(buf, off, len, segment);
this.isReadOnly = true;
#end[rw]
}
protected Heap$Type$Buffer$RW$($type$[] buf,
int mark, int pos, int lim, int cap,
int off)
int off, MemorySegmentProxy segment)
{
#if[rw]
super(mark, pos, lim, cap, buf, off);
super(mark, pos, lim, cap, buf, off, segment);
/*
hb = buf;
offset = off;
*/
this.address = ARRAY_BASE_OFFSET + off * ARRAY_INDEX_SCALE;
#else[rw]
super(buf, mark, pos, lim, cap, off);
super(buf, mark, pos, lim, cap, off, segment);
this.isReadOnly = true;
#end[rw]
}
@ -110,7 +111,7 @@ class Heap$Type$Buffer$RW$
0,
rem,
rem,
this.position() + offset);
this.position() + offset, segment);
}
@Override
@ -121,7 +122,7 @@ class Heap$Type$Buffer$RW$
0,
length,
length,
index + offset);
index + offset, segment);
}
public $Type$Buffer duplicate() {
@ -130,7 +131,7 @@ class Heap$Type$Buffer$RW$
this.position(),
this.limit(),
this.capacity(),
offset);
offset, segment);
}
public $Type$Buffer asReadOnlyBuffer() {
@ -140,7 +141,7 @@ class Heap$Type$Buffer$RW$
this.position(),
this.limit(),
this.capacity(),
offset);
offset, segment);
#else[rw]
return duplicate();
#end[rw]
@ -159,20 +160,23 @@ class Heap$Type$Buffer$RW$
#end[byte]
public $type$ get() {
checkSegment();
return hb[ix(nextGetIndex())];
}
public $type$ get(int i) {
checkSegment();
return hb[ix(checkIndex(i))];
}
#if[streamableType]
$type$ getUnchecked(int i) {
return hb[ix(i)];
return hb[ix(i)];
}
#end[streamableType]
public $Type$Buffer get($type$[] dst, int offset, int length) {
checkSegment();
Objects.checkFromIndexSize(offset, length, dst.length);
int pos = position();
if (length > limit() - pos)
@ -183,6 +187,7 @@ class Heap$Type$Buffer$RW$
}
public $Type$Buffer get(int index, $type$[] dst, int offset, int length) {
checkSegment();
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, dst.length);
System.arraycopy(hb, ix(index), dst, offset, length);
@ -201,6 +206,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put($type$ x) {
#if[rw]
checkSegment();
hb[ix(nextPutIndex())] = x;
return this;
#else[rw]
@ -210,6 +216,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put(int i, $type$ x) {
#if[rw]
checkSegment();
hb[ix(checkIndex(i))] = x;
return this;
#else[rw]
@ -219,6 +226,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put($type$[] src, int offset, int length) {
#if[rw]
checkSegment();
Objects.checkFromIndexSize(offset, length, src.length);
int pos = position();
if (length > limit() - pos)
@ -233,6 +241,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put($Type$Buffer src) {
#if[rw]
checkSegment();
if (src instanceof Heap$Type$Buffer) {
if (src == this)
throw createSameBufferException();
@ -264,6 +273,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer put(int index, $type$[] src, int offset, int length) {
#if[rw]
checkSegment();
Objects.checkFromIndexSize(index, length, limit());
Objects.checkFromIndexSize(offset, length, src.length);
System.arraycopy(src, offset, hb, ix(index), length);
@ -276,6 +286,7 @@ class Heap$Type$Buffer$RW$
#if[char]
public $Type$Buffer put(String src, int start, int end) {
checkSegment();
int length = end - start;
Objects.checkFromIndexSize(start, length, src.length());
if (isReadOnly())
@ -327,6 +338,7 @@ class Heap$Type$Buffer$RW$
#if[rw]
public char getChar() {
checkSegment();
return UNSAFE.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
@ -338,6 +350,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putChar(char x) {
#if[rw]
checkSegment();
UNSAFE.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
@ -347,6 +360,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putChar(int i, char x) {
#if[rw]
checkSegment();
UNSAFE.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
@ -364,13 +378,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (CharBuffer)(new ByteBufferAsCharBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -379,10 +393,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public short getShort() {
checkSegment();
return UNSAFE.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public short getShort(int i) {
checkSegment();
return UNSAFE.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
@ -390,6 +406,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putShort(short x) {
#if[rw]
checkSegment();
UNSAFE.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
@ -399,6 +416,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putShort(int i, short x) {
#if[rw]
checkSegment();
UNSAFE.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
@ -416,13 +434,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (ShortBuffer)(new ByteBufferAsShortBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -431,10 +449,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public int getInt() {
checkSegment();
return UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
}
public int getInt(int i) {
checkSegment();
return UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
}
@ -442,6 +462,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putInt(int x) {
#if[rw]
checkSegment();
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
return this;
#else[rw]
@ -451,6 +472,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putInt(int i, int x) {
#if[rw]
checkSegment();
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
return this;
#else[rw]
@ -468,13 +490,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (IntBuffer)(new ByteBufferAsIntBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -483,10 +505,12 @@ class Heap$Type$Buffer$RW$
#if[rw]
public long getLong() {
checkSegment();
return UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
}
public long getLong(int i) {
checkSegment();
return UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
}
@ -494,6 +518,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putLong(long x) {
#if[rw]
checkSegment();
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
return this;
#else[rw]
@ -503,6 +528,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putLong(int i, long x) {
#if[rw]
checkSegment();
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
return this;
#else[rw]
@ -520,13 +546,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (LongBuffer)(new ByteBufferAsLongBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -535,11 +561,13 @@ class Heap$Type$Buffer$RW$
#if[rw]
public float getFloat() {
checkSegment();
int x = UNSAFE.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
return Float.intBitsToFloat(x);
}
public float getFloat(int i) {
checkSegment();
int x = UNSAFE.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
return Float.intBitsToFloat(x);
}
@ -548,6 +576,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(float x) {
#if[rw]
checkSegment();
int y = Float.floatToRawIntBits(x);
UNSAFE.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
return this;
@ -558,6 +587,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(int i, float x) {
#if[rw]
checkSegment();
int y = Float.floatToRawIntBits(x);
UNSAFE.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
return this;
@ -576,13 +606,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (FloatBuffer)(new ByteBufferAsFloatBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -591,11 +621,13 @@ class Heap$Type$Buffer$RW$
#if[rw]
public double getDouble() {
checkSegment();
long x = UNSAFE.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
return Double.longBitsToDouble(x);
}
public double getDouble(int i) {
checkSegment();
long x = UNSAFE.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
return Double.longBitsToDouble(x);
}
@ -604,6 +636,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(double x) {
#if[rw]
checkSegment();
long y = Double.doubleToRawLongBits(x);
UNSAFE.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
return this;
@ -614,6 +647,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(int i, double x) {
#if[rw]
checkSegment();
long y = Double.doubleToRawLongBits(x);
UNSAFE.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
return this;
@ -632,13 +666,13 @@ class Heap$Type$Buffer$RW$
0,
size,
size,
addr))
addr, segment))
: (DoubleBuffer)(new ByteBufferAsDoubleBuffer$RW$L(this,
-1,
0,
size,
size,
addr)));
addr, segment)));
}
@ -666,7 +700,7 @@ class Heap$Type$Buffer$RW$
pos + start,
pos + end,
capacity(),
offset);
offset, segment);
}
#end[char]

View file

@ -28,6 +28,8 @@ package java.nio;
import java.io.FileDescriptor;
import java.lang.ref.Reference;
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.misc.Unsafe;
@ -88,21 +90,21 @@ public abstract class MappedByteBuffer
// This should only be invoked by the DirectByteBuffer constructors
//
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
FileDescriptor fd, boolean isSync) {
super(mark, pos, lim, cap);
FileDescriptor fd, boolean isSync, MemorySegmentProxy segment) {
super(mark, pos, lim, cap, segment);
this.fd = fd;
this.isSync = isSync;
}
MappedByteBuffer(int mark, int pos, int lim, int cap, // package-private
boolean isSync) {
super(mark, pos, lim, cap);
boolean isSync, MemorySegmentProxy segment) {
super(mark, pos, lim, cap, segment);
this.fd = null;
this.isSync = isSync;
}
MappedByteBuffer(int mark, int pos, int lim, int cap) { // package-private
super(mark, pos, lim, cap);
MappedByteBuffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
super(mark, pos, lim, cap, segment);
this.fd = null;
this.isSync = false;
}

View file

@ -35,7 +35,7 @@ class StringCharBuffer // package-private
CharSequence str;
StringCharBuffer(CharSequence s, int start, int end) { // package-private
super(-1, start, end, s.length());
super(-1, start, end, s.length(), null);
int n = s.length();
Objects.checkFromToIndex(start, end, n);
str = s;
@ -68,7 +68,7 @@ class StringCharBuffer // package-private
int limit,
int cap,
int offset) {
super(mark, pos, limit, cap, null, offset);
super(mark, pos, limit, cap, null, offset, null);
str = s;
this.isReadOnly = true;
}

View file

@ -37,6 +37,7 @@ import java.util.stream.$Streamtype$Stream;
#end[streamableType]
import java.util.Objects;
import jdk.internal.access.foreign.MemorySegmentProxy;
import jdk.internal.util.ArraysSupport;
/**
@ -279,17 +280,25 @@ public abstract class $Type$Buffer
// backing array, and array offset
//
$Type$Buffer(int mark, int pos, int lim, int cap, // package-private
$type$[] hb, int offset)
$type$[] hb, int offset, MemorySegmentProxy segment)
{
super(mark, pos, lim, cap);
super(mark, pos, lim, cap, segment);
this.hb = hb;
this.offset = offset;
}
// Creates a new buffer with the given mark, position, limit, and capacity
//
$Type$Buffer(int mark, int pos, int lim, int cap) { // package-private
this(mark, pos, lim, cap, null, 0);
$Type$Buffer(int mark, int pos, int lim, int cap, MemorySegmentProxy segment) { // package-private
this(mark, pos, lim, cap, null, 0, segment);
}
// Creates a new buffer with given base, address and capacity
//
$Type$Buffer($type$[] hb, long addr, int cap, MemorySegmentProxy segment) { // package-private
super(addr, cap, segment);
this.hb = hb;
this.offset = 0;
}
@Override
@ -348,7 +357,7 @@ public abstract class $Type$Buffer
public static $Type$Buffer allocate(int capacity) {
if (capacity < 0)
throw createCapacityException(capacity);
return new Heap$Type$Buffer(capacity, capacity);
return new Heap$Type$Buffer(capacity, capacity, null);
}
/**
@ -393,7 +402,7 @@ public abstract class $Type$Buffer
int offset, int length)
{
try {
return new Heap$Type$Buffer(array, offset, length);
return new Heap$Type$Buffer(array, offset, length, null);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}