From 2e6d523966c489e692e56920081f406ff4da6885 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Sun, 6 Oct 2013 17:59:06 +0400 Subject: [PATCH] Reading static fields supported --- .../org/objectweb/asm/tree/annotations.xml | 6 +++ src/org/jetbrains/eval4j/interpreter.kt | 37 +++---------- src/org/jetbrains/eval4j/members.kt | 53 +++++++++++++++++++ test/org/jetbrains/eval4j/test/TestData.java | 4 ++ test/org/jetbrains/eval4j/test/main.kt | 44 ++++++++++++--- 5 files changed, 109 insertions(+), 35 deletions(-) create mode 100644 src/org/jetbrains/eval4j/members.kt diff --git a/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml b/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml index 924d69cca1f..7866c5dc168 100644 --- a/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml +++ b/annotations/org.ow2.asm_asm-debug-all_4.1/org/objectweb/asm/tree/annotations.xml @@ -116,6 +116,9 @@ + + + @@ -125,6 +128,9 @@ + + + diff --git a/src/org/jetbrains/eval4j/interpreter.kt b/src/org/jetbrains/eval4j/interpreter.kt index 528606163b5..38734a2e413 100644 --- a/src/org/jetbrains/eval4j/interpreter.kt +++ b/src/org/jetbrains/eval4j/interpreter.kt @@ -14,27 +14,6 @@ import org.objectweb.asm.tree.TypeInsnNode import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.IincInsnNode -data class MethodDescription( - val ownerInternalName: String, - val name: String, - val desc: String, - val isStatic: Boolean -) - -fun MethodDescription(insn: MethodInsnNode): MethodDescription = - MethodDescription( - insn.owner, - insn.name, - insn.desc, - insn.getOpcode() == INVOKESTATIC - ) - -val MethodDescription.returnType: Type - get() = Type.getReturnType(desc) - -val MethodDescription.parameterTypes: List - get() = Type.getArgumentTypes(desc).toList() - class UnsupportedByteCodeException(message: String) : RuntimeException(message) trait Eval { @@ -50,12 +29,12 @@ trait Eval { fun getArrayElement(array: Value, index: Value): Value fun setArrayElement(array: Value, index: Value, newValue: Value) - fun getStaticField(fieldDesc: String): Value - fun setStaticField(fieldDesc: String, newValue: Value) + fun getStaticField(fieldDesc: FieldDescription): Value + fun setStaticField(fieldDesc: FieldDescription, newValue: Value) fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List): Value - fun getField(instance: Value, fieldDesc: String): Value - fun setField(instance: Value, fieldDesc: String, newValue: Value) + fun getField(instance: Value, fieldDesc: FieldDescription): Value + fun setField(instance: Value, fieldDesc: FieldDescription, newValue: Value) fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List, invokespecial: Boolean = false): Value } @@ -118,7 +97,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter( } } JSR -> LabelValue((insn as JumpInsnNode).label) - GETSTATIC -> eval.getStaticField((insn as FieldInsnNode).desc) + GETSTATIC -> eval.getStaticField(FieldDescription(insn as FieldInsnNode)) NEW -> eval.newInstance(Type.getType((insn as TypeInsnNode).desc)) else -> throw UnsupportedByteCodeException("$insn") } @@ -164,11 +143,11 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter( LOOKUPSWITCH -> throw UnsupportedByteCodeException("Switch is not supported yet") PUTSTATIC -> { - eval.setStaticField((insn as FieldInsnNode).desc, value) + eval.setStaticField(FieldDescription(insn as FieldInsnNode), value) null } - GETFIELD -> eval.getField(value, (insn as FieldInsnNode).desc) + GETFIELD -> eval.getField(value, FieldDescription(insn as FieldInsnNode)) NEWARRAY -> { val typeStr = when ((insn as IntInsnNode).operand) { @@ -313,7 +292,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter( } PUTFIELD -> { - eval.setField(value1, (insn as FieldInsnNode).desc, value2) + eval.setField(value1, FieldDescription(insn as FieldInsnNode), value2) null } diff --git a/src/org/jetbrains/eval4j/members.kt b/src/org/jetbrains/eval4j/members.kt new file mode 100644 index 00000000000..4961ca0bee4 --- /dev/null +++ b/src/org/jetbrains/eval4j/members.kt @@ -0,0 +1,53 @@ +package org.jetbrains.eval4j + +import org.objectweb.asm.tree.MethodInsnNode +import org.objectweb.asm.Opcodes.* +import org.objectweb.asm.* +import org.objectweb.asm.tree.FieldInsnNode + +open data class MemberDescription( + val ownerInternalName: String, + val name: String, + val desc: String, + val isStatic: Boolean +) + +class MethodDescription( + ownerInternalName: String, + name: String, + desc: String, + isStatic: Boolean +) : MemberDescription(ownerInternalName, name, desc, isStatic) + +fun MethodDescription(insn: MethodInsnNode): MethodDescription = + MethodDescription( + insn.owner, + insn.name, + insn.desc, + insn.getOpcode() == INVOKESTATIC + ) + +val MethodDescription.returnType: Type + get() = Type.getReturnType(desc) + +val MethodDescription.parameterTypes: List + get() = Type.getArgumentTypes(desc).toList() + + +class FieldDescription( + ownerInternalName: String, + name: String, + desc: String, + isStatic: Boolean +) : MemberDescription(ownerInternalName, name, desc, isStatic) + +fun FieldDescription(insn: FieldInsnNode): FieldDescription = + FieldDescription( + insn.owner, + insn.name, + insn.desc, + insn.getOpcode() in setOf(GETSTATIC, PUTSTATIC) + ) + +val FieldDescription.fieldType: Type + get() = Type.getType(desc) diff --git a/test/org/jetbrains/eval4j/test/TestData.java b/test/org/jetbrains/eval4j/test/TestData.java index ca446e9ace7..55c20d32cc0 100644 --- a/test/org/jetbrains/eval4j/test/TestData.java +++ b/test/org/jetbrains/eval4j/test/TestData.java @@ -152,4 +152,8 @@ class TestData { return String.valueOf("str"); } + static Object testGetStaticField() { + return String.CASE_INSENSITIVE_ORDER; + } + } diff --git a/test/org/jetbrains/eval4j/test/main.kt b/test/org/jetbrains/eval4j/test/main.kt index 158c3796cd9..5b958d5b225 100644 --- a/test/org/jetbrains/eval4j/test/main.kt +++ b/test/org/jetbrains/eval4j/test/main.kt @@ -9,6 +9,8 @@ import org.junit.Assert.* import junit.framework.TestSuite import junit.framework.TestCase import java.lang.reflect.Method +import java.lang.reflect.Field +import kotlin.test.assertNotNull fun suite(): TestSuite { val suite = TestSuite() @@ -129,11 +131,18 @@ object REFLECTION_EVAL : Eval { throw UnsupportedOperationException() } - override fun getStaticField(fieldDesc: String): Value { - throw UnsupportedOperationException() + override fun getStaticField(fieldDesc: FieldDescription): Value { + assertTrue(fieldDesc.isStatic) + val owner = lookup.findClass(fieldDesc.ownerInternalName) + assertNotNull("Class not found: ${fieldDesc.ownerInternalName}", owner) + val field = owner!!.findField(fieldDesc) + assertNotNull("Field not found: $fieldDesc", field) + val result = field!!.get(null) + return objectToValue(result, fieldDesc.fieldType) } - override fun setStaticField(fieldDesc: String, newValue: Value) { - throw UnsupportedOperationException() + + override fun setStaticField(fieldDesc: FieldDescription, newValue: Value) { + assertTrue(fieldDesc.isStatic) } override fun invokeStaticMethod(methodDesc: MethodDescription, arguments: List): Value { @@ -146,10 +155,10 @@ object REFLECTION_EVAL : Eval { return objectToValue(result, methodDesc.returnType) } - override fun getField(instance: Value, fieldDesc: String): Value { + override fun getField(instance: Value, fieldDesc: FieldDescription): Value { throw UnsupportedOperationException() } - override fun setField(instance: Value, fieldDesc: String, newValue: Value) { + override fun setField(instance: Value, fieldDesc: FieldDescription, newValue: Value) { throw UnsupportedOperationException() } override fun invokeMethod(instance: Value, methodDesc: MethodDescription, arguments: List, invokespecial: Boolean): Value { @@ -191,4 +200,27 @@ fun MethodDescription.matches(method: Method): Boolean { return returnType.matches(method.getReturnType()!!) } +[suppress("UNCHECKED_CAST")] +fun Class.findField(fieldDesc: FieldDescription): Field? { + for (declared in getDeclaredFields()) { + if (fieldDesc.matches(declared)) return declared + } + + val fromSuperClass = (getSuperclass() as Class).findField(fieldDesc) + if (fromSuperClass != null) return fromSuperClass + + for (supertype in getInterfaces()) { + val fromSuper = (supertype as Class).findField(fieldDesc) + if (fromSuper != null) return fromSuper + } + + return null +} + +fun FieldDescription.matches(field: Field): Boolean { + if (name != field.getName()) return false + + return fieldType.matches(field.getType()!!) +} + fun Type.matches(_class: Class<*>): Boolean = this == Type.getType(_class) \ No newline at end of file