mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8246095: Tweaks to memory access API
Add more user friendly API points to the foreign memory acesss API Reviewed-by: chegar, psandoz
This commit is contained in:
parent
eec7750e55
commit
f1e1cb7055
25 changed files with 1634 additions and 185 deletions
|
@ -989,6 +989,57 @@ class LambdaFormEditor {
|
|||
return putInCache(key, form);
|
||||
}
|
||||
|
||||
LambdaForm collectReturnValueForm(MethodType combinerType) {
|
||||
LambdaFormBuffer buf = buffer();
|
||||
buf.startEdit();
|
||||
int combinerArity = combinerType.parameterCount();
|
||||
int argPos = lambdaForm.arity();
|
||||
int exprPos = lambdaForm.names.length;
|
||||
|
||||
BoundMethodHandle.SpeciesData oldData = oldSpeciesData();
|
||||
BoundMethodHandle.SpeciesData newData = newSpeciesData(L_TYPE);
|
||||
|
||||
// The newly created LF will run with a different BMH.
|
||||
// Switch over any pre-existing BMH field references to the new BMH class.
|
||||
Name oldBaseAddress = lambdaForm.parameter(0); // BMH holding the values
|
||||
buf.replaceFunctions(oldData.getterFunctions(), newData.getterFunctions(), oldBaseAddress);
|
||||
Name newBaseAddress = oldBaseAddress.withConstraint(newData);
|
||||
buf.renameParameter(0, newBaseAddress);
|
||||
|
||||
// Now we set up the call to the filter
|
||||
Name getCombiner = new Name(newData.getterFunction(oldData.fieldCount()), newBaseAddress);
|
||||
|
||||
Object[] combinerArgs = new Object[combinerArity + 1];
|
||||
combinerArgs[0] = getCombiner; // first (synthetic) argument should be the MH that acts as a target of the invoke
|
||||
|
||||
// set up additional adapter parameters (in case the combiner is not a unary function)
|
||||
Name[] newParams = new Name[combinerArity - 1]; // last combiner parameter is the return adapter
|
||||
for (int i = 0; i < newParams.length; i++) {
|
||||
newParams[i] = new Name(argPos + i, basicType(combinerType.parameterType(i)));
|
||||
}
|
||||
|
||||
// set up remaining filter parameters to point to the corresponding adapter parameters (see above)
|
||||
System.arraycopy(newParams, 0,
|
||||
combinerArgs, 1, combinerArity - 1);
|
||||
|
||||
// the last filter argument is set to point at the result of the target method handle
|
||||
combinerArgs[combinerArity] = buf.name(lambdaForm.names.length - 1);
|
||||
Name callCombiner = new Name(combinerType, combinerArgs);
|
||||
|
||||
// insert the two new expressions
|
||||
buf.insertExpression(exprPos, getCombiner);
|
||||
buf.insertExpression(exprPos + 1, callCombiner);
|
||||
|
||||
// insert additional arguments
|
||||
int insPos = argPos;
|
||||
for (Name newParam : newParams) {
|
||||
buf.insertParameter(insPos++, newParam);
|
||||
}
|
||||
|
||||
buf.setResult(callCombiner);
|
||||
return buf.endEdit();
|
||||
}
|
||||
|
||||
LambdaForm foldArgumentsForm(int foldPos, boolean dropResult, MethodType combinerType) {
|
||||
int combinerArity = combinerType.parameterCount();
|
||||
byte kind = (dropResult ? FOLD_ARGS_TO_VOID : FOLD_ARGS);
|
||||
|
|
|
@ -5539,6 +5539,40 @@ System.out.println((int) f0.invokeExact("x", "y")); // 2
|
|||
throw newIllegalArgumentException("target and filter types do not match", targetType, filterType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the return value of a target method handle with a filter function. The filter function is
|
||||
* applied to the return value of the original handle; if the filter specifies more than one parameters,
|
||||
* then any remaining parameter is appended to the adapter handle. In other words, the adaptation works
|
||||
* as follows:
|
||||
* <blockquote><pre>{@code
|
||||
* T target(A...)
|
||||
* V filter(B... , T)
|
||||
* V adapter(A... a, B... b) {
|
||||
* T t = target(a...);
|
||||
* return filter(b..., t);
|
||||
* }</pre></blockquote>
|
||||
* <p>
|
||||
* If the filter handle is a unary function, then this method behaves like {@link #filterReturnValue(MethodHandle, MethodHandle)}.
|
||||
*
|
||||
* @param target the target method handle
|
||||
* @param filter the filter method handle
|
||||
* @return the adapter method handle
|
||||
*/
|
||||
/* package */ static MethodHandle collectReturnValue(MethodHandle target, MethodHandle filter) {
|
||||
MethodType targetType = target.type();
|
||||
MethodType filterType = filter.type();
|
||||
BoundMethodHandle result = target.rebind();
|
||||
LambdaForm lform = result.editor().collectReturnValueForm(filterType.basicType());
|
||||
MethodType newType = targetType.changeReturnType(filterType.returnType());
|
||||
if (filterType.parameterList().size() > 1) {
|
||||
for (int i = 0 ; i < filterType.parameterList().size() - 1 ; i++) {
|
||||
newType = newType.appendParameterTypes(filterType.parameterType(i));
|
||||
}
|
||||
}
|
||||
result = result.copyWithExtendL(newType, lform, filter);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts a target method handle by pre-processing
|
||||
* some of its arguments, and then calling the target with
|
||||
|
|
|
@ -356,43 +356,97 @@ final class VarHandles {
|
|||
noCheckedExceptions(filterToTarget);
|
||||
noCheckedExceptions(filterFromTarget);
|
||||
|
||||
List<Class<?>> newCoordinates = new ArrayList<>();
|
||||
List<Class<?>> additionalCoordinates = new ArrayList<>();
|
||||
newCoordinates.addAll(target.coordinateTypes());
|
||||
|
||||
//check that from/to filters have right signatures
|
||||
if (filterFromTarget.type().parameterCount() != 1) {
|
||||
if (filterFromTarget.type().parameterCount() != filterToTarget.type().parameterCount()) {
|
||||
throw newIllegalArgumentException("filterFromTarget and filterToTarget have different arity", filterFromTarget.type(), filterToTarget.type());
|
||||
} else if (filterFromTarget.type().parameterCount() < 1) {
|
||||
throw newIllegalArgumentException("filterFromTarget filter type has wrong arity", filterFromTarget.type());
|
||||
} else if (filterToTarget.type().parameterCount() != 1) {
|
||||
} else if (filterToTarget.type().parameterCount() < 1) {
|
||||
throw newIllegalArgumentException("filterToTarget filter type has wrong arity", filterFromTarget.type());
|
||||
} else if (filterFromTarget.type().parameterType(0) != filterToTarget.type().returnType() ||
|
||||
filterToTarget.type().parameterType(0) != filterFromTarget.type().returnType()) {
|
||||
} else if (filterFromTarget.type().lastParameterType() != filterToTarget.type().returnType() ||
|
||||
filterToTarget.type().lastParameterType() != filterFromTarget.type().returnType()) {
|
||||
throw newIllegalArgumentException("filterFromTarget and filterToTarget filter types do not match", filterFromTarget.type(), filterToTarget.type());
|
||||
} else if (target.varType() != filterFromTarget.type().parameterType(0)) {
|
||||
} else if (target.varType() != filterFromTarget.type().lastParameterType()) {
|
||||
throw newIllegalArgumentException("filterFromTarget filter type does not match target var handle type", filterFromTarget.type(), target.varType());
|
||||
} else if (target.varType() != filterToTarget.type().returnType()) {
|
||||
throw newIllegalArgumentException("filterFromTarget filter type does not match target var handle type", filterToTarget.type(), target.varType());
|
||||
} else if (filterFromTarget.type().parameterCount() > 1) {
|
||||
for (int i = 0 ; i < filterFromTarget.type().parameterCount() - 1 ; i++) {
|
||||
if (filterFromTarget.type().parameterType(i) != filterToTarget.type().parameterType(i)) {
|
||||
throw newIllegalArgumentException("filterFromTarget and filterToTarget filter types do not match", filterFromTarget.type(), filterToTarget.type());
|
||||
} else {
|
||||
newCoordinates.add(filterFromTarget.type().parameterType(i));
|
||||
additionalCoordinates.add((filterFromTarget.type().parameterType(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new IndirectVarHandle(target, filterFromTarget.type().returnType(), target.coordinateTypes().toArray(new Class<?>[0]),
|
||||
return new IndirectVarHandle(target, filterFromTarget.type().returnType(), newCoordinates.toArray(new Class<?>[0]),
|
||||
(mode, modeHandle) -> {
|
||||
int lastParameterPos = modeHandle.type().parameterCount() - 1;
|
||||
return switch (mode.at) {
|
||||
case GET -> MethodHandles.filterReturnValue(modeHandle, filterFromTarget);
|
||||
case SET -> MethodHandles.filterArgument(modeHandle, lastParameterPos, filterToTarget);
|
||||
case GET -> MethodHandles.collectReturnValue(modeHandle, filterFromTarget);
|
||||
case SET -> MethodHandles.collectArguments(modeHandle, lastParameterPos, filterToTarget);
|
||||
case GET_AND_UPDATE -> {
|
||||
MethodHandle adapter = MethodHandles.filterReturnValue(modeHandle, filterFromTarget);
|
||||
yield MethodHandles.filterArgument(adapter, lastParameterPos, filterToTarget);
|
||||
MethodHandle adapter = MethodHandles.collectReturnValue(modeHandle, filterFromTarget);
|
||||
MethodHandle res = MethodHandles.collectArguments(adapter, lastParameterPos, filterToTarget);
|
||||
if (additionalCoordinates.size() > 0) {
|
||||
res = joinDuplicateArgs(res, lastParameterPos,
|
||||
lastParameterPos + additionalCoordinates.size() + 1,
|
||||
additionalCoordinates.size());
|
||||
}
|
||||
yield res;
|
||||
}
|
||||
case COMPARE_AND_EXCHANGE -> {
|
||||
MethodHandle adapter = MethodHandles.filterReturnValue(modeHandle, filterFromTarget);
|
||||
adapter = MethodHandles.filterArgument(adapter, lastParameterPos, filterToTarget);
|
||||
yield MethodHandles.filterArgument(adapter, lastParameterPos - 1, filterToTarget);
|
||||
MethodHandle adapter = MethodHandles.collectReturnValue(modeHandle, filterFromTarget);
|
||||
adapter = MethodHandles.collectArguments(adapter, lastParameterPos, filterToTarget);
|
||||
if (additionalCoordinates.size() > 0) {
|
||||
adapter = joinDuplicateArgs(adapter, lastParameterPos,
|
||||
lastParameterPos + additionalCoordinates.size() + 1,
|
||||
additionalCoordinates.size());
|
||||
}
|
||||
MethodHandle res = MethodHandles.collectArguments(adapter, lastParameterPos - 1, filterToTarget);
|
||||
if (additionalCoordinates.size() > 0) {
|
||||
res = joinDuplicateArgs(res, lastParameterPos - 1,
|
||||
lastParameterPos + additionalCoordinates.size(),
|
||||
additionalCoordinates.size());
|
||||
}
|
||||
yield res;
|
||||
}
|
||||
case COMPARE_AND_SET -> {
|
||||
MethodHandle adapter = MethodHandles.filterArgument(modeHandle, lastParameterPos, filterToTarget);
|
||||
yield MethodHandles.filterArgument(adapter, lastParameterPos - 1, filterToTarget);
|
||||
MethodHandle adapter = MethodHandles.collectArguments(modeHandle, lastParameterPos, filterToTarget);
|
||||
MethodHandle res = MethodHandles.collectArguments(adapter, lastParameterPos - 1, filterToTarget);
|
||||
if (additionalCoordinates.size() > 0) {
|
||||
res = joinDuplicateArgs(res, lastParameterPos - 1,
|
||||
lastParameterPos + additionalCoordinates.size(),
|
||||
additionalCoordinates.size());
|
||||
}
|
||||
yield res;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private static MethodHandle joinDuplicateArgs(MethodHandle handle, int originalStart, int dropStart, int length) {
|
||||
int[] perms = new int[handle.type().parameterCount()];
|
||||
for (int i = 0 ; i < dropStart; i++) {
|
||||
perms[i] = i;
|
||||
}
|
||||
for (int i = 0 ; i < length ; i++) {
|
||||
perms[dropStart + i] = originalStart + i;
|
||||
}
|
||||
for (int i = dropStart + length ; i < perms.length ; i++) {
|
||||
perms[i] = i - length;
|
||||
}
|
||||
return MethodHandles.permuteArguments(handle,
|
||||
handle.type().dropParameterTypes(dropStart, dropStart + length),
|
||||
perms);
|
||||
}
|
||||
|
||||
public static VarHandle filterCoordinates(VarHandle target, int pos, MethodHandle... filters) {
|
||||
Objects.nonNull(target);
|
||||
Objects.nonNull(filters);
|
||||
|
@ -542,17 +596,23 @@ final class VarHandles {
|
|||
private static void noCheckedExceptions(MethodHandle handle) {
|
||||
if (handle instanceof DirectMethodHandle) {
|
||||
DirectMethodHandle directHandle = (DirectMethodHandle)handle;
|
||||
MethodHandleInfo info = MethodHandles.Lookup.IMPL_LOOKUP.revealDirect(directHandle);
|
||||
Class<?>[] exceptionTypes = switch (info.getReferenceKind()) {
|
||||
case MethodHandleInfo.REF_invokeInterface, MethodHandleInfo.REF_invokeSpecial,
|
||||
MethodHandleInfo.REF_invokeStatic, MethodHandleInfo.REF_invokeVirtual ->
|
||||
info.reflectAs(Method.class, MethodHandles.Lookup.IMPL_LOOKUP).getExceptionTypes();
|
||||
case MethodHandleInfo.REF_newInvokeSpecial ->
|
||||
info.reflectAs(Constructor.class, MethodHandles.Lookup.IMPL_LOOKUP).getExceptionTypes();
|
||||
case MethodHandleInfo.REF_getField, MethodHandleInfo.REF_getStatic,
|
||||
MethodHandleInfo.REF_putField, MethodHandleInfo.REF_putStatic -> null;
|
||||
default -> throw new AssertionError("Cannot get here");
|
||||
};
|
||||
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)
|
||||
.getExceptionTypes();
|
||||
} else if (MethodHandleNatives.refKindIsField(refKind)) {
|
||||
exceptionTypes = null;
|
||||
} else if (MethodHandleNatives.refKindIsConstructor(refKind)) {
|
||||
exceptionTypes = 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");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue