JDK1.8 The Java® Virtual Machine Specification《2.The Structure of the Java Virtual Mach》(5)

 

JDK1.8 The Java® Virtual Machine Specification《2.The Structure of the Java Virtual Mach》(5) JDK1.8 The Java® Virtual Machine Specification《2.The Structure of the Java Virtual Mach》(5)

2.6. Frames

2.6 栈帧

frame is used to store data and partial results, as well as to perform dynamic linking, return values for methods, and dispatch exceptions.

A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes, whether that completion is normal or abrupt (it throws an uncaught exception). Frames are allocated from the Java Virtual Machine stack (§2.5.2) of the thread creating the frame. Each frame has its own array of local variables (§2.6.1), its own operand stack (§2.6.2), and a reference to the run-time constant pool (§2.5.5) of the class of the current method.

A frame may be extended with additional implementation-specific information, such as debugging information.

The sizes of the local variable array and the operand stack are determined at compile-time and are supplied along with the code for the method associated with the frame (§4.7.3). Thus the size of the frame data structure depends only on the implementation of the Java Virtual Machine, and the memory for these structures can be allocated simultaneously on method invocation.

Only one frame, the frame for the executing method, is active at any point in a given thread of control. This frame is referred to as the current frame, and its method is known as the current method. The class in which the current method is defined is the current class. Operations on local variables and the operand stack are typically with reference to the current frame.

A frame ceases to be current if its method invokes another method or if its method completes. When a method is invoked, a new frame is created and becomes current when control transfers to the new method. On method return, the current frame passes back the result of its method invocation, if any, to the previous frame. The current frame is then discarded as the previous frame becomes the current one.

Note that a frame created by a thread is local to that thread and cannot be referenced by any other thread.

栈帧被用来存储数据和局部结果以及执行动态链接,方法和调度时异常的返回值。

每次调用方法的时候都会创建一个新的栈帧,当方法调用结束的时候栈帧也随即被销毁,无论这个方法成功与否(会抛出未捕获的异常)。栈帧是被java虚拟机的线程分配的,每一个栈帧都有它自己的局部变量,操作数栈和对当前方法类的运行时常量池的引用。

可以增加一些工具相关的信息来扩展栈帧,例如debug信息

局部变量和操作数栈的大小在编译时被确定,并且随着栈帧相关的方法的代码一起提供。因此栈帧数据结构的大小仅仅取决于java虚拟机的实现,并且可以在方法调用时同时的分配内存。

在给定的线程管理下,只有一个执行方法的栈帧是活动的。这个栈帧被称之为当前帧,并且这个方法被称之为当前方法。拥有当前线程执行方法的这个类称之为当前类。局部变量的操作和操作数栈通常会和当前栈帧有关。

当一个栈帧的方法调用另一个方法或者这个方法结束时,这个栈帧将不再是当前栈帧。当一个方法处于被调用状态,一个新的栈帧就会被创建,当控制权转移到新方法时新的栈帧会变成当前栈帧。当方法返回时,这个当前栈帧回传方法的回调结果给调用方。当前栈帧之后会被销毁,并且之前的栈帧会变成当前栈帧。

注意:栈帧是线程私有的不可能被其他线程引用。

2.6.1. Local Variables

2.6.1 局部变量

Each frame (§2.6) contains an array of variables known as its local variables. The length of the local variable array of a frame is determined at compile-time and supplied in the binary representation of a class or interface along with the code for the method associated with the frame (§4.7.3).

A single local variable can hold a value of type booleanbytecharshortintfloatreference, or returnAddress. A pair of local variables can hold a value of type long or double.

Local variables are addressed by indexing. The index of the first local variable is zero. An integer is considered to be an index into the local variable array if and only if that integer is between zero and one less than the size of the local variable array.

A value of type long or type double occupies two consecutive local variables. Such a value may only be addressed using the lesser index. For example, a value of type double stored in the local variable array at index n actually occupies the local variables with indices n and n+1; however, the local variable at index n+1 cannot be loaded from. It can be stored into. However, doing so invalidates the contents of local variable n.

