Java 什么是操作数栈?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24427056/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 12:07:19  来源:igfitidea点击:

What is an operand stack?

javajvm

提问by Abhijeet Panwar

I am reading about JVM architecture. Today I read about the concept of the Operand Stack. According to an article:

我正在阅读有关 JVM 架构的信息。今天我读到了操作数栈的概念。根据一篇文章:

The operand stack is used during the execution of byte code instructions in a similar way that general-purpose registers are used in a native CPU.

操作数堆栈在字节码指令的执行期间使用,其使用方式与本地 CPU 中使用通用寄存器的方式类似。

I can't understand: What exactly is an Operand Stack, and how does it work in jvm?

我无法理解:到底什么是操作数堆栈,它在 jvm 中是如何工作的?

采纳答案by T.J. Crowder

It's how the various individual bytecode operations get their input, and how they provide their output.

这是各种单独的字节码操作如何获取输入以及它们如何提供输出的方式。

For instance, consider the iaddoperation, which adds two ints together. To use it, you push two values on the stack and then use it:

例如,考虑iadd将两个ints 相加的操作。要使用它,您将两个值压入堆栈,然后使用它:

iload_0     # Push the value from local variable 0 onto the stack
iload_1     # Push the value from local variable 1 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result

Now the top value on the stack is the sum of those two local variables. The next operation might take that top stack value and store it somewhere, or we might push another value on the stack to do something else.

现在栈顶的值是这两个局部变量的总和。下一个操作可能会获取栈顶的值并将其存储在某个地方,或者我们可能会在栈上压入另一个值来做其他事情。

Suppose you want to add three values together. The stack makes that easy:

假设您想将三个值相加。堆栈使这变得容易:

iload_0     # Push the value from local variable 0 onto the stack
iload_1     # Push the value from local variable 1 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result
iload_2     # Push the value from local variable 2 onto the stack
iadd        # Pops those off the stack, adds them, and pushes the result

Now the top value on the stack is the result of adding together those three local variables.

现在栈顶的值是这三个局部变量相加的结果。

Let's look at that second example in more detail:

让我们更详细地看一下第二个例子:

We'll assume:

我们将假设:

  • The stack is empty to start with (which is almost never actually true, but we don't care what's on it before we start)
  • Local variable 0 contains 27
  • Local variable 1 contains 10
  • Local variable 2 contains 5
  • 堆栈一开始是空的(这几乎从来都不是真的,但在开始之前我们不在乎上面有什么)
  • 局部变量 0 包含 27
  • 局部变量 1 包含 10
  • 局部变量 2 包含 5

So initially:

所以最初:

+???????+
| stack |
+???????+
+???????+

Then we do

然后我们做

iload_0     # Push the value from local variable 0 onto the stack

Now we have

现在我们有

+???????+
| stack |
+???????+
|   27  |
+???????+

Next

下一个

iload_1     # Push the value from local variable 1 onto the stack
+???????+
| stack |
+???????+
|   10  |
|   27  |
+???????+

Now we do the addition:

现在我们做加法:

iadd        # Pops those off the stack, adds them, and pushes the result

It "pops" the 10and 27off the stack, adds them together, and pushes the result (37). Now we have:

它从堆栈中“弹出”1027,将它们相加,然后压入结果 ( 37)。现在我们有:

+???????+
| stack |
+???????+
|   37  |
+???????+

Time for our third int:

我们的第三次时间int

iload_2     # Push the value from local variable 2 onto the stack
+???????+
| stack |
+???????+
|    5  |
|   37  |
+???????+

We do our second iadd:

我们做我们的第二个iadd

iadd        # Pops those off the stack, adds them, and pushes the result

That gives us:

这给了我们:

+???????+
| stack |
+???????+
|   42  |
+???????+

(Which is, of course, the Answer to the Ultimate Question of Life the Universe and Everything.)

(当然,这是对宇宙和万物生命终极问题答案。)

回答by Not a bug

Operand stack holds the operand used by operators to perform operations. Each entry on the operand stack can hold a value of any Java Virtual Machine type.

操作数堆栈保存操作员用来执行操作的操作数。操作数堆栈上的每个条目都可以保存任何 Java 虚拟机类型的值。

From JVM specifications,

JVM规范来看,

Java Virtual Machine instructions take operands from the operand stack, operate on them, and push the result back onto the operand stack. The operand stack is also used to prepare parameters to be passed to methods and to receive method results.

Java 虚拟机指令从操作数堆栈中获取操作数,对其进行操作,并将结果推回到操作数堆栈上。操作数堆栈还用于准备要传递给方法的参数和接收方法结果。

For example, iaddinstruction will add two integer values, so it will pop top two integer values from operand stack and will push result into operand stack after adding them.

