Update FunctionImpl hack in Evaluate Expression and test data

Lambdas now have an additional superclass besides FunctionImpl: Lambda, which
should also be changed to inherit from MagicAccessorImpl
This commit is contained in:
Alexander Udalov
2015-05-19 00:37:10 +03:00
parent 4141e0a8df
commit b08bd3bc67
12 changed files with 51 additions and 35 deletions
@@ -16,15 +16,15 @@
package org.jetbrains.kotlin.idea.debugger.evaluate.compilingEvaluator
import kotlin.properties.Delegates
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.engine.DebugProcess
import com.sun.jdi.ClassLoaderReference
import com.intellij.openapi.projectRoots.JdkVersionUtil
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.debugger.engine.evaluation.EvaluateException
import com.intellij.debugger.engine.evaluation.EvaluationContext
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl
import com.intellij.openapi.projectRoots.JdkVersionUtil
import com.intellij.openapi.util.SystemInfo
import com.sun.jdi.ClassLoaderReference
import org.jetbrains.kotlin.idea.debugger.evaluate.CompilingEvaluatorUtils
import kotlin.properties.Delegates
public fun loadClasses(evaluationContext: EvaluationContextImpl, classes: Collection<Pair<String, ByteArray>>) {
val process = evaluationContext.getDebugProcess()
@@ -60,27 +60,30 @@ private fun defineClasses(
process: DebugProcess,
classLoader: ClassLoaderReference
) {
CompilingEvaluatorUtils.defineClass(FunctionImplBytes.name, FunctionImplBytes.bytes, context, process, classLoader)
for ((className, bytes) in classes) {
val lambdaSuperclasses = LAMBDA_SUPERCLASSES.map { it.name to it.bytes }
for ((className, bytes) in lambdaSuperclasses + classes) {
CompilingEvaluatorUtils.defineClass(className, bytes, context, process, classLoader)
}
}
private object FunctionImplBytes {
// The order is relevant here: if we load Lambda first instead, during the definition of Lambda the class loader will look for
// its superclasses and will try to load FunctionImpl itself. It will succeed, probably with the help of some parent class loader,
// and the subsequent attempt to define the patched version of FunctionImpl will fail with LinkageError (cannot redefine class)
private val LAMBDA_SUPERCLASSES = listOf(
ClassBytes("kotlin.jvm.internal.FunctionImpl"),
ClassBytes("kotlin.jvm.internal.Lambda")
)
private class ClassBytes(val name: String) {
val bytes: ByteArray by Delegates.lazy {
val inputStream = this.javaClass.getClassLoader().getResourceAsStream("kotlin/jvm/internal/FunctionImpl.class")
if (inputStream != null) {
try {
return@lazy inputStream.readBytes()
}
finally {
inputStream.close()
}
val inputStream = this.javaClass.getClassLoader().getResourceAsStream(name.replace('.', '/') + ".class")
?: throw EvaluateException("Couldn't find $name class in current class loader")
try {
inputStream.readBytes()
}
finally {
inputStream.close()
}
throw EvaluateException("Couldn't find kotlin.jvm.internal.FunctionImpl class in current classloader")
}
val name = "kotlin.jvm.internal.FunctionImpl"
}
}
@@ -26,10 +26,11 @@ fun foo(f: () -> Unit) {
// PRINT_FRAME
frame = invoke():11, FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1 {frameAnonymousObject}
this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1 = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1@uniqueID} (sp = null)
field = obProp: int = 1 (sp = frameAnonymousObject.kt, 6)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -36,7 +36,8 @@ fun foo(f: () -> Unit) {
// EXPRESSION: myFun()
// RESULT: 1: I
frame = invoke():16, A$test$1 {frameClassObject}
this = this = {frameClassObject.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameClassObject.A$test$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -84,7 +84,7 @@ fun lambda(f: () -> Unit) {
// EXPRESSION: bMyFun()
// RESULT: 1: I
frame = invoke():24, Outer$foo$LocalClass$test$1 {frameExtFunExtFun}
this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameExtFunExtFun.Outer$foo$LocalClass = {frameExtFunExtFun.Outer$foo$LocalClass@uniqueID} (sp = null)
field = lcProp: int = 1 (sp = frameExtFunExtFun.kt, 19)
field = this$0: frameExtFunExtFun.Outer = {frameExtFunExtFun.Outer@uniqueID} (sp = null)
@@ -95,6 +95,7 @@ fun lambda(f: () -> Unit) {
field = receiver$0: frameExtFunExtFun.B = {frameExtFunExtFun.B@uniqueID} (sp = null)
field = bProp: int = 1 (sp = frameExtFunExtFun.kt, 41)
field = $valTest: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -33,10 +33,12 @@ fun foo(f: () -> Unit) {
// EXPRESSION: val1 + val2
// RESULT: 2: I
frame = invoke():9, FrameInnerLambdaPackage$@packagePartHASH$main$1$1 {frameInnerLambda}
this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit> (sp = null)
this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit> (sp = null)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
field = $val2: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -22,8 +22,9 @@ fun foo(f: () -> Unit) {
// EXPRESSION: val1
// RESULT: 1: I
frame = invoke():7, FrameLambdaPackage$@packagePartHASH$main$1 {frameLambda}
this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -22,7 +22,8 @@ fun foo(f: () -> Unit) {
// EXPRESSION: val1
// RESULT: Cannot find local variable: name = val1
frame = invoke():7, FrameLambdaNotUsedPackage$@packagePartHASH$main$1 {frameLambdaNotUsed}
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -30,7 +30,8 @@ fun foo(f: () -> Unit) {
// EXPRESSION: O.obMyFun()
// RESULT: 1: I
frame = invoke():6, FrameObjectPackage$@packagePartHASH$main$1 {frameObject}
this = this = {frameObject.FrameObjectPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameObject.FrameObjectPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -22,9 +22,10 @@ fun foo(f: () -> Unit) {
// EXPRESSION: var1
// RESULT: 1: I
frame = invoke():7, FrameSharedVarPackage$@packagePartHASH$main$1 {frameSharedVar}
this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = $var1: kotlin.jvm.internal.Ref$IntRef = {kotlin.jvm.internal.Ref$IntRef@uniqueID}1 (sp = null)
field = element: int = 1 (sp = Ref.!EXT!)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -48,10 +48,11 @@ fun foo(f: () -> Unit) {
// EXPRESSION: myFun()
// RESULT: 1: I
frame = invoke():16, A$test$1 {frameThis0}
this = this = {frameThis0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameThis0.A$test$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameThis0.A = {frameThis0.A@uniqueID} (sp = null)
field = prop1: int = 1 (sp = frameThis0.kt, 8)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
local = val2: int = 1 (sp = frameThis0.kt, 14)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
@@ -64,12 +64,13 @@ fun foo(f: () -> Unit) {
// EXPRESSION: myFun2()
// RESULT: 1: I
frame = invoke():15, A$testExt$1 {frameThis0Ext}
this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.Function0<kotlin.Unit>
this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameThis0Ext.A = {frameThis0Ext.A@uniqueID} (sp = null)
field = prop1: int = 1 (sp = frameThis0Ext.kt, 8)
field = receiver$0: frameThis0Ext.AExt = {frameThis0Ext.AExt@uniqueID} (sp = null)
field = prop2: int = 1 (sp = frameThis0Ext.kt, 25)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0
@@ -50,12 +50,14 @@ fun foo(f: () -> Unit) {
// EXPRESSION: myFun()
// RESULT: 1: I
frame = invoke():17, A$test$1$1 {frameThis0This0}
this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.Function0<kotlin.Unit>
field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0<kotlin.Unit> (sp = null)
this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit>
field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.jvm.functions.Function0<kotlin.Unit> (sp = null)
field = this$0: frameThis0This0.A = {frameThis0This0.A@uniqueID} (sp = null)
field = prop1: int = 1 (sp = frameThis0This0.kt, 8)
field = $val1: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
field = $val2: int = 1 (sp = null)
field = arity: int = 0 (sp = Lambda.!EXT!)
Disconnected from the target VM, address: '!HOST_NAME!:PORT_NAME!', transport: 'socket'
Process finished with exit code 0