Java字节码顺序和堆栈上的参数

Java字节码顺序和堆栈上的参数,java,parameters,jvm,stack,bytecode,Java,Parameters,Jvm,Stack,Bytecode,在java字节码中,为什么接收器首先被推到堆栈上,然后是所有参数?我似乎记得这与效率有关 方法调用和设置字段都是如此 方法调用 class X { int p(int a) { //Do something } int main() { int ret = p(1); } } 主方法编译为: aload_0 // Load this onto the stack iconst_1 // Load constant 1 onto

在java字节码中,为什么接收器首先被推到堆栈上,然后是所有参数?我似乎记得这与效率有关

方法调用和设置字段都是如此

方法调用

class X {

    int p(int a) {
        //Do something
    }
    int main() {
        int ret = p(1);
    }

}
主方法编译为:

aload_0 // Load this onto the stack
iconst_1 // Load constant 1 onto the stack
invokevirtual <int p(int)> from class X
aload_0 // Load this onto the stack
iconst_1 // Load constant 1 onto the stack
putfield <int x> from class X
主方法编译为:

aload_0 // Load this onto the stack
iconst_1 // Load constant 1 onto the stack
invokevirtual <int p(int)> from class X
aload_0 // Load this onto the stack
iconst_1 // Load constant 1 onto the stack
putfield <int x> from class X
aload\u 0//将其加载到堆栈中
iconst_1//将常量1加载到堆栈中
来自X类的putfield

您是否在问为什么要推它?在这两种情况下,您都在访问属于该类实例的内容,因此
这必须是该过程的一部分


你是在问为什么要先推?只是Java惯例。我想不管接下来会发生什么事情,总是先有
这个
是很方便的。

先推有好处

  • 目标方法可以使用更密集的“aload0”字节码(小于 如果它在参数列表中要晚很多,并且必须使用 aload字节码的参数化版本。因为字段和方法访问的方法中经常引用“this”,所以它导致了真正的代码密度提高
  • 我们经常会执行级联方法发送,如“foo.bar().baz()”。当bar()返回时, .baz()的未来“this”已经神奇地位于 如果您像在Java中那样安排事情,那么就进行堆栈

我想我已经弄明白了,但我无法回答,因为我没有足够的分数!这是一个“无聊的好奇心”问题。很有趣,但答案没有实际用途……除非你正在考虑设计一个全新的字节码指令集。你的意思是?学习计算机如何工作是一种“无聊的好奇心”问大多数人。好吧……如果这是无聊的好奇,你应该做你自己的研究……问后者。例子清楚地表明我知道为什么会这样。这就是我想到的原因,但它不让我发布。它似乎不是基于效率的,因为我确信我被告知它是。假设,即使这是最后一次你应该仍然能够在编译时静态地解析它的位置。我想不出任何东西会意味着你不能,尽管我只知道非常基本的JVM构造。这些答案是合理的,但实际上字节码被编译为本机代码,一旦发生这种情况,这些优势都不会发挥出来。这是不正确的对于大多数RISC架构(如POWER)的第二点,参数和返回值实际上都在寄存器中。让它们正确排列(return->arg 0)可以很好地工作并提高性能。此外,在第一点上,虽然1个字节看起来不多,但JVM通常必须将字节码保留在内存中(想想JVMTI的类重写等)将数千个类中所有保存的1个字节相加,就构成了不平凡的内存。您假设字节码模型中的虚拟堆栈布局与JIT编译代码使用的物理堆栈布局相似。您能证明这一假设的合理性吗?重新使用内存,节省几万或几十万字节字节字节字节字节字节字节>>isI当然可以为IBMJVM(J9)证明这一点-我是技术负责人之一,编写了一个JIT代码生成器,虽然确切的堆栈形状不同,但返回值和参数零的特定排列非常非常方便。re:内存使用,我理解你的想法,但这是20年前在小型嵌入式系统环境中做出的决定。类似于我加起来,这里一个字节,那里一个字节。记住,我不是在证明2012年的决定是正确的,我是在证明它是如何在20世纪90年代早期做出的。re:字节码是JIT编译的,然后是GCD,你可以,你不想因为以下几个原因:1)JIT可能希望以后的字节码将一个方法内联到另一个方法中。或者在没有源字节码的情况下在更高的opt级别(J9和HotSpot都在不同程度上重新编译)进行重新编译,这并不容易。2)优化假设可以更改(加载的新类打破了JIT编译时假设)您需要重新编译以确保正确性。3) 类通常不存储在堆上,并且都是一个大的纠缠blob,因此在实践中回收部分类是一个挑战。