use of org.springsource.loaded.MethodMember in project spring-loaded by spring-projects.
the class Java8 method callLambdaMetaFactory.
// TODO [perf] How about a table of CallSites indexed by invokedynamic number through the class file. Computed on first reference but cleared on reload. Possibly extend this to all invoke types!
// TODO [lambda] Need to handle altMetaFactory which is used when the lambdas are more 'complex' (e.g. Serializable)
public static CallSite callLambdaMetaFactory(ReloadableType rtype, Object[] bsmArgs, Object lookup, String indyNameAndDescriptor, Class<?> executorClass) throws Exception {
MethodHandles.Lookup caller = (MethodHandles.Lookup) lookup;
ClassLoader callerLoader = caller.lookupClass().getClassLoader();
int descriptorStart = indyNameAndDescriptor.indexOf('(');
String invokedName = indyNameAndDescriptor.substring(0, descriptorStart);
MethodType invokedType = MethodType.fromMethodDescriptorString(indyNameAndDescriptor.substring(descriptorStart), callerLoader);
// Use bsmArgs to build the parameters
MethodType samMethodType = MethodType.fromMethodDescriptorString((((Type) bsmArgs[0]).getDescriptor()), callerLoader);
Handle bsmArgsHandle = (Handle) bsmArgs[1];
String owner = bsmArgsHandle.getOwner();
String name = bsmArgsHandle.getName();
String descriptor = bsmArgsHandle.getDesc();
MethodType implMethodType = MethodType.fromMethodDescriptorString(descriptor, callerLoader);
// Looking up the lambda$run method in the caller class (note the caller class is the executor, which gets us around the
// problem of having to hack into LambdaMetafactory to intercept reflection)
MethodHandle implMethod = null;
switch(bsmArgsHandle.getTag()) {
case Opcodes.H_INVOKESTATIC:
implMethod = caller.findStatic(caller.lookupClass(), name, implMethodType);
break;
case Opcodes.H_INVOKESPECIAL:
// will be static with a new leading parameter.
if (executorClass == null) {
// TODO is final parameter here correct?
implMethod = caller.findSpecial(caller.lookupClass(), name, implMethodType, caller.lookupClass());
} else {
implMethod = caller.findStatic(caller.lookupClass(), name, MethodType.fromMethodDescriptorString("(L" + owner + ";" + descriptor.substring(1), callerLoader));
}
break;
case Opcodes.H_INVOKEVIRTUAL:
// There is a possibility to 'shortcut' here. Basically we are trying to resolve a callsite reference
// to the method that satisfies it. The easiest option is to just find the method on the originally
// loaded version of the target class and return that. A more optimal shortcut could return the
// method on the executor class if the target has been reloaded (effectively bypassing the method
// on the originally loaded version since we know that it will be acting as a pass through). But this
// opens up a can of worms related to visibility. The executor is loaded into the child classloader,
// and if the caller has not been reloaded it will not be able to 'see' the executor (since it is in
// a child classloader). So, basically keep this dumb (but reliable) for now.
TypeRegistry typeRegistry = rtype.getTypeRegistry();
ReloadableType ownerRType = typeRegistry.getReloadableType(owner);
if (null == ownerRType || !ownerRType.hasBeenReloaded()) {
// target containing the reference/lambdaMethod has not been reloaded, no need to get over
// complicated.
Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
implMethod = caller.findVirtual(clazz, name, implMethodType);
} else {
MethodMember targetReferenceMethodMember = ownerRType.getCurrentMethod(name, descriptor);
String targetReferenceDescriptor = targetReferenceMethodMember.getDescriptor();
MethodType targetReferenceMethodType = MethodType.fromMethodDescriptorString(targetReferenceDescriptor, callerLoader);
Class<?> targetReferenceClass = ownerRType.getClazz();
MethodMember currentMethod = ownerRType.getCurrentMethod(name, descriptor);
if (currentMethod.original == null) {
// caller and reloaded target are in the same child classloader (no visibility problem).
if (!rtype.hasBeenReloaded()) {
throw new IllegalStateException("Assertion violated: When a method added on reload is being referenced" + "in target type '" + ownerRType.getName() + "', expected the caller to also have been reloaded: '" + rtype.getName() + "'");
}
CurrentLiveVersion ownerLiveVersion = ownerRType.getLiveVersion();
Class<?> ownerExecutorClass = ownerLiveVersion.getExecutorClass();
Method executorMethod = ownerLiveVersion.getExecutorMethod(currentMethod);
String methodDescriptor = Type.getType(executorMethod).getDescriptor();
MethodType type = MethodType.fromMethodDescriptorString(methodDescriptor, callerLoader);
implMethod = caller.findStatic(ownerExecutorClass, name, type);
} else {
// This finds the reference method on the originally loaded class. It will pass through
// to the actual code on the reloaded version.
implMethod = caller.findVirtual(targetReferenceClass, name, targetReferenceMethodType);
}
}
break;
case Opcodes.H_NEWINVOKESPECIAL:
Class<?> clazz = callerLoader.loadClass(owner.replace("/", "."));
implMethod = caller.findConstructor(clazz, implMethodType);
break;
case Opcodes.H_INVOKEINTERFACE:
Handle h = (Handle) bsmArgs[1];
String interfaceOwner = h.getOwner();
// TODO Should there not be a more direct way to this than classloading?
// TODO What about when this is a method added to the interface on a reload? It won't really exist, should we point
// to the executor? or something else? (maybe just directly the real method that will satisfy the interface - if it can be worked out)
// interface type, eg StreamB$Foo
Class<?> interfaceClass = callerLoader.loadClass(interfaceOwner.replace('/', '.'));
implMethod = caller.findVirtual(interfaceClass, name, implMethodType);
break;
default:
throw new IllegalStateException("nyi " + bsmArgsHandle.getTag());
}
MethodType instantiatedMethodType = MethodType.fromMethodDescriptorString((((Type) bsmArgs[2]).getDescriptor()), callerLoader);
return LambdaMetafactory.metafactory(caller, invokedName, invokedType, samMethodType, implMethod, instantiatedMethodType);
}
use of org.springsource.loaded.MethodMember in project spring-loaded by spring-projects.
the class TypeDescriptorMethodProvider method getDeclaredMethods.
@Override
public List<Invoker> getDeclaredMethods() {
TypeDescriptor typeDescriptor = getTypeDescriptor();
MethodMember[] methods = typeDescriptor.getMethods();
List<Invoker> invokers = new ArrayList<Invoker>();
for (MethodMember method : methods) {
// TODO [perf] create constant for this check?
if (((MethodMember.BIT_CATCHER | MethodMember.BIT_SUPERDISPATCHER | MethodMember.WAS_DELETED) & method.bits) == 0) {
invokers.add(invokerFor(method));
}
}
return invokers;
}
use of org.springsource.loaded.MethodMember in project spring-loaded by spring-projects.
the class ReflectiveInterceptor method jlrMethodGetParameterAnnotations.
public static Annotation[][] jlrMethodGetParameterAnnotations(Method method) {
ReloadableType rtype = getReloadableTypeIfHasBeenReloaded(method.getDeclaringClass());
if (rtype == null) {
//Nothing special to be done
return method.getParameterAnnotations();
} else {
// Method could have changed...
CurrentLiveVersion clv = rtype.getLiveVersion();
MethodMember currentMethod = rtype.getCurrentMethod(method.getName(), Type.getMethodDescriptor(method));
Method executor = clv.getExecutorMethod(currentMethod);
Annotation[][] result = executor.getParameterAnnotations();
if (!currentMethod.isStatic()) {
//Non=static methods have an extra param.
//Though extra param is added to front...
//Annotations aren't being moved so we have to actually drop the *last* array element
result = Utils.arrayCopyOf(result, result.length - 1);
}
return result;
}
}
use of org.springsource.loaded.MethodMember in project spring-loaded by spring-projects.
the class ReflectiveInterceptor method fixModifier.
protected static void fixModifier(ReloadableType rtype, Constructor<?> constructor) {
String desc = Type.getConstructorDescriptor(constructor);
MethodMember rCons = rtype.getCurrentConstructor(desc);
if (constructor.getModifiers() != rCons.getModifiers()) {
JVM.setConstructorModifiers(constructor, rCons.getModifiers());
}
}
use of org.springsource.loaded.MethodMember in project spring-loaded by spring-projects.
the class IncrementalTypeDescriptorTests method simpleExtractor.
/**
* Test comparison of two simple classes.
*/
@Test
public void simpleExtractor() {
TypeRegistry registry = getTypeRegistry("");
byte[] bytes = loadBytesForClass("data.SimpleClass");
TypeDescriptor typeDescriptor = new TypeDescriptorExtractor(registry).extract(bytes, true);
byte[] bytes2 = ClassRenamer.rename("data.SimpleClass", loadBytesForClass("data.SimpleClass002"));
TypeDescriptor typeDescriptor2 = new TypeDescriptorExtractor(registry).extract(bytes2, true);
IncrementalTypeDescriptor itd = new IncrementalTypeDescriptor(typeDescriptor);
itd.setLatestTypeDescriptor(typeDescriptor2);
List<MethodMember> newMethods = itd.getNewOrChangedMethods();
Assert.assertEquals(1, newMethods.size());
Assert.assertEquals("0x1 bar()Ljava/lang/String;", newMethods.get(0).toString());
List<MethodMember> deletedMethods = itd.getDeletedMethods();
Assert.assertEquals(1, deletedMethods.size());
Assert.assertEquals("0x1 foo()V", deletedMethods.get(0).toString());
}
Aggregations