From b08bd3bc675fcddc1e4747183dc49c9bbfb8c96e Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Tue, 19 May 2015 00:37:10 +0300 Subject: [PATCH] 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 --- .../debugger/evaluate/compilingEvaluator.kt | 47 ++++++++++--------- .../tinyApp/outs/frameAnonymousObject.out | 3 +- .../tinyApp/outs/frameClassObject.out | 3 +- .../tinyApp/outs/frameExtFunExtFun.out | 3 +- .../tinyApp/outs/frameInnerLambda.out | 6 ++- .../debugger/tinyApp/outs/frameLambda.out | 3 +- .../tinyApp/outs/frameLambdaNotUsed.out | 3 +- .../debugger/tinyApp/outs/frameObject.out | 3 +- .../debugger/tinyApp/outs/frameSharedVar.out | 3 +- .../debugger/tinyApp/outs/frameThis0.out | 3 +- .../debugger/tinyApp/outs/frameThis0Ext.out | 3 +- .../debugger/tinyApp/outs/frameThis0This0.out | 6 ++- 12 files changed, 51 insertions(+), 35 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/compilingEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/compilingEvaluator.kt index e88676c81ed..16105738a08 100644 --- a/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/compilingEvaluator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/debugger/evaluate/compilingEvaluator.kt @@ -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>) { 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" -} \ No newline at end of file +} diff --git a/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out b/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out index 889e8a9920a..219164cbbdc 100644 --- a/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out +++ b/idea/testData/debugger/tinyApp/outs/frameAnonymousObject.out @@ -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 + this = this = {frameAnonymousObject.FrameAnonymousObjectPackage$@packagePartHASH$main$o$1$run$1@uniqueID}kotlin.jvm.functions.Function0 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameClassObject.out b/idea/testData/debugger/tinyApp/outs/frameClassObject.out index 8049d79c0f3..7d4fea17e68 100644 --- a/idea/testData/debugger/tinyApp/outs/frameClassObject.out +++ b/idea/testData/debugger/tinyApp/outs/frameClassObject.out @@ -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 + this = this = {frameClassObject.A$test$1@uniqueID}kotlin.jvm.functions.Function0 + 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out b/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out index 8ccac44f394..1a66873b070 100644 --- a/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out +++ b/idea/testData/debugger/tinyApp/outs/frameExtFunExtFun.out @@ -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 + this = this = {frameExtFunExtFun.Outer$foo$LocalClass$test$1@uniqueID}kotlin.jvm.functions.Function0 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out b/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out index 3c6384e2727..2a435ff065e 100644 --- a/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out +++ b/idea/testData/debugger/tinyApp/outs/frameInnerLambda.out @@ -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 - field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.Function0 (sp = null) + this = this = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1$1@uniqueID}kotlin.jvm.functions.Function0 + field = this$0: frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1 = {frameInnerLambda.FrameInnerLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0 (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 diff --git a/idea/testData/debugger/tinyApp/outs/frameLambda.out b/idea/testData/debugger/tinyApp/outs/frameLambda.out index 21330ac7c06..6cca1b60409 100644 --- a/idea/testData/debugger/tinyApp/outs/frameLambda.out +++ b/idea/testData/debugger/tinyApp/outs/frameLambda.out @@ -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 + this = this = {frameLambda.FrameLambdaPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out b/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out index 4dc7e966b8e..16a25fff2ec 100644 --- a/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out +++ b/idea/testData/debugger/tinyApp/outs/frameLambdaNotUsed.out @@ -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 + this = this = {frameLambdaNotUsed.FrameLambdaNotUsedPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0 + 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameObject.out b/idea/testData/debugger/tinyApp/outs/frameObject.out index 5d10453fbea..43fff505714 100644 --- a/idea/testData/debugger/tinyApp/outs/frameObject.out +++ b/idea/testData/debugger/tinyApp/outs/frameObject.out @@ -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 + this = this = {frameObject.FrameObjectPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0 + 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameSharedVar.out b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out index aca31410807..645a2be1b55 100644 --- a/idea/testData/debugger/tinyApp/outs/frameSharedVar.out +++ b/idea/testData/debugger/tinyApp/outs/frameSharedVar.out @@ -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 + this = this = {frameSharedVar.FrameSharedVarPackage$@packagePartHASH$main$1@uniqueID}kotlin.jvm.functions.Function0 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameThis0.out b/idea/testData/debugger/tinyApp/outs/frameThis0.out index bbdade53727..fa8498c6fba 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0.out @@ -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 + this = this = {frameThis0.A$test$1@uniqueID}kotlin.jvm.functions.Function0 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' diff --git a/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out b/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out index 3cd6adc3028..7edd865b846 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0Ext.out @@ -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 + this = this = {frameThis0Ext.A$testExt$1@uniqueID}kotlin.jvm.functions.Function0 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 diff --git a/idea/testData/debugger/tinyApp/outs/frameThis0This0.out b/idea/testData/debugger/tinyApp/outs/frameThis0This0.out index 8884228c3e2..c2728a0f87d 100644 --- a/idea/testData/debugger/tinyApp/outs/frameThis0This0.out +++ b/idea/testData/debugger/tinyApp/outs/frameThis0This0.out @@ -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 - field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.Function0 (sp = null) + this = this = {frameThis0This0.A$test$1$1@uniqueID}kotlin.jvm.functions.Function0 + field = this$0: frameThis0This0.A$test$1 = {frameThis0This0.A$test$1@uniqueID}kotlin.jvm.functions.Function0 (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