ASM如何在复制操作数堆栈(DUP_X1和DUP操作数)时检查最大堆栈大小

时间:2014-06-05 06:26:42

标签: java bytecode java-bytecode-asm bytecode-manipulation

我试图通过字节码操作(使用ASM framework)来记录实例级别(或类级别)对象初始化或对象分配

这样的事情:

这是我声明一些实例变量的类:

class DeclarationTestClass1{

    /** Assume This Class has some public instance variables **/
    private MultipleDeclarationTestClass multiClass = null;
    private List<String> arrayList1_String = null;
    public static Hashtable<Integer,Integer> staticHashTable = null;


    public List<String> getArrayList1_String() {
        return arrayList1_String;
    }

    public void setArrayList1_String(List<String> arrayList1_String) {
        this.arrayList1_String = arrayList1_String;
    }
}

现在,我想做:

DeclarationTestClass1 object1 = new DeclarationTestClass1();
MultipleDeclarationTestClass object1 .object1_innerObject = new MultipleDeclarationTestClass();

RecordingClass.recordingMethod(object1.arrayList1_String = new ArrayList<String>());
RecordingClass.recordingMethod(object1 .object1_innerObject.someMap = new HashMap<String,String>());

现在,当我使用ASMifier查看所需类的输出时,我可以看到在调用实际putfield之前,有一个DUP_X1被调用。

现在,我的理解是,由于实例级对象是通过另一个对象引用的(即:object1.arrayList1_String = new ArrayList<String>(),所以栈的第二个字保存了引用它的对象(即object1)。 如果我错了,请纠正我。

但是,我无法理解,在第二种情况下,当实例级别对象通过另一个额外对象(即:object1 .object1_innerObject.someMap = new HashMap<String,String>())引用时,它在堆栈中有另一个额外的对象,对吗?

所以我的问题是:

1)为什么在第二种情况下,还会调用DUP_X1

2)我在asm中使用COMPUTE_MAXS标志,其中asm为我计算最大堆栈大小。因此,如果我不覆盖visitMaxs中的MethodVisitor方法,这种重复会产生任何影响。

非常感谢这方面的任何帮助。

2 个答案:

答案 0 :(得分:2)

作为Antimony has pointed out,您是否拥有x.y = foox.y.z.a.b.c = foo形式的代码与堆栈大小无关。

对于链的每个节点,getfield指令将从堆栈中弹出字段所有者实例,并将字段值推送到堆栈(将成为下一个节点的所有者)。

所以唯一有趣的部分是putfield。它将从堆栈,字段所有者和新值中弹出两个值。由于您使用的格式为method(x.y=foo),因此您需要第二次使用该值,以便将其传递给方法。

因此需要一种dup,但由于后续putfield将使用两个项目,因此必须将值的副本下推到字段所有者下方:

dup_x1:       …, owner, value]        → …, value, owner, value]
putfield:     …, value, owner, value] → …, value]
invokestatic: …, value]               → …]

答案 1 :(得分:1)

在2个间接超过1的情况下,你实际上不会在堆栈上有任何额外的东西,因为分配只需要最后一个对象。想一想。

object1.object1_innerObject.someMap = new HashMap<String,String>())

在此代码中,您评估object1.object1_innerObject(称之为t1),然后new HashMap<String,String>()(称之为t2),最后执行分配,{{1 }}

等效字节码(假设object1在局部变量槽1中)

t1.someMap = t2

堆叠中最多有3个项目,但这与您aload_1 getfield object1type object1_innnerObject innerobjecttype new HashMap dup invokespecial java/util/HashMap <init> ()V setfield innerobjecttype someMap java/util/HashMap 只有一样。