hotspot source code - jvm stack frame

vm/runtime/frame.hpp54行,关于栈帧操作的系列方法定义,源码如下:

54555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
class CodeBlob;class FrameValues;class vframeArray;// A frame represents a physical stack frame (an activation).  Frames// can be C or Java frames, and the Java frames can be interpreted or// compiled.  In contrast, vframes represent source-level activations,// so that one physical frame can correspond to multiple source level// frames because of inlining.class frame VALUE_OBJ_CLASS_SPEC { private:  // Instance variables:  intptr_t* _sp; // stack pointer (from Thread::last_Java_sp)  address   _pc; // program counter (the next instruction after the call)  CodeBlob* _cb; // CodeBlob that "owns" pc  enum deopt_state {    not_deoptimized,    is_deoptimized,    unknown  };  deopt_state _deopt_state; public:  // Constructors  frame();#ifndef PRODUCT  // This is a generic constructor which is only used by pns() in debug.cpp.  // pns (i.e. print native stack) uses this constructor to create a starting  // frame for stack walking. The implementation of this constructor is platform  // dependent (i.e. SPARC doesn't need an 'fp' argument an will ignore it) but  // we want to keep the signature generic because pns() is shared code.  frame(void* sp, void* fp, void* pc);#endif  // Accessors  // pc: Returns the pc at which this frame will continue normally.  // It must point at the beginning of the next instruction to execute.  address pc() const             { return _pc; }  // This returns the pc that if you were in the debugger you'd see. Not  // the idealized value in the frame object. This undoes the magic conversion  // that happens for deoptimized frames. In addition it makes the value the  // hardware would want to see in the native frame. The only user (at this point)  // is deoptimization. It likely no one else should ever use it.  address raw_pc() const;  void set_pc( address   newpc );  intptr_t* sp() const           { return _sp; }  void set_sp( intptr_t* newsp ) { _sp = newsp; }  CodeBlob* cb() const           { return _cb; }  // patching operations  void   patch_pc(Thread* thread, address pc);  // Every frame needs to return a unique id which distinguishes it from all other frames.  // For sparc and ia32 use sp. ia64 can have memory frames that are empty so multiple frames  // will have identical sp values. For ia64 the bsp (fp) value will serve. No real frame  // should have an id() of NULL so it is a distinguishing value for an unmatchable frame.  // We also have relationals which allow comparing a frame to anoth frame's id() allow  // us to distinguish younger (more recent activation) from older (less recent activations)  // A NULL id is only valid when comparing for equality.  intptr_t* id(void) const;  bool is_younger(intptr_t* id) const;  bool is_older(intptr_t* id) const;  // testers  // Compares for strict equality. Rarely used or needed.  // It can return a different result than f1.id() == f2.id()  bool equal(frame other) const;  // type testers  bool is_interpreted_frame()    const;  bool is_java_frame()           const;  bool is_entry_frame()          const;             // Java frame called from C?  bool is_stub_frame()           const;  bool is_ignored_frame()        const;  bool is_native_frame()         const;  bool is_runtime_frame()        const;  bool is_compiled_frame()       const;  bool is_safepoint_blob_frame() const;  bool is_deoptimized_frame()    const;  // testers  bool is_first_frame() const; // oldest frame? (has no sender)  bool is_first_java_frame() const;              // same for Java frame  bool is_interpreted_frame_valid(JavaThread* thread) const;       // performs sanity checks on interpreted frames.  // tells whether this frame is marked for deoptimization  bool should_be_deoptimized() const;  // tells whether this frame can be deoptimized  bool can_be_deoptimized() const;  // returns the frame size in stack slots  int frame_size(RegisterMap* map) const;  // returns the sending frame  frame sender(RegisterMap* map) const;  // for Profiling - acting on another frame. walks sender frames  // if valid.  frame profile_find_Java_sender_frame(JavaThread *thread);  bool safe_for_sender(JavaThread *thread);  // returns the sender, but skips conversion frames  frame real_sender(RegisterMap* map) const;  // returns the the sending Java frame, skipping any intermediate C frames  // NB: receiver must not be first frame  frame java_sender() const; private:  // Helper methods for better factored code in frame::sender  frame sender_for_compiled_frame(RegisterMap* map) const;  frame sender_for_entry_frame(RegisterMap* map) const;  frame sender_for_interpreter_frame(RegisterMap* map) const;  frame sender_for_native_frame(RegisterMap* map) const;  // All frames:  // A low-level interface for vframes: public:  intptr_t* addr_at(int index) const             { return &fp()[index];    }  intptr_t  at(int index) const                  { return *addr_at(index); }  // accessors for locals  oop obj_at(int offset) const                   { return *obj_at_addr(offset);  }  void obj_at_put(int offset, oop value)         { *obj_at_addr(offset) = value; }  jint int_at(int offset) const                  { return *int_at_addr(offset);  }  void int_at_put(int offset, jint value)        { *int_at_addr(offset) = value; }  oop*      obj_at_addr(int offset) const        { return (oop*)     addr_at(offset); }  oop*      adjusted_obj_at_addr(Method* method, int index) { return obj_at_addr(adjust_offset(method, index)); } private:  jint*    int_at_addr(int offset) const         { return (jint*)    addr_at(offset); } public:  // Link (i.e., the pointer to the previous frame)  intptr_t* link() const;  void set_link(intptr_t* addr);  // Return address  address  sender_pc() const;  // Support for deoptimization  void deoptimize(JavaThread* thread);  // The frame's original SP, before any extension by an interpreted callee;  // used for packing debug info into vframeArray objects and vframeArray lookup.  intptr_t* unextended_sp() const;  // returns the stack pointer of the calling frame  intptr_t* sender_sp() const;  // Returns the real 'frame pointer' for the current frame.  // This is the value expected by the platform ABI when it defines a  // frame pointer register. It may differ from the effective value of  // the FP register when that register is used in the JVM for other  // purposes (like compiled frames on some platforms).  // On other platforms, it is defined so that the stack area used by  // this frame goes from real_fp() to sp().  intptr_t* real_fp() const;  // Deoptimization info, if needed (platform dependent).  // Stored in the initial_info field of the unroll info, to be used by  // the platform dependent deoptimization blobs.  intptr_t *initial_deoptimization_info();  // Interpreter frames: private:  intptr_t** interpreter_frame_locals_addr() const;  intptr_t*  interpreter_frame_bcx_addr() const;  intptr_t*  interpreter_frame_mdx_addr() const; public:  // Locals  // The _at version returns a pointer because the address is used for GC.  intptr_t* interpreter_frame_local_at(int index) const;  void interpreter_frame_set_locals(intptr_t* locs);  // byte code index/pointer (use these functions for unchecked frame access only!)  intptr_t interpreter_frame_bcx() const                  { return *interpreter_frame_bcx_addr(); }  void interpreter_frame_set_bcx(intptr_t bcx);  // byte code index  jint interpreter_frame_bci() const;  void interpreter_frame_set_bci(jint bci);  // byte code pointer  address interpreter_frame_bcp() const;  void    interpreter_frame_set_bcp(address bcp);  // Unchecked access to the method data index/pointer.  // Only use this if you know what you are doing.  intptr_t interpreter_frame_mdx() const                  { return *interpreter_frame_mdx_addr(); }  void interpreter_frame_set_mdx(intptr_t mdx);  // method data pointer  address interpreter_frame_mdp() const;  void    interpreter_frame_set_mdp(address dp);  // Find receiver out of caller's (compiled) argument list  oop retrieve_receiver(RegisterMap *reg_map);  // Return the monitor owner and BasicLock for compiled synchronized  // native methods so that biased locking can revoke the receiver's  // bias if necessary.  This is also used by JVMTI's GetLocalInstance method  // (via VM_GetReceiver) to retrieve the receiver from a native wrapper frame.  BasicLock* get_native_monitor();  oop        get_native_receiver();  // Find receiver for an invoke when arguments are just pushed on stack (i.e., callee stack-frame is  // not setup)  oop interpreter_callee_receiver(Symbol* signature)     { return *interpreter_callee_receiver_addr(signature); }  oop* interpreter_callee_receiver_addr(Symbol* signature);  // expression stack (may go up or down, direction == 1 or -1) public:  intptr_t* interpreter_frame_expression_stack() const;  static  jint  interpreter_frame_expression_stack_direction();  // The _at version returns a pointer because the address is used for GC.  intptr_t* interpreter_frame_expression_stack_at(jint offset) const;  // top of expression stack  intptr_t* interpreter_frame_tos_at(jint offset) const;  intptr_t* interpreter_frame_tos_address() const;  jint  interpreter_frame_expression_stack_size() const;  intptr_t* interpreter_frame_sender_sp() const;#ifndef CC_INTERP  // template based interpreter deoptimization support  void  set_interpreter_frame_sender_sp(intptr_t* sender_sp);  void interpreter_frame_set_monitor_end(BasicObjectLock* value);#endif // CC_INTERP  // Address of the temp oop in the frame. Needed as GC root.  oop* interpreter_frame_temp_oop_addr() const;  // BasicObjectLocks:  //  // interpreter_frame_monitor_begin is higher in memory than interpreter_frame_monitor_end  // Interpreter_frame_monitor_begin points to one element beyond the oldest one,  // interpreter_frame_monitor_end   points to the youngest one, or if there are none,  //                                 it points to one beyond where the first element will be.  // interpreter_frame_monitor_size  reports the allocation size of a monitor in the interpreter stack.  //                                 this value is >= BasicObjectLock::size(), and may be rounded up  BasicObjectLock* interpreter_frame_monitor_begin() const;  BasicObjectLock* interpreter_frame_monitor_end()   const;  BasicObjectLock* next_monitor_in_interpreter_frame(BasicObjectLock* current) const;  BasicObjectLock* previous_monitor_in_interpreter_frame(BasicObjectLock* current) const;  static int interpreter_frame_monitor_size();  void interpreter_frame_verify_monitor(BasicObjectLock* value) const;  // Tells whether the current interpreter_frame frame pointer  // corresponds to the old compiled/deoptimized fp  // The receiver used to be a top level frame  bool interpreter_frame_equals_unpacked_fp(intptr_t* fp);  // Return/result value from this interpreter frame  // If the method return type is T_OBJECT or T_ARRAY populates oop_result  // For other (non-T_VOID) the appropriate field in the jvalue is populated  // with the result value.  // Should only be called when at method exit when the method is not  // exiting due to an exception.  BasicType interpreter_frame_result(oop* oop_result, jvalue* value_result); public:  // Method & constant pool cache  Method* interpreter_frame_method() const;  void interpreter_frame_set_method(Method* method);  Method** interpreter_frame_method_addr() const;  ConstantPoolCache** interpreter_frame_cache_addr() const; public:  // Entry frames  JavaCallWrapper* entry_frame_call_wrapper() const { return *entry_frame_call_wrapper_addr(); }  JavaCallWrapper* entry_frame_call_wrapper_if_safe(JavaThread* thread) const;  JavaCallWrapper** entry_frame_call_wrapper_addr() const;  intptr_t* entry_frame_argument_at(int offset) const;  // tells whether there is another chunk of Delta stack above  bool entry_frame_is_first() const;  // Compiled frames: public:  // Given the index of a local, and the number of argument words  // in this stack frame, tell which word of the stack frame to find  // the local in.  Arguments are stored above the ofp/rpc pair,  // while other locals are stored below it.  // Since monitors (BasicLock blocks) are also assigned indexes,  // but may have different storage requirements, their presence  // can also affect the calculation of offsets.  static int local_offset_for_compiler(int local_index, int nof_args, int max_nof_locals, int max_nof_monitors);  // Given the index of a monitor, etc., tell which word of the  // stack frame contains the start of the BasicLock block.  // Note that the local index by convention is the __higher__  // of the two indexes allocated to the block.  static int monitor_offset_for_compiler(int local_index, int nof_args, int max_nof_locals, int max_nof_monitors);  // Tell the smallest value that local_offset_for_compiler will attain.  // This is used to help determine how much stack frame to allocate.  static int min_local_offset_for_compiler(int nof_args, int max_nof_locals, int max_nof_monitors);  // Tells if this register must be spilled during a call.  // On Intel, all registers are smashed by calls.  static bool volatile_across_calls(Register reg);