The Java Virtual Machine does not require n to be even. In intuitive terms, values of types long and double need not be 64-bit aligned in the local variables array. Implementors are free to decide the appropriate way to represent such values using the two local variables reserved for the value.

The Java Virtual Machine uses local variables to pass parameters on method invocation. On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

每一个栈帧都包含一个变量数组,它被称之为局部变量,这个栈帧的局部变量数组的长度会在编译时被确定,并且它和与帧相关的方法代码一起在类或接口的二进制的形式提供出来。

一个单一的局部变量可以属于 booleanbytecharshortintfloatreference, 或者 返回地址类型。一对儿局部变量可以包含long或者double类型的数据

局部变量通过索引编址。第一个局部变量的地址是0。一个整数当且仅当介于0和局部变量数组长度之间时,它才能被考虑作为索引值。

一个long和double类型的局部变量会占据两个的存储单元。这样的浮点型数值只能通过较小的那个索引来定位。例如一个double类型的值他的局部变量数组起始索引是n,但是它事实上占用了n 和 n+1 两个索引值,无论如何,这个局部变量的都不能通过 n+1这个索引获得。可以往n+1这个地址的区域存数据,但是你根本无法从n地址获得有效的内容。

java虚拟机并不需要n是一个偶数,直观而言long和double类型的数据并不需要在局部变量数组中是64位对齐的(其实我不太懂对齐是什么意思,也许是按照64位的排列顺序??)。实现者可以*的决定一个适当的方式去保留着两个局部变量。

java虚拟机使用局部变量去传递方法调用的参数。一个类方法的调用,任何参数都会从连续的以索引值0开始的局部变量数组中被传递。当实例方法调用,局部变量0索引始终用于传递一个调用实例方法的对象的引用(例如java编程语言中的this)。任何参数会随着该引用接踵而来,并且参数传递的起始位置是1.

2.6.2. Operand Stacks

2.6.2 操作数栈

Each frame (§2.6) contains a last-in-first-out (LIFO) stack known as its operand stack. The maximum depth of the operand stack of a frame is determined at compile-time and is supplied along with the code for the method associated with the frame (§4.7.3).

Where it is clear by context, we will sometimes refer to the operand stack of the current frame as simply the operand stack.

The operand stack is empty when the frame that contains it is created. The Java Virtual Machine supplies instructions to load constants or values from local variables or fields onto the operand stack. Other 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.

For example, the iadd instruction (§iadd) adds two int values together. It requires that the int values to be added be the top two values of the operand stack, pushed there by previous instructions. Both of the int values are popped from the operand stack. They are added, and their sum is pushed back onto the operand stack. Subcomputations may be nested on the operand stack, resulting in values that can be used by the encompassing computation.

Each entry on the operand stack can hold a value of any Java Virtual Machine type, including a value of type long or type double.

Values from the operand stack must be operated upon in ways appropriate to their types. It is not possible, for example, to push two int values and subsequently treat them as a long or to push two float values and subsequently add them with an iadd instruction. A small number of Java Virtual Machine instructions (the dup instructions (§dup) and swap (§swap)) operate on run-time data areas as raw values without regard to their specific types; these instructions are defined in such a way that they cannot be used to modify or break up individual values. These restrictions on operand stack manipulation are enforced through class file verification (§4.10).

At any point in time, an operand stack has an associated depth, where a value of type long or double contributes two units to the depth and a value of any other type contributes one unit.

每一个栈帧都包含一个后进先出的操作数栈,这个站的最大深度取决于编译的结果,并且会随着与栈先关的方法代码一起提供。

如果上下文环境清晰,我们会称当前栈帧的操作数栈为操作数栈(???WTF)

当包含这个操作数栈的栈帧刚被创建时,这个操作数栈是空的。java虚拟机提供指令去加载常量或者局部变量或者字段到操作数栈中。其他的java虚拟机指令从操作数栈获取操作数,执行相关操作指令并且将返回的结果压入操作数栈。操作数栈还被用于准备将要传递给方法的参数和方法返回的结果。

