duke@435: /* duke@435: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: // A frame represents a physical stack frame (an activation). Frames can be duke@435: // C or Java frames, and the Java frames can be interpreted or compiled. duke@435: // In contrast, vframes represent source-level activations, so that one physical frame duke@435: // can correspond to multiple source level frames because of inlining. duke@435: // A frame is comprised of {pc, fp, sp} duke@435: // ------------------------------ Asm interpreter ---------------------------------------- duke@435: // Layout of asm interpreter frame: duke@435: // [expression stack ] * <- sp duke@435: // [monitors ] \ duke@435: // ... | monitor block size duke@435: // [monitors ] / duke@435: // [monitor block size ] duke@435: // [byte code index/pointr] = bcx() bcx_offset duke@435: // [pointer to locals ] = locals() locals_offset duke@435: // [constant pool cache ] = cache() cache_offset duke@435: // [methodData ] = mdp() mdx_offset duke@435: // [methodOop ] = method() method_offset duke@435: // [last sp ] = last_sp() last_sp_offset duke@435: // [old stack pointer ] (sender_sp) sender_sp_offset duke@435: // [old frame pointer ] <- fp = link() duke@435: // [return pc ] duke@435: // [oop temp ] (only for native calls) duke@435: // [locals and parameters ] duke@435: // <- sender sp duke@435: // ------------------------------ Asm interpreter ---------------------------------------- duke@435: duke@435: // ------------------------------ C++ interpreter ---------------------------------------- duke@435: // duke@435: // Layout of C++ interpreter frame: (While executing in BytecodeInterpreter::run) duke@435: // duke@435: // <- SP (current esp/rsp) duke@435: // [local variables ] BytecodeInterpreter::run local variables duke@435: // ... BytecodeInterpreter::run local variables duke@435: // [local variables ] BytecodeInterpreter::run local variables duke@435: // [old frame pointer ] fp [ BytecodeInterpreter::run's ebp/rbp ] duke@435: // [return pc ] (return to frame manager) duke@435: // [interpreter_state* ] (arg to BytecodeInterpreter::run) -------------- duke@435: // [expression stack ] <- last_Java_sp | duke@435: // [... ] * <- interpreter_state.stack | duke@435: // [expression stack ] * <- interpreter_state.stack_base | duke@435: // [monitors ] \ | duke@435: // ... | monitor block size | duke@435: // [monitors ] / <- interpreter_state.monitor_base | duke@435: // [struct interpretState ] <-----------------------------------------| duke@435: // [return pc ] (return to callee of frame manager [1] duke@435: // [locals and parameters ] duke@435: // <- sender sp duke@435: duke@435: // [1] When the c++ interpreter calls a new method it returns to the frame duke@435: // manager which allocates a new frame on the stack. In that case there duke@435: // is no real callee of this newly allocated frame. The frame manager is duke@435: // aware of the additional frame(s) and will pop them as nested calls duke@435: // complete. Howevers tTo make it look good in the debugger the frame duke@435: // manager actually installs a dummy pc pointing to RecursiveInterpreterActivation duke@435: // with a fake interpreter_state* parameter to make it easy to debug duke@435: // nested calls. duke@435: duke@435: // Note that contrary to the layout for the assembly interpreter the duke@435: // expression stack allocated for the C++ interpreter is full sized. duke@435: // However this is not as bad as it seems as the interpreter frame_manager duke@435: // will truncate the unused space on succesive method calls. duke@435: // duke@435: // ------------------------------ C++ interpreter ---------------------------------------- duke@435: duke@435: public: duke@435: enum { duke@435: pc_return_offset = 0, duke@435: // All frames duke@435: link_offset = 0, duke@435: return_addr_offset = 1, duke@435: // non-interpreter frames duke@435: sender_sp_offset = 2, duke@435: duke@435: #ifndef CC_INTERP duke@435: duke@435: // Interpreter frames duke@435: interpreter_frame_result_handler_offset = 3, // for native calls only duke@435: interpreter_frame_oop_temp_offset = 2, // for native calls only duke@435: duke@435: interpreter_frame_sender_sp_offset = -1, duke@435: // outgoing sp before a call to an invoked method duke@435: interpreter_frame_last_sp_offset = interpreter_frame_sender_sp_offset - 1, duke@435: interpreter_frame_method_offset = interpreter_frame_last_sp_offset - 1, duke@435: interpreter_frame_mdx_offset = interpreter_frame_method_offset - 1, duke@435: interpreter_frame_cache_offset = interpreter_frame_mdx_offset - 1, duke@435: interpreter_frame_locals_offset = interpreter_frame_cache_offset - 1, duke@435: interpreter_frame_bcx_offset = interpreter_frame_locals_offset - 1, duke@435: interpreter_frame_initial_sp_offset = interpreter_frame_bcx_offset - 1, duke@435: duke@435: interpreter_frame_monitor_block_top_offset = interpreter_frame_initial_sp_offset, duke@435: interpreter_frame_monitor_block_bottom_offset = interpreter_frame_initial_sp_offset, duke@435: duke@435: #endif // CC_INTERP duke@435: duke@435: // Entry frames duke@435: #ifdef AMD64 duke@435: #ifdef _WIN64 duke@435: entry_frame_after_call_words = 8, duke@435: entry_frame_call_wrapper_offset = 2, duke@435: duke@435: arg_reg_save_area_bytes = 32, // Register argument save area duke@435: #else duke@435: entry_frame_after_call_words = 13, duke@435: entry_frame_call_wrapper_offset = -6, duke@435: duke@435: arg_reg_save_area_bytes = 0, duke@435: #endif // _WIN64 duke@435: #else duke@435: entry_frame_call_wrapper_offset = 2, duke@435: #endif // AMD64 duke@435: duke@435: // Native frames duke@435: duke@435: native_frame_initial_param_offset = 2 duke@435: duke@435: }; duke@435: duke@435: intptr_t ptr_at(int offset) const { duke@435: return *ptr_at_addr(offset); duke@435: } duke@435: duke@435: void ptr_at_put(int offset, intptr_t value) { duke@435: *ptr_at_addr(offset) = value; duke@435: } duke@435: duke@435: private: duke@435: // an additional field beyond _sp and _pc: duke@435: intptr_t* _fp; // frame pointer duke@435: // The interpreter and adapters will extend the frame of the caller. duke@435: // Since oopMaps are based on the sp of the caller before extension duke@435: // we need to know that value. However in order to compute the address duke@435: // of the return address we need the real "raw" sp. Since sparc already duke@435: // uses sp() to mean "raw" sp and unextended_sp() to mean the caller's duke@435: // original sp we use that convention. duke@435: duke@435: intptr_t* _unextended_sp; duke@435: duke@435: intptr_t* ptr_at_addr(int offset) const { duke@435: return (intptr_t*) addr_at(offset); duke@435: } duke@435: twisti@1639: #if ASSERT twisti@1639: // Used in frame::sender_for_{interpreter,compiled}_frame twisti@1639: static void verify_deopt_original_pc( nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); twisti@1639: static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { twisti@1639: verify_deopt_original_pc(nm, unextended_sp, true); twisti@1639: } twisti@1639: #endif twisti@1639: duke@435: public: duke@435: // Constructors duke@435: duke@435: frame(intptr_t* sp, intptr_t* fp, address pc); duke@435: duke@435: frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc); duke@435: duke@435: frame(intptr_t* sp, intptr_t* fp); duke@435: duke@435: // accessors for the instance variables duke@435: intptr_t* fp() const { return _fp; } duke@435: duke@435: inline address* sender_pc_addr() const; duke@435: duke@435: // return address of param, zero origin index. duke@435: inline address* native_param_addr(int idx) const; duke@435: duke@435: // expression stack tos if we are nested in a java call duke@435: intptr_t* interpreter_frame_last_sp() const; duke@435: duke@435: #ifndef CC_INTERP duke@435: // deoptimization support duke@435: void interpreter_frame_set_last_sp(intptr_t* sp); duke@435: #endif // CC_INTERP duke@435: duke@435: #ifdef CC_INTERP duke@435: inline interpreterState get_interpreterState() const; duke@435: #endif // CC_INTERP