/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/cppInterpreter.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "oops/arrayOop.hpp"
#include "oops/methodDataOop.hpp"
#include "oops/methodOop.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/jvmtiThreadState.hpp"
#include "runtime/arguments.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.hpp"
#include "runtime/vframeArray.hpp"
#ifdef SHARK
#include "shark/shark_globals.hpp"
#endif
#ifdef CC_INTERP
// Routine exists to make tracebacks look decent in debugger
// while we are recursed in the frame manager/c++ interpreter.
// We could use an address in the frame manager but having
// frames look natural in the debugger is a plus.
{
//
}
Label fast_accessor_slow_entry_path; // fast accessor methods need to be able to jmp to unsynchronized
// c++ interpreter entry point this holds that entry point label.
// default registers for state and sender_sp
// state and sender_sp are the same on 32bit because we have no choice.
// state could be rsi on 64bit but it is an arg reg and not callee save
// so r13 is better choice.
// NEEDED for JVMTI?
// address AbstractInterpreter::_remove_activation_preserving_args_entry;
int i = 0;
switch (type) {
case T_BOOLEAN: i = 0; break;
case T_CHAR : i = 1; break;
case T_BYTE : i = 2; break;
case T_SHORT : i = 3; break;
case T_INT : i = 4; break;
case T_VOID : i = 5; break;
case T_FLOAT : i = 8; break;
case T_LONG : i = 9; break;
case T_DOUBLE : i = 6; break;
case T_OBJECT : // fall through
case T_ARRAY : i = 7; break;
default : ShouldNotReachHere();
}
return i;
}
// Is this pc anywhere within code owned by the interpreter?
// This only works for pc that might possibly be exposed to frame
// walkers. It clearly misses all of the actual c++ interpreter
// implementation
}
switch (type) {
case T_VOID : // fall thru
case T_LONG : // fall thru
case T_INT : /* nothing to do */ break;
case T_DOUBLE :
case T_FLOAT :
{
// Must return a result for interpreter or compiler. In SSE
// mode, results are returned in xmm0 and the FPU stack must
// be empty.
#ifndef _LP64
// Load ST0
// Store as float and empty fpu stack
#endif // !_LP64
// and reload
} else {
// restore ST0
}
// and pop the temp
}
break;
case T_OBJECT :
// retrieve result from frame
// and verify it
break;
default : ShouldNotReachHere();
}
return entry;
}
// tosca based result to c++ interpreter stack based result.
// Result goes to top of native stack.
// A result is in the tosca (abi result) from either a native method call or compiled
// code. Place this result on the java expression stack so C++ interpreter can use it.
switch (type) {
case T_VOID:
break;
case T_BOOLEAN:
#ifdef EXTEND
#endif
break;
case T_CHAR :
#ifdef EXTEND
#endif
break;
case T_BYTE :
#ifdef EXTEND
#endif
break;
case T_SHORT :
#ifdef EXTEND
#endif
break;
case T_LONG :
break;
case T_INT :
break;
case T_FLOAT :
// Result is in ST(0)/xmm0
if ( UseSSE < 1) {
} else {
}
break;
case T_DOUBLE :
if ( UseSSE < 2 ) {
} else {
}
break;
case T_OBJECT :
break;
default : ShouldNotReachHere();
}
return entry;
}
// A result is in the java expression stack of the interpreted method that has just
// returned. Place this result on the java expression stack of the caller.
//
// result. So we know that the result of this method is on the top of the current
// execution stack (which is pre-pushed) and will be return to the top of the caller
// stack. The top of the callers stack is the bottom of the locals of the current
// activation.
// Because of the way activation are managed by the frame manager the value of rsp is
// below both the stack top of the current activation and naturally the stack top
// of the calling activation. This enable this routine to leave the return address
// to the frame manager on the stack and do a vanilla return.
//
// rax - new stack top for caller activation (i.e. activation in _prev_link)
//
// Can destroy rdx, rcx.
//
switch (type) {
case T_VOID:
break;
case T_FLOAT :
case T_BOOLEAN:
case T_CHAR :
case T_BYTE :
case T_SHORT :
case T_INT :
// 1 word result
break;
case T_LONG :
case T_DOUBLE :
// return top two words on current expression stack to caller's expression stack
// The caller's expression stack is adjacent to the current frame manager's intepretState
// except we allocated one extra word for this intepretState so we won't overwrite it
// when we return a two word result.
break;
case T_OBJECT :
break;
default : ShouldNotReachHere();
}
return entry;
}
// A result is in the java expression stack of the interpreted method that has just
// returned. Place this result in the native abi that the caller expects.
//
// Similar to generate_stack_to_stack_converter above. Called at a similar time from the
// and so rather than return result onto caller's java expression stack we return the
// result in the expected location based on the native abi.
switch (type) {
case T_VOID:
break;
case T_BOOLEAN:
case T_CHAR :
case T_BYTE :
case T_SHORT :
case T_INT :
break;
case T_LONG :
break;
case T_FLOAT :
if ( UseSSE >= 1) {
} else {
}
break;
case T_DOUBLE :
if ( UseSSE > 1) {
} else {
}
break;
case T_OBJECT :
break;
default : ShouldNotReachHere();
}
return entry;
}
// make it look good in the debugger
}
if (length != 0) {
switch (state) {
case ctos:
case stos:
}
} else {
}
return ret;
}
// C++ Interpreter
bool native) {
// On entry the "locals" argument points to locals[0] (or where it would be in case no locals in
// a static method). "state" contains any previous frame manager state which we must save a link
// to in the newly generated state object. On return "state" is a pointer to the newly allocated
// state object. We must allocate and initialize a new interpretState object and the method
// expression stack. Because the returned result (if any) of the method will be placed on the caller's
// be sure to leave space on the caller's stack so that this result will not overwrite values when
// locals[0] and locals[1] do not exist (and in fact are return address and saved rbp). So when
// we are non-native we in essence ensure that locals[0-1] exist. We play an extra trick in
// non-product builds and initialize this last local with the previous interpreterState as
// this makes things look real nice in the debugger.
// State on entry
// Assumes locals == &locals[0]
// Assumes state == any previous frame manager state (assuming call path from c++ interpreter)
// Assumes rax = return address
// rcx == senders_sp
// rbx == method
// Modifies rcx, rdx, rax
// Returns:
// state == address of new interpreterState
// rsp == bottom of method's expression stack.
// On entry sp is the sender's sp. This includes the space for the arguments
// that the sender pushed. If the sender pushed no args (a static) and the
// caller returns a long then we need two words on the sender's stack which
// are not present (although when we return a restore full size stack the
// space will be present). If we didn't allocate two words here then when
// we "push" the result of the caller's stack we would overwrite the return
// address and the saved rbp. Not good. So simply allocate 2 words now
// just to be safe. This is the "static long no_params() method" issue.
// See Lo.java for a testcase.
// We don't need this for native calls because they return result in
// register and the stack is expanded in the caller before we store
// the results on the stack.
if (!native) {
#ifdef PRODUCT
#else /* PRODUCT */
#endif /* PRODUCT */
}
// Now that we are assure of space for stack result, setup typical linkage
// initialize the "shadow" frame so that use since C++ interpreter not directly
// recursive. Simpler to recurse but we can't trim expression stack as we call
// new methods.
#ifdef _LP64
#else
#endif // _LP64
if (native) {
} else {
}
__ movl(STATE(_msg), (int32_t) BytecodeInterpreter::method_entry); // state->_msg = initial method entry
__ movptr(STATE(_result._to_call._callee), (int32_t) NULL_WORD); // state->_result._to_call._callee_callee = NULL
__ movptr(STATE(_monitor_base), rsp); // set monitor block bottom (grows down) this would point to entry [0]
// entries run from -1..x where &monitor[x] ==
{
// Must not attempt to lock method until we enter interpreter as gc won't be able to find the
// initial frame. However we allocate a free monitor so we don't have to shuffle the expression stack
// immediately.
// synchronize method
// Allocate initial monitor and pre initialize it
// get synchronization object
// add space for monitor & lock
}
if (native) {
} else {
// compute full expression stack limit
// Allocate expression stack
}
#ifdef _LP64
// Make sure stack is properly aligned and sized for the abi
#endif // _LP64
}
// Helpers for commoning out cases in the various type of method entries.
//
// increment invocation count & check for overflow
//
// Note: checking for negative value instead of overflow
// so we have a 'sticky' overflow test
//
// rbx,: method
// rcx: invocation counter
//
void InterpreterGenerator::generate_counter_incr(Label* overflow, Label* profile_method, Label* profile_method_continue) {
const Address invocation_counter(rbx, methodOopDesc::invocation_counter_offset() + InvocationCounter::counter_offset());
const Address backedge_counter (rbx, methodOopDesc::backedge_counter_offset() + InvocationCounter::counter_offset());
if (ProfileInterpreter) { // %%% Merge this into methodDataOop
}
// Update standard invocation counters
// profile_method is non-null only for interpreted method so
// profile_method != NULL == !native_call
// BytecodeInterpreter only calls for native so code is elided.
}
// C++ interpreter on entry
// rbp - interpreter frame pointer
// rbx - method
// On return (i.e. jump to entry_point) [ back to invocation of interpreter ]
// rbx, - method
// rcx - rcvr (assuming there is one)
// top of stack return address of interpreter caller
// rsp - sender_sp
// C++ interpreter only
// InterpreterRuntime::frequency_counter_overflow takes one argument
// indicating if the counter overflow occurs at a backwards branch (non-NULL bcp).
// The call returns the address of the verified entry point for the method or NULL
// if the compilation did not complete (either went background or bailed out).
// for c++ interpreter can rsi really be munged?
}
// see if we've got enough room on the stack for locals plus overhead.
// the expression stack grows down incrementally, so the normal guard
// page mechanism will work for that.
//
// Registers live on entry:
//
// Asm interpreter
// rdx: number of additional locals this frame needs (what we must check)
// rbx,: methodOop
// C++ Interpreter
// rdi: &locals[0]
// rcx: # of locals
// rdx: number of additional locals this frame needs (what we must check)
// rbx: methodOop
// destroyed on exit
// rax,
// NOTE: since the additional locals are also always pushed (wasn't obvious in
// generate_method_entry) so the guard should work for them too.
//
// monitor entry size: see picture of stack set (generate_method_entry) and frame_i486.hpp
// total overhead size: entry_size + (saved rbp, thru expr stack bottom).
// compute rsp as if this were going to be the last frame on
// the stack before the red zone
// save rsi == caller's bytecode ptr (c++ previous interp. state)
// QQQ problem here?? rsi overload????
// locals + overhead, in bytes
// Always give one monitor to allow us to start interp if sync method.
// Any additional monitors need a check when moving the expression stack
#ifdef ASSERT
// verify that thread stack base is non-zero
// verify that thread stack size is non-zero
#endif
// Add stack base to locals and subtract stack size
// We should have a magic number here for the size of the c++ interpreter frame.
// We can't actually tell this ahead of time. The debug version size is around 3k
// product is 1k and fastdebug is 4k
// Use the maximum number of pages we might bang.
// Only need this if we are stack banging which is temporary while
// we're debugging.
// check against the current stack bottom
// throw exception return address becomes throwing pc
// all done with frame size check
}
// Find preallocated monitor and lock method (C++ interpreter)
// rbx - methodOop
//
// minimally destroys rax, rdx|c_rarg1, rdi
//
// synchronize method
// find initial monitor i.e. monitors[-1]
#ifdef ASSERT
{ Label L;
}
#endif // ASSERT
// get synchronization object
}
#ifdef ASSERT
{ Label L;
}
#endif // ASSERT
// can destroy rax, rdx|c_rarg1, rcx, and (via call_VM) rdi!
}
// Call an accessor method (assuming it is resolved, otherwise drop into vanilla (slow path) entry
// rbx: methodOop
// do fastpath for resolved accessor methods
if (UseFastAccessorMethods) {
// If we need a safepoint check, generate full interpreter entry.
// ASM/C++ Interpreter
// Code: _aload_0, _(i|a)getfield, _(i|a)return or any rewrites thereof; parameter size = 1
// Note: We can only use this code if the getfield has been resolved
// and if we don't have a null-pointer exception => check for
// these conditions first and use slow path if necessary.
// rbx,: method
// rcx: receiver
// check if local 0 != NULL and read field
// read first instruction word and extract bytecode @ 1 and index @ 2
// Shift codes right to get the index on the right.
// The bytecode fetched looks like <index><0xb4><0x2a>
// rax,: local 0
// rbx,: method
// rcx: receiver - do not destroy since it is needed for slow path!
// rcx: scratch
// rdx: constant pool cache index
// rdi: constant pool cache
// check if getfield has been resolved and read constant pool cache entry
// check the validity of the cache entry by testing whether _indices field
// contains Bytecode::_getfield in b1 byte.
rdx,
Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::indices_offset()));
// Note: constant pool entry is not valid before bytecode is resolved
rdx,
Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::f2_offset()));
rdx,
Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::flags_offset()));
// Need to differentiate between igetfield, agetfield, bgetfield etc.
// because they are different sizes.
// Use the type from the constant pool cache
// Make sure we don't need to mask rdx after the above shift
#ifdef _LP64
// atos
#endif // _LP64
#ifdef ASSERT
#ifndef _LP64
#endif // _LP64
#endif // ASSERT
// All the rest are a 32 bit wordsize
// _ireturn/_areturn
// generate a vanilla interpreter entry as the slow path
// We will enter c++ interpreter looking like it was
// called by the call_stub this will cause it to return
// a tosca result to the invoker which might have been
// the c++ interpreter itself.
return entry_point;
} else {
return NULL;
}
}
#ifndef SERIALGC
if (UseG1GC) {
// We need to generate have a routine that generates code to:
// * load the value in the referent field
// * passes that value to the pre-barrier.
//
// In the case of G1 this will record the value of the
// referent in an SATB buffer if marking is active.
// This will cause concurrent marking to mark the referent
// field as live.
}
#endif // SERIALGC
// If G1 is not enabled then attempt to go through the accessor entry point
// Reference.get is an accessor
return generate_accessor_entry();
}
//
// C++ Interpreter stub for calling a native method.
// This sets up a somewhat different looking stack for calling the native method
// than the typical interpreter frame setup but still has the pointer to
// an interpreter state.
//
// determine code generation flags
// rbx: methodOop
// rcx: receiver (unused)
const Address invocation_counter(rbx, methodOopDesc::invocation_counter_offset() + InvocationCounter::counter_offset());
// get parameter size (always needed)
// rbx: methodOop
// rcx: size of parameters
// for natives the size of locals is zero
// compute beginning of parameters /locals
// initialize fixed part of activation frame
// Assumes rax = return address
// allocate and initialize new interpreterState and method expression stack
// IN(locals) -> locals
// destroys rax, rcx, rdx
// OUT (state) -> new interpreterState
// OUT(rsp) -> bottom of methods expression stack
// save sender_sp
// start with NULL previous state
#ifdef ASSERT
{ Label L;
#ifdef _LP64
// duplicate the alignment rsp got after setting stack_base
#endif // _LP64
}
#endif
// Since at this point in the method invocation the exception handler
// would try to exit the monitor of synchronized methods which hasn't
// been entered yet, we set the thread local variable
// _do_not_unlock_if_synchronized to true. The remove_activation will
// check this flag.
// make sure method is native & not abstract
#ifdef ASSERT
{
Label L;
}
{ Label L;
}
#endif
// increment invocation count & check for overflow
if (inc_counter) {
}
bang_stack_shadow_pages(true);
// reset the _do_not_unlock_if_synchronized flag
// check for synchronized native methods
//
// Note: This must happen *after* invocation counter check, since
// when overflow happens, the method should not be locked.
if (synchronized) {
// potentially kills rax, rcx, rdx, rdi
lock_method();
} else {
// no synchronization necessary
#ifdef ASSERT
{ Label L;
}
#endif
}
// start execution
// jvmti support
// work registers
// allocate space for parameters
#ifdef _LP64
#else
#endif // _LP64
// get signature handler
{ Label L;
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), method, false);
}
#ifdef ASSERT
{
Label L;
}
#endif //
// call signature handler
// The generated handlers do not touch RBX (the method oop).
// However, large signatures cannot be cached and are generated
// each time here. The slow-path generator will blow RBX
// sometime, so we must reload it after the call.
// result handler is in rax
// set result handler
// get native function entry point
{ Label L;
}
// pass mirror handle if static call
{ Label L;
// get mirror
// copy mirror into activation object
// pass handle to mirror
#ifdef _LP64
#else
#endif // _LP64
}
#ifdef ASSERT
{
Label L;
}
#endif //
// pass JNIEnv
#ifdef _LP64
#else
#endif // _LP64
#ifdef ASSERT
{
Label L;
}
#endif //
#ifdef ASSERT
{ Label L;
}
#endif
// Change state to native (we save the return address in the thread, since it might not
// be pushed on the stack when we do a a stack traversal). It is enough that the pc()
// points into the right code segment. It does not have to be the correct return pc.
// result potentially in rdx:rax or ST0
// The potential result is in ST(0) & rdx:rax
// With C++ interpreter we leave any possible result in ST(0) until we are in result handler and then
// we do the appropriate stuff for returning the result. rdx:rax must always be saved because just about
// anything we do here will destroy it, st(0) is only saved if we re-enter the vm where it would
// be destroyed.
// It is safe to do these pushes because state is _thread_in_native and return address will be found
// via _last_native_pc and not via _last_jave_sp
// Must save the value of ST(0)/xmm0 since it could be destroyed before we get to result handler
if ( UseSSE < 2 ) {
} else {
}
}
// save rax:rdx for potential use by result handler.
#ifndef _LP64
#endif // _LP64
// Verify or restore cpu control state after JNI call
// change thread state
// Write serialization page so VM thread can do a pseudo remote membar.
// We use the current thread pointer to calculate a thread specific
// offset to write to within the page. This minimizes bus traffic
// due to cache line collision.
}
// threads running native code and they are expected to self-suspend
// when leaving the _thread_in_native state. We need to check for
// pending suspend requests here.
Label L;
// Don't use call_VM as it will see a possible pending exception and forward it
// and never return here preventing us from clearing _last_native_pc down below.
// Also can't use call_VM_leaf either as it will check to see if rsi & rdi are
//
((MacroAssembler*)_masm)->call_VM_leaf(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
thread);
}
// change thread state
// reset handle block
// If result was an oop then unbox and save it in the frame
{ Label L;
#ifndef _LP64
#endif // _LP64
// unbox
// keep stack depth as expected by pushing oop which will eventually be discarded
#ifndef _LP64
#endif // _LP64
}
{
__ cmpl(Address(thread, JavaThread::stack_guard_state_offset()), JavaThread::stack_guard_yellow_disabled);
}
// QQQ Seems like for native methods we simply return and the caller will see the pending
// exception and do the right thing. Certainly the interpreter will, don't know about
// compiled methods.
// Seems that the answer to above is no this is wrong. The old code would see the exception
// and forward it before doing the unlocking and notifying jvmdi that method has exited.
// This seems wrong need to investigate the spec.
// handle exceptions (exception handling will handle unlocking!)
{ Label L;
// return and let caller deal with exception. This skips the unlocking here which
// seems wrong but seems to be what asm interpreter did. Can't find this in the spec.
// Note: must preverve method in rbx
//
// remove activation
// The skips unlocking!! This seems to be what asm interpreter does but seems
// very wrong. Not clear if this violates the spec.
}
// do unlocking if necessary
{ Label L;
// the code below should be shared with interpreter macro assembler implementation
// BasicObjectLock will be first in list, since this is a synchronized method. However, need
// to check that the object has not been unlocked by an explicit monitorexit bytecode.
__ subptr(monitor, frame::interpreter_frame_monitor_size() * wordSize); // address of initial monitor
// Entry already unlocked, need to throw exception
__ MacroAssembler::call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_illegal_monitor_state_exception));
// unlock can blow rbx so restore it for path that needs it below
}
}
// jvmti support
// the exception handler code notifies the runtime of method exits
// not properly paired (was bug - gri 11/22/99).
// restore potential result in rdx:rax, call result handler to restore potential result in ST0 & handle result
#ifndef _LP64
#endif // _LP64
// remove activation
__ movptr(state, STATE(_prev_link)); // get previous state for return (if c++ interpreter was caller)
// invocation counter overflow
if (inc_counter) {
// Handle overflow of counter and compile method
}
return entry_point;
}
// Generate entries that will put a result type index into rcx
// Generate entries that will put a result type index into rcx
// deopt needs to jump to here to enter the interpreter (return a result)
// rax is live here
// deopt needs to jump to here to enter the interpreter (return a result)
// rax is live here
__ movl(rcx, AbstractInterpreter::BasicType_as_index(T_BOOLEAN)); // Result stub address array index
// deopt needs to jump to here to enter the interpreter (return a result)
// rax is live here
// deopt needs to jump to here to enter the interpreter (return a result)
// rax,rdx are live here
// deopt needs to jump to here to enter the interpreter (return a result)
// st(0) is live here
// deopt needs to jump to here to enter the interpreter (return a result)
// st(0) is live here
// deopt needs to jump to here to enter the interpreter (return a result)
// Deopt return common
// an index is present in rcx that lets us move any possible result being
// return to the interpreter's stack
//
// Because we have a full sized interpreter frame on the youngest
// activation the stack is pushed too deep to share the tosca to
// stack converters directly. We shrink the stack to the desired
// amount and then push result and then re-extend the stack.
// We could have the code in size_activation layout a short
// frame for the top activation but that would look different
// than say sparc (which needs a full size activation because
// the windows are in the way. Really it could be short? QQQ
//
// setup rsp so we can push the "result" as needed.
// Address index(noreg, rcx, Address::times_ptr);
// __ movl(rcx, Address(noreg, rcx, Address::times_ptr, int(AbstractInterpreter::_tosca_to_stack)));
// result if any on stack already )
}
// Generate the code to handle a more_monitors message from the c++ interpreter
// 1. compute new pointers // rsp: old expression stack top
// 2. move expression stack contents
// now zero the slot so we can find it.
}
// Initial entry to C++ interpreter from the call_stub.
// This entry point is called the frame manager since it handles the generation
// of interpreter activation frames via requests directly from the vm (via call_stub)
// and via requests from the interpreter. The requests from the call_stub happen
// directly thru the entry point. Requests from the interpreter happen via returning
// from the interpreter and examining the message the interpreter has returned to
// the frame manager. The frame manager can take the following requests:
// NO_REQUEST - error, should never happen.
// MORE_MONITORS - need a new monitor. Shuffle the expression stack on down and
// allocate a new monitor.
// CALL_METHOD - setup a new activation to call a new method. Very similar to what
// happens during entry during the entry via the call stub.
// RETURN_FROM_METHOD - remove an activation. Return to interpreter or call stub.
//
// Arguments:
//
// rbx: methodOop
// rcx: receiver - unused (retrieved from stack as needed)
//
//
// Stack layout at entry
//
// [ return address ] <--- rsp
// [ parameter n ]
// ...
// [ parameter 1 ]
// [ expression stack ]
//
//
// We are free to blow any registers we like because the call_stub which brought us here
// initially has preserved the callee save registers already.
//
//
// rbx: methodOop
// Because we redispatch "recursive" interpreter entries thru this same entry point
// the "input" register usage is a little strange and not what you expect coming
// state are NULL but on "recursive" dispatches they are what you'd expect.
// A single frame manager is plenty as we don't specialize for synchronized. We could and
// the code is pretty much ready. Would need to change the test below and for good measure
// modify generate_interpreter_state to only do the (pre) sync stuff stuff for synchronized
// routines. Not clear this is worth it yet.
if (interpreter_frame_manager) return interpreter_frame_manager;
// Fast accessor methods share this entry point.
// This works because frame manager is in the same codelet
// save sender sp (doesn't include return address
// save sender sp
// const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
// const Address monitor_block_bot (rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
// const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock));
// get parameter size (always needed)
// rbx: methodOop
// rcx: size of parameters
// see if we've got enough room on the stack for locals plus overhead.
generate_stack_overflow_check(); // C++
// c++ interpreter does not use stack banging or any implicit exceptions
// leave for now to verify that check is proper.
bang_stack_shadow_pages(false);
// compute beginning of parameters (rdi)
// save sender's sp
// __ movl(rcx, rsp);
// get sender's sp
// get return address
// rdx - # of additional locals
// allocate space for locals
// explicitly initialize locals
{
}
// Assumes rax = return address
// allocate and initialize new interpreterState and method expression stack
// IN(locals) -> locals
// IN(state) -> any current interpreter activation
// destroys rax, rcx, rdx, rdi
// OUT (state) -> new interpreterState
// OUT(rsp) -> bottom of methods expression stack
// Call interpreter
// c++ interpreter does not use stack banging or any implicit exceptions
// leave for now to verify that check is proper.
bang_stack_shadow_pages(false);
// Call interpreter enter here if message is
// set and we know stack size is valid
{
#ifdef _LP64
#else
#endif // _LP64
// We can setup the frame anchor with everything we want at this point
// as we are thread_in_Java and no safepoints can occur until we go to
// vm mode. We do have to clear flags on return from vm but that is it
//
// Call the interpreter
//
// state is preserved since it is callee saved
//
// reset_last_Java_frame
}
// examine msg from interpreter to determine next action
// Allocate more monitor space, shuffle expression stack....
// uncommon trap needs to jump to here to enter the interpreter (re-execute current bytecode)
//
// Load the registers we need.
//=============================================================================
// Returning from a compiled method into a deopted method. The bytecode at the
// bcp has completed. The result of the bytecode is in the native abi (the tosca
// for the template based interpreter). Any stack space that was used by the
// bytecode that has completed has been removed (e.g. parameters for an invoke)
// so all that we have to do is place any pending result on the expression stack
// and resume execution on the next bytecode.
// Current frame has caught an exception we need to dispatch to the
// handler. We can get here because a native interpreter frame caught
// an exception in which case there is no handler and we must rethrow
// If it is a vanilla interpreted frame the we simply drop into the
// interpreter and let it do the lookup.
// rax: exception
// restore state pointer.
#ifdef _LP64
#else
// Store exception with interpreter will expect it
#endif // _LP64
// is current frame vanilla or native?
// We drop thru to unwind a native interpreted frame with a pending exception
// We jump here for the initial interpreter frame with exception pending
// We unwind the current acivation and forward it to our caller.
// unwind rbp, return stack to unextended value and re-push return address
// Return point from a call which returns a result in the native abi
// (c1/c2/jni-native). This result must be processed onto the java
// expression stack.
//
// A pending exception may be present in which case there is no result present
// The FPU stack is clean if UseSSE >= 2 but must be cleaned in other cases
if (UseSSE < 2) {
#endif // COMPILER2
#ifdef COMPILER2
for (int i = 1; i < 8; i++) {
}
#endif // COMPILER2
#ifdef COMPILER2
for (int i = 1; i < 8; i++) {
}
#endif // COMPILER2
} else {
}
// Result if any is in tosca. The java expression stack is in the state that the
// calling convention left it (i.e. params may or may not be present)
// Copy the result from tosca and place it on java expression stack.
// restore stack to what we had when we left (in case i2c extended it)
// If there is a pending exception then we don't really have a result to process
#ifdef _LP64
#else
#endif // _LP64
// get method just executed
// callee left args on top of expression stack, remove them
// Address index(noreg, rax, Address::times_ptr);
// __ movl(rcx, Address(noreg, rcx, Address::times_ptr, int(AbstractInterpreter::_tosca_to_stack)));
// An exception is being caught on return to a vanilla interpreter frame.
// Empty the stack and resume interpreter
// Exception present, empty stack
// Return from interpreted method we return result appropriate to the caller (i.e. "recursive"
// interpreter call, or native) and unwind this interpreter activation.
// All monitors should be unlocked.
// Copy result to callers java stack
// Address index(noreg, rax, Address::times_ptr);
// __ movl(rax, Address(noreg, rax, Address::times_ptr, int(AbstractInterpreter::_stack_to_stack)));
// returning to interpreter method from "recursive" interpreter call
// result converter left rax pointing to top of the java stack for method we are returning
// to. Now all we must do is unwind the state from the completed call
// Resume the interpreter. The current frame contains the current interpreter
// state object.
//
// state == interpreterState object for method we are resuming
// result if any on stack already )
// convert result and unwind initial activation
// rax - result index
// Address index(noreg, rax, Address::times_ptr);
/* Current stack picture
[ incoming parameters ]
[ extra locals ]
BytecodeInterpreter object
expression stack
sp ->
*/
// return restoring the stack to the original sender_sp value
// set stack to sender's sp
// OSR request, adjust return address to make current frame into adapter frame
// and enter OSR nmethod
// We are going to pop this frame. Is there another interpreter frame underneath
// Move buffer to the expected parameter location
// We know we are calling compiled so push specialized return
// method uses specialized entry, push a return so we look like call stub setup
// this path will handle fact that result is returned in registers and not
// on the java stack.
// get real return
// set stack to sender's sp
// repush real return
// Enter OSR nmethod
// Call a new method. All we do is (temporarily) trim the expression stack
// push a return address to bring us back to here and leap to the new entry.
// stack points to next free location and not top element on expression stack
// method expects sp to be pointing to topmost element
// don't need a return address if reinvoking interpreter
// Make it look like call_stub calling conventions
// Get (potential) receiver
// get specialized entry
// set sender SP
// method uses specialized entry, push a return so we look like call stub setup
// this path will handle fact that result is returned in registers and not
// on the java stack.
// Interpreted method "returned" with an exception pass it on...
// Pass result, unwind activation and continue/return to interpreter/call_stub
// We handle result (if any) differently based on return to interpreter or call_stub
__ jcc(Assembler::equal, unwind_initial_with_pending_exception); // no, back to native code (call_stub/c1/c2)
// We will unwind the current (initial) interpreter frame and forward
// the exception to the caller. We must put the exception in the
// expected register and clear pending exception and then forward.
return entry_point;
}
// determine code generation flags
bool synchronized = false;
switch (kind) {
case Interpreter::zerolocals : break;
case Interpreter::native : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(false); break;
case Interpreter::native_synchronized : entry_point = ((InterpreterGenerator*)this)->generate_native_entry(true); break;
case Interpreter::empty : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry(); break;
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
case Interpreter::method_handle : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
case Interpreter::java_lang_math_sqrt : entry_point = ((InterpreterGenerator*)this)->generate_math_entry(kind); break;
default : ShouldNotReachHere(); break;
}
if (entry_point) return entry_point;
}
generate_all(); // down here so it can be "virtual"
}
// Deoptimization helpers for C++ interpreter
// How much stack a method activation needs in words.
// Save space for one monitor to get into the interpreted method in case
// the method is synchronized
// total static overhead size. Account for interpreter state object, return
// address, saved rbp and 2 words for a "static long no_params() method" issue.
}
// returns the activation size.
return (extra_locals_size + // the addition space for locals
sizeof(BytecodeInterpreter) + // interpreterState
monitor_size); // monitors
}
bool is_top_frame
)
{
// What about any vtable?
//
// This gets filled in later but make it something recognizable for now
} else {
}
if (caller->is_interpreted_frame()) {
// *current->register_addr(GR_Iprev_state) = (intptr_t) prev;
// Make the prev callee look proper
} else {
}
}
// Need +1 here because stack_base points to the word just above the first expr stack entry
// and stack_limit is supposed to point to the word just below the last expr stack entry.
// See generate_compute_interpreter_state.
"Stack top out of range");
}
int tempcount, //
int popframe_extra_args,
int moncount,
int callee_param_count,
int callee_locals,
bool is_top_frame,
bool is_bottom_frame) {
// NOTE this code must exactly mimic what InterpreterGenerator::generate_compute_interpreter_state()
// does as far as allocating an interpreter frame.
// If interpreter_frame!=NULL, set up the method, locals, and monitors.
// The frame interpreter_frame, if not NULL, is guaranteed to be the right size,
// as determined by a previous call to this method.
// It is also guaranteed to be walkable even though it is in a skeletal state
// NOTE: return size is in words not bytes
// NOTE: tempcount is the current size of the java expression stack. For top most
// frames we will allocate a full sized expression stack and not the curback
// version that non-top frames have.
// Calculate the amount our frame will be adjust by the callee. For top frame
// this is zero.
// NOTE: ia64 seems to do this wrong (or at least backwards) in that it
// calculates the extra locals based on itself. Not what the callee does
// to it. So it ignores last_frame_adjust value. Seems suspicious as far
// as getting sender_sp correct.
// First calculate the frame size without any java expression stack
// Now with full size expression stack
// and now with only live portion of the expression stack
// the size the activation is right now. Only top frame is full size
if (interpreter_frame != NULL) {
#ifdef ASSERT
assert(caller->unextended_sp() == interpreter_frame->interpreter_frame_sender_sp(), "Frame not properly walkable");
#endif
// MUCHO HACK
intptr_t* frame_bottom = (intptr_t*) ((intptr_t)interpreter_frame->sp() - (full_frame_size - frame_size));
/* Now fillin the interpreterState object */
// The state object is the first thing on the frame and easily located
interpreterState cur_state = (interpreterState) ((intptr_t)interpreter_frame->fp() - sizeof(BytecodeInterpreter));
// Find the locals pointer. This is rather simple on x86 because there is no
// confusing rounding at the callee to account for. We can trivially locate
// our locals based on the current fp().
// Note: the + 2 is for handling the "static long no_params() method" issue.
// (too bad I don't really remember that issue well...)
// If the caller is interpreted we need to make sure that locals points to the first
// argument that the caller passed and not in an area where the stack might have been extended.
// because the stack to stack to converter needs a proper locals value in order to remove the
// arguments from the caller and place the result in the proper location. Hmm maybe it'd be
// simpler if we simply stored the result in the BytecodeInterpreter object and let the c++ code
// adjust the stack?? HMMM QQQ
//
if (caller->is_interpreted_frame()) {
// locals must agree with the caller because it will be used to set the
// caller's tos when we return.
// stack() is prepushed.
// locals = caller->unextended_sp() + (method->size_of_parameters() - 1);
// os::breakpoint();
}
} else {
// this is where a c2i would have placed locals (except for the +2)
}
/* +1 because stack is always prepushed */
// BytecodeInterpreter::pd_layout_interpreterState(cur_state, interpreter_return_address, interpreter_frame->fp());
}
return frame_size/BytesPerWord;
}
#endif // CC_INTERP (all)