例如iadd指令让两个整型数据相加,它要求这两个整型数据作为操作数栈的前两位,由之前的指令压人栈中。这两个整型数据会被从栈中取出,然后相加并把它们的结果压回栈中。子计算可以嵌套在其中,包含这个子计算的计算指令可以获得这个结果。

每一个操作数栈的元素都可以拥有全部java虚拟机数据类型,包括long和double。

操作数栈中的值必须以适合其类型的方式进行操作。例如,不能压入两个int值,但是用long或者两个浮点的形式去压入,并且用iadd指令去相加。少数的Java虚拟机指令(DUP指令dup交换swap指令)将运行时数据区域作为原始值进行操作,而不考虑其特定类型; 这些指令不能用于修改或分解单个值。操作数栈的这些操作限制是通过class文件验证强制执行的。

在任何时候,操作数堆栈具有相关联的深度,其中类型值为long或 double占用两个单位深度,任何其他类型的值占用一个单位深度。

 

2.6.3. Dynamic Linking

2.6.3 动态链接

Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.

This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.

每一个栈帧都包含一个运行时常量池的引用,对于当前方法的这种引用类型提供了一个方法代码的动态链接(恕我愚昧。。真的没太懂)。。。小弟我看不懂啊。。。

 

2.6.4. Normal Method Invocation Completion

2.6.4正常的方法调用完成

A method invocation completes normally if that invocation does not cause an exception (§2.10) to be thrown, either directly from the Java Virtual Machine or as a result of executing an explicit throw statement. If the invocation of the current method completes normally, then a value may be returned to the invoking method. This occurs when the invoked method executes one of the return instructions (§2.11.8), the choice of which must be appropriate for the type of the value being returned (if any).

The current frame (§2.6) is used in this case to restore the state of the invoker, including its local variables and operand stack, with the program counter of the invoker appropriately incremented to skip past the method invocation instruction. Execution then continues normally in the invoking method's frame with the returned value (if any) pushed onto the operand stack of that frame.

如果调用不会引起异常抛出,或一个显式的异常抛出语句被执行,那么这个方法调用就是正常完成,并且返回值会交还给调用者。如果发生正常方法调用完成 return指令必须已核实的方式返回合适类型的值。

当前栈帧用于恢复调用者的状态,包括其局部变量和操作数对战。调用者的程序计数器会增加用来跳过方法调用指令。然后方法调用者将会继续正常执行,他的栈帧会到操作数栈中压入返回的结果。

2.6.5. Abrupt Method Invocation Completion

2.6.5 意外方法调用完成

A method invocation completes abruptly if execution of a Java Virtual Machine instruction within the method causes the Java Virtual Machine to throw an exception (§2.10), and that exception is not handled within the method. Execution of an athrow instruction (§athrow) also causes an exception to be explicitly thrown and, if the exception is not caught by the current method, results in abrupt method invocation completion. A method invocation that completes abruptly never returns a value to its invoker.

指一个方法调用翻车,调用指令的时候虚拟机抛出异常,并且异常没有在方法中处理。指令athrow的执行会导致异常明确抛出并且如果当前方法没有捕获异常,将会产生意外的方法调用完成。这个意外的方法调用完成不会给调用者返回任何值

2.7. Representation of Objects

2.7 对象的表示

The Java Virtual Machine does not mandate any particular internal structure for objects.

In some of Oracle’s implementations of the Java Virtual Machine, a reference to a class instance is a pointer to a handle that is itself a pair of pointers: one to a table containing the methods of the object and a pointer to the Class object that represents the type of the object, and the other to the memory allocated from the heap for the object data.

Java虚拟机并不要求对象的任何特定内部结构

在一些oracle Java虚拟机的实现中,对类实例的的引用是一个指向句柄的指针,这个句柄本身也是一对儿指针:其中包括一个指向对象方法表和指向对象类型的指针,另一个是指向对象所在堆地址的指针。