Through the introduction in the previous article, we learned about the data types and data zones in JVM. In this article, we will give a detailed introduction to the frames of the JVM stack to learn about the implementation of methods.
Frames are usually used to store data and partial results. They are also used to execute Dynamic Links, return methods, and deliver exceptions.
Frames are created when the method is called and destroyed when the method is complete. It is allocated to space in the JVM stack where the thread is created, each frame has its own local variable array, the operand stack, and a reference to the runtime constant pool of the class where the current method is located.
Its local variable array and the size of the operand Stack are determined during compilation, and it is provided together with the code of the method associated with it, therefore, the size of its data structure only depends on the memory that can be allocated during JVM implementation and method calls.
For the method being executed, only one frame is active. This frame is called the current frame. Its method is the current method, and the class of the current method is defined as the current class. Operations on local variables and the operand Stack are usually related to the current frame.
If another method or method is called to end a frame, the frame is no longer the current frame. If another method is called, a new frame is created and converted to the current frame when the control is switched to the new method. If the method ends, if a method is returned, the current frame passes the result of its method call to the previous frame. When the current frame becomes the current frame, the current frame is discarded.
Note that frames created by one thread are local to this thread, and other threads cannot reference it.
Each frame contains a variable array, which is a well-known local variable array. A local variable can save a boolean, byte, char, short, int, float, reference, or returnAddress value. A local variable can save a long or double value.
Local variables are addressable Based on the index, and the index of the first local variable is 0. If an integer value is between 0 and the length of the local variable array, and only in this range, it will be indexed as a local variable array.
Values of the long or double type occupy two consecutive local variables. Such values may only use smaller index values for addressing. For example, the value of the double variable whose index is n in the local variable array actually occupies n and n + 1, but the local variable n + 1 cannot be read and can be written, however, this will invalidate the content of the local variable n. The JVM does not require n to be an even number, which means that values of the double and long types do not have to be 64-bit aligned in the local variable array. The JVM implementers can decide to use an appropriate method to represent such values.
JVM uses local variables to pass the parameters of method calls. For Class method calls (that is, static methods), all parameters are continuously stored in the local variable table and start from 0, for instance method calls, all parameters are continuous but start from 1. The local variable 0 stores the reference of the class instance where the instance method is located.
Each frame contains a back-to-first-out stack, that is, its operand stack.
The operand stack is empty when it was just created. JVM provides commands to load constants or values from local variables or members to the stack. Other JVM commands extract operands from the operand stack, operate on them and put the result back into the operand stack. The operand stack is also used to prepare parameters passed to the method and the result of receiving the method.
For example, an iadd command adds two int values. This Command requires the previous command to push the two values to be added to the top of the operand stack, it extracts the two values from the operand stack and adds the result to the operand stack.
Subcomputation may be nested in the operand stack, and the generated values can be used for Embedded computation.
Each item in the operand stack can save any type of JVM value, including long and double.
The value in the operand stack must be operated based on its type. The following situations are all impossible: press two int values, and the subsequent operation uses them as long or two float values. The subsequent operation is the iadd command (the operation object of this command is two int values ). A small number of JVM commands (such as dup and swap) operate on the value of the runtime data zone as the raw value without considering its type, these commands are defined in a way that cannot be used to modify or break down individual values. These restrictions on the operations on the operand Stack are enforced by class file verification.
At any time, the operand Stack has its corresponding depth. The values of the long or double type are two units while the other values are one unit.
Each frame contains a reference to the runtime constant pool corresponding to the current method type to support dynamic links to the method code. The method code in the class File Code refers to the called method and variables that can be accessed through symbol reference, dynamic links translate these symbolic method references into specific method references, load classes when necessary to parse undefined symbols, and translate variable access into the runtime location of those variables in the storage structure. The late binding of methods and variables makes it less likely that changes to other classes used by methods can damage the code.
If a method call does not cause an exception (whether thrown by JVM or explicitly thrown by Code), it is considered that the method call ends normally. If the current method call ends normally, a value may be returned to the method that calls it.
In this case, the current frame is used to restore the caller's status, including its local variables and the operand stack, and appropriately add program counters to skip the method call command. The program of the frame in which the method caller is located continues normally. If a method is returned, the returned value is pushed into the operand stack of the frame.
If the execution of a JVM command in the method causes the JVM to throw an exception and the exception is not processed in the method, the method call ends suddenly, executing an athrow command can also cause an exception to be thrown explicitly. If the exception is not captured by the current method, the method call may end suddenly, A method call that suddenly ends will never return a value to its caller.
A frame may be extended by implementation-related information such as debugging information.