1

I am using ASM to insert a method after a special method. For example, a method as follows:

a.doSomeThing(p1, p2, p3, p4, p5, p6)

I want to insert a method follow it, just like this:

a.doSomeThing(p1, p2, p3, p4, p5, p6)
MyClass.myMethod(a, p1, p2, p3, p4, p5, p6) //insert a static method

The insert method has the same parameters as the previous one.

I know that when invoking virtual doSomeThing, the values are at the top of the stack. How can I duplicate them, and use them for myMethod?

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
user5549139
  • 157
  • 9
  • 1
    Unless you’re doing hot code replacement, the simplest solution supporting an arbitrary number of parameters would be injecting a little helper method invoking both. – Holger Mar 09 '20 at 11:44
  • @Holger Two Questions: (1) what is the hot code replacement? (2)You means is that i can call `a.doSomeThing` in `myMethod` ? – user5549139 Mar 09 '20 at 13:51
  • 2
    There are three forms of Instrumentation 1) static, changing the code at some time between compilation and actual use 2) load time, changing when a class loader has loaded it, before it materialized 3) redefine aka hot code replacement, change after a class has been loaded and perhaps even executed. In the 3rd case, you can’t add methods to the existing class. Calling `a.doSomeThing` in `myMethod` would be one, less flexible solution. I meant, injecting a helper method `generatedUniqueName` calling `a.doSomeThing` and `myMethod`, then replace the `a.doSomeThing` call with `generatedUniqueName` – Holger Mar 09 '20 at 13:58
  • About first form, if i want to change code at compilation, how can i do that? Does ASM has methods to get status of stack frames? – user5549139 Mar 10 '20 at 01:50
  • 1
    Which kind of status do you have in mind? Something going into [this direction](https://stackoverflow.com/q/48802291/2711488) – Holger Mar 10 '20 at 08:08

2 Answers2

1

If there is only one parameter, or only two parameters that are not longs or doubles, you can use the DUP or DUP2 instructions respectively. If there are more than two parameters, there is no way to duplicate them directly using bytecode. Instead, you need to save them to local variables and then read them back.

Antimony
  • 37,781
  • 10
  • 100
  • 107
1

Finally, i solve it. When call a.doSomeThing(p1, p2, p3, p4, p5, p6), the operand stack frame order in the stack is a p1 p2 p3 p4 p5 p6, so i just need to store them to local variables as p6 p5 p4 p3 p2 p1 a, now i load them from local variables to stack again, and call a.doSomeThing(p1, p2, p3, p4, p5, p6), next, load local variables again and call MyClass.myMethod(a, p1, p2, p3, p4, p5, p6).
By this way, i insert my codes which have same parameters with the previous method.

user5549139
  • 157
  • 9
  • 1
    You just have to make sure, the variable indices are not in use… – Holger Mar 11 '20 at 08:10
  • Yes, I will use ASM `MethodNode` API, it helps calculate the `maxLocals`, and i will store parameters to local which the variable indices start from `maxLocals` to `maxLocals + parameter size - 1`. The local stack size will be increase to `maxLocals + parameter size` – user5549139 Mar 11 '20 at 08:18
  • 1
    Indeed, with the Tree API, it’s easy. Appending them after max locals may use more slots than necessary, but for most purposes that doesn’t matter. But there is no reason change the stack size, the required stack doesn’t change. And you shouldn’t mix up maxLocals and maxStack. Note that injecting new variables is even possible in a single pass with the Visitor API, by using `LocalVariablesSorter`. – Holger Mar 11 '20 at 08:25