diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java index db0ec415b8c1..ed59946f6f51 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/DebugProcessImpl.java @@ -1530,6 +1530,7 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb invokerArgs.add(objRef); // object invokerArgs.add(DebuggerUtilsEx.mirrorOfString(method.name() + ";" + method.signature(), evaluationContext)); // method name and descriptor + invokerArgs.add(method.declaringType().classLoader()); // method's declaring type class loader to be able to resolve parameter types // argument values List args = new ArrayList<>(originalArgs); @@ -1549,16 +1550,19 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb boxedArgs.add((Value)BoxingEvaluator.box(arg, evaluationContext)); } - ArrayType objectArrayClass = (ArrayType)debugProcess.findClass( - evaluationContext, - CommonClassNames.JAVA_LANG_OBJECT + "[]", - evaluationContext.getClassLoader()); + if (boxedArgs.size() < 10) { + invokerArgs.addAll(boxedArgs); // args + return DebuggerUtilsImpl.invokeHelperMethod(evaluationContext, MethodInvoker.class, "invoke" + boxedArgs.size(), invokerArgs, false); + } + else { + ArrayType objectArrayClass = (ArrayType)debugProcess.findClass( + evaluationContext, + CommonClassNames.JAVA_LANG_OBJECT + "[]", + evaluationContext.getClassLoader()); - // reserve one extra element for the return value - boxedArgs.add(null); - invokerArgs.add(DebuggerUtilsEx.mirrorOfArray(objectArrayClass, boxedArgs, evaluationContext)); // args - invokerArgs.add(method.declaringType().classLoader()); // method's declaring type class loader to be able to resolve parameter types - return DebuggerUtilsImpl.invokeHelperMethod(evaluationContext, MethodInvoker.class, "invoke", invokerArgs, false); + invokerArgs.add(DebuggerUtilsEx.mirrorOfArray(objectArrayClass, boxedArgs, evaluationContext)); // args + return DebuggerUtilsImpl.invokeHelperMethod(evaluationContext, MethodInvoker.class, "invoke", invokerArgs, false); + } } private static ThreadReferenceProxy getEvaluationThread(final EvaluationContext evaluationContext) throws EvaluateException { diff --git a/java/java-runtime/src/com/intellij/rt/debugger/MethodInvoker.java b/java/java-runtime/src/com/intellij/rt/debugger/MethodInvoker.java index 3d025f794545..75f5c4d76203 100644 --- a/java/java-runtime/src/com/intellij/rt/debugger/MethodInvoker.java +++ b/java/java-runtime/src/com/intellij/rt/debugger/MethodInvoker.java @@ -8,14 +8,158 @@ import java.lang.invoke.WrongMethodTypeException; import java.lang.reflect.Array; import java.util.Arrays; +@SuppressWarnings({"SSBasedInspection", "unused"}) public final class MethodInvoker { + // TODO: may leak objects here + static ThreadLocal returnValue = new ThreadLocal<>(); + + public static Object invoke0(MethodHandles.Lookup lookup, Class cls, Object obj, String nameAndDescriptor, ClassLoader loader) + throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{}); + } + + public static Object invoke1(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1}); + } + + public static Object invoke2(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2}); + } + + public static Object invoke3(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3}); + } + + public static Object invoke4(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4}); + } + + public static Object invoke5(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5}); + } + + public static Object invoke6(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5, + Object arg6) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5, arg6}); + } + + public static Object invoke7(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5, + Object arg6, + Object arg7) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5, arg6, arg7}); + } + + public static Object invoke8(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5, + Object arg6, + Object arg7, + Object arg8) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8}); + } + + public static Object invoke9(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5, + Object arg6, + Object arg7, + Object arg8, + Object arg9) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9}); + } + + public static Object invoke10(MethodHandles.Lookup lookup, + Class cls, + Object obj, + String nameAndDescriptor, + ClassLoader loader, + Object arg1, + Object arg2, + Object arg3, + Object arg4, + Object arg5, + Object arg6, + Object arg7, + Object arg8, + Object arg9, + Object arg10) throws Throwable { + return invoke(lookup, cls, obj, nameAndDescriptor, loader, new Object[]{arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10}); + } + + public static Object invoke(MethodHandles.Lookup lookup, Class cls, Object obj, String nameAndDescriptor, - Object[] argsArray, - ClassLoader loader) - throws Throwable { + ClassLoader loader, + Object[] args) throws Throwable { try { int separatorIndex = nameAndDescriptor.indexOf(';'); String name = nameAndDescriptor.substring(0, separatorIndex); @@ -33,9 +177,6 @@ public final class MethodInvoker { method = lookup.findStatic(cls, name, mt); } - // the last element is always null, it is reserved for the return value - Object[] args = Arrays.copyOf(argsArray, argsArray.length - 1); - Object result; // handle the case where null is passed as the vararg array @@ -55,7 +196,7 @@ public final class MethodInvoker { } result = method.invokeWithArguments(args); } - argsArray[argsArray.length - 1] = result; // store the result as the last array element to avoid it being collected + returnValue.set(result); return result; } catch (WrongMethodTypeException | ClassCastException e) {