diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt index 7d648a386ff..f9943308ae9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/AbstractAndroidClassLoadingAdapter.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.engine.evaluation.EvaluationContextImpl -import com.intellij.debugger.impl.DebuggerUtilsEx import com.sun.jdi.* abstract class AbstractAndroidClassLoadingAdapter : ClassLoadingAdapter { @@ -27,18 +26,6 @@ abstract class AbstractAndroidClassLoadingAdapter : ClassLoadingAdapter { return AndroidDexer.getInstances(context.project).single().dex(classes) } - protected fun mirrorOfByteArray(bytes: ByteArray, context: EvaluationContextImpl, process: DebugProcessImpl): ArrayReference { - val arrayClass = process.findClass(context, "byte[]", context.classLoader) as ArrayType - val reference = process.newInstance(arrayClass, bytes.size) - DebuggerUtilsEx.keep(reference, context) - - for (i in 0..bytes.lastIndex) { - reference.setValue(i, process.virtualMachineProxy.mirrorOf(bytes[i])) - } - - return reference - } - protected fun wrapToByteBuffer(bytes: ArrayReference, context: EvaluationContext, process: DebugProcessImpl): ObjectReference { val byteBufferClass = process.findClass(context, "java.nio.ByteBuffer", context.classLoader) as ClassType val wrapMethod = byteBufferClass.concreteMethodByName("wrap", "([B)Ljava/nio/ByteBuffer;") diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt index 578d42eef75..f8f2a5d0af2 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/ClassLoadingAdapter.kt @@ -16,9 +16,12 @@ package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading +import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.evaluation.EvaluationContextImpl -import com.intellij.psi.PsiFile -import com.sun.jdi.ClassLoaderReference +import com.intellij.debugger.impl.DebuggerUtilsEx +import com.sun.jdi.ArrayReference +import com.sun.jdi.ArrayType +import com.sun.jdi.Value interface ClassLoadingAdapter { companion object { @@ -41,4 +44,18 @@ interface ClassLoadingAdapter { fun isApplicable(context: EvaluationContextImpl, classes: Collection): Boolean fun loadClasses(context: EvaluationContextImpl, classes: Collection): ClassLoaderHandler + + fun mirrorOfByteArray(bytes: ByteArray, context: EvaluationContextImpl, process: DebugProcessImpl): ArrayReference { + val arrayClass = process.findClass(context, "byte[]", context.classLoader) as ArrayType + val reference = process.newInstance(arrayClass, bytes.size) + DebuggerUtilsEx.keep(reference, context) + + val mirrors = ArrayList(bytes.size) + for (byte in bytes) { + mirrors += process.virtualMachineProxy.mirrorOf(byte) + } + reference.values = mirrors + + return reference + } } \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt index 35aa320040b..8fef53b4a86 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/classLoading/OrdinaryClassLoadingAdapter.kt @@ -16,14 +16,15 @@ package org.jetbrains.kotlin.idea.debugger.evaluate.classLoading -import com.intellij.debugger.engine.DebugProcess +import com.intellij.debugger.engine.DebugProcessImpl import com.intellij.debugger.engine.evaluation.EvaluateException -import com.intellij.debugger.engine.evaluation.EvaluationContext import com.intellij.debugger.engine.evaluation.EvaluationContextImpl import com.intellij.debugger.impl.ClassLoadingUtils +import com.intellij.debugger.impl.DebuggerUtilsEx import com.intellij.openapi.projectRoots.JdkVersionUtil import com.intellij.openapi.util.SystemInfo import com.sun.jdi.ClassLoaderReference +import com.sun.jdi.ClassType import org.jetbrains.kotlin.idea.debugger.evaluate.CompilingEvaluatorUtils class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { @@ -72,8 +73,8 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { private fun defineClasses( classes: Collection, - context: EvaluationContext, - process: DebugProcess, + context: EvaluationContextImpl, + process: DebugProcessImpl, classLoader: ClassLoaderReference ) { val classesToLoad = if (classes.size == 1) { @@ -89,10 +90,35 @@ class OrdinaryClassLoadingAdapter : ClassLoadingAdapter { for ((className, _, bytes) in classesToLoad) { val patchedBytes = CompilingEvaluatorUtils.changeSuperToMagicAccessor(bytes) - ClassLoadingUtils.defineClass(className, patchedBytes, context, process, classLoader) + defineClass(className, patchedBytes, context, process, classLoader) } } + fun defineClass( + name: String, + bytes: ByteArray, + context: EvaluationContextImpl, + process: DebugProcessImpl, + classLoader: ClassLoaderReference + ) { + try { + val vm = process.virtualMachineProxy + val classLoaderType = classLoader.referenceType() as ClassType + val defineMethod = classLoaderType.concreteMethodByName("defineClass", "(Ljava/lang/String;[BII)Ljava/lang/Class;") + val nameObj = vm.mirrorOf(name) + + DebuggerUtilsEx.keep(nameObj, context) + + process.invokeMethod( + context, classLoader, defineMethod, + listOf(nameObj, mirrorOfByteArray(bytes, context, process), vm.mirrorOf(0), vm.mirrorOf(bytes.size))) + } + catch (e: Exception) { + throw EvaluateException("Error during class $name definition: $e", e) + } + + } + private class ClassBytes(val name: String) { val bytes: ByteArray by lazy { val inputStream = this::class.java.classLoader.getResourceAsStream(name.replace('.', '/') + ".class")