Search code examples
javabytecodejava-bytecode-asmbytecode-manipulation

How ASM checks maximum stack size when duplicating operand stack (DUP_X1 and DUP operands)


I am trying to record instance level (or class level ) object initialization or object assignments through bytecode manipulation (using ASM framework )

Something like this :

This is the class where I am declaring some instance variables :

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;
    }
}

Now, I want to do :

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>());

Now when I see the output of the desired class using ASMifier , I can see that before the actual putfield is called , there is one DUP_X1 getting called.

Now , my understanding is that as the instance level object is referred through another object (i.e : object1.arrayList1_String = new ArrayList<String>() , second word of the stack holds the object through which it is referred (i.e object1 ). Please correct me if I am wrong.

But , what I can not understand , in the second scenario , when the instance level object is reffered through another extra object (i.e: object1 .object1_innerObject.someMap = new HashMap<String,String>()) , it has another extra object in the stack , right ?

So my questions are :

1) Why in the second scenario also , DUP_X1 is called ?

2) I am using COMPUTE_MAXS flag in asm , by dint of which asm calculates the max stack size for me . So , will this duplicating have any impact if I do not override visitMaxs method in MethodVisitor.

Any help in this regard , is much much appreciated.


Solution

  • As Antimony has pointed out, it doesn’t matter to the stack size whether you have code of the form x.y = foo or x.y.z.a.b.c = foo.

    For each node of the chain the getfield instruction will pop the field owner instance from the stack and push the field value onto the stack (which will become the owner for the next node).

    So the only interesting part is the putfield. It will pop two values from the stack, the field owner and the new value. Since you are using an expression of the form method(x.y=foo) you need the value a second time, for passing it to the method.

    So a kind of dup is required, but since the follow-up putfield will consume two items, the copy of the value must be pushed down below the field owner:

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