Reading static fields supported

This commit is contained in:
Andrey Breslav
2013-10-06 17:59:06 +04:00
parent b7c169fc89
commit 2e6d523966
5 changed files with 109 additions and 35 deletions
@@ -116,6 +116,9 @@
<item name='org.objectweb.asm.tree.FieldInsnNode desc'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.objectweb.asm.tree.FieldInsnNode name'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.objectweb.asm.tree.FieldInsnNode org.objectweb.asm.tree.AbstractInsnNode clone(java.util.Map&lt;org.objectweb.asm.tree.LabelNode,org.objectweb.asm.tree.LabelNode&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
@@ -125,6 +128,9 @@
<val name="value" val="{org.jetbrains.kannotator.controlFlow.builder.analysis.NullabilityKey.class}"/>
</annotation>
</item>
<item name='org.objectweb.asm.tree.FieldInsnNode owner'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.objectweb.asm.tree.FieldInsnNode void accept(org.objectweb.asm.MethodVisitor) 0'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
+8 -29
View File
@@ -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<Type>
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>): 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<Value>, invokespecial: Boolean = false): Value
}
@@ -118,7 +97,7 @@ class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(
}
}
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<Value>(
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<Value>(
}
PUTFIELD -> {
eval.setField(value1, (insn as FieldInsnNode).desc, value2)
eval.setField(value1, FieldDescription(insn as FieldInsnNode), value2)
null
}
+53
View File
@@ -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<Type>
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)
@@ -152,4 +152,8 @@ class TestData {
return String.valueOf("str");
}
static Object testGetStaticField() {
return String.CASE_INSENSITIVE_ORDER;
}
}
+38 -6
View File
@@ -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>): 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<Value>, invokespecial: Boolean): Value {
@@ -191,4 +200,27 @@ fun MethodDescription.matches(method: Method): Boolean {
return returnType.matches(method.getReturnType()!!)
}
[suppress("UNCHECKED_CAST")]
fun Class<Any?>.findField(fieldDesc: FieldDescription): Field? {
for (declared in getDeclaredFields()) {
if (fieldDesc.matches(declared)) return declared
}
val fromSuperClass = (getSuperclass() as Class<Any?>).findField(fieldDesc)
if (fromSuperClass != null) return fromSuperClass
for (supertype in getInterfaces()) {
val fromSuper = (supertype as Class<Any?>).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)