我知道BCEL,但这个项目似乎已经死了,因为它已经两年没有发布了.Java世界继续前进.例如,JDK 1.6具有新的类文件格式.
那么什么库可以用来为JVM创建字节码.如果没有库,程序也可以,如果我可以详细操作生成的代码,例如字节码 - 汇编程序.
你能推荐哪种软件?是否容易使用?有很好的例子/教程?
编辑:所有问:是的,javac很好.但是为了在运行时生成一些类,直接到字节码的路径会更清晰.
我意识到字节码与本机代码(可移植性)的好处.
但是说你总是知道你的代码将在x86架构上运行,为什么不编译为x86并获得性能优势呢?
请注意,我假设本机代码编译有性能提升.有些人回答说实际上可能没有收获对我来说是个新闻.
我写了一个包含属性元数据的自定义注释,并且AnnotationProcessor:
@SupportedAnnotationTypes({"<package>.Property"})
public class PropertyProcessor extends AbstractProcessor {
@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
// Get messager object
Messager messager = processingEnv.getMessager();
// Iterate through the annotations
for(TypeElement typeElement : annotations) {
// Iterate through the annotated elements
for(Element element : roundEnv.getElementsAnnotatedWith(typeElement)) {
// Get Property annotation
Property property = element.getAnnotation(Property.class);
}
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个问题,我之前使用过Javassist,但它依赖于类加载器,我认为它不适合OSGi应用程序.我想在Property编译带有注释的类时更改生成的字节码.
我想用函数types.CodeType()创建一个新的代码对象.
几乎没有关于这个的文档和现有的文档说"不是为了胆小的"
告诉我我需要什么,并给我一些关于传递给types.CodeType的每个参数的信息,
可能发布一个例子.
注意:
在正常使用情况下,您只需要内置函数compile()
只有当您想要创建无法编写正常源代码并且需要直接访问字节码的新指令时,才应使用types.CodeType().
我正在查看JVM字节码指令,并惊讶地发现类之间的所有交互(例如,转换new等)依赖于对其他类的标识的常量池查找.
我是否正确地推断这意味着一个班级不能知道超过64k其他人的存在,因为不可能引用它们?如果确实需要引用那么多,那么应该做什么 - 将工作委托给多个类,每个类都可以有自己的<64k交互?
(我感兴趣的原因是我习惯于编写代码生成器,有时会生成数千个不同的类,并且某些语言(例如Scala)会大量创建类.所以看来如果是真的我必须要小心:如果我在一个类中有数百个方法,每个方法使用数百个(不同的)类,我可以超过常量池空间.)
我正在尝试编写单元测试以解决有关缺少stackmap帧的问题的解决方法,但为此目的,我将需要生成一个在Java 8上无法验证的类,如果它缺少stackmap帧.
下面你可以看到我的测试用例(依赖项:ASM,Guava,JUnit).它从GuineaPig类中删除了stackmap帧,希望导致其字节码无法验证.我遇到问题的部分是使用最少的代码来填充GuineaPig中的TODO,这需要堆栈图框架,以便测试通过.
import com.google.common.io.*;
import org.junit.*;
import org.junit.rules.ExpectedException;
import org.objectweb.asm.*;
import java.io.*;
import static org.objectweb.asm.Opcodes.ASM5;
public class Java6MissingStackMapFrameFixerTest {
@Rule
public final ExpectedException thrown = ExpectedException.none();
public static class GuineaPig {
public GuineaPig() {
// TODO: make me require stackmap frames
}
}
@Test
public void example_class_cannot_be_loaded_because_of_missing_stackmap_frame() throws Exception {
byte[] originalBytecode = getBytecode(GuineaPig.class);
ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = new ClassVisitor(ASM5, cw) {
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, …Run Code Online (Sandbox Code Playgroud) 我正在阅读和研究计算系统的元素,但我一度陷入困境.示例章节跳过下面的5条指令可以在这里找到.
无论如何,我正在尝试实现一个虚拟机(或一个字节代码到汇编转换器),但我坚持跳过下一个5指令一点.
您可以在此处找到装配符号.
目标是实现将特定字节代码转换为此汇编代码的转换器.
我成功完成的一个例子是字节码
push constant 5
Run Code Online (Sandbox Code Playgroud)
这被翻译成:
@5
D=A
@256
M=D
Run Code Online (Sandbox Code Playgroud)
正如我所说,Hack的汇编语言可以在我提供的链接中找到,但基本上是:
@5 // Load constant 5 to Register A
D=A // Assign the value in Reg A to Reg D
@256// Load constant 256 to Register A
M=D // Store the value found in Register D to Memory Location[A]
Run Code Online (Sandbox Code Playgroud)
嗯这很直接.根据定义,存储器位置256是堆栈的顶部.所以
push constant 5
push constant 98
Run Code Online (Sandbox Code Playgroud)
将被翻译为:
@5
D=A
@256
M=D
@98
D=A
@257
M=D
Run Code Online (Sandbox Code Playgroud)
这一切都很好..
我还想再举一个例子:
push constant 5
push …Run Code Online (Sandbox Code Playgroud) Java 8似乎生成了表示lambda表达式的类.例如,代码:
Runnable r = app::doStuff;
Run Code Online (Sandbox Code Playgroud)
大致表现为:
// $FF: synthetic class
final class App$$Lambda$1 implements Runnable {
private final App arg$1;
private App$$Lambda$1(App var1) {
this.arg$1 = var1;
}
private static Runnable get$Lambda(App var0) {
return new App$$Lambda$1(var0);
}
public void run() {
this.arg$1.doStuff();
}
}
Run Code Online (Sandbox Code Playgroud)
据我了解,代码是在运行时生成的.现在,假设有人想将代码注入run上述类的方法中.迄今为止的实验产生了NoClassDefFound和VerifyError:
java.lang.NoClassDefFoundError: App$$Lambda$2
at App$$Lambda$2/1329552164.run(Unknown Source)
at App.main(App.java:9)
Caused by: java.lang.ClassNotFoundException: App$$Lambda$2
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 2 more
Run Code Online (Sandbox Code Playgroud)
这是针对:
$ java -version
java …Run Code Online (Sandbox Code Playgroud) (注意:正确答案必须超越复制).
在数百万次调用之后,quicksort1肯定比quicksort2更快,除了这个额外的arg之外,它们具有相同的代码.
代码在帖子的末尾.Spoiler:我还发现jit代码比224字节更胖,即使它实际上应该更简单(如字节代码大小告诉;请参阅下面的最后更新).
即使试图用一些微基准线束(JMH)来解决这种影响,性能差异仍然存在.
我在问:为什么生成的本机代码存在这样的差异,它在做什么?
通过向方法添加参数,它使它更快......!我知道gc/jit/warmup/etc效果.您可以按原样运行代码,也可以使用更大/更小的迭代计数.实际上,你甚至应该注释掉一个然后另一个性能测试并在不同的jvm实例中运行它们,只是为了证明它不是彼此之间的干扰.
字节码没有显示出太大的区别,除了明显的getstatic为sleft/sright,还有一个奇怪的'iload 4'而不是"iload_3"(和istore 4/istore_3)
到底他妈发生了什么?iload_3/istore_3真的比iload 4/istore 4慢吗?即使添加的getstatic调用仍然没有让它变慢,那要慢得多?我猜测静态字段是未使用的,因此jit可能只是跳过它.
无论如何,我的方面没有任何歧义,因为它总是可重复的,我正在寻找解释为什么javac/jit做了他们所做的,以及为什么性能受到如此大的影响.这些是相同的递归算法,具有相同的数据,相同的内存流失等等...如果我愿意,我无法进行更加孤立的更改,以显示可重复的运行时差异.
ENV:
java version "1.8.0_161"
Java(TM) SE Runtime Environment (build 1.8.0_161-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.161-b12, mixed mode)
(also tried and reproduced on java9)
on a 4 core i5 laptop 8GB ram.
windows 10 with the meltdown/specter patch.
Run Code Online (Sandbox Code Playgroud)
使用-verbose:gc -XX:+ PrintCompilation,没有gc和jit编译在C2(第4层)中已经稳定.
n = 20000时:
main]: qs1: 1561.3336199999999 ms (res=null)
main]: qs2: 1749.748416 ms (res=null)
main]: qs1: 1422.0767509999998 ms (res=null)
main]: qs2: 1700.4858689999999 ms (res=null)
main]: qs1: …Run Code Online (Sandbox Code Playgroud) 我正在设计一种编译语言,编译成中间字节码.但是,我在设计字节码结构时遇到了很多麻烦.有没有人对如何用二进制表示程序有任何指示?或者,是否有任何资源(最好是免费的)如何做到这一点?我发现的最接近的是Lua解释器的字节码的描述.
编辑:更多信息:我正在实现我自己的垃圾收集方案,该方案针对不可变性和并发性进行了大量优化.为了提高效率,我需要一些独特的字节码指令,允许程序与垃圾收集方案进行交互.
bytecode ×10
java ×7
jvm ×2
algorithm ×1
assembly ×1
hotspot ×1
interpreter ×1
java-8 ×1
jit ×1
jvm-hotspot ×1
nand2tetris ×1
native ×1
osgi ×1
properties ×1
python ×1
python-3.x ×1