实际我在类中有一个方法如下.
public static final void print(String str){
System.out.println(str);
}
Run Code Online (Sandbox Code Playgroud)
我想final从met hod中删除修饰符.所以在这之后,我的方法将如下所示:
public static void print(String str){
System.out.println(str);
}
Run Code Online (Sandbox Code Playgroud)
使用ASM,我们将获得此信息
public MethodVisitor visitMethod(int access, String name,
String desc, String signature,
String[] exceptions) { }
Run Code Online (Sandbox Code Playgroud)
在上面,我认为要实现上述情况,我们需要使用access参数.但访问是公共+静态+最终的总和.如何删除最终是我的问题?
类级最终修饰符也一样吗?
我无法在使用 ASM 库修改字节码后加载类。
这里是恒等变换器,我希望得到与字节一大小相同的修改后的数组,但它短两倍!(439 比 278)
String path = SimpleClass.class.getName().replace(".", "/") + ".class";
ClassLoader classLoader = SimpleClass.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream(path);
byte[] bytes = IOUtils.toByteArray(is);
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, 0);
byte[] modified = writer.toByteArray();
Run Code Online (Sandbox Code Playgroud)
无法加载并没有什么了不起的。我怀疑标头被截断,但两个数组中的第一个字节是相同的。
-54, -2, -70
static class ByteClassLoader extends ClassLoader {
public Class define(String name, byte[] body) {
return defineClass(name, body, 0, body.length);
}
}
ByteClassLoader myLoader = new ByteClassLoader();
Class myClass = myLoader.define("Ooo", modified);
Run Code Online (Sandbox Code Playgroud)
失败并出现错误:
java.lang.UnsupportedClassVersionError: Ooo has been compiled …Run Code Online (Sandbox Code Playgroud) 所以基本上我试图System.out.println("hey");
在方法的最后添加一个简单的.我使用了树API.但是我一直收到这个错误:
java.lang.VerifyError:期望分支目标38处的stackmap帧
这是我的代码:
public class MethodNodeCustom extends MethodNode {
public MethodNodeCustom(int paramInt, String paramString1, String paramString2, String paramString3, String[] paramArrayOfString) {
this(327680, paramInt, paramString1, paramString2, paramString3, paramArrayOfString);
return;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public MethodNodeCustom(int paramInt1, int paramInt2, String paramString1, String paramString2, String paramString3,
String[] paramArrayOfString) {
super(paramInt1);
this.access = paramInt2;
this.name = paramString1;
this.desc = paramString2;
this.signature = paramString3;
this.exceptions = new ArrayList((paramArrayOfString == null) ? 0 : paramArrayOfString.length);
int i = ((paramInt2 & 0x400) != 0) …Run Code Online (Sandbox Code Playgroud) java bytecode bytecode-manipulation java-bytecode-asm jvm-bytecode
所以我有一些类已插入“虚拟方法调用”;即具有空主体的专用类中的静态方法。
这个想法是获取在方法调用之前推送到堆栈的参数,将它们存储在局部变量中,然后用实际实现替换方法调用。
为了看看当地人是如何处理的,我运行
A.java
package asmvisit;
public class A {
long y;
public long doSomething(int x, A a){
if(a == null){
this.y = (long)x;
return -1L;
}
else{
long old = y;
this.y += (long)x;
return old;
}
}
}
Run Code Online (Sandbox Code Playgroud)
通过文本编辑器(代码在帖子底部)。
正如您在输出中看到的(也在帖子的底部),局部变量
LOCALVARIABLE old J L4 L6 3
LOCALVARIABLE this Lasmvisit/A; L0 L6 0
LOCALVARIABLE x I L0 L6 1
LOCALVARIABLE a Lasmvisit/A; L0 L6 2
Run Code Online (Sandbox Code Playgroud)
在方法的最后被访问。
从技术上讲,我们将被允许更早地访问它们,但我明白为什么在任意位置插入局部变量可能会搞乱编号 - 以及程序。
因此,在我看来,添加更多局部变量的唯一安全方法是对每个方法运行两次:
visitMaxs,使用计数器来跟踪新局部变量最终将拥有的索引。有没有更简单的替代方案,不需要两次通过?
文本化器
package asmvisit; …Run Code Online (Sandbox Code Playgroud) 因此,我有一些功能不良的代码可以调试在某些地方抛出NPE的地方,我想逐步介绍一些生成的方法,以尝试找出原因。
除了盲目踏步不是真正有用的。
Thread-4[1] list
Source file not found: Foo.java
Thread-4[1] locals
Local variable information not available. Compile with -g to generate variable information
Run Code Online (Sandbox Code Playgroud)
代码已生成,因此当然没有.java可用于JDB的文件。
而且由于我不使用javac进行编译,因此也没有指定任何-g标志。
我可以告诉JDB给我看一下字节码吗(他显然有字节码,因为否则Java将没有任何执行力)?
我可以告诉ASM生成本地信息,就像使用它进行编译一样javac -g吗?
还是那里有一个有用的调试器可以满足我的需求?
该ASM引导谈到构造函数:
Run Code Online (Sandbox Code Playgroud)package pkg; public class Bean { private int f; public int getF() { return this.f; } public void setF(int f) { this.f = f; } }Bean类还具有由编译器生成的默认公共构造函数,因为程序员没有定义任何显式构造函数。此默认的公共构造函数生成为
Bean() { super(); }。该构造函数的字节码如下:Run Code Online (Sandbox Code Playgroud)ALOAD 0 INVOKESPECIAL java/lang/Object <init> ()V RETURN第一条指令压
this入操作数堆栈。第二条指令从堆栈中弹出该值,并调用类中<init>定义的方法Object。这对应于super()调用,即对超类的构造函数的调用Object。您可以在此处看到,在编译类和源类中,构造函数的名称不同:在编译类中,它们总是命名为<init>,而在源类中,它们具有定义它们的类的名称。最后,最后一条指令返回给调用者。
this在构造函数的第一条指令之前,JVM已知的值如何?
我有一个类似的界面:
public interface Getter {
Object get(Params params);
}
Run Code Online (Sandbox Code Playgroud)
我使用对不同方法的反射调用来实现:
public class GetterImpl implements Getter {
private final Object target;
private final Method method; //doStuff method
public GetterImpl(Object target, Method method) {
this.target = target;
this.method = method;
}
@Override
public Object get(Params params) {
//both the target and arguments depend on Params
return method.invoke(chooseTarget(params), prepareArgs(params));
}
private Object chooseTarget(Params params) {
if (params.getTargetOverride() != null) {
return params.getTargetOverride();
}
return target;
}
private Object[] prepareArgs(Params params) {
...
} …Run Code Online (Sandbox Code Playgroud) 你好。
我想找到方法调用开始和结束之间的指令范围。
我不想简单地更改方法调用所有者/名称/描述。
有了预期的结果,我希望能够做到:
我一直在尝试不同的技术来实现这一目标:
start和end
我会给你一些我想要什么的例子,以防这里有任何混淆。
首先,看看我下面的测试代码,然后回到这里。
我希望找到/删除整个方法调用anotherMethod4并将其替换为一个简单的true,从而生成以下代码:
System.out.println(
anotherMethod1(
anotherMethod2("a", "b") ?
"c" : anotherMethod3("d", "e") ? "f" : "g",
true ? "j" : "k"
) ? "l" : "m"
);
Run Code Online (Sandbox Code Playgroud)
我希望找到/删除整个方法调用anotherMethod1并将其替换为一个简单的false,从而生成以下代码:
System.out.println(
false ? "l" : "m"
);
Run Code Online (Sandbox Code Playgroud)
我希望删除对 的整个方法调用System.out.println,从而生成以下代码:
private Main()
{
}
Run Code Online (Sandbox Code Playgroud)
这一定是可能的吗?
这是我当前的测试代码:
private Main()
{
System.out.println(
anotherMethod1(
anotherMethod2("a", …Run Code Online (Sandbox Code Playgroud) 我编译了以下方法:
public static final boolean equalTo(final int x, final int y) {
return x == y;
}
Run Code Online (Sandbox Code Playgroud)
可以javap看到为其生成了以下字节码:
public static final boolean equalTo(int, int);
descriptor: (II)Z
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: ireturn
LineNumberTable:
line 72: 0
StackMapTable: number_of_entries = 2
frame_type = 9 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
Run Code Online (Sandbox Code Playgroud)
我编写了 …
尝试加载使用ASM生成的类时,我得到了预期的ClassVerifyErrors.在进一步检查时,我可以看到jvm是正确的,并且该方法所讨论的具有无效的MAX_STACK值.奇怪的是我正在使用自动计算堆栈和最大本地选项,所以这不应该是一个问题...使用无效选项的方法非常简单,但结果是错误的字节码.
我编写了一个带有预期方法的类,并将我的asm生成的类与javac生成的类比较,字节代码匹配,唯一的错误是max stack为0,这是错误的,而javac设置的值为2.
我想避免自己计算最大堆栈/本地人.