cpu/x86/vm/bytecodeInterpreter_x86.hpp69行,定义了javaStackjavaLocals相关的操作,源码如下:

69707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
// JavaStack Implementation#define GET_STACK_SLOT(offset)    (*((intptr_t*) &topOfStack[-(offset)]))#define STACK_SLOT(offset)    ((address) &topOfStack[-(offset)])#define STACK_ADDR(offset)    (*((address *) &topOfStack[-(offset)]))#define STACK_INT(offset)     (*((jint*) &topOfStack[-(offset)]))#define STACK_FLOAT(offset)   (*((jfloat *) &topOfStack[-(offset)]))#define STACK_OBJECT(offset)  (*((oop *) &topOfStack [-(offset)]))#define STACK_DOUBLE(offset)  (((VMJavaVal64*) &topOfStack[-(offset)])->d)#define STACK_LONG(offset)    (((VMJavaVal64 *) &topOfStack[-(offset)])->l)#define SET_STACK_SLOT(value, offset)   (*(intptr_t*)&topOfStack[-(offset)] = *(intptr_t*)(value))#define SET_STACK_ADDR(value, offset)   (*((address *)&topOfStack[-(offset)]) = (value))#define SET_STACK_INT(value, offset)    (*((jint *)&topOfStack[-(offset)]) = (value))#define SET_STACK_FLOAT(value, offset)  (*((jfloat *)&topOfStack[-(offset)]) = (value))#define SET_STACK_OBJECT(value, offset) (*((oop *)&topOfStack[-(offset)]) = (value))#define SET_STACK_DOUBLE(value, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d = (value))#define SET_STACK_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&topOfStack[-(offset)])->d =  \                                                 ((VMJavaVal64*)(addr))->d)#define SET_STACK_LONG(value, offset)   (((VMJavaVal64*)&topOfStack[-(offset)])->l = (value))#define SET_STACK_LONG_FROM_ADDR(addr, offset)   (((VMJavaVal64*)&topOfStack[-(offset)])->l =  \                                                 ((VMJavaVal64*)(addr))->l)// JavaLocals implementation#define LOCALS_SLOT(offset)    ((intptr_t*)&locals[-(offset)])#define LOCALS_ADDR(offset)    ((address)locals[-(offset)])#define LOCALS_INT(offset)     ((jint)(locals[-(offset)]))#define LOCALS_FLOAT(offset)   (*((jfloat*)&locals[-(offset)]))#define LOCALS_OBJECT(offset)  (cast_to_oop(locals[-(offset)]))#define LOCALS_DOUBLE(offset)  (((VMJavaVal64*)&locals[-((offset) + 1)])->d)#define LOCALS_LONG(offset)    (((VMJavaVal64*)&locals[-((offset) + 1)])->l)#define LOCALS_LONG_AT(offset) (((address)&locals[-((offset) + 1)]))#define LOCALS_DOUBLE_AT(offset) (((address)&locals[-((offset) + 1)]))#define SET_LOCALS_SLOT(value, offset)    (*(intptr_t*)&locals[-(offset)] = *(intptr_t *)(value))#define SET_LOCALS_ADDR(value, offset)    (*((address *)&locals[-(offset)]) = (value))#define SET_LOCALS_INT(value, offset)     (*((jint *)&locals[-(offset)]) = (value))#define SET_LOCALS_FLOAT(value, offset)   (*((jfloat *)&locals[-(offset)]) = (value))#define SET_LOCALS_OBJECT(value, offset)  (*((oop *)&locals[-(offset)]) = (value))#define SET_LOCALS_DOUBLE(value, offset)  (((VMJavaVal64*)&locals[-((offset)+1)])->d = (value))#define SET_LOCALS_LONG(value, offset)    (((VMJavaVal64*)&locals[-((offset)+1)])->l = (value))#define SET_LOCALS_DOUBLE_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->d = \                                                  ((VMJavaVal64*)(addr))->d)#define SET_LOCALS_LONG_FROM_ADDR(addr, offset) (((VMJavaVal64*)&locals[-((offset)+1)])->l = \                                                ((VMJavaVal64*)(addr))->l)

