我正在编写一个用于赋值的静态分析工具,它使用ASM库分析Java字节码.我们使用的ASM的一个部分需要(或者至少似乎要求)从ClassLoader加载该类.
我们希望该工具能够分析.class文件,而不需要它们在类路径上.我们已经在运行时从指定目录加载.classes并使用InputStream读取它们.在大多数情况下,这对于ASM是可接受的.有些类,例如SimpleVerifier,尝试加载类.
在这种情况下,是否可以注册要加载的.class文件,以便调用Class.forName()将加载它们?或者是否有一种简单的方法来扩展ClassLoader以允许它?
编辑:URLClassLoader有用的信息.不幸的是,使用Thread.currentThread().setContextClassLoader()它的实例在这种情况下不起作用.我正在调用的库代码使用它在实例初始化时检索的加载器getClass().getClassLoader().
当我设置URLClassLoader时,该类尚未初始化,所以我猜contextClassLoader不加载该类.
我是否正确理解了答案?是否可以使用URLClassLoader加载第三方类?
如果我想使用字节码检测实现分析器,我应该使用JVMTI编写本机代理还是应该使用该包编写java代理?java.lang.instrument
如果我想使用像ASM这样的库- 如果你想创建一个严肃的探查器似乎是强制性的 - 我必须使用java代理.这使我感到困惑,因为我认为本机代理可以完成Java代理可以做的所有事情.但对我来说,编写java代理似乎更容易.
还有替代品吗?是否应该使用java代理和本地代理组合?
我正在使用ASM来监视Java中的对象创建.目前,我将调用init作为创建新对象的指示器并从中调整程序
invoke XXX.init
Run Code Online (Sandbox Code Playgroud)
至
dup;
invoke XXX.init;
call_my_method(Object)
Run Code Online (Sandbox Code Playgroud)
我的想法是复制newObjectReference的副本,并且在此对象的init之后,我调用我的方法来保留此对象.
但是,在运行时期间,有一个例外:
java.lang.VerifyError, Expecting to find unitialized object on stack.
Run Code Online (Sandbox Code Playgroud)
当我使用"-noverify"选项时,在运行时,如果有一个线程实例,则抛出第二个异常:
Exception in thread "main" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Unknown Source)
at test.ThreadTest.test
Run Code Online (Sandbox Code Playgroud)
对于第二种情况,我确信除了原始程序之外,没有调用线程的start().
有没有更好的方法来监控新对象的创建?
非常感谢.
为什么字节码生成为
.annotation system Ldalvik/annotation/Throws;
value = {
Ljava/io/FileNotFoundException;
}
.end annotation
Run Code Online (Sandbox Code Playgroud)
而不是.throws Ljava/io/FileNotFoundException
throws FileNotFoundException如果一个方法在java代码的标头中声明?
是否可以在编译时使用像ASM这样的字节码操作库?
具体来说,我想使用Java的注释处理API在带注释的类上实现样板重的方法.实现注释处理器很简单,但运行时似乎.class文件尚不存在Processor.还有另外一种方法吗?
我正在使用 ASM 代码迭代一个类而不操作任何字节代码。但是当我将 classwriter 转换为 bytearray(cw.toByteArray()) 时,我得到的方法代码太大了!例外。
谁能告诉我这是什么时候发生的..
我的代码片段如下---
InputStream in= new FileInputStream("D:/AshiqWorkspace/RandD/ByteCodeStudy/temp/GameManager.class");
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES);
ClassVisitor ca = null;
ca = new CustomClassNode(cw); // CustomClassNode class extends ClassNode implements Opcodes
cr.accept(ca, 0);
File outputDir=new File("D:/AshiqWorkspace/RandD/ByteCodeStudy/out");
outputDir.mkdirs();
DataOutputStream dout=new DataOutputStream(new FileOutputStream(new File(outputDir,"GameManager.class")));
dout.write(cw.toByteArray()); // on this line "method code too large exception coming"
Run Code Online (Sandbox Code Playgroud) 前段时间,我在将方法的现有代码嵌入 try-finally 块中询问如何使用 ASM 将方法的主体包装在 try-finally 块中。解决方案是访问 in 方法体开头的 try 块的标签,visitCode()并在访问具有返回操作码 in 的指令时完成 try-finally 块visitInsn()。我知道如果一个方法没有返回指令,则该解决方案将不起作用,如果该方法总是以异常情况离开则适用。
不过,我发现前一种解决方案有时也不适用于带有返回指令的方法。如果一个方法有多个返回指令,它将不起作用。原因是它生成了无效的字节码,因为在方法的开头添加了一个 try-finally 块,但完成了不止一个 try-finally 块。
通常(但可能取决于 javac 编译器),字节码方法包含单个返回指令,并且所有返回路径通过跳转到该指令结束。但是,使用 Eclipse 编译以下代码将导致带有两个返回指令的字节码:
public boolean isEven(int x) {
return x % 2 == 0;
}
Run Code Online (Sandbox Code Playgroud)
用Eclipse编译的字节码:
0: iload_1
1: iconst_2
2: irem
3: ifne 8
6: iconst_1
7: ireturn // javac compilation: goto 9
8: iconst_0
9: ireturn
Run Code Online (Sandbox Code Playgroud)
因此,我想知道包装方法代码的整个代码的正确方法是什么。
java instrumentation bytecode bytecode-manipulation java-bytecode-asm
[TL; DR:以下JVM字节码指令似乎不起作用:
iconst_0
istore 6
...sequential
iinc 6 1
jsr L42
...
; L42
iload 6
ifeq L53 ; Always branches!!!
astore 8
iinc 6 -1
; L53
LDC 100
ISUB ; ERROR, returnAddress is at the top of the stack
Run Code Online (Sandbox Code Playgroud)
可以在此处找到测试.class (具有稍微复杂的逻辑)。如果您想进一步了解为什么我会看到这些说明,请继续阅读。]
我正在编写针对JVM字节码的Whitespace编译器。尽管是一种深奥的语言,但是Whitespace向堆栈计算机描述了一组有趣的汇编指令,该堆栈计算机很好地映射到了JVM。
空格具有标签,它们都是跳转(goto / jump-if-zero / jump-if-negative)和函数调用的目标。相关说明(由我给定的名称,在规范中以空格,制表符和换行符的组合形式给出)为:
mark <label>:为以下说明设置标签jump[-if-neg|-if-zero] <label>:无条件或有条件地跳转到给定标签call <label>:调用标签所指向的函数end <label>:结束功能,返回到调用方。我的编译器以类的main方法输出整个Whitespace程序。实现call和的最简单方法end是使用JSR和RET操作码,用于实现子例程。JSR操作完成后,堆栈将包含一个returnAddress引用,该引用应存储在变量中,以供以后在中使用end。
但是,mark …
defineClass(className, byte[], offset, length)。new CustomClassLoader(Thread.currentThread().getContextClassLoader())。因此,CustomClassLoader的父级是当前线程中的ClassLoader。Thread.currentThread().setContextClassLoader()用CustomClassLoader 设置了。Class.forName(String, true, the CustomClassLoader)。我怎么了?如果您需要更多信息,请在我的GitHub上找到详细的主题。
Java字节码指令集提供了多种形式的dup指令。我无法理解这些说明和swap说明如何有用。编译时,哪些 Java 代码会使用这些指令生成字节码?
java ×8
bytecode ×4
classloader ×2
jvm ×2
android ×1
classpath ×1
compilation ×1
dalvik ×1
jasmin ×1
jvm-bytecode ×1
jvmti ×1
superclass ×1