分析这个简单类的字节码,我得出的结论是编译器不保留有关局部变量的任何信息final.这看起来很奇怪,因为我相信HotSpot编译器实际上可以使用这些信息来进行优化.
代码:
public static void main(String[] args)
{
final int i = 10;
System.out.println(i);
}
Run Code Online (Sandbox Code Playgroud)
字节码:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: bipush 10
2: istore_1
3: getstatic #16 // Field java/lang/System.out:Ljava/io/PrintStream;
6: bipush 10
8: invokevirtual #22 // Method java/io/PrintStream.println:(I)V
11: return
LineNumberTable:
line 7: 0
line 8: 3
line 9: 11
LocalVariableTable:
Start Length Slot Name Signature
0 12 0 args [Ljava/lang/String;
3 9 1 i …Run Code Online (Sandbox Code Playgroud) 当我从一些小的java函数中读取jvm字节码时,我发现当一个新的局部变量在操作数堆栈上计算时,假设它将存储在局部变量表中,但通常它会立即加载到操作数堆栈中(仅字面上的字节码).我操作不好,是不必要的操作?
我知道内联关键字的意思是避免调用功能的调用开销。但是我不知道扩展属性可以用于什么内联?
假设我们有两个名为foo的扩展属性,另一个带有名为bar的内联属性
val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
Run Code Online (Sandbox Code Playgroud)
执行其中的任何一个,我们将期望的输出,即当前时间。
该文件的字节码如下:
val Any.foo : Long
get() = Date().time
inline val Any.bar : Long
get() = Date().time
Run Code Online (Sandbox Code Playgroud)
我们可以看到两者相似,但仅在以下几行不同:
foo提取:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
Run Code Online (Sandbox Code Playgroud)
酒吧摘录:
LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
LOCALVARIABLE $i$f$getBar I L0 L2 1
MAXSTACK = 2
MAXLOCALS = 2
Run Code Online (Sandbox Code Playgroud)
我真的不明白这里发生了什么。有人可以指点我看一下它的行为,或java中的等效行为,或对此的一些用法吗?
编辑
给定编译器将替换内联属性的内容,可以方便地内联每个没有繁重操作的扩展属性。
谢谢
我正在阅读 JVM 版本 8 规范的第 4.10.2.2 节(https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html)如何验证字节码。在这种情况下,当堆栈现在包含一个槽时,如果来自一个源,则包含一个 int[] ;如果来自另一个源,则包含一个 String[] ,控制流中会发生什么情况。
我阅读了以下内容,该内容在 JVM 版本 7 文档中不存在:
如果对应的值都是数组引用类型,则检查它们的维度。如果数组类型具有相同的维度,则合并的值是对数组类型实例的引用,该数组类型是两种数组类型的第一个公共超类型。(如果其中一个或两个数组类型具有原始元素类型,则使用 Object 作为元素类型。)
...
甚至int[]和String[]也可以合并;结果是 Object[],因为在计算第一个公共超类型时使用了 Object 而不是 int。
这对我来说没有任何意义,因为这意味着 int[] 可以转换为 Object[]。但在 Java 中,原始类型的数组不能转换为 Object[]。
谁能解释一下这背后的理由吗?
我知道,只要Y> = X,就可以保证版本JDK X生成的字节码可以在JVM Y上运行。
这对所有版本的JDK / JVM都适用吗?即期望JDK 1生成的类文件在JVM 11上运行是否公平?
参考JVM规范,JDK 8兼容性指南和Java 11 JSR 在那里找不到精确的答案。
Java 14 中扩展的 switch 表达式,除了程序员/审阅者的视觉清晰度之外,switch 表达式的需求并不明确。是吗
参考: https: //www.techgeeknext.com/java/java14-features
JDK 14版本:
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
Run Code Online (Sandbox Code Playgroud)
JDK 14 字节代码
0: iconst_1
1: istore_1
2: iload_1
3: tableswitch { // 1 to 7
1: 44
2: 44
3: 44
4: 49
5: 54
6: 54
7: 59
default: 64
}
44: bipush 6
46: goto 65 …Run Code Online (Sandbox Code Playgroud) 我知道 iload 接受整数 -1 到 5,但是如何使用 bipush 指令扩展到更高的数字?特定整数如何与字节码一起存储?
我正在使用 AspectJ 1.8.8 编译时编织,并且我有一个像这样的块
@SomeAnnotation(value="someValue")
public List doSomething(String someArg) {
...
}
Run Code Online (Sandbox Code Playgroud)
where@SomeAnnotation是通过“Around”建议实现的。
使用 JD-GUI 查看字节码,我看到以下生成的代码(略有格式):
public class SomeClass {
private static Annotation ajc$anno$5;
...
@SomeAnnotation(value="someValue")
public List doSomething(String someArg)
{
String str = someArg;
JoinPoint localJoinPoint = Factory.makeJP(ajc$tjp_5, this, this, str);
Object[] arrayOfObject = new Object[3];
arrayOfObject[0] = this;
arrayOfObject[1] = str;
arrayOfObject[2] = localJoinPoint;
Annotation tmp56_53 = ajc$anno$5;
if (tmp56_53 == null) {
tmp56_53;
}
return (List)new SomeClass.AjcClosure11(arrayOfObject).linkClosureAndJoinPoint(69648).around(tmp56_53, (SomeAnnotation)(ajc$anno$5 = SomeClass.class.getDeclaredMethod("doSomething", new Class[] { String.class }).getAnnotation(SomeAnnotation.class))); …Run Code Online (Sandbox Code Playgroud) 我玩了一个很棒的沙盒塔防游戏Mindustry。
很酷的事情是您可以使用游戏嵌入式处理器块来控制单元。你可以命令他们建造积木、在地图上巡逻、包围最弱的敌人、治疗朋友并将弹药带到炮塔。
有一些示例如何对此类块进行“编程”:
一些“文档”可以在这里找到:
问题是处理器“语言”非常原始。只有一个控制语句:jump-to-line-if-statement-is-true. 没有 if/else 语句,没有 for 循环,没有函数和类。因此,使用这些指令编写任何复杂的东西几乎是不可能的。
所以我的想法是让我自己的简单编译器从“真正的”编程语言(带有 if、else、for、function、struct/class)到这些原始指令,然后将其导出到游戏中。
我的第一个想法是在 Mindustry 中实现 JVM 或 LLVM-IR VirtualMachine 来运行编译后的字节码,但它看起来很复杂。这些字节码中有很多指令。
然后我考虑实现 Lua 或简化的 Python 解释器,它看起来是可能的,但无论如何这是一项艰巨的工作:-)
我很好奇最简单的方法:-) 也许有基于 ~10 条指令或一些示例项目的简化 JVM/LLVM 字节码,或者在 Brainfuck 或一些有限的架构上运行 Lua/Python :-)
====嵌入式CPU语言====
所以控制指令集是:
op add result x y~ result=x+y- 将变量设置为 arifmethics 操作的结果 + - * / …compiler-construction interpreter bytecode llvm-ir jvm-bytecode
我有以下人为的代码示例。为了保持字节码较小,它没有做任何有用的事情,但希望您可以看到,通过一些更改,它会如何发挥作用。
List<String> letters = Arrays.asList("a", "b");
Stream.of(/*a, b, c, d*/).filter(letters::contains).toArray(String[]::new);
Run Code Online (Sandbox Code Playgroud)
Java 8 生成以下字节码
public Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=4, locals=2, args_size=1
start local 0 // Main this
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: iconst_2
5: anewarray #2 // class java/lang/String
8: dup
9: iconst_0
10: ldc #3 // String a
12: aastore
13: dup
14: iconst_1
15: ldc #4 // String b
17: aastore
18: invokestatic #5 // Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
21: astore_1
start local 1 …Run Code Online (Sandbox Code Playgroud) jvm-bytecode ×10
java ×8
jvm ×4
bytecode ×3
aop ×1
aspectj ×1
final ×1
inline ×1
interpreter ×1
java-14 ×1
java-8 ×1
jd-gui ×1
kotlin ×1
llvm-ir ×1
performance ×1