8144917: Prepare AbstractJavaLinker/BeanLinker codebase for missing member implementation

Reviewed-by: mhaupt, sundar
This commit is contained in:
Attila Szegedi
2016-01-14 13:22:58 +01:00
parent e267b166cb
commit 0beda5bcab
3 changed files with 155 additions and 111 deletions

View File

@@ -359,45 +359,70 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
}
}
List<Operation> operations = Arrays.asList(
CompositeOperation.getOperations(
NamedOperation.getBaseOperation(operation)));
final Object name = NamedOperation.getName(operation);
final GuardedInvocationComponent gic = getGuardedInvocationComponent(
new ComponentLinkRequest(request, linkerServices));
return gic != null ? gic.getGuardedInvocation() : null;
}
while(!operations.isEmpty()) {
final GuardedInvocationComponent gic =
getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, name);
if(gic != null) {
return gic.getGuardedInvocation();
static final class ComponentLinkRequest {
final LinkRequest linkRequest;
final LinkerServices linkerServices;
final List<Operation> operations;
final Object name;
ComponentLinkRequest(final LinkRequest linkRequest,
final LinkerServices linkerServices) {
this.linkRequest = linkRequest;
this.linkerServices = linkerServices;
final Operation operation = linkRequest.getCallSiteDescriptor().getOperation();
this.operations = Arrays.asList(
CompositeOperation.getOperations(
NamedOperation.getBaseOperation(operation)));
this.name = NamedOperation.getName(operation);
}
private ComponentLinkRequest(final LinkRequest linkRequest,
final LinkerServices linkerServices,
final List<Operation> operations, final Object name) {
this.linkRequest = linkRequest;
this.linkerServices = linkerServices;
this.operations = operations;
this.name = name;
}
CallSiteDescriptor getDescriptor() {
return linkRequest.getCallSiteDescriptor();
}
ComponentLinkRequest popOperations() {
return new ComponentLinkRequest(linkRequest, linkerServices,
operations.subList(1, operations.size()), name);
}
}
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req)
throws Exception {
final Operation op = req.operations.get(0);
if (op instanceof StandardOperation) {
switch((StandardOperation)op) {
case GET_PROPERTY: return getPropertyGetter(req.popOperations());
case SET_PROPERTY: return getPropertySetter(req.popOperations());
case GET_METHOD: return getMethodGetter(req.popOperations());
default:
}
operations = pop(operations);
}
return null;
}
protected GuardedInvocationComponent getGuardedInvocationComponent(
final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices,
final List<Operation> operations, final Object name)
throws Exception {
if(operations.isEmpty()) {
GuardedInvocationComponent getNextComponent(final ComponentLinkRequest req) throws Exception {
if (req.operations.isEmpty()) {
return null;
}
final Operation op = operations.get(0);
// Either GET_PROPERTY:name(this) or GET_PROPERTY(this, name)
if(op == StandardOperation.GET_PROPERTY) {
return getPropertyGetter(callSiteDescriptor, linkerServices, pop(operations), name);
final GuardedInvocationComponent gic = getGuardedInvocationComponent(req);
if (gic != null) {
return gic;
}
// Either SET_PROPERTY:name(this, value) or SET_PROPERTY(this, name, value)
if(op == StandardOperation.SET_PROPERTY) {
return getPropertySetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
// Either GET_METHOD:name(this), or GET_METHOD(this, name)
if(op == StandardOperation.GET_METHOD) {
return getMethodGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
return null;
return getNextComponent(req.popOperations());
}
static final <T> List<T> pop(final List<T> l) {
@@ -483,16 +508,15 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
private static final MethodHandle CONSTANT_NULL_DROP_METHOD_HANDLE = MethodHandles.dropArguments(
MethodHandles.constant(Object.class, null), 0, MethodHandle.class);
private GuardedInvocationComponent getPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
if (name == null) {
return getUnnamedPropertySetter(callSiteDescriptor, linkerServices, operations);
private GuardedInvocationComponent getPropertySetter(final ComponentLinkRequest req) throws Exception {
if (req.name == null) {
return getUnnamedPropertySetter(req);
}
return getNamedPropertySetter(callSiteDescriptor, linkerServices, operations, name);
return getNamedPropertySetter(req);
}
private GuardedInvocationComponent getUnnamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations) throws Exception {
private GuardedInvocationComponent getUnnamedPropertySetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
// Must have three arguments: target object, property name, and property value.
assertParameterCount(callSiteDescriptor, 3);
@@ -501,6 +525,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// invoked, we'll conservatively presume Object return type. The one exception is void return.
final MethodType origType = callSiteDescriptor.getMethodType();
final MethodType type = origType.returnType() == void.class ? origType : origType.changeReturnType(Object.class);
final LinkerServices linkerServices = req.linkerServices;
// What's below is basically:
// foldArguments(guardWithTest(isNotNull, invoke, null|nextComponent.invocation),
@@ -527,11 +552,10 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// Handle to invoke the setter, dropping unnecessary fold arguments R(MethodHandle, O, N, V)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandle, 2, type.parameterType(
1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, null);
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
if (nextComponent == null) {
// Object(MethodHandle)->Object(MethodHandle, O, N, V); returns constant null
fallbackFolded = MethodHandles.dropArguments(CONSTANT_NULL_DROP_METHOD_HANDLE, 1,
type.parameterList()).asType(type.insertParameterTypes(0, MethodHandle.class));
@@ -551,19 +575,19 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return nextComponent.compose(compositeSetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedPropertySetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
private GuardedInvocationComponent getNamedPropertySetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
// Must have two arguments: target object and property value
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, linkerServices,
name.toString(), propertySetters);
final GuardedInvocation gi = createGuardedDynamicMethodInvocation(callSiteDescriptor, req.linkerServices,
req.name.toString(), propertySetters);
// If we have a property setter with this name, this composite operation will always stop here
if(gi != null) {
return new GuardedInvocationComponent(gi, clazz, ValidationType.EXACT_CLASS);
}
// If we don't have a property setter with this name, always fall back to the next operation in the
// composite (if any)
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, operations, name);
return getNextComponent(req);
}
private static final Lookup privateLookup = new Lookup(MethodHandles.lookup());
@@ -576,20 +600,18 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
"getTarget", MethodType.methodType(MethodHandle.class, CallSiteDescriptor.class, LinkerServices.class));
private static final MethodHandle GETTER_INVOKER = MethodHandles.invoker(MethodType.methodType(Object.class, Object.class));
private GuardedInvocationComponent getPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
if (name == null) {
return getUnnamedPropertyGetter(callSiteDescriptor, linkerServices, ops);
private GuardedInvocationComponent getPropertyGetter(final ComponentLinkRequest req) throws Exception {
if (req.name == null) {
return getUnnamedPropertyGetter(req);
}
return getNamedPropertyGetter(callSiteDescriptor, linkerServices, ops, name);
return getNamedPropertyGetter(req);
}
private GuardedInvocationComponent getUnnamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops) throws Exception {
private GuardedInvocationComponent getUnnamedPropertyGetter(final ComponentLinkRequest req) throws Exception {
// Since we can't know what kind of a getter we'll get back on different invocations, we'll just
// conservatively presume Object. Note we can't just coerce to a narrower call site type as the linking
// runtime might not allow coercing at that call site.
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
@@ -600,6 +622,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// AnnotatedDynamicMethod; if it is non-null, invoke its "handle" field, otherwise either return null,
// or delegate to next component's invocation.
final LinkerServices linkerServices = req.linkerServices;
final MethodHandle typedGetter = linkerServices.asType(getPropertyGetterHandle, type.changeReturnType(
AnnotatedDynamicMethod.class));
final MethodHandle callSiteBoundMethodGetter = MethodHandles.insertArguments(
@@ -613,8 +636,7 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
// Object(AnnotatedDynamicMethod, T0)->Object(AnnotatedDynamicMethod, T0, T1)
final MethodHandle invokeHandleFolded = MethodHandles.dropArguments(invokeHandleTyped, 2,
type.parameterType(1));
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops, null);
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final MethodHandle fallbackFolded;
if(nextComponent == null) {
@@ -639,17 +661,17 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedPropertyGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
private GuardedInvocationComponent getNamedPropertyGetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
// Fixed name
final AnnotatedDynamicMethod annGetter = propertyGetters.get(name.toString());
final AnnotatedDynamicMethod annGetter = propertyGetters.get(req.name.toString());
if(annGetter == null) {
// We have no such property, always delegate to the next component operation
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
return getNextComponent(req);
}
final MethodHandle getter = annGetter.getInvocation(callSiteDescriptor, linkerServices);
final MethodHandle getter = annGetter.getInvocation(req);
// NOTE: since property getters (not field getters!) are no-arg, we don't have to worry about them being
// overloaded in a subclass. Therefore, we can discover the most abstract superclass that has the
// method, and use that as the guard with Guards.isInstance() for a more stably linked call site. If
@@ -686,28 +708,27 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
MethodType.methodType(boolean.class, Object.class));
private static final MethodHandle OBJECT_IDENTITY = MethodHandles.identity(Object.class);
private GuardedInvocationComponent getMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name) throws Exception {
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
// be visible outside of this linker, declare it to return Object.
final MethodType type = callSiteDescriptor.getMethodType().changeReturnType(Object.class);
if (name == null) {
return getUnnamedMethodGetter(callSiteDescriptor, linkerServices, ops, type);
private GuardedInvocationComponent getMethodGetter(final ComponentLinkRequest req) throws Exception {
if (req.name == null) {
return getUnnamedMethodGetter(req);
}
return getNamedMethodGetter(callSiteDescriptor, linkerServices, ops, name, type);
return getNamedMethodGetter(req);
}
private GuardedInvocationComponent getUnnamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final MethodType type) throws Exception {
private static MethodType getMethodGetterType(final ComponentLinkRequest req) {
// The created method handle will always return a DynamicMethod (or null), but since we don't want that type to
// be visible outside of this linker, declare it to return Object.
return req.getDescriptor().getMethodType().changeReturnType(Object.class);
}
private GuardedInvocationComponent getUnnamedMethodGetter(final ComponentLinkRequest req) throws Exception {
// Must have exactly two arguments: receiver and name
assertParameterCount(callSiteDescriptor, 2);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, ops, null);
if(nextComponent == null || !InternalTypeUtilities.areAssignable(DynamicMethod.class,
nextComponent.getGuardedInvocation().getInvocation().type().returnType())) {
// No next component operation, or it can never produce a dynamic method; just return a component
// for this operation.
assertParameterCount(req.getDescriptor(), 2);
final GuardedInvocationComponent nextComponent = getNextComponent(req);
final LinkerServices linkerServices = req.linkerServices;
final MethodType type = getMethodGetterType(req);
if(nextComponent == null) {
// No next component operation; just return a component for this operation.
return getClassGuardedInvocationComponent(linkerServices.asType(getDynamicMethod, type), type);
}
@@ -728,25 +749,28 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
final MethodHandle nextCombinedInvocation = MethodHandles.dropArguments(nextComponentInvocation, 0,
Object.class);
// Assemble it all into a fold(guard(isNotNull, identity, nextInvocation), get)
// Note that nextCombinedInvocation needs to have its return type changed to Object
final MethodHandle compositeGetter = MethodHandles.foldArguments(MethodHandles.guardWithTest(
IS_DYNAMIC_METHOD, returnMethodHandle, nextCombinedInvocation), typedGetter);
IS_DYNAMIC_METHOD, returnMethodHandle,
nextCombinedInvocation.asType(nextCombinedInvocation.type().changeReturnType(Object.class))),
typedGetter);
return nextComponent.compose(compositeGetter, getClassGuard(type), clazz, ValidationType.EXACT_CLASS);
}
private GuardedInvocationComponent getNamedMethodGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> ops, final Object name, final MethodType type)
private GuardedInvocationComponent getNamedMethodGetter(final ComponentLinkRequest req)
throws Exception {
// Must have exactly one argument: receiver
assertParameterCount(callSiteDescriptor, 1);
final DynamicMethod method = getDynamicMethod(name.toString());
assertParameterCount(req.getDescriptor(), 1);
final DynamicMethod method = getDynamicMethod(req.name.toString());
if(method == null) {
// We have no such method, always delegate to the next component
return getGuardedInvocationComponent(callSiteDescriptor, linkerServices, ops, name);
return getNextComponent(req);
}
// No delegation to the next component of the composite operation; if we have a method with that name,
// we'll always return it at this point.
return getClassGuardedInvocationComponent(linkerServices.asType(MethodHandles.dropArguments(
final MethodType type = getMethodGetterType(req);
return getClassGuardedInvocationComponent(req.linkerServices.asType(MethodHandles.dropArguments(
MethodHandles.constant(Object.class, method), 0, type.parameterType(0)), type), type);
}
@@ -876,8 +900,8 @@ abstract class AbstractJavaLinker implements GuardingDynamicLinker {
this.validationType = validationType;
}
MethodHandle getInvocation(final CallSiteDescriptor callSiteDescriptor, final LinkerServices linkerServices) {
return method.getInvocation(callSiteDescriptor, linkerServices);
MethodHandle getInvocation(final ComponentLinkRequest req) {
return method.getInvocation(req.getDescriptor(), req.linkerServices);
}
@SuppressWarnings("unused")

View File

@@ -129,25 +129,21 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
}
@Override
protected GuardedInvocationComponent getGuardedInvocationComponent(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, name);
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception {
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req);
if(superGic != null) {
return superGic;
}
if(operations.isEmpty()) {
return null;
}
final Operation op = operations.get(0);
if(op == StandardOperation.GET_ELEMENT) {
return getElementGetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
if(op == StandardOperation.SET_ELEMENT) {
return getElementSetter(callSiteDescriptor, linkerServices, pop(operations), name);
}
if(op == StandardOperation.GET_LENGTH) {
return getLengthGetter(callSiteDescriptor);
if (!req.operations.isEmpty()) {
final Operation op = req.operations.get(0);
if (op instanceof StandardOperation) {
switch ((StandardOperation)op) {
case GET_ELEMENT: return getElementGetter(req.popOperations());
case SET_ELEMENT: return getElementSetter(req.popOperations());
case GET_LENGTH: return getLengthGetter(req.getDescriptor());
default:
}
}
}
return null;
}
@@ -170,12 +166,12 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
ARRAY, LIST, MAP
};
private GuardedInvocationComponent getElementGetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
private GuardedInvocationComponent getElementGetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
final LinkerServices linkerServices = req.linkerServices;
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
final GuardedInvocationComponent nextComponent = getGuardedInvocationComponent(callSiteDescriptor,
linkerServices, operations, name);
final GuardedInvocationComponent nextComponent = getNextComponent(req);
// If declared type of receiver at the call site is already an array, a list or map, bind without guard. Thing
// is, it'd be quite stupid of a call site creator to go though invokedynamic when it knows in advance they're
@@ -211,6 +207,7 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
// Convert the key to a number if we're working with a list or array
final Object typedName;
final Object name = req.name;
if(collectionType != CollectionType.MAP && name != null) {
typedName = convertKeyToInteger(name, linkerServices);
if(typedName == null) {
@@ -399,8 +396,9 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
private static final MethodHandle PUT_MAP_ELEMENT = Lookup.PUBLIC.findVirtual(Map.class, "put",
MethodType.methodType(Object.class, Object.class, Object.class));
private GuardedInvocationComponent getElementSetter(final CallSiteDescriptor callSiteDescriptor,
final LinkerServices linkerServices, final List<Operation> operations, final Object name) throws Exception {
private GuardedInvocationComponent getElementSetter(final ComponentLinkRequest req) throws Exception {
final CallSiteDescriptor callSiteDescriptor = req.getDescriptor();
final LinkerServices linkerServices = req.linkerServices;
final MethodType callSiteType = callSiteDescriptor.getMethodType();
final Class<?> declaredType = callSiteType.parameterType(0);
@@ -441,14 +439,14 @@ class BeanLinker extends AbstractJavaLinker implements TypeBasedGuardingDynamicL
// In contrast to, say, getElementGetter, we only compute the nextComponent if the target object is not a map,
// as maps will always succeed in setting the element and will never need to fall back to the next component
// operation.
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getGuardedInvocationComponent(
callSiteDescriptor, linkerServices, operations, name);
final GuardedInvocationComponent nextComponent = collectionType == CollectionType.MAP ? null : getNextComponent(req);
if(gic == null) {
return nextComponent;
}
// Convert the key to a number if we're working with a list or array
final Object typedName;
final Object name = req.name;
if(collectionType != CollectionType.MAP && name != null) {
typedName = convertKeyToInteger(name, linkerServices);
if(typedName == null) {

View File

@@ -91,6 +91,7 @@ import java.util.Arrays;
import java.util.Set;
import jdk.dynalink.CallSiteDescriptor;
import jdk.dynalink.NamedOperation;
import jdk.dynalink.Operation;
import jdk.dynalink.StandardOperation;
import jdk.dynalink.beans.GuardedInvocationComponent.ValidationType;
import jdk.dynalink.linker.GuardedInvocation;
@@ -161,6 +162,27 @@ class StaticClassLinker implements TypeBasedGuardingDynamicLinker {
return null;
}
@Override
protected GuardedInvocationComponent getGuardedInvocationComponent(final ComponentLinkRequest req) throws Exception {
final GuardedInvocationComponent superGic = super.getGuardedInvocationComponent(req);
if (superGic != null) {
return superGic;
}
if (!req.operations.isEmpty()) {
final Operation op = req.operations.get(0);
if (op instanceof StandardOperation) {
switch ((StandardOperation)op) {
case GET_ELEMENT:
case SET_ELEMENT:
// StaticClass doesn't behave as a collection
return getNextComponent(req.popOperations());
default:
}
}
}
return null;
}
@Override
SingleDynamicMethod getConstructorMethod(final String signature) {
return constructor != null? constructor.getMethodForExactParamTypes(signature) : null;