Pass byte array more efficiently
Filling byte[] values is especially slow on Android (>3000ms to fill a byte[3000] on emulator).
This commit is contained in:
-13
@@ -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;")
|
||||
|
||||
+19
-2
@@ -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<ClassToLoad>): Boolean
|
||||
|
||||
fun loadClasses(context: EvaluationContextImpl, classes: Collection<ClassToLoad>): 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<Value>(bytes.size)
|
||||
for (byte in bytes) {
|
||||
mirrors += process.virtualMachineProxy.mirrorOf(byte)
|
||||
}
|
||||
reference.values = mirrors
|
||||
|
||||
return reference
|
||||
}
|
||||
}
|
||||
+31
-5
@@ -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<ClassToLoad>,
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user