mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 22:51:17 +07:00
[debugger] made invocation helper use method handles
GitOrigin-RevId: 340efd6c3cfacd29266b704ef80f0f9f3e2f3a11
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1d58994a43
commit
e8576838b4
@@ -1,57 +1,52 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.rt.debugger;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
|
||||
public final class MethodInvoker {
|
||||
// TODO: may leak objects here
|
||||
static ThreadLocal<Object> returnValue = new ThreadLocal<>();
|
||||
|
||||
public static Object invoke(Class<?> cls, Object obj, String name, Class<?>[] parameterTypes, Object[] args)
|
||||
public static Object invoke(MethodHandles.Lookup lookup,
|
||||
Class<?> cls,
|
||||
Object obj,
|
||||
String name,
|
||||
String descriptor,
|
||||
Object[] args,
|
||||
ClassLoader loader)
|
||||
throws Throwable {
|
||||
ArrayList<Method> methods = new ArrayList<>();
|
||||
// TODO: better collect methods lazily
|
||||
addMatchingMethods(methods, cls, name, parameterTypes);
|
||||
for (Method method : methods) {
|
||||
try {
|
||||
method.setAccessible(true);
|
||||
Object res = method.invoke(obj, args);
|
||||
returnValue.set(res); // to avoid gc for the result object
|
||||
return res;
|
||||
}
|
||||
catch (InvocationTargetException e) {
|
||||
throw e.getCause();
|
||||
}
|
||||
catch (IllegalAccessException | SecurityException e) {
|
||||
// try the next method
|
||||
}
|
||||
catch (Exception e) {
|
||||
// InaccessibleObjectException appeared in jdk 9
|
||||
if (!"java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
|
||||
throw e;
|
||||
}
|
||||
// try the next method
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to execute the method " + name);
|
||||
}
|
||||
|
||||
//TODO: avoid recursion
|
||||
private static void addMatchingMethods(List<Method> methods, Class<?> cls, String name, Class<?>[] parameterTypes) {
|
||||
try {
|
||||
methods.add(cls.getDeclaredMethod(name, parameterTypes));
|
||||
MethodType mt = MethodType.fromMethodDescriptorString(descriptor, loader);
|
||||
MethodHandle method;
|
||||
if ("<init>".equals(name)) {
|
||||
method = lookup.findConstructor(cls, mt);
|
||||
}
|
||||
else if (obj != null) {
|
||||
method = lookup.findVirtual(cls, name, mt).bindTo(obj);
|
||||
}
|
||||
else {
|
||||
method = lookup.findStatic(cls, name, mt);
|
||||
}
|
||||
|
||||
Object result;
|
||||
|
||||
// handle the case where null is passed as the vararg array
|
||||
// TODO: handle when vararg is not the only parameter
|
||||
if (mt.parameterCount() == 1 && args.length == 1 && args[0] == null && mt.parameterType(0).isArray()) {
|
||||
result = method.invoke((Object[])null);
|
||||
}
|
||||
else {
|
||||
result = method.invokeWithArguments(args);
|
||||
}
|
||||
returnValue.set(result);
|
||||
return result;
|
||||
}
|
||||
catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
Class<?> superclass = cls.getSuperclass();
|
||||
if (superclass != null) {
|
||||
addMatchingMethods(methods, superclass, name, parameterTypes);
|
||||
}
|
||||
for (Class<?> anInterface : cls.getInterfaces()) {
|
||||
addMatchingMethods(methods, anInterface, name, parameterTypes);
|
||||
catch (WrongMethodTypeException | ClassCastException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user