例如,iadd指令将两个整数值相加,因此它将从操作数堆栈中弹出顶部的两个整数值,并将它们相加后将结果压入操作数堆栈。

For more detailed reference, you can check JVMS#2.5 : Run-Time Data Areas

有关更详细的参考,您可以查看JVMS#2.5 : Run-Time Data Areas

Summarizing it in context of Operand stack,

在操作数堆栈的上下文中总结它,

    _______________________________
   |        _____________________  |
   |       |         + --------+ | |
   |  JVM  |         | Operand | | | 
   | Stack |  FRAME  |  Stack  | | |
   |       |         +---------+ | |
   |       |_____________________| |
   |_______________________________|
  • JVM supports multithreaded execution environment. Each thread of execution has its private java virtual machine stack (JVM Stack) created at the same time of thread creation.
  • This Java virtual machine stack stores frames. Frame holds data, partial results, method return values and performs dynamic linking.
  • Each frame contains stack, known as Operand stack, which holds the operand values of JVM types. A depth of operand stack is determined at compile time and updated with operators.
  • JVM 支持多线程执行环境。每个执行线程在创建线程的同时创建了自己的私有java虚拟机栈(JVM Stack)。
  • 这个 Java 虚拟机堆栈存储帧。Frame 保存数据、部分结果、方法返回值并执行动态链接。
  • 每个帧包含堆栈,称为操作数堆栈,其中保存 JVM 类型的操作数值。操作数堆栈的深度在编译时确定并用运算符更新。

回答by Stephen C

But could's not understand exactly that what it is and how it works in jvm?

但是不能完全理解它是什么以及它在 jvm 中是如何工作的?

The JVM defines virtual computer, and the instruction set of that computer is stack based. What this means is that instructions in the JVM instruction set will typically push and pop operands from the stack. So for example,

JVM 定义了虚拟计算机,该计算机的指令集是基于堆栈的。这意味着 JVM 指令集中的指令通常会从堆栈中压入和弹出操作数。例如,

  • a load instruction might fetch a value from a local variable, instance variable or class variable and push it onto the operand stack,
  • an arithmetical instruction will pop values from the operand stack, perform the computation and push the result back onto the stack, and
  • a store instruction will pop a value from the stack and store it ...
  • 加载指令可能会从局部变量、实例变量或类变量中获取一个值并将其压入操作数堆栈,
  • 算术指令将从操作数堆栈中弹出值,执行计算并将结果推回堆栈,并且
  • 存储指令将从堆栈中弹出一个值并将其存储...

@T.J.Crowder's answer gives a more concrete example in lots of detail.

@TJCrowder 的回答给出了一个更详细的更具体的例子。

How the operand stack is implemented is platform specific, and it depends on whether code is being interpreted or whether it has been JIT compiled.

操作数堆栈的实现方式是特定于平台的,这取决于代码是被解释的还是被 JIT 编译的。

  • In the interpreted case, the operand stack is probably an array that is managed by the interpreter code. The push and pop micro-operations would be implemented something like:

        stack[top++] = value;
    

    and

        value = stack[--top];
    
  • When the code is JIT compiled, the bytecode instruction sequences are transformed into native instruction sequences that achieve the same thing as the bytecodes did. The operand stack locations get mapped to either native registers or memory locations; e.g. in the current native stack frame. The mapping involves various optimizations that are aimed at using registers (fast) in preference to memory (slower).

    Thus in the JIT compiled case, the operand stack no longer has a clear physical existence, but the overall behaviour of the compiled program is the same as ifthe operand stack did exist1.

  • 在解释的情况下,操作数堆栈可能是一个由解释器代码管理的数组。推送和弹出微操作将实现如下:

        stack[top++] = value;
    

        value = stack[--top];
    
  • 当代码被 JIT 编译时,字节码指令序列被转换为实现与字节码相同的本机指令序列。操作数堆栈位置被映射到本地寄存器或内存位置;例如在当前本机堆栈帧中。映射涉及各种优化,旨在优先使用寄存器(快速)而不是内存(较慢)。

    因此,在JIT编译的情况下,操作数堆栈不再有明确的物理存在,但已编译的程序的整体行为是一样的,如果操作数栈中确实存在1



1 - Actually, it may not be exactly the same when you take the Java memory model into account. However, the memory model places clear boundary on what the differences may be. And in the case of a single threaded computation that doesn't interact with the outside (e.g. I/O, clocks, etc), there can be no observable differences.

1 - 实际上,当您考虑 Java 内存模型时,它可能并不完全相同。但是,内存模型对可能存在的差异设置了明确的界限。并且在不与外部交互(例如 I/O、时钟等)的单线程计算的情况下,没有可观察到的差异。