cpu/x86/vm/frame_x86.hpp31行,描述了frame的数据结构,源码如下:

313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
// A frame represents a physical stack frame (an activation).  Frames can be// C or Java frames, and the Java frames can be interpreted or compiled.// In contrast, vframes represent source-level activations, so that one physical frame// can correspond to multiple source level frames because of inlining.// A frame is comprised of {pc, fp, sp}// ------------------------------ Asm interpreter ----------------------------------------// Layout of asm interpreter frame://    [expression stack      ] * <- sp//    [monitors              ]   \//     ...                        | monitor block size//    [monitors              ]   ///    [monitor block size    ]//    [byte code index/pointr]                   = bcx()                bcx_offset//    [pointer to locals     ]                   = locals()             locals_offset//    [constant pool cache   ]                   = cache()              cache_offset//    [methodData            ]                   = mdp()                mdx_offset//    [Method*               ]                   = method()             method_offset//    [last sp               ]                   = last_sp()            last_sp_offset//    [old stack pointer     ]                     (sender_sp)          sender_sp_offset//    [old frame pointer     ]   <- fp           = link()//    [return pc             ]//    [oop temp              ]                     (only for native calls)//    [locals and parameters ]//                               <- sender sp// ------------------------------ Asm interpreter ----------------------------------------// ------------------------------ C++ interpreter ----------------------------------------//// Layout of C++ interpreter frame: (While executing in BytecodeInterpreter::run)////                             <- SP (current esp/rsp)//    [local variables         ] BytecodeInterpreter::run local variables//    ...                        BytecodeInterpreter::run local variables//    [local variables         ] BytecodeInterpreter::run local variables//    [old frame pointer       ]   fp [ BytecodeInterpreter::run's ebp/rbp ]//    [return pc               ]  (return to frame manager)//    [interpreter_state*      ]  (arg to BytecodeInterpreter::run)   --------------//    [expression stack        ] <- last_Java_sp                           |//    [...                     ] * <- interpreter_state.stack              |//    [expression stack        ] * <- interpreter_state.stack_base         |//    [monitors                ]   \                                       |//     ...                          | monitor block size                   |//    [monitors                ]   / <- interpreter_state.monitor_base     |//    [struct interpretState   ] <-----------------------------------------|//    [return pc               ] (return to callee of frame manager [1]//    [locals and parameters   ]//                               <- sender sp// [1] When the C++ interpreter calls a new method it returns to the frame//     manager which allocates a new frame on the stack. In that case there//     is no real callee of this newly allocated frame. The frame manager is//     aware of the additional frame(s) and will pop them as nested calls//     complete. However, to make it look good in the debugger the frame//     manager actually installs a dummy pc pointing to RecursiveInterpreterActivation//     with a fake interpreter_state* parameter to make it easy to debug//     nested calls.// Note that contrary to the layout for the assembly interpreter the// expression stack allocated for the C++ interpreter is full sized.// However this is not as bad as it seems as the interpreter frame_manager// will truncate the unused space on successive method calls.//// ------------------------------ C++ interpreter ---------------------------------------- public:  enum {    pc_return_offset                                 =  0,    // All frames    link_offset                                      =  0,    return_addr_offset                               =  1,    // non-interpreter frames    sender_sp_offset                                 =  2,#ifndef CC_INTERP    // Interpreter frames    interpreter_frame_result_handler_offset          =  3, // for native calls only    interpreter_frame_oop_temp_offset                =  2, // for native calls only    interpreter_frame_sender_sp_offset               = -1,    // outgoing sp before a call to an invoked method    interpreter_frame_last_sp_offset                 = interpreter_frame_sender_sp_offset - 1,    interpreter_frame_method_offset                  = interpreter_frame_last_sp_offset - 1,    interpreter_frame_mdx_offset                     = interpreter_frame_method_offset - 1,    interpreter_frame_cache_offset                   = interpreter_frame_mdx_offset - 1,    interpreter_frame_locals_offset                  = interpreter_frame_cache_offset - 1,    interpreter_frame_bcx_offset                     = interpreter_frame_locals_offset - 1,    interpreter_frame_initial_sp_offset              = interpreter_frame_bcx_offset - 1,    interpreter_frame_monitor_block_top_offset       = interpreter_frame_initial_sp_offset,    interpreter_frame_monitor_block_bottom_offset    = interpreter_frame_initial_sp_offset,#endif // CC_INTERP

References

  1. vm/runtime/frame.hpp
  2. cpu/x86/vm/bytecodeInterpreter_x86.hpp
  3. cpu/x86/vm/frame_x86.hpp