8275063: Implementation of Foreign Function & Memory API (Second incubator)

Reviewed-by: erikj, psandoz, jvernee, darcy
This commit is contained in:
Maurizio Cimadamore 2021-11-24 11:51:16 +00:00
parent 17e68caad7
commit 96e36071b6
191 changed files with 9463 additions and 7631 deletions

View file

@ -1667,6 +1667,10 @@ abstract class MethodHandleImpl {
return caller.makeHiddenClassDefiner(name, bytes, Set.of()).defineClassAsLookup(initialize, classData);
}
@Override
public Class<?>[] exceptionTypes(MethodHandle handle) {
return VarHandles.exceptionTypes(handle);
}
});
}
@ -2273,15 +2277,16 @@ abstract class MethodHandleImpl {
// Indexes into constant method handles:
static final int
MH_cast = 0,
MH_selectAlternative = 1,
MH_countedLoopPred = 2,
MH_countedLoopStep = 3,
MH_initIterator = 4,
MH_iteratePred = 5,
MH_iterateNext = 6,
MH_Array_newInstance = 7,
MH_LIMIT = 8;
MH_cast = 0,
MH_selectAlternative = 1,
MH_countedLoopPred = 2,
MH_countedLoopStep = 3,
MH_initIterator = 4,
MH_iteratePred = 5,
MH_iterateNext = 6,
MH_Array_newInstance = 7,
MH_VarHandles_handleCheckedExceptions = 8,
MH_LIMIT = 9;
static MethodHandle getConstantHandle(int idx) {
MethodHandle handle = HANDLES[idx];
@ -2331,6 +2336,9 @@ abstract class MethodHandleImpl {
case MH_Array_newInstance:
return IMPL_LOOKUP.findStatic(Array.class, "newInstance",
MethodType.methodType(Object.class, Class.class, int.class));
case MH_VarHandles_handleCheckedExceptions:
return IMPL_LOOKUP.findStatic(VarHandles.class, "handleCheckedExceptions",
MethodType.methodType(void.class, Throwable.class));
}
} catch (ReflectiveOperationException ex) {
throw newInternalError(ex);

View file

@ -31,12 +31,9 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -45,8 +42,6 @@ import java.util.stream.Stream;
import static java.lang.invoke.MethodHandleStatics.UNSAFE;
import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT;
import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
final class VarHandles {
@ -359,13 +354,13 @@ final class VarHandles {
return target;
}
public static VarHandle filterValue(VarHandle target, MethodHandle filterToTarget, MethodHandle filterFromTarget) {
public static VarHandle filterValue(VarHandle target, MethodHandle pFilterToTarget, MethodHandle pFilterFromTarget) {
Objects.requireNonNull(target);
Objects.requireNonNull(filterToTarget);
Objects.requireNonNull(filterFromTarget);
Objects.requireNonNull(pFilterToTarget);
Objects.requireNonNull(pFilterFromTarget);
//check that from/to filters do not throw checked exceptions
noCheckedExceptions(filterToTarget);
noCheckedExceptions(filterFromTarget);
MethodHandle filterToTarget = adaptForCheckedExceptions(pFilterToTarget);
MethodHandle filterFromTarget = adaptForCheckedExceptions(pFilterFromTarget);
List<Class<?>> newCoordinates = new ArrayList<>();
List<Class<?>> additionalCoordinates = new ArrayList<>();
@ -473,8 +468,9 @@ final class VarHandles {
List<Class<?>> newCoordinates = new ArrayList<>(targetCoordinates);
for (int i = 0 ; i < filters.length ; i++) {
noCheckedExceptions(filters[i]);
MethodType filterType = filters[i].type();
MethodHandle filter = Objects.requireNonNull(filters[i]);
filter = adaptForCheckedExceptions(filter);
MethodType filterType = filter.type();
if (filterType.parameterCount() != 1) {
throw newIllegalArgumentException("Invalid filter type " + filterType);
} else if (newCoordinates.get(pos + i) != filterType.returnType()) {
@ -564,10 +560,10 @@ final class VarHandles {
return adjustedType;
}
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle filter) {
public static VarHandle collectCoordinates(VarHandle target, int pos, MethodHandle pFilter) {
Objects.requireNonNull(target);
Objects.requireNonNull(filter);
noCheckedExceptions(filter);
Objects.requireNonNull(pFilter);
MethodHandle filter = adaptForCheckedExceptions(pFilter);
List<Class<?>> targetCoordinates = target.coordinateTypes();
if (pos < 0 || pos >= targetCoordinates.size()) {
@ -604,42 +600,55 @@ final class VarHandles {
(mode, modeHandle) -> MethodHandles.dropArguments(modeHandle, 1 + pos, valueTypes));
}
private static void noCheckedExceptions(MethodHandle handle) {
private static MethodHandle adaptForCheckedExceptions(MethodHandle target) {
Class<?>[] exceptionTypes = exceptionTypes(target);
if (exceptionTypes != null) { // exceptions known
if (Stream.of(exceptionTypes).anyMatch(VarHandles::isCheckedException)) {
throw newIllegalArgumentException("Cannot adapt a var handle with a method handle which throws checked exceptions");
}
return target; // no adaptation needed
} else {
MethodHandle handler = MethodHandleImpl.getConstantHandle(MethodHandleImpl.MH_VarHandles_handleCheckedExceptions);
MethodHandle zero = MethodHandles.zero(target.type().returnType()); // dead branch
handler = MethodHandles.collectArguments(zero, 0, handler);
return MethodHandles.catchException(target, Throwable.class, handler);
}
}
static void handleCheckedExceptions(Throwable throwable) throws Throwable {
if (isCheckedException(throwable.getClass())) {
throw new IllegalStateException("Adapter handle threw checked exception", throwable);
}
throw throwable;
}
static Class<?>[] exceptionTypes(MethodHandle handle) {
if (handle instanceof DirectMethodHandle directHandle) {
byte refKind = directHandle.member.getReferenceKind();
MethodHandleInfo info = new InfoFromMemberName(
MethodHandles.Lookup.IMPL_LOOKUP,
directHandle.member,
refKind);
final Class<?>[] exceptionTypes;
if (MethodHandleNatives.refKindIsMethod(refKind)) {
exceptionTypes = info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP)
return info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP)
.getExceptionTypes();
} else if (MethodHandleNatives.refKindIsField(refKind)) {
exceptionTypes = null;
return new Class<?>[0];
} else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
exceptionTypes = info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP)
return info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP)
.getExceptionTypes();
} else {
throw new AssertionError("Cannot get here");
}
if (exceptionTypes != null) {
if (Stream.of(exceptionTypes).anyMatch(VarHandles::isCheckedException)) {
throw newIllegalArgumentException("Cannot adapt a var handle with a method handle which throws checked exceptions");
}
}
} else if (handle instanceof DelegatingMethodHandle) {
noCheckedExceptions(((DelegatingMethodHandle)handle).getTarget());
} else {
//bound
BoundMethodHandle boundHandle = (BoundMethodHandle)handle;
for (int i = 0 ; i < boundHandle.fieldCount() ; i++) {
Object arg = boundHandle.arg(i);
if (arg instanceof MethodHandle){
noCheckedExceptions((MethodHandle) arg);
}
}
return exceptionTypes(((DelegatingMethodHandle)handle).getTarget());
} else if (handle instanceof NativeMethodHandle) {
return new Class<?>[0];
}
assert handle instanceof BoundMethodHandle : "Unexpected handle type: " + handle;
// unknown
return null;
}
private static boolean isCheckedException(Class<?> clazz) {