摘要:对于每个方法指令( MethodInsnNode ),使用ASM,给定字节码类,我需要获取正在其上使用的引用。
考虑以下课程:
public void myMethod(){
String str1 = "str12";
String str2 = str1;
String str3 = "str3";
Boolean myBool = true;
Boolean myBool2 = true;
Cemo cemo = new Cemo();
assertTrue(cemo.isTrue());
assertTrue(cemo.isTrue());
}
考虑以下生成的字节码指令:
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void myMethod();
Code:
0: ldc #2 // String str12
2: astore_1
3: aload_1
4: astore_2
5: ldc #3 // String str3
7: astore_3
8: iconst_1
9: invokestatic #4 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
12: astore 4
14: iconst_1
15: invokestatic #4 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
18: astore 5
20: new #5 // class com/devfactory/utqg/analysis/InstrumentationClass$Cemo
23: dup
24: aconst_null
25: invokespecial #6 // Method com/devfactory/utqg/analysis/InstrumentationClass$Cemo."<init>":(Lcom/devfactory/utqg/analysis/InstrumentationClass$1;)V
28: astore 6
30: aload_0
31: aload 6
33: invokevirtual #7 // Method com/d/utqg/analysis/InstrumentationClass$Cemo.isTrue:()Z
36: invokestatic #4 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
39: invokespecial #8 // Method assertTrue:(Ljava/lang/Boolean;)V
42: aload_0
43: aload 6
45: invokevirtual #7 // Method com/d/utqg/analysis/InstrumentationClass$Cemo.isTrue:()Z
48: invokestatic #4 // Method java/lang/Boolean.valueOf:(Z)Ljava/lang/Boolean;
51: invokespecial #8 // Method assertTrue:(Ljava/lang/Boolean;)V
54: return
}
我试图找出一种如何获取使用ASM调用的对象引用的方法。在字节码级别,每次调用INVOKESPECIAL
指令时,它都会加载之前将使用的值。例如:
31: aload 6 //Loading the value stored in 6 position
33: invokevirtual #7 // Method com/d/utqg/analysis/InstrumentationClass$Cemo.isTrue:()Z
所以那里有一个参考。但在ASM中,没有this
的引用。确切的堆栈跟踪就像这个,它由包含&#34; prev&#34;的实际指令组成。 attr将是被调用以加载该变量的方法:
问题是我们有owner属性,name属性,但是我无法获得对该对象的引用。在以下情况中:
Boolean myBool2 = true;
Cemo cemo = new Cemo();
assertTrue(cemo.isTrue());
我需要提及&#34; cemo&#34; ASM中的对象。
到目前为止我尝试过的事情:
- 获取帧对象,但它只包含变量&#34; slots&#34;,没有引用它。
- 分析MethodInsnNode
之前的说明。
我该如何做到这一点?
答案 0 :(得分:4)
JVM是一个堆栈机器,即总是在操作数堆栈的顶部值上调用方法,其中this
引用是非静态方法的第一个隐式参数。为了完成您的计划,您需要随时跟踪操作数堆栈上的所有参数,然后在字节代码中处理方法调用后确定当前为static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
DataTable dt; // values here
MyComboBox cb = new MyComboBox();
cb.InitItems(dt);
MyDataGridViewComboBoxColumn gvcb = new MyDataGridViewComboBoxColumn();
cb.InitItems(dt);
}
}
public class MyComboBox : ComboBox, Itest
{
// apply Sir Rufo answer here
public void InitItems(DataTable table)
{
Items.Clear();
foreach (DataRow row in table.Rows)
{
Items.Add(row);
}
}
}
public class MyDataGridViewComboBoxColumn: DataGridViewComboBoxColumn, Itest
{
// apply Sir Rufo answer here
public void InitItems(DataTable table)
{
Items.Clear();
foreach (DataRow row in table.Rows)
{
Items.Add(row);
}
}
}
public interface Itest
{
void InitItems(DataTable table);
}
填充的值。
这意味着您需要处理方法的任何指令并跟踪当前引用的任何寄存器和堆栈槽的对象。以有限的方式,这允许您跟踪调用方法的实例。但请注意,Java(字节码)程序可能非常复杂,因为它们强加了Java编程语言之外的其他限制,并允许在代码中进行任意跳转。基本上,为了知道方法在任何时间点的作用,你需要模拟一般情况下的方法调用,这样你就可以设置一些相当困难的东西了。