mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
Merge
This commit is contained in:
commit
83163dbfe6
146 changed files with 10955 additions and 1143 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue