mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-29 04:28:30 +00:00
3073 lines
110 KiB
C++
3073 lines
110 KiB
C++
|
|
/*
|
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
|
* Copyright 2012, 2014 SAP AG. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* 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 "asm/macroAssembler.inline.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/methodData.hpp"
|
|
#include "oops/method.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/timer.hpp"
|
|
#include "runtime/vframeArray.hpp"
|
|
#include "utilities/debug.hpp"
|
|
#ifdef SHARK
|
|
#include "shark/shark_globals.hpp"
|
|
#endif
|
|
|
|
#ifdef CC_INTERP
|
|
|
|
#define __ _masm->
|
|
|
|
// Contains is used for identifying interpreter frames during a stack-walk.
|
|
// A frame with a PC in InterpretMethod must be identified as a normal C frame.
|
|
bool CppInterpreter::contains(address pc) {
|
|
return _code->contains(pc);
|
|
}
|
|
|
|
#ifdef PRODUCT
|
|
#define BLOCK_COMMENT(str) // nothing
|
|
#else
|
|
#define BLOCK_COMMENT(str) __ block_comment(str)
|
|
#endif
|
|
|
|
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
|
|
|
|
static address interpreter_frame_manager = NULL;
|
|
static address frame_manager_specialized_return = NULL;
|
|
static address native_entry = NULL;
|
|
|
|
static address interpreter_return_address = NULL;
|
|
|
|
static address unctrap_frame_manager_entry = NULL;
|
|
|
|
static address deopt_frame_manager_return_atos = NULL;
|
|
static address deopt_frame_manager_return_btos = NULL;
|
|
static address deopt_frame_manager_return_itos = NULL;
|
|
static address deopt_frame_manager_return_ltos = NULL;
|
|
static address deopt_frame_manager_return_ftos = NULL;
|
|
static address deopt_frame_manager_return_dtos = NULL;
|
|
static address deopt_frame_manager_return_vtos = NULL;
|
|
|
|
// A result handler converts/unboxes a native call result into
|
|
// a java interpreter/compiler result. The current frame is an
|
|
// interpreter frame.
|
|
address CppInterpreterGenerator::generate_result_handler_for(BasicType type) {
|
|
return AbstractInterpreterGenerator::generate_result_handler_for(type);
|
|
}
|
|
|
|
// tosca based result to c++ interpreter stack based result.
|
|
address CppInterpreterGenerator::generate_tosca_to_stack_converter(BasicType type) {
|
|
//
|
|
// A result is in the native abi result register from a native
|
|
// method call. We need to return this result to the interpreter by
|
|
// pushing the result on the interpreter's stack.
|
|
//
|
|
// Registers alive:
|
|
// R3_ARG1(R3_RET)/F1_ARG1(F1_RET) - result to move
|
|
// R4_ARG2 - address of tos
|
|
// LR
|
|
//
|
|
// Registers updated:
|
|
// R3_RET(R3_ARG1) - address of new tos (== R17_tos for T_VOID)
|
|
//
|
|
|
|
int number_of_used_slots = 1;
|
|
|
|
const Register tos = R4_ARG2;
|
|
Label done;
|
|
Label is_false;
|
|
|
|
address entry = __ pc();
|
|
|
|
switch (type) {
|
|
case T_BOOLEAN:
|
|
__ cmpwi(CCR0, R3_RET, 0);
|
|
__ beq(CCR0, is_false);
|
|
__ li(R3_RET, 1);
|
|
__ stw(R3_RET, 0, tos);
|
|
__ b(done);
|
|
__ bind(is_false);
|
|
__ li(R3_RET, 0);
|
|
__ stw(R3_RET, 0, tos);
|
|
break;
|
|
case T_BYTE:
|
|
case T_CHAR:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
__ stw(R3_RET, 0, tos);
|
|
break;
|
|
case T_LONG:
|
|
number_of_used_slots = 2;
|
|
// mark unused slot for debugging
|
|
// long goes to topmost slot
|
|
__ std(R3_RET, -BytesPerWord, tos);
|
|
__ li(R3_RET, 0);
|
|
__ std(R3_RET, 0, tos);
|
|
break;
|
|
case T_OBJECT:
|
|
__ verify_oop(R3_RET);
|
|
__ std(R3_RET, 0, tos);
|
|
break;
|
|
case T_FLOAT:
|
|
__ stfs(F1_RET, 0, tos);
|
|
break;
|
|
case T_DOUBLE:
|
|
number_of_used_slots = 2;
|
|
// mark unused slot for debugging
|
|
__ li(R3_RET, 0);
|
|
__ std(R3_RET, 0, tos);
|
|
// double goes to topmost slot
|
|
__ stfd(F1_RET, -BytesPerWord, tos);
|
|
break;
|
|
case T_VOID:
|
|
number_of_used_slots = 0;
|
|
break;
|
|
default:
|
|
ShouldNotReachHere();
|
|
}
|
|
|
|
__ BIND(done);
|
|
|
|
// new expression stack top
|
|
__ addi(R3_RET, tos, -BytesPerWord * number_of_used_slots);
|
|
|
|
__ blr();
|
|
|
|
return entry;
|
|
}
|
|
|
|
address CppInterpreterGenerator::generate_stack_to_stack_converter(BasicType type) {
|
|
//
|
|
// Copy the result from the callee's stack to the caller's stack,
|
|
// caller and callee both being interpreted.
|
|
//
|
|
// Registers alive
|
|
// R3_ARG1 - address of callee's tos + BytesPerWord
|
|
// R4_ARG2 - address of caller's tos [i.e. free location]
|
|
// LR
|
|
//
|
|
// stack grows upwards, memory grows downwards.
|
|
//
|
|
// [ free ] <-- callee's tos
|
|
// [ optional result ] <-- R3_ARG1
|
|
// [ optional dummy ]
|
|
// ...
|
|
// [ free ] <-- caller's tos, R4_ARG2
|
|
// ...
|
|
// Registers updated
|
|
// R3_RET(R3_ARG1) - address of caller's new tos
|
|
//
|
|
// stack grows upwards, memory grows downwards.
|
|
//
|
|
// [ free ] <-- current tos, R3_RET
|
|
// [ optional result ]
|
|
// [ optional dummy ]
|
|
// ...
|
|
//
|
|
|
|
const Register from = R3_ARG1;
|
|
const Register ret = R3_ARG1;
|
|
const Register tos = R4_ARG2;
|
|
const Register tmp1 = R21_tmp1;
|
|
const Register tmp2 = R22_tmp2;
|
|
|
|
address entry = __ pc();
|
|
|
|
switch (type) {
|
|
case T_BOOLEAN:
|
|
case T_BYTE:
|
|
case T_CHAR:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
case T_FLOAT:
|
|
__ lwz(tmp1, 0, from);
|
|
__ stw(tmp1, 0, tos);
|
|
// New expression stack top.
|
|
__ addi(ret, tos, - BytesPerWord);
|
|
break;
|
|
case T_LONG:
|
|
case T_DOUBLE:
|
|
// Move both entries for debug purposes even though only one is live.
|
|
__ ld(tmp1, BytesPerWord, from);
|
|
__ ld(tmp2, 0, from);
|
|
__ std(tmp1, 0, tos);
|
|
__ std(tmp2, -BytesPerWord, tos);
|
|
// New expression stack top.
|
|
__ addi(ret, tos, - 2 * BytesPerWord); // two slots
|
|
break;
|
|
case T_OBJECT:
|
|
__ ld(tmp1, 0, from);
|
|
__ verify_oop(tmp1);
|
|
__ std(tmp1, 0, tos);
|
|
// New expression stack top.
|
|
__ addi(ret, tos, - BytesPerWord);
|
|
break;
|
|
case T_VOID:
|
|
// New expression stack top.
|
|
__ mr(ret, tos);
|
|
break;
|
|
default:
|
|
ShouldNotReachHere();
|
|
}
|
|
|
|
__ blr();
|
|
|
|
return entry;
|
|
}
|
|
|
|
address CppInterpreterGenerator::generate_stack_to_native_abi_converter(BasicType type) {
|
|
//
|
|
// Load a result from the callee's stack into the caller's expecting
|
|
// return register, callee being interpreted, caller being call stub
|
|
// or jit code.
|
|
//
|
|
// Registers alive
|
|
// R3_ARG1 - callee expression tos + BytesPerWord
|
|
// LR
|
|
//
|
|
// stack grows upwards, memory grows downwards.
|
|
//
|
|
// [ free ] <-- callee's tos
|
|
// [ optional result ] <-- R3_ARG1
|
|
// [ optional dummy ]
|
|
// ...
|
|
//
|
|
// Registers updated
|
|
// R3_RET(R3_ARG1)/F1_RET - result
|
|
//
|
|
|
|
const Register from = R3_ARG1;
|
|
const Register ret = R3_ARG1;
|
|
const FloatRegister fret = F1_ARG1;
|
|
|
|
address entry = __ pc();
|
|
|
|
// Implemented uniformly for both kinds of endianness. The interpreter
|
|
// implements boolean, byte, char, and short as jint (4 bytes).
|
|
switch (type) {
|
|
case T_BOOLEAN:
|
|
case T_CHAR:
|
|
// zero extension
|
|
__ lwz(ret, 0, from);
|
|
break;
|
|
case T_BYTE:
|
|
case T_SHORT:
|
|
case T_INT:
|
|
// sign extension
|
|
__ lwa(ret, 0, from);
|
|
break;
|
|
case T_LONG:
|
|
__ ld(ret, 0, from);
|
|
break;
|
|
case T_OBJECT:
|
|
__ ld(ret, 0, from);
|
|
__ verify_oop(ret);
|
|
break;
|
|
case T_FLOAT:
|
|
__ lfs(fret, 0, from);
|
|
break;
|
|
case T_DOUBLE:
|
|
__ lfd(fret, 0, from);
|
|
break;
|
|
case T_VOID:
|
|
break;
|
|
default:
|
|
ShouldNotReachHere();
|
|
}
|
|
|
|
__ blr();
|
|
|
|
return entry;
|
|
}
|
|
|
|
address CppInterpreter::return_entry(TosState state, int length, Bytecodes::Code code) {
|
|
assert(interpreter_return_address != NULL, "Not initialized");
|
|
return interpreter_return_address;
|
|
}
|
|
|
|
address CppInterpreter::deopt_entry(TosState state, int length) {
|
|
address ret = NULL;
|
|
if (length != 0) {
|
|
switch (state) {
|
|
case atos: ret = deopt_frame_manager_return_atos; break;
|
|
case btos: ret = deopt_frame_manager_return_itos; break;
|
|
case ctos:
|
|
case stos:
|
|
case itos: ret = deopt_frame_manager_return_itos; break;
|
|
case ltos: ret = deopt_frame_manager_return_ltos; break;
|
|
case ftos: ret = deopt_frame_manager_return_ftos; break;
|
|
case dtos: ret = deopt_frame_manager_return_dtos; break;
|
|
case vtos: ret = deopt_frame_manager_return_vtos; break;
|
|
default: ShouldNotReachHere();
|
|
}
|
|
} else {
|
|
ret = unctrap_frame_manager_entry; // re-execute the bytecode (e.g. uncommon trap, popframe)
|
|
}
|
|
assert(ret != NULL, "Not initialized");
|
|
return ret;
|
|
}
|
|
|
|
//
|
|
// Helpers for commoning out cases in the various type of method entries.
|
|
//
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R1_SP - old stack pointer
|
|
// R19_method - callee's Method
|
|
// R17_tos - address of caller's tos (prepushed)
|
|
// R15_prev_state - address of caller's BytecodeInterpreter or 0
|
|
// return_pc in R21_tmp15 (only when called within generate_native_entry)
|
|
//
|
|
// Registers updated
|
|
// R14_state - address of callee's interpreter state
|
|
// R1_SP - new stack pointer
|
|
// CCR4_is_synced - current method is synchronized
|
|
//
|
|
void CppInterpreterGenerator::generate_compute_interpreter_state(Label& stack_overflow_return) {
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// F1 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// alignment (optional)
|
|
// [F1's outgoing Java arguments] <-- R17_tos
|
|
// ...
|
|
// F2 [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
|
|
//=============================================================================
|
|
// Allocate space for locals other than the parameters, the
|
|
// interpreter state, monitors, and the expression stack.
|
|
|
|
const Register local_count = R21_tmp1;
|
|
const Register parameter_count = R22_tmp2;
|
|
const Register max_stack = R23_tmp3;
|
|
// Must not be overwritten within this method!
|
|
// const Register return_pc = R29_tmp9;
|
|
|
|
const ConditionRegister is_synced = CCR4_is_synced;
|
|
const ConditionRegister is_native = CCR6;
|
|
const ConditionRegister is_static = CCR7;
|
|
|
|
assert(is_synced != is_native, "condition code registers must be distinct");
|
|
assert(is_synced != is_static, "condition code registers must be distinct");
|
|
assert(is_native != is_static, "condition code registers must be distinct");
|
|
|
|
{
|
|
|
|
// Local registers
|
|
const Register top_frame_size = R24_tmp4;
|
|
const Register access_flags = R25_tmp5;
|
|
const Register state_offset = R26_tmp6;
|
|
Register mem_stack_limit = R27_tmp7;
|
|
const Register page_size = R28_tmp8;
|
|
|
|
BLOCK_COMMENT("compute_interpreter_state {");
|
|
|
|
// access_flags = method->access_flags();
|
|
// TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size");
|
|
__ lwa(access_flags, method_(access_flags));
|
|
|
|
// parameter_count = method->constMethod->size_of_parameters();
|
|
// TODO: PPC port: assert(2 == ConstMethod::sz_size_of_parameters(), "unexpected field size");
|
|
__ ld(max_stack, in_bytes(Method::const_offset()), R19_method); // Max_stack holds constMethod for a while.
|
|
__ lhz(parameter_count, in_bytes(ConstMethod::size_of_parameters_offset()), max_stack);
|
|
|
|
// local_count = method->constMethod()->max_locals();
|
|
// TODO: PPC port: assert(2 == ConstMethod::sz_max_locals(), "unexpected field size");
|
|
__ lhz(local_count, in_bytes(ConstMethod::size_of_locals_offset()), max_stack);
|
|
|
|
// max_stack = method->constMethod()->max_stack();
|
|
// TODO: PPC port: assert(2 == ConstMethod::sz_max_stack(), "unexpected field size");
|
|
__ lhz(max_stack, in_bytes(ConstMethod::max_stack_offset()), max_stack);
|
|
|
|
// Take into account 'extra_stack_entries' needed by method handles (see method.hpp).
|
|
__ addi(max_stack, max_stack, Method::extra_stack_entries());
|
|
|
|
// mem_stack_limit = thread->stack_limit();
|
|
__ ld(mem_stack_limit, thread_(stack_overflow_limit));
|
|
|
|
// Point locals at the first argument. Method's locals are the
|
|
// parameters on top of caller's expression stack.
|
|
|
|
// tos points past last Java argument
|
|
__ sldi(R18_locals, parameter_count, Interpreter::logStackElementSize);
|
|
__ add(R18_locals, R17_tos, R18_locals);
|
|
|
|
// R18_locals - i*BytesPerWord points to i-th Java local (i starts at 0)
|
|
|
|
// Set is_native, is_synced, is_static - will be used later.
|
|
__ testbitdi(is_native, R0, access_flags, JVM_ACC_NATIVE_BIT);
|
|
__ testbitdi(is_synced, R0, access_flags, JVM_ACC_SYNCHRONIZED_BIT);
|
|
assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile");
|
|
__ testbitdi(is_static, R0, access_flags, JVM_ACC_STATIC_BIT);
|
|
|
|
// PARENT_IJAVA_FRAME_ABI
|
|
//
|
|
// frame_size =
|
|
// round_to((local_count - parameter_count)*BytesPerWord +
|
|
// 2*BytesPerWord +
|
|
// alignment +
|
|
// frame::interpreter_frame_cinterpreterstate_size_in_bytes()
|
|
// sizeof(PARENT_IJAVA_FRAME_ABI)
|
|
// method->is_synchronized() ? sizeof(BasicObjectLock) : 0 +
|
|
// max_stack*BytesPerWord,
|
|
// 16)
|
|
//
|
|
// Note that this calculation is exactly mirrored by
|
|
// AbstractInterpreter::layout_activation_impl() [ and
|
|
// AbstractInterpreter::size_activation() ]. Which is used by
|
|
// deoptimization so that it can allocate the proper sized
|
|
// frame. This only happens for interpreted frames so the extra
|
|
// notes below about max_stack below are not important. The other
|
|
// thing to note is that for interpreter frames other than the
|
|
// current activation the size of the stack is the size of the live
|
|
// portion of the stack at the particular bcp and NOT the maximum
|
|
// stack that the method might use.
|
|
//
|
|
// If we're calling a native method, we replace max_stack (which is
|
|
// zero) with space for the worst-case signature handler varargs
|
|
// vector, which is:
|
|
//
|
|
// max_stack = max(Argument::n_register_parameters, parameter_count+2);
|
|
//
|
|
// We add two slots to the parameter_count, one for the jni
|
|
// environment and one for a possible native mirror. We allocate
|
|
// space for at least the number of ABI registers, even though
|
|
// InterpreterRuntime::slow_signature_handler won't write more than
|
|
// parameter_count+2 words when it creates the varargs vector at the
|
|
// top of the stack. The generated slow signature handler will just
|
|
// load trash into registers beyond the necessary number. We're
|
|
// still going to cut the stack back by the ABI register parameter
|
|
// count so as to get SP+16 pointing at the ABI outgoing parameter
|
|
// area, so we need to allocate at least that much even though we're
|
|
// going to throw it away.
|
|
//
|
|
|
|
// Adjust max_stack for native methods:
|
|
Label skip_native_calculate_max_stack;
|
|
__ bfalse(is_native, skip_native_calculate_max_stack);
|
|
// if (is_native) {
|
|
// max_stack = max(Argument::n_register_parameters, parameter_count+2);
|
|
__ addi(max_stack, parameter_count, 2*Interpreter::stackElementWords);
|
|
__ cmpwi(CCR0, max_stack, Argument::n_register_parameters);
|
|
__ bge(CCR0, skip_native_calculate_max_stack);
|
|
__ li(max_stack, Argument::n_register_parameters);
|
|
// }
|
|
__ bind(skip_native_calculate_max_stack);
|
|
// max_stack is now in bytes
|
|
__ slwi(max_stack, max_stack, Interpreter::logStackElementSize);
|
|
|
|
// Calculate number of non-parameter locals (in slots):
|
|
Label not_java;
|
|
__ btrue(is_native, not_java);
|
|
// if (!is_native) {
|
|
// local_count = non-parameter local count
|
|
__ sub(local_count, local_count, parameter_count);
|
|
// } else {
|
|
// // nothing to do: method->max_locals() == 0 for native methods
|
|
// }
|
|
__ bind(not_java);
|
|
|
|
|
|
// Calculate top_frame_size and parent_frame_resize.
|
|
{
|
|
const Register parent_frame_resize = R12_scratch2;
|
|
|
|
BLOCK_COMMENT("Compute top_frame_size.");
|
|
// top_frame_size = TOP_IJAVA_FRAME_ABI
|
|
// + size of interpreter state
|
|
__ li(top_frame_size, frame::top_ijava_frame_abi_size
|
|
+ frame::interpreter_frame_cinterpreterstate_size_in_bytes());
|
|
// + max_stack
|
|
__ add(top_frame_size, top_frame_size, max_stack);
|
|
// + stack slots for a BasicObjectLock for synchronized methods
|
|
{
|
|
Label not_synced;
|
|
__ bfalse(is_synced, not_synced);
|
|
__ addi(top_frame_size, top_frame_size, frame::interpreter_frame_monitor_size_in_bytes());
|
|
__ bind(not_synced);
|
|
}
|
|
// align
|
|
__ round_to(top_frame_size, frame::alignment_in_bytes);
|
|
|
|
|
|
BLOCK_COMMENT("Compute parent_frame_resize.");
|
|
// parent_frame_resize = R1_SP - R17_tos
|
|
__ sub(parent_frame_resize, R1_SP, R17_tos);
|
|
//__ li(parent_frame_resize, 0);
|
|
// + PARENT_IJAVA_FRAME_ABI
|
|
// + extra two slots for the no-parameter/no-locals
|
|
// method result
|
|
__ addi(parent_frame_resize, parent_frame_resize,
|
|
frame::parent_ijava_frame_abi_size
|
|
+ 2*Interpreter::stackElementSize);
|
|
// + (locals_count - params_count)
|
|
__ sldi(R0, local_count, Interpreter::logStackElementSize);
|
|
__ add(parent_frame_resize, parent_frame_resize, R0);
|
|
// align
|
|
__ round_to(parent_frame_resize, frame::alignment_in_bytes);
|
|
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// The new frame F0 hasn't yet been pushed, F1 is still the top frame.
|
|
//
|
|
// F0 [TOP_IJAVA_FRAME_ABI]
|
|
// alignment (optional)
|
|
// [F0's full operand stack]
|
|
// [F0's monitors] (optional)
|
|
// [F0's BytecodeInterpreter object]
|
|
// F1 [PARENT_IJAVA_FRAME_ABI]
|
|
// alignment (optional)
|
|
// [F0's Java result]
|
|
// [F0's non-arg Java locals]
|
|
// [F1's outgoing Java arguments] <-- R17_tos
|
|
// ...
|
|
// F2 [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
|
|
|
|
// Calculate new R14_state
|
|
// and
|
|
// test that the new memory stack pointer is above the limit,
|
|
// throw a StackOverflowError otherwise.
|
|
__ sub(R11_scratch1/*F1's SP*/, R1_SP, parent_frame_resize);
|
|
__ addi(R14_state, R11_scratch1/*F1's SP*/,
|
|
-frame::interpreter_frame_cinterpreterstate_size_in_bytes());
|
|
__ sub(R11_scratch1/*F0's SP*/,
|
|
R11_scratch1/*F1's SP*/, top_frame_size);
|
|
|
|
BLOCK_COMMENT("Test for stack overflow:");
|
|
__ cmpld(CCR0/*is_stack_overflow*/, R11_scratch1, mem_stack_limit);
|
|
__ blt(CCR0/*is_stack_overflow*/, stack_overflow_return);
|
|
|
|
|
|
//=============================================================================
|
|
// Frame_size doesn't overflow the stack. Allocate new frame and
|
|
// initialize interpreter state.
|
|
|
|
// Register state
|
|
//
|
|
// R15 - local_count
|
|
// R16 - parameter_count
|
|
// R17 - max_stack
|
|
//
|
|
// R18 - frame_size
|
|
// R19 - access_flags
|
|
// CCR4_is_synced - is_synced
|
|
//
|
|
// GR_Lstate - pointer to the uninitialized new BytecodeInterpreter.
|
|
|
|
// _last_Java_pc just needs to be close enough that we can identify
|
|
// the frame as an interpreted frame. It does not need to be the
|
|
// exact return address from either calling
|
|
// BytecodeInterpreter::InterpretMethod or the call to a jni native method.
|
|
// So we can initialize it here with a value of a bundle in this
|
|
// code fragment. We only do this initialization for java frames
|
|
// where InterpretMethod needs a a way to get a good pc value to
|
|
// store in the thread state. For interpreter frames used to call
|
|
// jni native code we just zero the value in the state and move an
|
|
// ip as needed in the native entry code.
|
|
//
|
|
// const Register last_Java_pc_addr = GR24_SCRATCH; // QQQ 27
|
|
// const Register last_Java_pc = GR26_SCRATCH;
|
|
|
|
// Must reference stack before setting new SP since Windows
|
|
// will not be able to deliver the exception on a bad SP.
|
|
// Windows also insists that we bang each page one at a time in order
|
|
// for the OS to map in the reserved pages. If we bang only
|
|
// the final page, Windows stops delivering exceptions to our
|
|
// VectoredExceptionHandler and terminates our program.
|
|
// Linux only requires a single bang but it's rare to have
|
|
// to bang more than 1 page so the code is enabled for both OS's.
|
|
|
|
// BANG THE STACK
|
|
//
|
|
// Nothing to do for PPC, because updating the SP will automatically
|
|
// bang the page.
|
|
|
|
// Up to here we have calculated the delta for the new C-frame and
|
|
// checked for a stack-overflow. Now we can savely update SP and
|
|
// resize the C-frame.
|
|
|
|
// R14_state has already been calculated.
|
|
__ push_interpreter_frame(top_frame_size, parent_frame_resize,
|
|
R25_tmp5, R26_tmp6, R27_tmp7, R28_tmp8);
|
|
|
|
}
|
|
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// F0 has been been pushed!
|
|
//
|
|
// F0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// alignment (optional) (now it's here, if required)
|
|
// [F0's full operand stack]
|
|
// [F0's monitors] (optional)
|
|
// [F0's BytecodeInterpreter object]
|
|
// F1 [PARENT_IJAVA_FRAME_ABI]
|
|
// alignment (optional) (now it's here, if required)
|
|
// [F0's Java result]
|
|
// [F0's non-arg Java locals]
|
|
// [F1's outgoing Java arguments]
|
|
// ...
|
|
// F2 [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
//
|
|
// R14_state points to F0's BytecodeInterpreter object.
|
|
//
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// new BytecodeInterpreter-object is save, let's initialize it:
|
|
BLOCK_COMMENT("New BytecodeInterpreter-object is save.");
|
|
|
|
{
|
|
// Locals
|
|
const Register bytecode_addr = R24_tmp4;
|
|
const Register constants = R25_tmp5;
|
|
const Register tos = R26_tmp6;
|
|
const Register stack_base = R27_tmp7;
|
|
const Register local_addr = R28_tmp8;
|
|
{
|
|
Label L;
|
|
__ btrue(is_native, L);
|
|
// if (!is_native) {
|
|
// bytecode_addr = constMethod->codes();
|
|
__ ld(bytecode_addr, method_(const));
|
|
__ addi(bytecode_addr, bytecode_addr, in_bytes(ConstMethod::codes_offset()));
|
|
// }
|
|
__ bind(L);
|
|
}
|
|
|
|
__ ld(constants, in_bytes(Method::const_offset()), R19_method);
|
|
__ ld(constants, in_bytes(ConstMethod::constants_offset()), constants);
|
|
|
|
// state->_prev_link = prev_state;
|
|
__ std(R15_prev_state, state_(_prev_link));
|
|
|
|
// For assertions only.
|
|
// TODO: not needed anyway because it coincides with `_monitor_base'. remove!
|
|
// state->_self_link = state;
|
|
DEBUG_ONLY(__ std(R14_state, state_(_self_link));)
|
|
|
|
// state->_thread = thread;
|
|
__ std(R16_thread, state_(_thread));
|
|
|
|
// state->_method = method;
|
|
__ std(R19_method, state_(_method));
|
|
|
|
// state->_locals = locals;
|
|
__ std(R18_locals, state_(_locals));
|
|
|
|
// state->_oop_temp = NULL;
|
|
__ li(R0, 0);
|
|
__ std(R0, state_(_oop_temp));
|
|
|
|
// state->_last_Java_fp = *R1_SP // Use *R1_SP as fp
|
|
__ ld(R0, _abi(callers_sp), R1_SP);
|
|
__ std(R0, state_(_last_Java_fp));
|
|
|
|
BLOCK_COMMENT("load Stack base:");
|
|
{
|
|
// Stack_base.
|
|
// if (!method->synchronized()) {
|
|
// stack_base = state;
|
|
// } else {
|
|
// stack_base = (uintptr_t)state - sizeof(BasicObjectLock);
|
|
// }
|
|
Label L;
|
|
__ mr(stack_base, R14_state);
|
|
__ bfalse(is_synced, L);
|
|
__ addi(stack_base, stack_base, -frame::interpreter_frame_monitor_size_in_bytes());
|
|
__ bind(L);
|
|
}
|
|
|
|
// state->_mdx = NULL;
|
|
__ li(R0, 0);
|
|
__ std(R0, state_(_mdx));
|
|
|
|
{
|
|
// if (method->is_native()) state->_bcp = NULL;
|
|
// else state->_bcp = bytecode_addr;
|
|
Label label1, label2;
|
|
__ bfalse(is_native, label1);
|
|
__ std(R0, state_(_bcp));
|
|
__ b(label2);
|
|
__ bind(label1);
|
|
__ std(bytecode_addr, state_(_bcp));
|
|
__ bind(label2);
|
|
}
|
|
|
|
|
|
// state->_result._to_call._callee = NULL;
|
|
__ std(R0, state_(_result._to_call._callee));
|
|
|
|
// state->_monitor_base = state;
|
|
__ std(R14_state, state_(_monitor_base));
|
|
|
|
// state->_msg = BytecodeInterpreter::method_entry;
|
|
__ li(R0, BytecodeInterpreter::method_entry);
|
|
__ stw(R0, state_(_msg));
|
|
|
|
// state->_last_Java_sp = R1_SP;
|
|
__ std(R1_SP, state_(_last_Java_sp));
|
|
|
|
// state->_stack_base = stack_base;
|
|
__ std(stack_base, state_(_stack_base));
|
|
|
|
// tos = stack_base - 1 slot (prepushed);
|
|
// state->_stack.Tos(tos);
|
|
__ addi(tos, stack_base, - Interpreter::stackElementSize);
|
|
__ std(tos, state_(_stack));
|
|
|
|
|
|
{
|
|
BLOCK_COMMENT("get last_Java_pc:");
|
|
// if (!is_native) state->_last_Java_pc = <some_ip_in_this_code_buffer>;
|
|
// else state->_last_Java_pc = NULL; (just for neatness)
|
|
Label label1, label2;
|
|
__ btrue(is_native, label1);
|
|
__ get_PC_trash_LR(R0);
|
|
__ std(R0, state_(_last_Java_pc));
|
|
__ b(label2);
|
|
__ bind(label1);
|
|
__ li(R0, 0);
|
|
__ std(R0, state_(_last_Java_pc));
|
|
__ bind(label2);
|
|
}
|
|
|
|
|
|
// stack_limit = tos - max_stack;
|
|
__ sub(R0, tos, max_stack);
|
|
// state->_stack_limit = stack_limit;
|
|
__ std(R0, state_(_stack_limit));
|
|
|
|
|
|
// cache = method->constants()->cache();
|
|
__ ld(R0, ConstantPool::cache_offset_in_bytes(), constants);
|
|
// state->_constants = method->constants()->cache();
|
|
__ std(R0, state_(_constants));
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// synchronized method, allocate and initialize method object lock.
|
|
// if (!method->is_synchronized()) goto fill_locals_with_0x0s;
|
|
Label fill_locals_with_0x0s;
|
|
__ bfalse(is_synced, fill_locals_with_0x0s);
|
|
|
|
// pool_holder = method->constants()->pool_holder();
|
|
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
|
|
{
|
|
Label label1, label2;
|
|
// lockee = NULL; for java methods, correct value will be inserted in BytecodeInterpretMethod.hpp
|
|
__ li(R0,0);
|
|
__ bfalse(is_native, label2);
|
|
|
|
__ bfalse(is_static, label1);
|
|
// if (method->is_static()) lockee =
|
|
// pool_holder->klass_part()->java_mirror();
|
|
__ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(), constants);
|
|
__ ld(R0/*lockee*/, mirror_offset, R11_scratch1/*pool_holder*/);
|
|
__ b(label2);
|
|
|
|
__ bind(label1);
|
|
// else lockee = *(oop*)locals;
|
|
__ ld(R0/*lockee*/, 0, R18_locals);
|
|
__ bind(label2);
|
|
|
|
// monitor->set_obj(lockee);
|
|
__ std(R0/*lockee*/, BasicObjectLock::obj_offset_in_bytes(), stack_base);
|
|
}
|
|
|
|
// See if we need to zero the locals
|
|
__ BIND(fill_locals_with_0x0s);
|
|
|
|
|
|
//=============================================================================
|
|
// fill locals with 0x0s
|
|
Label locals_zeroed;
|
|
__ btrue(is_native, locals_zeroed);
|
|
|
|
if (true /* zerolocals */ || ClearInterpreterLocals) {
|
|
// local_count is already num_locals_slots - num_param_slots
|
|
__ sldi(R0, parameter_count, Interpreter::logStackElementSize);
|
|
__ sub(local_addr, R18_locals, R0);
|
|
__ cmpdi(CCR0, local_count, 0);
|
|
__ ble(CCR0, locals_zeroed);
|
|
|
|
__ mtctr(local_count);
|
|
//__ ld_const_addr(R0, (address) 0xcafe0000babe);
|
|
__ li(R0, 0);
|
|
|
|
Label zero_slot;
|
|
__ bind(zero_slot);
|
|
|
|
// first local is at local_addr
|
|
__ std(R0, 0, local_addr);
|
|
__ addi(local_addr, local_addr, -BytesPerWord);
|
|
__ bdnz(zero_slot);
|
|
}
|
|
|
|
__ BIND(locals_zeroed);
|
|
|
|
}
|
|
BLOCK_COMMENT("} compute_interpreter_state");
|
|
}
|
|
|
|
// Generate code to initiate compilation on invocation counter overflow.
|
|
void CppInterpreterGenerator::generate_counter_overflow(Label& continue_entry) {
|
|
// Registers alive
|
|
// R14_state
|
|
// R16_thread
|
|
//
|
|
// Registers updated
|
|
// R14_state
|
|
// R3_ARG1 (=R3_RET)
|
|
// R4_ARG2
|
|
|
|
// After entering the vm we remove the activation and retry the
|
|
// entry point in case the compilation is complete.
|
|
|
|
// InterpreterRuntime::frequency_counter_overflow takes one argument
|
|
// that indicates if the counter overflow occurs at a backwards
|
|
// branch (NULL bcp). We pass zero. 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).
|
|
__ li(R4_ARG2, 0);
|
|
|
|
// Pass false to call_VM so it doesn't check for pending exceptions,
|
|
// since at this point in the method invocation the exception
|
|
// handler would try to exit the monitor of synchronized methods
|
|
// which haven't been entered yet.
|
|
//
|
|
// Returns verified_entry_point or NULL, we don't care which.
|
|
//
|
|
// Do not use the variant `frequency_counter_overflow' that returns
|
|
// a structure, because this will change the argument list by a
|
|
// hidden parameter (gcc 4.1).
|
|
|
|
__ call_VM(noreg,
|
|
CAST_FROM_FN_PTR(address, InterpreterRuntime::frequency_counter_overflow),
|
|
R4_ARG2,
|
|
false);
|
|
// Returns verified_entry_point or NULL, we don't care which as we ignore it
|
|
// and run interpreted.
|
|
|
|
// Reload method, it may have moved.
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
// We jump now to the label "continue_after_compile".
|
|
__ b(continue_entry);
|
|
}
|
|
|
|
// Increment invocation count and check for overflow.
|
|
//
|
|
// R19_method must contain Method* of method to profile.
|
|
void CppInterpreterGenerator::generate_counter_incr(Label& overflow) {
|
|
Label done;
|
|
const Register Rcounters = R12_scratch2;
|
|
const Register iv_be_count = R11_scratch1;
|
|
const Register invocation_limit = R12_scratch2;
|
|
const Register invocation_limit_addr = invocation_limit;
|
|
|
|
// Load and ev. allocate MethodCounters object.
|
|
__ get_method_counters(R19_method, Rcounters, done);
|
|
|
|
// Update standard invocation counters.
|
|
__ increment_invocation_counter(Rcounters, iv_be_count, R0);
|
|
|
|
// Compare against limit.
|
|
BLOCK_COMMENT("Compare counter against limit:");
|
|
assert(4 == sizeof(InvocationCounter::InterpreterInvocationLimit),
|
|
"must be 4 bytes");
|
|
__ load_const(invocation_limit_addr, (address)&InvocationCounter::InterpreterInvocationLimit);
|
|
__ lwa(invocation_limit, 0, invocation_limit_addr);
|
|
__ cmpw(CCR0, iv_be_count, invocation_limit);
|
|
__ bge(CCR0, overflow);
|
|
__ bind(done);
|
|
}
|
|
|
|
//
|
|
// Call a JNI method.
|
|
//
|
|
// Interpreter stub for calling a native method. (C++ interpreter)
|
|
// This sets up a somewhat different looking stack for calling the native method
|
|
// than the typical interpreter frame setup.
|
|
//
|
|
address CppInterpreterGenerator::generate_native_entry(void) {
|
|
if (native_entry != NULL) return native_entry;
|
|
address entry = __ pc();
|
|
|
|
// Read
|
|
// R16_thread
|
|
// R15_prev_state - address of caller's BytecodeInterpreter, if this snippet
|
|
// gets called by the frame manager.
|
|
// R19_method - callee's Method
|
|
// R17_tos - address of caller's tos
|
|
// R1_SP - caller's stack pointer
|
|
// R21_sender_SP - initial caller sp
|
|
//
|
|
// Update
|
|
// R14_state - address of caller's BytecodeInterpreter
|
|
// R3_RET - integer result, if any.
|
|
// F1_RET - float result, if any.
|
|
//
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// alignment (optional)
|
|
// [outgoing Java arguments] <-- R17_tos
|
|
// ...
|
|
// PARENT [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
//
|
|
|
|
const bool inc_counter = UseCompiler || CountCompiledCalls;
|
|
|
|
const Register signature_handler_fd = R21_tmp1;
|
|
const Register pending_exception = R22_tmp2;
|
|
const Register result_handler_addr = R23_tmp3;
|
|
const Register native_method_fd = R24_tmp4;
|
|
const Register access_flags = R25_tmp5;
|
|
const Register active_handles = R26_tmp6;
|
|
const Register sync_state = R27_tmp7;
|
|
const Register sync_state_addr = sync_state; // Address is dead after use.
|
|
const Register suspend_flags = R24_tmp4;
|
|
|
|
const Register return_pc = R28_tmp8; // Register will be locked for some time.
|
|
|
|
const ConditionRegister is_synced = CCR4_is_synced; // Live-on-exit from compute_interpreter_state.
|
|
|
|
|
|
// R1_SP still points to caller's SP at this point.
|
|
|
|
// Save initial_caller_sp to caller's abi. The caller frame must be
|
|
// resized before returning to get rid of the c2i arguments (if
|
|
// any).
|
|
// Override the saved SP with the senderSP so we can pop c2i
|
|
// arguments (if any) off when we return
|
|
__ std(R21_sender_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP);
|
|
|
|
// Save LR to caller's frame. We don't use _abi(lr) here, because it is not safe.
|
|
__ mflr(return_pc);
|
|
__ std(return_pc, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
|
|
assert(return_pc->is_nonvolatile(), "return_pc must be a non-volatile register");
|
|
|
|
__ verify_method_ptr(R19_method);
|
|
|
|
//=============================================================================
|
|
|
|
// If this snippet gets called by the frame manager (at label
|
|
// `call_special'), then R15_prev_state is valid. If this snippet
|
|
// is not called by the frame manager, but e.g. by the call stub or
|
|
// by compiled code, then R15_prev_state is invalid.
|
|
{
|
|
// Set R15_prev_state to 0 if we don't return to the frame
|
|
// manager; we will return to the call_stub or to compiled code
|
|
// instead. If R15_prev_state is 0 there will be only one
|
|
// interpreter frame (we will set this up later) in this C frame!
|
|
// So we must take care about retrieving prev_state_(_prev_link)
|
|
// and restoring R1_SP when popping that interpreter.
|
|
Label prev_state_is_valid;
|
|
|
|
__ load_const(R11_scratch1/*frame_manager_returnpc_addr*/, (address)&frame_manager_specialized_return);
|
|
__ ld(R12_scratch2/*frame_manager_returnpc*/, 0, R11_scratch1/*frame_manager_returnpc_addr*/);
|
|
__ cmpd(CCR0, return_pc, R12_scratch2/*frame_manager_returnpc*/);
|
|
__ beq(CCR0, prev_state_is_valid);
|
|
|
|
__ li(R15_prev_state, 0);
|
|
|
|
__ BIND(prev_state_is_valid);
|
|
}
|
|
|
|
//=============================================================================
|
|
// Allocate new frame and initialize interpreter state.
|
|
|
|
Label exception_return;
|
|
Label exception_return_sync_check;
|
|
Label stack_overflow_return;
|
|
|
|
// Generate new interpreter state and jump to stack_overflow_return in case of
|
|
// a stack overflow.
|
|
generate_compute_interpreter_state(stack_overflow_return);
|
|
|
|
//=============================================================================
|
|
// Increment invocation counter. On overflow, entry to JNI method
|
|
// will be compiled.
|
|
Label invocation_counter_overflow;
|
|
if (inc_counter) {
|
|
generate_counter_incr(invocation_counter_overflow);
|
|
}
|
|
|
|
Label continue_after_compile;
|
|
__ BIND(continue_after_compile);
|
|
|
|
// access_flags = method->access_flags();
|
|
// Load access flags.
|
|
assert(access_flags->is_nonvolatile(),
|
|
"access_flags must be in a non-volatile register");
|
|
// Type check.
|
|
// TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size");
|
|
__ lwz(access_flags, method_(access_flags));
|
|
|
|
// We don't want to reload R19_method and access_flags after calls
|
|
// to some helper functions.
|
|
assert(R19_method->is_nonvolatile(), "R19_method must be a non-volatile register");
|
|
|
|
// Check for synchronized methods. Must happen AFTER invocation counter
|
|
// check, so method is not locked if counter overflows.
|
|
|
|
{
|
|
Label method_is_not_synced;
|
|
// Is_synced is still alive.
|
|
assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile");
|
|
__ bfalse(is_synced, method_is_not_synced);
|
|
|
|
lock_method();
|
|
// Reload method, it may have moved.
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
__ BIND(method_is_not_synced);
|
|
}
|
|
|
|
// jvmti/jvmpi support
|
|
__ notify_method_entry();
|
|
|
|
// Reload method, it may have moved.
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
//=============================================================================
|
|
// Get and call the signature handler
|
|
|
|
__ ld(signature_handler_fd, method_(signature_handler));
|
|
Label call_signature_handler;
|
|
|
|
__ cmpdi(CCR0, signature_handler_fd, 0);
|
|
__ bne(CCR0, call_signature_handler);
|
|
|
|
// Method has never been called. Either generate a specialized
|
|
// handler or point to the slow one.
|
|
//
|
|
// Pass parameter 'false' to avoid exception check in call_VM.
|
|
__ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::prepare_native_call), R19_method, false);
|
|
|
|
// Check for an exception while looking up the target method. If we
|
|
// incurred one, bail.
|
|
__ ld(pending_exception, thread_(pending_exception));
|
|
__ cmpdi(CCR0, pending_exception, 0);
|
|
__ bne(CCR0, exception_return_sync_check); // has pending exception
|
|
|
|
// reload method
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
// Reload signature handler, it may have been created/assigned in the meanwhile
|
|
__ ld(signature_handler_fd, method_(signature_handler));
|
|
|
|
__ BIND(call_signature_handler);
|
|
|
|
// Before we call the signature handler we push a new frame to
|
|
// protect the interpreter frame volatile registers when we return
|
|
// from jni but before we can get back to Java.
|
|
|
|
// First set the frame anchor while the SP/FP registers are
|
|
// convenient and the slow signature handler can use this same frame
|
|
// anchor.
|
|
|
|
// We have a TOP_IJAVA_FRAME here, which belongs to us.
|
|
__ set_top_ijava_frame_at_SP_as_last_Java_frame(R1_SP, R12_scratch2/*tmp*/);
|
|
|
|
// Now the interpreter frame (and its call chain) have been
|
|
// invalidated and flushed. We are now protected against eager
|
|
// being enabled in native code. Even if it goes eager the
|
|
// registers will be reloaded as clean and we will invalidate after
|
|
// the call so no spurious flush should be possible.
|
|
|
|
// Call signature handler and pass locals address.
|
|
//
|
|
// Our signature handlers copy required arguments to the C stack
|
|
// (outgoing C args), R3_ARG1 to R10_ARG8, and F1_ARG1 to
|
|
// F13_ARG13.
|
|
__ mr(R3_ARG1, R18_locals);
|
|
#if !defined(ABI_ELFv2)
|
|
__ ld(signature_handler_fd, 0, signature_handler_fd);
|
|
#endif
|
|
__ call_stub(signature_handler_fd);
|
|
// reload method
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
// Remove the register parameter varargs slots we allocated in
|
|
// compute_interpreter_state. SP+16 ends up pointing to the ABI
|
|
// outgoing argument area.
|
|
//
|
|
// Not needed on PPC64.
|
|
//__ add(SP, SP, Argument::n_register_parameters*BytesPerWord);
|
|
|
|
assert(result_handler_addr->is_nonvolatile(), "result_handler_addr must be in a non-volatile register");
|
|
// Save across call to native method.
|
|
__ mr(result_handler_addr, R3_RET);
|
|
|
|
// Set up fixed parameters and call the native method.
|
|
// If the method is static, get mirror into R4_ARG2.
|
|
|
|
{
|
|
Label method_is_not_static;
|
|
// access_flags is non-volatile and still, no need to restore it
|
|
|
|
// restore access flags
|
|
__ testbitdi(CCR0, R0, access_flags, JVM_ACC_STATIC_BIT);
|
|
__ bfalse(CCR0, method_is_not_static);
|
|
|
|
// constants = method->constants();
|
|
__ ld(R11_scratch1, in_bytes(Method::const_offset()), R19_method);
|
|
__ ld(R11_scratch1/*constants*/, in_bytes(ConstMethod::constants_offset()), R11_scratch1);
|
|
// pool_holder = method->constants()->pool_holder();
|
|
__ ld(R11_scratch1/*pool_holder*/, ConstantPool::pool_holder_offset_in_bytes(),
|
|
R11_scratch1/*constants*/);
|
|
|
|
const int mirror_offset = in_bytes(Klass::java_mirror_offset());
|
|
|
|
// mirror = pool_holder->klass_part()->java_mirror();
|
|
__ ld(R0/*mirror*/, mirror_offset, R11_scratch1/*pool_holder*/);
|
|
// state->_native_mirror = mirror;
|
|
__ std(R0/*mirror*/, state_(_oop_temp));
|
|
// R4_ARG2 = &state->_oop_temp;
|
|
__ addir(R4_ARG2, state_(_oop_temp));
|
|
|
|
__ BIND(method_is_not_static);
|
|
}
|
|
|
|
// At this point, arguments have been copied off the stack into
|
|
// their JNI positions. Oops are boxed in-place on the stack, with
|
|
// handles copied to arguments. The result handler address is in a
|
|
// register.
|
|
|
|
// pass JNIEnv address as first parameter
|
|
__ addir(R3_ARG1, thread_(jni_environment));
|
|
|
|
// Load the native_method entry before we change the thread state.
|
|
__ ld(native_method_fd, method_(native_function));
|
|
|
|
//=============================================================================
|
|
// Transition from _thread_in_Java to _thread_in_native. As soon as
|
|
// we make this change the safepoint code needs to be certain that
|
|
// the last Java frame we established is good. The pc in that frame
|
|
// just needs to be near here not an actual return address.
|
|
|
|
// We use release_store_fence to update values like the thread state, where
|
|
// we don't want the current thread to continue until all our prior memory
|
|
// accesses (including the new thread state) are visible to other threads.
|
|
__ li(R0, _thread_in_native);
|
|
__ release();
|
|
|
|
// TODO: PPC port: assert(4 == JavaThread::sz_thread_state(), "unexpected field size");
|
|
__ stw(R0, thread_(thread_state));
|
|
|
|
if (UseMembar) {
|
|
__ fence();
|
|
}
|
|
|
|
//=============================================================================
|
|
// Call the native method. Argument registers must not have been
|
|
// overwritten since "__ call_stub(signature_handler);" (except for
|
|
// ARG1 and ARG2 for static methods)
|
|
__ call_c(native_method_fd);
|
|
|
|
__ std(R3_RET, state_(_native_lresult));
|
|
__ stfd(F1_RET, state_(_native_fresult));
|
|
|
|
// The frame_manager_lr field, which we use for setting the last
|
|
// java frame, gets overwritten by the signature handler. Restore
|
|
// it now.
|
|
__ get_PC_trash_LR(R11_scratch1);
|
|
__ std(R11_scratch1, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
|
|
// Because of GC R19_method may no longer be valid.
|
|
|
|
// Block, if necessary, before resuming in _thread_in_Java state.
|
|
// In order for GC to work, don't clear the last_Java_sp until after
|
|
// blocking.
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// Switch thread to "native transition" state before reading the
|
|
// synchronization state. This additional state is necessary
|
|
// because reading and testing the synchronization state is not
|
|
// atomic w.r.t. GC, as this scenario demonstrates: Java thread A,
|
|
// in _thread_in_native state, loads _not_synchronized and is
|
|
// preempted. VM thread changes sync state to synchronizing and
|
|
// suspends threads for GC. Thread A is resumed to finish this
|
|
// native method, but doesn't block here since it didn't see any
|
|
// synchronization in progress, and escapes.
|
|
|
|
// We use release_store_fence to update values like the thread state, where
|
|
// we don't want the current thread to continue until all our prior memory
|
|
// accesses (including the new thread state) are visible to other threads.
|
|
__ li(R0/*thread_state*/, _thread_in_native_trans);
|
|
__ release();
|
|
__ stw(R0/*thread_state*/, thread_(thread_state));
|
|
if (UseMembar) {
|
|
__ fence();
|
|
}
|
|
// Write serialization page so that the 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.
|
|
else {
|
|
__ serialize_memory(R16_thread, R11_scratch1, R12_scratch2);
|
|
}
|
|
|
|
// Now before we return to java we must look for a current safepoint
|
|
// (a new safepoint can not start since we entered native_trans).
|
|
// We must check here because a current safepoint could be modifying
|
|
// the callers registers right this moment.
|
|
|
|
// Acquire isn't strictly necessary here because of the fence, but
|
|
// sync_state is declared to be volatile, so we do it anyway.
|
|
__ load_const(sync_state_addr, SafepointSynchronize::address_of_state());
|
|
|
|
// TODO: PPC port: assert(4 == SafepointSynchronize::sz_state(), "unexpected field size");
|
|
__ lwz(sync_state, 0, sync_state_addr);
|
|
|
|
// TODO: PPC port: assert(4 == Thread::sz_suspend_flags(), "unexpected field size");
|
|
__ lwz(suspend_flags, thread_(suspend_flags));
|
|
|
|
__ acquire();
|
|
|
|
Label sync_check_done;
|
|
Label do_safepoint;
|
|
// No synchronization in progress nor yet synchronized
|
|
__ cmpwi(CCR0, sync_state, SafepointSynchronize::_not_synchronized);
|
|
// not suspended
|
|
__ cmpwi(CCR1, suspend_flags, 0);
|
|
|
|
__ bne(CCR0, do_safepoint);
|
|
__ beq(CCR1, sync_check_done);
|
|
__ bind(do_safepoint);
|
|
// Block. We do the call directly and leave the current
|
|
// last_Java_frame setup undisturbed. We must save any possible
|
|
// native result acrosss the call. No oop is present
|
|
|
|
__ mr(R3_ARG1, R16_thread);
|
|
#if defined(ABI_ELFv2)
|
|
__ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans),
|
|
relocInfo::none);
|
|
#else
|
|
__ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans),
|
|
relocInfo::none);
|
|
#endif
|
|
__ bind(sync_check_done);
|
|
|
|
//=============================================================================
|
|
// <<<<<< Back in Interpreter Frame >>>>>
|
|
|
|
// We are in thread_in_native_trans here and back in the normal
|
|
// interpreter frame. We don't have to do anything special about
|
|
// safepoints and we can switch to Java mode anytime we are ready.
|
|
|
|
// Note: frame::interpreter_frame_result has a dependency on how the
|
|
// method result is saved across the call to post_method_exit. For
|
|
// native methods it assumes that the non-FPU/non-void result is
|
|
// saved in _native_lresult and a FPU result in _native_fresult. If
|
|
// this changes then the interpreter_frame_result implementation
|
|
// will need to be updated too.
|
|
|
|
// On PPC64, we have stored the result directly after the native call.
|
|
|
|
//=============================================================================
|
|
// back in Java
|
|
|
|
// We use release_store_fence to update values like the thread state, where
|
|
// we don't want the current thread to continue until all our prior memory
|
|
// accesses (including the new thread state) are visible to other threads.
|
|
__ li(R0/*thread_state*/, _thread_in_Java);
|
|
__ release();
|
|
__ stw(R0/*thread_state*/, thread_(thread_state));
|
|
if (UseMembar) {
|
|
__ fence();
|
|
}
|
|
|
|
__ reset_last_Java_frame();
|
|
|
|
// Reload GR27_method, call killed it. We can't look at
|
|
// state->_method until we're back in java state because in java
|
|
// state gc can't happen until we get to a safepoint.
|
|
//
|
|
// We've set thread_state to _thread_in_Java already, so restoring
|
|
// R19_method from R14_state works; R19_method is invalid, because
|
|
// GC may have happened.
|
|
__ ld(R19_method, state_(_method)); // reload method, may have moved
|
|
|
|
// jvmdi/jvmpi support. Whether we've got an exception pending or
|
|
// not, and whether unlocking throws an exception or not, we notify
|
|
// on native method exit. If we do have an exception, we'll end up
|
|
// in the caller's context to handle it, so if we don't do the
|
|
// notify here, we'll drop it on the floor.
|
|
|
|
__ notify_method_exit(true/*native method*/,
|
|
ilgl /*illegal state (not used for native methods)*/,
|
|
InterpreterMacroAssembler::NotifyJVMTI,
|
|
false /*check_exceptions*/);
|
|
|
|
//=============================================================================
|
|
// Handle exceptions
|
|
|
|
// See if we must unlock.
|
|
//
|
|
{
|
|
Label method_is_not_synced;
|
|
// is_synced is still alive
|
|
assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile");
|
|
__ bfalse(is_synced, method_is_not_synced);
|
|
|
|
unlock_method();
|
|
|
|
__ bind(method_is_not_synced);
|
|
}
|
|
|
|
// Reset active handles after returning from native.
|
|
// thread->active_handles()->clear();
|
|
__ ld(active_handles, thread_(active_handles));
|
|
// JNIHandleBlock::_top is an int.
|
|
// TODO: PPC port: assert(4 == JNIHandleBlock::top_size_in_bytes(), "unexpected field size");
|
|
__ li(R0, 0);
|
|
__ stw(R0, JNIHandleBlock::top_offset_in_bytes(), active_handles);
|
|
|
|
Label no_pending_exception_from_native_method;
|
|
__ ld(R0/*pending_exception*/, thread_(pending_exception));
|
|
__ cmpdi(CCR0, R0/*pending_exception*/, 0);
|
|
__ beq(CCR0, no_pending_exception_from_native_method);
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// An exception is pending. We call into the runtime only if the
|
|
// caller was not interpreted. If it was interpreted the
|
|
// interpreter will do the correct thing. If it isn't interpreted
|
|
// (call stub/compiled code) we will change our return and continue.
|
|
__ BIND(exception_return);
|
|
|
|
Label return_to_initial_caller_with_pending_exception;
|
|
__ cmpdi(CCR0, R15_prev_state, 0);
|
|
__ beq(CCR0, return_to_initial_caller_with_pending_exception);
|
|
|
|
// We are returning to an interpreter activation, just pop the state,
|
|
// pop our frame, leave the exception pending, and return.
|
|
__ pop_interpreter_state(/*prev_state_may_be_0=*/false);
|
|
__ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2);
|
|
__ mtlr(R21_tmp1);
|
|
__ blr();
|
|
|
|
__ BIND(exception_return_sync_check);
|
|
|
|
assert(is_synced->is_nonvolatile(), "is_synced must be non-volatile");
|
|
__ bfalse(is_synced, exception_return);
|
|
unlock_method();
|
|
__ b(exception_return);
|
|
|
|
|
|
__ BIND(return_to_initial_caller_with_pending_exception);
|
|
// We are returning to a c2i-adapter / call-stub, get the address of the
|
|
// exception handler, pop the frame and return to the handler.
|
|
|
|
// First, pop to caller's frame.
|
|
__ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2);
|
|
|
|
__ push_frame_reg_args(0, R11_scratch1);
|
|
// Get the address of the exception handler.
|
|
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
|
|
R16_thread,
|
|
R21_tmp1 /* return pc */);
|
|
__ pop_frame();
|
|
|
|
// Load the PC of the the exception handler into LR.
|
|
__ mtlr(R3_RET);
|
|
|
|
// Load exception into R3_ARG1 and clear pending exception in thread.
|
|
__ ld(R3_ARG1/*exception*/, thread_(pending_exception));
|
|
__ li(R4_ARG2, 0);
|
|
__ std(R4_ARG2, thread_(pending_exception));
|
|
|
|
// Load the original return pc into R4_ARG2.
|
|
__ mr(R4_ARG2/*issuing_pc*/, R21_tmp1);
|
|
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
// Return to exception handler.
|
|
__ blr();
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// No exception pending.
|
|
__ BIND(no_pending_exception_from_native_method);
|
|
|
|
// Move native method result back into proper registers and return.
|
|
// Invoke result handler (may unbox/promote).
|
|
__ ld(R3_RET, state_(_native_lresult));
|
|
__ lfd(F1_RET, state_(_native_fresult));
|
|
__ call_stub(result_handler_addr);
|
|
|
|
// We have created a new BytecodeInterpreter object, now we must destroy it.
|
|
//
|
|
// Restore previous R14_state and caller's SP. R15_prev_state may
|
|
// be 0 here, because our caller may be the call_stub or compiled
|
|
// code.
|
|
__ pop_interpreter_state(/*prev_state_may_be_0=*/true);
|
|
__ pop_interpreter_frame(R11_scratch1, R12_scratch2, R21_tmp1 /* set to return pc */, R22_tmp2);
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
// Must use the return pc which was loaded from the caller's frame
|
|
// as the VM uses return-pc-patching for deoptimization.
|
|
__ mtlr(R21_tmp1);
|
|
__ blr();
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// We encountered an exception while computing the interpreter
|
|
// state, so R14_state isn't valid. Act as if we just returned from
|
|
// the callee method with a pending exception.
|
|
__ BIND(stack_overflow_return);
|
|
|
|
//
|
|
// Register state:
|
|
// R14_state invalid; trashed by compute_interpreter_state
|
|
// R15_prev_state valid, but may be 0
|
|
//
|
|
// R1_SP valid, points to caller's SP; wasn't yet updated by
|
|
// compute_interpreter_state
|
|
//
|
|
|
|
// Create exception oop and make it pending.
|
|
|
|
// Throw the exception via RuntimeStub "throw_StackOverflowError_entry".
|
|
//
|
|
// Previously, we called C-Code directly. As a consequence, a
|
|
// possible GC tried to process the argument oops of the top frame
|
|
// (see RegisterMap::clear, which sets the corresponding flag to
|
|
// true). This lead to crashes because:
|
|
// 1. The top register map did not contain locations for the argument registers
|
|
// 2. The arguments are dead anyway, could be already overwritten in the worst case
|
|
// Solution: Call via special runtime stub that pushes it's own
|
|
// frame. This runtime stub has the flag "CodeBlob::caller_must_gc_arguments()"
|
|
// set to "false", what prevents the dead arguments getting GC'd.
|
|
//
|
|
// 2 cases exist:
|
|
// 1. We were called by the c2i adapter / call stub
|
|
// 2. We were called by the frame manager
|
|
//
|
|
// Both cases are handled by this code:
|
|
// 1. - initial_caller_sp was saved in both cases on entry, so it's safe to load it back even if it was not changed.
|
|
// - control flow will be:
|
|
// throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->excp_blob of caller method
|
|
// 2. - control flow will be:
|
|
// throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->rethrow_excp_entry of frame manager->resume_method
|
|
// Since we restored the caller SP above, the rethrow_excp_entry can restore the original interpreter state
|
|
// registers using the stack and resume the calling method with a pending excp.
|
|
|
|
// Pop any c2i extension from the stack, restore LR just to be sure
|
|
__ ld(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
__ mtlr(R0);
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order");
|
|
// Load target address of the runtime stub.
|
|
__ load_const(R12_scratch2, (StubRoutines::throw_StackOverflowError_entry()));
|
|
__ mtctr(R12_scratch2);
|
|
__ bctr();
|
|
|
|
|
|
//=============================================================================
|
|
// Counter overflow.
|
|
|
|
if (inc_counter) {
|
|
// Handle invocation counter overflow
|
|
__ bind(invocation_counter_overflow);
|
|
|
|
generate_counter_overflow(continue_after_compile);
|
|
}
|
|
|
|
native_entry = entry;
|
|
return entry;
|
|
}
|
|
|
|
bool AbstractInterpreter::can_be_compiled(methodHandle m) {
|
|
// No special entry points that preclude compilation.
|
|
return true;
|
|
}
|
|
|
|
// Unlock the current method.
|
|
//
|
|
void CppInterpreterGenerator::unlock_method(void) {
|
|
// Find preallocated monitor and unlock method. Method monitor is
|
|
// the first one.
|
|
|
|
// Registers alive
|
|
// R14_state
|
|
//
|
|
// Registers updated
|
|
// volatiles
|
|
//
|
|
const Register monitor = R4_ARG2;
|
|
|
|
// Pass address of initial monitor we allocated.
|
|
//
|
|
// First monitor.
|
|
__ addi(monitor, R14_state, -frame::interpreter_frame_monitor_size_in_bytes());
|
|
|
|
// Unlock method
|
|
__ unlock_object(monitor);
|
|
}
|
|
|
|
// Lock the current method.
|
|
//
|
|
void CppInterpreterGenerator::lock_method(void) {
|
|
// Find preallocated monitor and lock method. Method monitor is the
|
|
// first one.
|
|
|
|
//
|
|
// Registers alive
|
|
// R14_state
|
|
//
|
|
// Registers updated
|
|
// volatiles
|
|
//
|
|
|
|
const Register monitor = R4_ARG2;
|
|
const Register object = R5_ARG3;
|
|
|
|
// Pass address of initial monitor we allocated.
|
|
__ addi(monitor, R14_state, -frame::interpreter_frame_monitor_size_in_bytes());
|
|
|
|
// Pass object address.
|
|
__ ld(object, BasicObjectLock::obj_offset_in_bytes(), monitor);
|
|
|
|
// Lock method.
|
|
__ lock_object(monitor, object);
|
|
}
|
|
|
|
// Generate code for handling resuming a deopted method.
|
|
void CppInterpreterGenerator::generate_deopt_handling(Register result_index) {
|
|
|
|
//=============================================================================
|
|
// 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.
|
|
|
|
Label return_from_deopt_common;
|
|
|
|
// R3_RET and F1_RET are live here! Load the array index of the
|
|
// required result stub address and continue at return_from_deopt_common.
|
|
|
|
// Deopt needs to jump to here to enter the interpreter (return a result).
|
|
deopt_frame_manager_return_atos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_OBJECT));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_btos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_BOOLEAN));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_itos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_INT));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_ltos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_LONG));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_ftos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_FLOAT));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_dtos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_DOUBLE));
|
|
__ b(return_from_deopt_common);
|
|
|
|
deopt_frame_manager_return_vtos = __ pc();
|
|
__ li(result_index, AbstractInterpreter::BasicType_as_index(T_VOID));
|
|
// Last one, fall-through to return_from_deopt_common.
|
|
|
|
// Deopt return common. An index is present that lets us move any
|
|
// possible result being return to the interpreter's stack.
|
|
//
|
|
__ BIND(return_from_deopt_common);
|
|
|
|
}
|
|
|
|
// Generate the code to handle a more_monitors message from the c++ interpreter.
|
|
void CppInterpreterGenerator::generate_more_monitors() {
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R15_prev_state - previous BytecodeInterpreter or 0
|
|
// R14_state - BytecodeInterpreter* address of receiver's interpreter state
|
|
// R1_SP - old stack pointer
|
|
//
|
|
// Registers updated
|
|
// R1_SP - new stack pointer
|
|
//
|
|
|
|
// Very-local scratch registers.
|
|
const Register old_tos = R21_tmp1;
|
|
const Register new_tos = R22_tmp2;
|
|
const Register stack_base = R23_tmp3;
|
|
const Register stack_limit = R24_tmp4;
|
|
const Register slot = R25_tmp5;
|
|
const Register n_slots = R25_tmp5;
|
|
|
|
// Interpreter state fields.
|
|
const Register msg = R24_tmp4;
|
|
|
|
// Load up relevant interpreter state.
|
|
|
|
__ ld(stack_base, state_(_stack_base)); // Old stack_base
|
|
__ ld(old_tos, state_(_stack)); // Old tos
|
|
__ ld(stack_limit, state_(_stack_limit)); // Old stack_limit
|
|
|
|
// extracted monitor_size
|
|
int monitor_size = frame::interpreter_frame_monitor_size_in_bytes();
|
|
assert(Assembler::is_aligned((unsigned int)monitor_size,
|
|
(unsigned int)frame::alignment_in_bytes),
|
|
"size of a monitor must respect alignment of SP");
|
|
|
|
// Save and restore top LR
|
|
__ ld(R12_scratch2, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
__ resize_frame(-monitor_size, R11_scratch1);// Allocate space for new monitor
|
|
__ std(R12_scratch2, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
// Initial_caller_sp is used as unextended_sp for non initial callers.
|
|
__ std(R1_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP);
|
|
__ addi(stack_base, stack_base, -monitor_size); // New stack_base
|
|
__ addi(new_tos, old_tos, -monitor_size); // New tos
|
|
__ addi(stack_limit, stack_limit, -monitor_size); // New stack_limit
|
|
|
|
__ std(R1_SP, state_(_last_Java_sp)); // Update frame_bottom
|
|
|
|
__ std(stack_base, state_(_stack_base)); // Update stack_base
|
|
__ std(new_tos, state_(_stack)); // Update tos
|
|
__ std(stack_limit, state_(_stack_limit)); // Update stack_limit
|
|
|
|
__ li(msg, BytecodeInterpreter::got_monitors); // Tell interpreter we allocated the lock
|
|
__ stw(msg, state_(_msg));
|
|
|
|
// Shuffle expression stack down. Recall that stack_base points
|
|
// just above the new expression stack bottom. Old_tos and new_tos
|
|
// are used to scan thru the old and new expression stacks.
|
|
|
|
Label copy_slot, copy_slot_finished;
|
|
__ sub(n_slots, stack_base, new_tos);
|
|
__ srdi_(n_slots, n_slots, LogBytesPerWord); // compute number of slots to copy
|
|
assert(LogBytesPerWord == 3, "conflicts assembler instructions");
|
|
__ beq(CCR0, copy_slot_finished); // nothing to copy
|
|
|
|
__ mtctr(n_slots);
|
|
|
|
// loop
|
|
__ bind(copy_slot);
|
|
__ ldu(slot, BytesPerWord, old_tos); // slot = *++old_tos;
|
|
__ stdu(slot, BytesPerWord, new_tos); // *++new_tos = slot;
|
|
__ bdnz(copy_slot);
|
|
|
|
__ bind(copy_slot_finished);
|
|
|
|
// Restart interpreter
|
|
__ li(R0, 0);
|
|
__ std(R0, BasicObjectLock::obj_offset_in_bytes(), stack_base); // Mark lock as unused
|
|
}
|
|
|
|
address CppInterpreterGenerator::generate_normal_entry(void) {
|
|
if (interpreter_frame_manager != NULL) return interpreter_frame_manager;
|
|
|
|
address entry = __ pc();
|
|
|
|
address return_from_native_pc = (address) NULL;
|
|
|
|
// Initial entry to frame manager (from call_stub or c2i_adapter)
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R19_method - callee's Method (method to be invoked)
|
|
// R17_tos - address of sender tos (prepushed)
|
|
// R1_SP - SP prepared by call stub such that caller's outgoing args are near top
|
|
// LR - return address to caller (call_stub or c2i_adapter)
|
|
// R21_sender_SP - initial caller sp
|
|
//
|
|
// Registers updated
|
|
// R15_prev_state - 0
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// alignment (optional)
|
|
// [outgoing Java arguments] <-- R17_tos
|
|
// ...
|
|
// PARENT [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
//
|
|
|
|
// Save initial_caller_sp to caller's abi.
|
|
// The caller frame must be resized before returning to get rid of
|
|
// the c2i part on top of the calling compiled frame (if any).
|
|
// R21_tmp1 must match sender_sp in gen_c2i_adapter.
|
|
// Now override the saved SP with the senderSP so we can pop c2i
|
|
// arguments (if any) off when we return.
|
|
__ std(R21_sender_SP, _top_ijava_frame_abi(initial_caller_sp), R1_SP);
|
|
|
|
// Save LR to caller's frame. We don't use _abi(lr) here,
|
|
// because it is not safe.
|
|
__ mflr(R0);
|
|
__ std(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
|
|
// If we come here, it is the first invocation of the frame manager.
|
|
// So there is no previous interpreter state.
|
|
__ li(R15_prev_state, 0);
|
|
|
|
|
|
// Fall through to where "recursive" invocations go.
|
|
|
|
//=============================================================================
|
|
// Dispatch an instance of the interpreter. Recursive activations
|
|
// come here.
|
|
|
|
Label re_dispatch;
|
|
__ BIND(re_dispatch);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R19_method - callee's Method
|
|
// R17_tos - address of caller's tos (prepushed)
|
|
// R15_prev_state - address of caller's BytecodeInterpreter or 0
|
|
// R1_SP - caller's SP trimmed such that caller's outgoing args are near top.
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI]
|
|
// alignment (optional)
|
|
// [outgoing Java arguments]
|
|
// ...
|
|
// PARENT [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
|
|
// fall through to interpreted execution
|
|
|
|
//=============================================================================
|
|
// Allocate a new Java frame and initialize the new interpreter state.
|
|
|
|
Label stack_overflow_return;
|
|
|
|
// Create a suitable new Java frame plus a new BytecodeInterpreter instance
|
|
// in the current (frame manager's) C frame.
|
|
generate_compute_interpreter_state(stack_overflow_return);
|
|
|
|
// fall through
|
|
|
|
//=============================================================================
|
|
// Interpreter dispatch.
|
|
|
|
Label call_interpreter;
|
|
__ BIND(call_interpreter);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R15_prev_state - previous BytecodeInterpreter or 0
|
|
// R14_state - address of receiver's BytecodeInterpreter
|
|
// R1_SP - receiver's stack pointer
|
|
//
|
|
|
|
// Thread fields.
|
|
const Register pending_exception = R21_tmp1;
|
|
|
|
// Interpreter state fields.
|
|
const Register msg = R24_tmp4;
|
|
|
|
// Method fields.
|
|
const Register parameter_count = R25_tmp5;
|
|
const Register result_index = R26_tmp6;
|
|
|
|
const Register dummy = R28_tmp8;
|
|
|
|
// Address of various interpreter stubs.
|
|
// R29_tmp9 is reserved.
|
|
const Register stub_addr = R27_tmp7;
|
|
|
|
// Uncommon trap needs to jump to here to enter the interpreter
|
|
// (re-execute current bytecode).
|
|
unctrap_frame_manager_entry = __ pc();
|
|
|
|
// If we are profiling, store our fp (BSP) in the thread so we can
|
|
// find it during a tick.
|
|
if (Arguments::has_profile()) {
|
|
// On PPC64 we store the pointer to the current BytecodeInterpreter,
|
|
// instead of the bsp of ia64. This should suffice to be able to
|
|
// find all interesting information.
|
|
__ std(R14_state, thread_(last_interpreter_fp));
|
|
}
|
|
|
|
// R16_thread, R14_state and R15_prev_state are nonvolatile
|
|
// registers. There is no need to save these. If we needed to save
|
|
// some state in the current Java frame, this could be a place to do
|
|
// so.
|
|
|
|
// Call Java bytecode dispatcher passing "BytecodeInterpreter* istate".
|
|
__ call_VM_leaf(CAST_FROM_FN_PTR(address,
|
|
JvmtiExport::can_post_interpreter_events()
|
|
? BytecodeInterpreter::runWithChecks
|
|
: BytecodeInterpreter::run),
|
|
R14_state);
|
|
|
|
interpreter_return_address = __ last_calls_return_pc();
|
|
|
|
// R16_thread, R14_state and R15_prev_state have their values preserved.
|
|
|
|
// If we are profiling, clear the fp in the thread to tell
|
|
// the profiler that we are no longer in the interpreter.
|
|
if (Arguments::has_profile()) {
|
|
__ li(R11_scratch1, 0);
|
|
__ std(R11_scratch1, thread_(last_interpreter_fp));
|
|
}
|
|
|
|
// Load message from bytecode dispatcher.
|
|
// TODO: PPC port: guarantee(4 == BytecodeInterpreter::sz_msg(), "unexpected field size");
|
|
__ lwz(msg, state_(_msg));
|
|
|
|
|
|
Label more_monitors;
|
|
Label return_from_native;
|
|
Label return_from_native_common;
|
|
Label return_from_native_no_exception;
|
|
Label return_from_interpreted_method;
|
|
Label return_from_recursive_activation;
|
|
Label unwind_recursive_activation;
|
|
Label resume_interpreter;
|
|
Label return_to_initial_caller;
|
|
Label unwind_initial_activation;
|
|
Label unwind_initial_activation_pending_exception;
|
|
Label call_method;
|
|
Label call_special;
|
|
Label retry_method;
|
|
Label retry_method_osr;
|
|
Label popping_frame;
|
|
Label throwing_exception;
|
|
|
|
// Branch according to the received message
|
|
|
|
__ cmpwi(CCR1, msg, BytecodeInterpreter::call_method);
|
|
__ cmpwi(CCR2, msg, BytecodeInterpreter::return_from_method);
|
|
|
|
__ beq(CCR1, call_method);
|
|
__ beq(CCR2, return_from_interpreted_method);
|
|
|
|
__ cmpwi(CCR3, msg, BytecodeInterpreter::more_monitors);
|
|
__ cmpwi(CCR4, msg, BytecodeInterpreter::throwing_exception);
|
|
|
|
__ beq(CCR3, more_monitors);
|
|
__ beq(CCR4, throwing_exception);
|
|
|
|
__ cmpwi(CCR5, msg, BytecodeInterpreter::popping_frame);
|
|
__ cmpwi(CCR6, msg, BytecodeInterpreter::do_osr);
|
|
|
|
__ beq(CCR5, popping_frame);
|
|
__ beq(CCR6, retry_method_osr);
|
|
|
|
__ stop("bad message from interpreter");
|
|
|
|
|
|
//=============================================================================
|
|
// Add a monitor just below the existing one(s). State->_stack_base
|
|
// points to the lowest existing one, so we insert the new one just
|
|
// below it and shuffle the expression stack down. Ref. the above
|
|
// stack layout picture, we must update _stack_base, _stack, _stack_limit
|
|
// and _last_Java_sp in the interpreter state.
|
|
|
|
__ BIND(more_monitors);
|
|
|
|
generate_more_monitors();
|
|
__ b(call_interpreter);
|
|
|
|
generate_deopt_handling(result_index);
|
|
|
|
// Restoring the R14_state is already done by the deopt_blob.
|
|
|
|
// Current tos includes no parameter slots.
|
|
__ ld(R17_tos, state_(_stack));
|
|
__ li(msg, BytecodeInterpreter::deopt_resume);
|
|
__ b(return_from_native_common);
|
|
|
|
// We are sent here when we are unwinding from a native method or
|
|
// adapter with an exception pending. We need to notify the interpreter
|
|
// that there is an exception to process.
|
|
// We arrive here also if the frame manager called an (interpreted) target
|
|
// which returns with a StackOverflow exception.
|
|
// The control flow is in this case is:
|
|
// frame_manager->throw_excp_stub->forward_excp->rethrow_excp_entry
|
|
|
|
AbstractInterpreter::_rethrow_exception_entry = __ pc();
|
|
|
|
// Restore R14_state.
|
|
__ ld(R14_state, 0, R1_SP);
|
|
__ addi(R14_state, R14_state,
|
|
-frame::interpreter_frame_cinterpreterstate_size_in_bytes());
|
|
|
|
// Store exception oop into thread object.
|
|
__ std(R3_RET, thread_(pending_exception));
|
|
__ li(msg, BytecodeInterpreter::method_resume /*rethrow_exception*/);
|
|
//
|
|
// NOTE: the interpreter frame as setup be deopt does NOT include
|
|
// any parameter slots (good thing since we have no callee here
|
|
// and couldn't remove them) so we don't have to do any calculations
|
|
// here to figure it out.
|
|
//
|
|
__ ld(R17_tos, state_(_stack));
|
|
__ b(return_from_native_common);
|
|
|
|
|
|
//=============================================================================
|
|
// Returning from a native method. Result is in the native abi
|
|
// location so we must move it to the java expression stack.
|
|
|
|
__ BIND(return_from_native);
|
|
guarantee(return_from_native_pc == (address) NULL, "precondition");
|
|
return_from_native_pc = __ pc();
|
|
|
|
// Restore R14_state.
|
|
__ ld(R14_state, 0, R1_SP);
|
|
__ addi(R14_state, R14_state, -frame::interpreter_frame_cinterpreterstate_size_in_bytes());
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R14_state - address of caller's BytecodeInterpreter.
|
|
// R3_RET - integer result, if any.
|
|
// F1_RET - float result, if any.
|
|
//
|
|
// Registers updated
|
|
// R19_method - callee's Method
|
|
// R17_tos - caller's tos, with outgoing args popped
|
|
// result_index - index of result handler.
|
|
// msg - message for resuming interpreter.
|
|
//
|
|
|
|
// Very-local scratch registers.
|
|
|
|
const ConditionRegister have_pending_exception = CCR0;
|
|
|
|
// Load callee Method, gc may have moved it.
|
|
__ ld(R19_method, state_(_result._to_call._callee));
|
|
|
|
// Load address of caller's tos. includes parameter slots.
|
|
__ ld(R17_tos, state_(_stack));
|
|
|
|
// Pop callee's parameters.
|
|
|
|
__ ld(parameter_count, in_bytes(Method::const_offset()), R19_method);
|
|
__ lhz(parameter_count, in_bytes(ConstMethod::size_of_parameters_offset()), parameter_count);
|
|
__ sldi(parameter_count, parameter_count, Interpreter::logStackElementSize);
|
|
__ add(R17_tos, R17_tos, parameter_count);
|
|
|
|
// Result stub address array index
|
|
// TODO: PPC port: assert(4 == sizeof(AccessFlags), "unexpected field size");
|
|
__ lwa(result_index, method_(result_index));
|
|
|
|
__ li(msg, BytecodeInterpreter::method_resume);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R14_state - address of caller's BytecodeInterpreter.
|
|
// R17_tos - address of caller's tos with outgoing args already popped
|
|
// R3_RET - integer return value, if any.
|
|
// F1_RET - float return value, if any.
|
|
// result_index - index of result handler.
|
|
// msg - message for resuming interpreter.
|
|
//
|
|
// Registers updated
|
|
// R3_RET - new address of caller's tos, including result, if any
|
|
//
|
|
|
|
__ BIND(return_from_native_common);
|
|
|
|
// Check for pending exception
|
|
__ ld(pending_exception, thread_(pending_exception));
|
|
__ cmpdi(CCR0, pending_exception, 0);
|
|
__ beq(CCR0, return_from_native_no_exception);
|
|
|
|
// If there's a pending exception, we really have no result, so
|
|
// R3_RET is dead. Resume_interpreter assumes the new tos is in
|
|
// R3_RET.
|
|
__ mr(R3_RET, R17_tos);
|
|
// `resume_interpreter' expects R15_prev_state to be alive.
|
|
__ ld(R15_prev_state, state_(_prev_link));
|
|
__ b(resume_interpreter);
|
|
|
|
__ BIND(return_from_native_no_exception);
|
|
|
|
// No pending exception, copy method result from native ABI register
|
|
// to tos.
|
|
|
|
// Address of stub descriptor address array.
|
|
__ load_const(stub_addr, CppInterpreter::tosca_result_to_stack());
|
|
|
|
// Pass address of tos to stub.
|
|
__ mr(R4_ARG2, R17_tos);
|
|
|
|
// Address of stub descriptor address.
|
|
__ sldi(result_index, result_index, LogBytesPerWord);
|
|
__ add(stub_addr, stub_addr, result_index);
|
|
|
|
// Stub descriptor address.
|
|
__ ld(stub_addr, 0, stub_addr);
|
|
|
|
// TODO: don't do this via a call, do it in place!
|
|
//
|
|
// call stub via descriptor
|
|
// in R3_ARG1/F1_ARG1: result value (R3_RET or F1_RET)
|
|
__ call_stub(stub_addr);
|
|
|
|
// new tos = result of call in R3_RET
|
|
|
|
// `resume_interpreter' expects R15_prev_state to be alive.
|
|
__ ld(R15_prev_state, state_(_prev_link));
|
|
__ b(resume_interpreter);
|
|
|
|
//=============================================================================
|
|
// We encountered an exception while computing the interpreter
|
|
// state, so R14_state isn't valid. Act as if we just returned from
|
|
// the callee method with a pending exception.
|
|
__ BIND(stack_overflow_return);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R1_SP - old stack pointer
|
|
// R19_method - callee's Method
|
|
// R17_tos - address of caller's tos (prepushed)
|
|
// R15_prev_state - address of caller's BytecodeInterpreter or 0
|
|
// R18_locals - address of callee's locals array
|
|
//
|
|
// Registers updated
|
|
// R3_RET - address of resuming tos, if recursive unwind
|
|
|
|
Label Lskip_unextend_SP;
|
|
|
|
{
|
|
const ConditionRegister is_initial_call = CCR0;
|
|
const Register tos_save = R21_tmp1;
|
|
const Register tmp = R22_tmp2;
|
|
|
|
assert(tos_save->is_nonvolatile(), "need a nonvolatile");
|
|
|
|
// Is the exception thrown in the initial Java frame of this frame
|
|
// manager frame?
|
|
__ cmpdi(is_initial_call, R15_prev_state, 0);
|
|
__ bne(is_initial_call, Lskip_unextend_SP);
|
|
|
|
// Pop any c2i extension from the stack. This is necessary in the
|
|
// non-recursive case (that is we were called by the c2i adapter,
|
|
// meaning we have to prev state). In this case we entered the frame
|
|
// manager through a special entry which pushes the orignal
|
|
// unextended SP to the stack. Here we load it back.
|
|
__ ld(R0, _top_ijava_frame_abi(frame_manager_lr), R1_SP);
|
|
__ mtlr(R0);
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
// Fall through
|
|
|
|
__ bind(Lskip_unextend_SP);
|
|
|
|
// Throw the exception via RuntimeStub "throw_StackOverflowError_entry".
|
|
//
|
|
// Previously, we called C-Code directly. As a consequence, a
|
|
// possible GC tried to process the argument oops of the top frame
|
|
// (see RegisterMap::clear, which sets the corresponding flag to
|
|
// true). This lead to crashes because:
|
|
// 1. The top register map did not contain locations for the argument registers
|
|
// 2. The arguments are dead anyway, could be already overwritten in the worst case
|
|
// Solution: Call via special runtime stub that pushes it's own frame. This runtime stub has the flag
|
|
// "CodeBlob::caller_must_gc_arguments()" set to "false", what prevents the dead arguments getting GC'd.
|
|
//
|
|
// 2 cases exist:
|
|
// 1. We were called by the c2i adapter / call stub
|
|
// 2. We were called by the frame manager
|
|
//
|
|
// Both cases are handled by this code:
|
|
// 1. - initial_caller_sp was saved on stack => Load it back and we're ok
|
|
// - control flow will be:
|
|
// throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->excp_blob of calling method
|
|
// 2. - control flow will be:
|
|
// throw_stackoverflow_stub->VM->throw_stackoverflow_stub->forward_excep->
|
|
// ->rethrow_excp_entry of frame manager->resume_method
|
|
// Since we restored the caller SP above, the rethrow_excp_entry can restore the original interpreter state
|
|
// registers using the stack and resume the calling method with a pending excp.
|
|
|
|
assert(StubRoutines::throw_StackOverflowError_entry() != NULL, "generated in wrong order");
|
|
__ load_const(R3_ARG1, (StubRoutines::throw_StackOverflowError_entry()));
|
|
__ mtctr(R3_ARG1);
|
|
__ bctr();
|
|
}
|
|
//=============================================================================
|
|
// We have popped a frame from an interpreted call. We are assured
|
|
// of returning to an interpreted call by the popframe abi. We have
|
|
// no return value all we have to do is pop the current frame and
|
|
// then make sure that the top of stack (of the caller) gets set to
|
|
// where it was when we entered the callee (i.e. the args are still
|
|
// in place). Or we are returning to the interpreter. In the first
|
|
// case we must extract result (if any) from the java expression
|
|
// stack and store it in the location the native abi would expect
|
|
// for a call returning this type. In the second case we must simply
|
|
// do a stack to stack move as we unwind.
|
|
|
|
__ BIND(popping_frame);
|
|
|
|
// Registers alive
|
|
// R14_state
|
|
// R15_prev_state
|
|
// R17_tos
|
|
//
|
|
// Registers updated
|
|
// R19_method
|
|
// R3_RET
|
|
// msg
|
|
{
|
|
Label L;
|
|
|
|
// Reload callee method, gc may have moved it.
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
// We may be returning to a deoptimized frame in which case the
|
|
// usual assumption of a recursive return is not true.
|
|
|
|
// not equal = is recursive call
|
|
__ cmpdi(CCR0, R15_prev_state, 0);
|
|
|
|
__ bne(CCR0, L);
|
|
|
|
// Pop_frame capability.
|
|
// The pop_frame api says that the underlying frame is a Java frame, in this case
|
|
// (prev_state==null) it must be a compiled frame:
|
|
//
|
|
// Stack at this point: I, C2I + C, ...
|
|
//
|
|
// The outgoing arguments of the call have just been copied (popframe_preserve_args).
|
|
// By the pop_frame api, we must end up in an interpreted frame. So the compiled frame
|
|
// will be deoptimized. Deoptimization will restore the outgoing arguments from
|
|
// popframe_preserve_args, adjust the tos such that it includes the popframe_preserve_args,
|
|
// and adjust the bci such that the call will be executed again.
|
|
// We have no results, just pop the interpreter frame, resize the compiled frame to get rid
|
|
// of the c2i extension and return to the deopt_handler.
|
|
__ b(unwind_initial_activation);
|
|
|
|
// is recursive call
|
|
__ bind(L);
|
|
|
|
// Resume_interpreter expects the original tos in R3_RET.
|
|
__ ld(R3_RET, prev_state_(_stack));
|
|
|
|
// We're done.
|
|
__ li(msg, BytecodeInterpreter::popping_frame);
|
|
|
|
__ b(unwind_recursive_activation);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
|
|
// We have finished an interpreted call. We are either returning to
|
|
// native (call_stub/c2) or we are returning to the interpreter.
|
|
// When returning to native, we must extract the result (if any)
|
|
// from the java expression stack and store it in the location the
|
|
// native abi expects. When returning to the interpreter we must
|
|
// simply do a stack to stack move as we unwind.
|
|
|
|
__ BIND(return_from_interpreted_method);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread - JavaThread*
|
|
// R15_prev_state - address of caller's BytecodeInterpreter or 0
|
|
// R14_state - address of callee's interpreter state
|
|
// R1_SP - callee's stack pointer
|
|
//
|
|
// Registers updated
|
|
// R19_method - callee's method
|
|
// R3_RET - address of result (new caller's tos),
|
|
//
|
|
// if returning to interpreted
|
|
// msg - message for interpreter,
|
|
// if returning to interpreted
|
|
//
|
|
|
|
// Check if this is the initial invocation of the frame manager.
|
|
// If so, R15_prev_state will be null.
|
|
__ cmpdi(CCR0, R15_prev_state, 0);
|
|
|
|
// Reload callee method, gc may have moved it.
|
|
__ ld(R19_method, state_(_method));
|
|
|
|
// Load the method's result type.
|
|
__ lwz(result_index, method_(result_index));
|
|
|
|
// Go to return_to_initial_caller if R15_prev_state is null.
|
|
__ beq(CCR0, return_to_initial_caller);
|
|
|
|
// Copy callee's result to caller's expression stack via inline stack-to-stack
|
|
// converters.
|
|
{
|
|
Register new_tos = R3_RET;
|
|
Register from_temp = R4_ARG2;
|
|
Register from = R5_ARG3;
|
|
Register tos = R6_ARG4;
|
|
Register tmp1 = R7_ARG5;
|
|
Register tmp2 = R8_ARG6;
|
|
|
|
ConditionRegister result_type_is_void = CCR1;
|
|
ConditionRegister result_type_is_long = CCR2;
|
|
ConditionRegister result_type_is_double = CCR3;
|
|
|
|
Label stack_to_stack_void;
|
|
Label stack_to_stack_double_slot; // T_LONG, T_DOUBLE
|
|
Label stack_to_stack_single_slot; // T_BOOLEAN, T_BYTE, T_CHAR, T_SHORT, T_INT, T_FLOAT, T_OBJECT
|
|
Label stack_to_stack_done;
|
|
|
|
// Pass callee's address of tos + BytesPerWord
|
|
__ ld(from_temp, state_(_stack));
|
|
|
|
// result type: void
|
|
__ cmpwi(result_type_is_void, result_index, AbstractInterpreter::BasicType_as_index(T_VOID));
|
|
|
|
// Pass caller's tos == callee's locals address
|
|
__ ld(tos, state_(_locals));
|
|
|
|
// result type: long
|
|
__ cmpwi(result_type_is_long, result_index, AbstractInterpreter::BasicType_as_index(T_LONG));
|
|
|
|
__ addi(from, from_temp, Interpreter::stackElementSize);
|
|
|
|
// !! don't branch above this line !!
|
|
|
|
// handle void
|
|
__ beq(result_type_is_void, stack_to_stack_void);
|
|
|
|
// result type: double
|
|
__ cmpwi(result_type_is_double, result_index, AbstractInterpreter::BasicType_as_index(T_DOUBLE));
|
|
|
|
// handle long or double
|
|
__ beq(result_type_is_long, stack_to_stack_double_slot);
|
|
__ beq(result_type_is_double, stack_to_stack_double_slot);
|
|
|
|
// fall through to single slot types (incl. object)
|
|
|
|
{
|
|
__ BIND(stack_to_stack_single_slot);
|
|
// T_BOOLEAN, T_BYTE, T_CHAR, T_SHORT, T_INT, T_FLOAT, T_OBJECT
|
|
|
|
__ ld(tmp1, 0, from);
|
|
__ std(tmp1, 0, tos);
|
|
// New expression stack top
|
|
__ addi(new_tos, tos, - BytesPerWord);
|
|
|
|
__ b(stack_to_stack_done);
|
|
}
|
|
|
|
{
|
|
__ BIND(stack_to_stack_double_slot);
|
|
// T_LONG, T_DOUBLE
|
|
|
|
// Move both entries for debug purposes even though only one is live
|
|
__ ld(tmp1, BytesPerWord, from);
|
|
__ ld(tmp2, 0, from);
|
|
__ std(tmp1, 0, tos);
|
|
__ std(tmp2, -BytesPerWord, tos);
|
|
|
|
// new expression stack top
|
|
__ addi(new_tos, tos, - 2 * BytesPerWord); // two slots
|
|
__ b(stack_to_stack_done);
|
|
}
|
|
|
|
{
|
|
__ BIND(stack_to_stack_void);
|
|
// T_VOID
|
|
|
|
// new expression stack top
|
|
__ mr(new_tos, tos);
|
|
// fall through to stack_to_stack_done
|
|
}
|
|
|
|
__ BIND(stack_to_stack_done);
|
|
}
|
|
|
|
// new tos = R3_RET
|
|
|
|
// Get the message for the interpreter
|
|
__ li(msg, BytecodeInterpreter::method_resume);
|
|
|
|
// And fall thru
|
|
|
|
|
|
//=============================================================================
|
|
// Restore caller's interpreter state and pass pointer to caller's
|
|
// new tos to caller.
|
|
|
|
__ BIND(unwind_recursive_activation);
|
|
|
|
//
|
|
// Registers alive
|
|
// R15_prev_state - address of caller's BytecodeInterpreter
|
|
// R3_RET - address of caller's tos
|
|
// msg - message for caller's BytecodeInterpreter
|
|
// R1_SP - callee's stack pointer
|
|
//
|
|
// Registers updated
|
|
// R14_state - address of caller's BytecodeInterpreter
|
|
// R15_prev_state - address of its parent or 0
|
|
//
|
|
|
|
// Pop callee's interpreter and set R14_state to caller's interpreter.
|
|
__ pop_interpreter_state(/*prev_state_may_be_0=*/false);
|
|
|
|
// And fall thru
|
|
|
|
|
|
//=============================================================================
|
|
// Resume the (calling) interpreter after a call.
|
|
|
|
__ BIND(resume_interpreter);
|
|
|
|
//
|
|
// Registers alive
|
|
// R14_state - address of resuming BytecodeInterpreter
|
|
// R15_prev_state - address of its parent or 0
|
|
// R3_RET - address of resuming tos
|
|
// msg - message for resuming interpreter
|
|
// R1_SP - callee's stack pointer
|
|
//
|
|
// Registers updated
|
|
// R1_SP - caller's stack pointer
|
|
//
|
|
|
|
// Restore C stack pointer of caller (resuming interpreter),
|
|
// R14_state already points to the resuming BytecodeInterpreter.
|
|
__ pop_interpreter_frame_to_state(R14_state, R21_tmp1, R11_scratch1, R12_scratch2);
|
|
|
|
// Store new address of tos (holding return value) in interpreter state.
|
|
__ std(R3_RET, state_(_stack));
|
|
|
|
// Store message for interpreter.
|
|
__ stw(msg, state_(_msg));
|
|
|
|
__ b(call_interpreter);
|
|
|
|
//=============================================================================
|
|
// Interpreter returning to native code (call_stub/c1/c2) from
|
|
// initial activation. Convert stack result and unwind activation.
|
|
|
|
__ BIND(return_to_initial_caller);
|
|
|
|
//
|
|
// Registers alive
|
|
// R19_method - callee's Method
|
|
// R14_state - address of callee's interpreter state
|
|
// R16_thread - JavaThread
|
|
// R1_SP - callee's stack pointer
|
|
//
|
|
// Registers updated
|
|
// R3_RET/F1_RET - result in expected output register
|
|
//
|
|
|
|
// If we have an exception pending we have no result and we
|
|
// must figure out where to really return to.
|
|
//
|
|
__ ld(pending_exception, thread_(pending_exception));
|
|
__ cmpdi(CCR0, pending_exception, 0);
|
|
__ bne(CCR0, unwind_initial_activation_pending_exception);
|
|
|
|
__ lwa(result_index, method_(result_index));
|
|
|
|
// Address of stub descriptor address array.
|
|
__ load_const(stub_addr, CppInterpreter::stack_result_to_native());
|
|
|
|
// Pass address of callee's tos + BytesPerWord.
|
|
// Will then point directly to result.
|
|
__ ld(R3_ARG1, state_(_stack));
|
|
__ addi(R3_ARG1, R3_ARG1, Interpreter::stackElementSize);
|
|
|
|
// Address of stub descriptor address
|
|
__ sldi(result_index, result_index, LogBytesPerWord);
|
|
__ add(stub_addr, stub_addr, result_index);
|
|
|
|
// Stub descriptor address
|
|
__ ld(stub_addr, 0, stub_addr);
|
|
|
|
// TODO: don't do this via a call, do it in place!
|
|
//
|
|
// call stub via descriptor
|
|
__ call_stub(stub_addr);
|
|
|
|
__ BIND(unwind_initial_activation);
|
|
|
|
// Unwind from initial activation. No exception is pending.
|
|
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// ...
|
|
// CALLER [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
// CALLER [unextended ABI]
|
|
// ...
|
|
//
|
|
// The CALLER frame has a C2I adapter or is an entry-frame.
|
|
//
|
|
|
|
// An interpreter frame exists, we may pop the TOP_IJAVA_FRAME and
|
|
// turn the caller's PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME.
|
|
// But, we simply restore the return pc from the caller's frame and
|
|
// use the caller's initial_caller_sp as the new SP which pops the
|
|
// interpreter frame and "resizes" the caller's frame to its "unextended"
|
|
// size.
|
|
|
|
// get rid of top frame
|
|
__ pop_frame();
|
|
|
|
// Load return PC from parent frame.
|
|
__ ld(R21_tmp1, _parent_ijava_frame_abi(lr), R1_SP);
|
|
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
// update LR
|
|
__ mtlr(R21_tmp1);
|
|
|
|
// return
|
|
__ blr();
|
|
|
|
//=============================================================================
|
|
// Unwind from initial activation. An exception is pending
|
|
|
|
__ BIND(unwind_initial_activation_pending_exception);
|
|
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// ...
|
|
// CALLER [PARENT_IJAVA_FRAME_ABI]
|
|
// ...
|
|
// CALLER [unextended ABI]
|
|
// ...
|
|
//
|
|
// The CALLER frame has a C2I adapter or is an entry-frame.
|
|
//
|
|
|
|
// An interpreter frame exists, we may pop the TOP_IJAVA_FRAME and
|
|
// turn the caller's PARENT_IJAVA_FRAME back into a TOP_IJAVA_FRAME.
|
|
// But, we just pop the current TOP_IJAVA_FRAME and fall through
|
|
|
|
__ pop_frame();
|
|
__ ld(R3_ARG1, _top_ijava_frame_abi(lr), R1_SP);
|
|
|
|
//
|
|
// Stack layout at this point:
|
|
//
|
|
// CALLER [PARENT_IJAVA_FRAME_ABI] <-- R1_SP
|
|
// ...
|
|
// CALLER [unextended ABI]
|
|
// ...
|
|
//
|
|
// The CALLER frame has a C2I adapter or is an entry-frame.
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R3_ARG1 - return address to caller
|
|
//
|
|
// Registers updated
|
|
// R3_ARG1 - address of pending exception
|
|
// R4_ARG2 - issuing pc = return address to caller
|
|
// LR - address of exception handler stub
|
|
//
|
|
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
__ mr(R14, R3_ARG1); // R14 := ARG1
|
|
__ mr(R4_ARG2, R3_ARG1); // ARG2 := ARG1
|
|
|
|
// Find the address of the "catch_exception" stub.
|
|
__ push_frame_reg_args(0, R11_scratch1);
|
|
__ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::exception_handler_for_return_address),
|
|
R16_thread,
|
|
R4_ARG2);
|
|
__ pop_frame();
|
|
|
|
// Load continuation address into LR.
|
|
__ mtlr(R3_RET);
|
|
|
|
// Load address of pending exception and clear it in thread object.
|
|
__ ld(R3_ARG1/*R3_RET*/, thread_(pending_exception));
|
|
__ li(R4_ARG2, 0);
|
|
__ std(R4_ARG2, thread_(pending_exception));
|
|
|
|
// re-load issuing pc
|
|
__ mr(R4_ARG2, R14);
|
|
|
|
// Branch to found exception handler.
|
|
__ blr();
|
|
|
|
//=============================================================================
|
|
// Call a new method. Compute new args and trim the expression stack
|
|
// to only what we are currently using and then recurse.
|
|
|
|
__ BIND(call_method);
|
|
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R14_state - address of caller's BytecodeInterpreter
|
|
// R1_SP - caller's stack pointer
|
|
//
|
|
// Registers updated
|
|
// R15_prev_state - address of caller's BytecodeInterpreter
|
|
// R17_tos - address of caller's tos
|
|
// R19_method - callee's Method
|
|
// R1_SP - trimmed back
|
|
//
|
|
|
|
// Very-local scratch registers.
|
|
|
|
const Register offset = R21_tmp1;
|
|
const Register tmp = R22_tmp2;
|
|
const Register self_entry = R23_tmp3;
|
|
const Register stub_entry = R24_tmp4;
|
|
|
|
const ConditionRegister cr = CCR0;
|
|
|
|
// Load the address of the frame manager.
|
|
__ load_const(self_entry, &interpreter_frame_manager);
|
|
__ ld(self_entry, 0, self_entry);
|
|
|
|
// Load BytecodeInterpreter._result._to_call._callee (callee's Method).
|
|
__ ld(R19_method, state_(_result._to_call._callee));
|
|
// Load BytecodeInterpreter._stack (outgoing tos).
|
|
__ ld(R17_tos, state_(_stack));
|
|
|
|
// Save address of caller's BytecodeInterpreter.
|
|
__ mr(R15_prev_state, R14_state);
|
|
|
|
// Load the callee's entry point.
|
|
// Load BytecodeInterpreter._result._to_call._callee_entry_point.
|
|
__ ld(stub_entry, state_(_result._to_call._callee_entry_point));
|
|
|
|
// Check whether stub_entry is equal to self_entry.
|
|
__ cmpd(cr, self_entry, stub_entry);
|
|
// if (self_entry == stub_entry)
|
|
// do a re-dispatch
|
|
__ beq(cr, re_dispatch);
|
|
// else
|
|
// call the specialized entry (adapter for jni or compiled code)
|
|
__ BIND(call_special);
|
|
|
|
//
|
|
// Call the entry generated by `InterpreterGenerator::generate_native_entry'.
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R15_prev_state - address of caller's BytecodeInterpreter
|
|
// R19_method - callee's Method
|
|
// R17_tos - address of caller's tos
|
|
// R1_SP - caller's stack pointer
|
|
//
|
|
|
|
// Mark return from specialized entry for generate_native_entry.
|
|
guarantee(return_from_native_pc != (address) NULL, "precondition");
|
|
frame_manager_specialized_return = return_from_native_pc;
|
|
|
|
// Set sender_SP in case we call interpreter native wrapper which
|
|
// will expect it. Compiled code should not care.
|
|
__ mr(R21_sender_SP, R1_SP);
|
|
|
|
// Do a tail call here, and let the link register point to
|
|
// frame_manager_specialized_return which is return_from_native_pc.
|
|
__ load_const(tmp, frame_manager_specialized_return);
|
|
__ call_stub_and_return_to(stub_entry, tmp /* return_pc=tmp */);
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// InterpretMethod triggered OSR compilation of some Java method M
|
|
// and now asks to run the compiled code. We call this code the
|
|
// `callee'.
|
|
//
|
|
// This is our current idea on how OSR should look like on PPC64:
|
|
//
|
|
// While interpreting a Java method M the stack is:
|
|
//
|
|
// (InterpretMethod (M), IJAVA_FRAME (M), ANY_FRAME, ...).
|
|
//
|
|
// After having OSR compiled M, `InterpretMethod' returns to the
|
|
// frame manager, sending the message `retry_method_osr'. The stack
|
|
// is:
|
|
//
|
|
// (IJAVA_FRAME (M), ANY_FRAME, ...).
|
|
//
|
|
// The compiler will have generated an `nmethod' suitable for
|
|
// continuing execution of M at the bytecode index at which OSR took
|
|
// place. So now the frame manager calls the OSR entry. The OSR
|
|
// entry sets up a JIT_FRAME for M and continues execution of M with
|
|
// initial state determined by the IJAVA_FRAME.
|
|
//
|
|
// (JIT_FRAME (M), IJAVA_FRAME (M), ANY_FRAME, ...).
|
|
//
|
|
|
|
__ BIND(retry_method_osr);
|
|
{
|
|
//
|
|
// Registers alive
|
|
// R16_thread
|
|
// R15_prev_state - address of caller's BytecodeInterpreter
|
|
// R14_state - address of callee's BytecodeInterpreter
|
|
// R1_SP - callee's SP before call to InterpretMethod
|
|
//
|
|
// Registers updated
|
|
// R17 - pointer to callee's locals array
|
|
// (declared via `interpreter_arg_ptr_reg' in the AD file)
|
|
// R19_method - callee's Method
|
|
// R1_SP - callee's SP (will become SP of OSR adapter frame)
|
|
//
|
|
|
|
// Provide a debugger breakpoint in the frame manager if breakpoints
|
|
// in osr'd methods are requested.
|
|
#ifdef COMPILER2
|
|
NOT_PRODUCT( if (OptoBreakpointOSR) { __ illtrap(); } )
|
|
#endif
|
|
|
|
// Load callee's pointer to locals array from callee's state.
|
|
// __ ld(R17, state_(_locals));
|
|
|
|
// Load osr entry.
|
|
__ ld(R12_scratch2, state_(_result._osr._osr_entry));
|
|
|
|
// Load address of temporary osr buffer to arg1.
|
|
__ ld(R3_ARG1, state_(_result._osr._osr_buf));
|
|
__ mtctr(R12_scratch2);
|
|
|
|
// Load method, gc may move it during execution of osr'd method.
|
|
__ ld(R22_tmp2, state_(_method));
|
|
// Load message 'call_method'.
|
|
__ li(R23_tmp3, BytecodeInterpreter::call_method);
|
|
|
|
{
|
|
// Pop the IJAVA frame of the method which we are going to call osr'd.
|
|
Label no_state, skip_no_state;
|
|
__ pop_interpreter_state(/*prev_state_may_be_0=*/true);
|
|
__ cmpdi(CCR0, R14_state,0);
|
|
__ beq(CCR0, no_state);
|
|
// return to interpreter
|
|
__ pop_interpreter_frame_to_state(R14_state, R11_scratch1, R12_scratch2, R21_tmp1);
|
|
|
|
// Init _result._to_call._callee and tell gc that it contains a valid oop
|
|
// by setting _msg to 'call_method'.
|
|
__ std(R22_tmp2, state_(_result._to_call._callee));
|
|
// TODO: PPC port: assert(4 == BytecodeInterpreter::sz_msg(), "unexpected field size");
|
|
__ stw(R23_tmp3, state_(_msg));
|
|
|
|
__ load_const(R21_tmp1, frame_manager_specialized_return);
|
|
__ b(skip_no_state);
|
|
__ bind(no_state);
|
|
|
|
// Return to initial caller.
|
|
|
|
// Get rid of top frame.
|
|
__ pop_frame();
|
|
|
|
// Load return PC from parent frame.
|
|
__ ld(R21_tmp1, _parent_ijava_frame_abi(lr), R1_SP);
|
|
|
|
// Resize frame to get rid of a potential extension.
|
|
__ resize_frame_to_initial_caller(R11_scratch1, R12_scratch2);
|
|
|
|
__ bind(skip_no_state);
|
|
|
|
// Update LR with return pc.
|
|
__ mtlr(R21_tmp1);
|
|
}
|
|
// Jump to the osr entry point.
|
|
__ bctr();
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// Interpreted method "returned" with an exception, pass it on.
|
|
// Pass no result, unwind activation and continue/return to
|
|
// interpreter/call_stub/c2.
|
|
|
|
__ BIND(throwing_exception);
|
|
|
|
// Check if this is the initial invocation of the frame manager. If
|
|
// so, previous interpreter state in R15_prev_state will be null.
|
|
|
|
// New tos of caller is callee's first parameter address, that is
|
|
// callee's incoming arguments are popped.
|
|
__ ld(R3_RET, state_(_locals));
|
|
|
|
// Check whether this is an initial call.
|
|
__ cmpdi(CCR0, R15_prev_state, 0);
|
|
// Yes, called from the call stub or from generated code via a c2i frame.
|
|
__ beq(CCR0, unwind_initial_activation_pending_exception);
|
|
|
|
// Send resume message, interpreter will see the exception first.
|
|
|
|
__ li(msg, BytecodeInterpreter::method_resume);
|
|
__ b(unwind_recursive_activation);
|
|
|
|
|
|
//=============================================================================
|
|
// Push the last instruction out to the code buffer.
|
|
|
|
{
|
|
__ unimplemented("end of InterpreterGenerator::generate_normal_entry", 128);
|
|
}
|
|
|
|
interpreter_frame_manager = entry;
|
|
return interpreter_frame_manager;
|
|
}
|
|
|
|
// Generate code for various sorts of method entries
|
|
//
|
|
address AbstractInterpreterGenerator::generate_method_entry(AbstractInterpreter::MethodKind kind) {
|
|
address entry_point = NULL;
|
|
|
|
switch (kind) {
|
|
case Interpreter::zerolocals : break;
|
|
case Interpreter::zerolocals_synchronized : break;
|
|
case Interpreter::native : // Fall thru
|
|
case Interpreter::native_synchronized : entry_point = ((CppInterpreterGenerator*)this)->generate_native_entry(); break;
|
|
case Interpreter::empty : break;
|
|
case Interpreter::accessor : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry(); break;
|
|
case Interpreter::abstract : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry(); break;
|
|
// These are special interpreter intrinsics which we don't support so far.
|
|
case Interpreter::java_lang_math_sin : break;
|
|
case Interpreter::java_lang_math_cos : break;
|
|
case Interpreter::java_lang_math_tan : break;
|
|
case Interpreter::java_lang_math_abs : break;
|
|
case Interpreter::java_lang_math_log : break;
|
|
case Interpreter::java_lang_math_log10 : break;
|
|
case Interpreter::java_lang_math_sqrt : break;
|
|
case Interpreter::java_lang_math_pow : break;
|
|
case Interpreter::java_lang_math_exp : break;
|
|
case Interpreter::java_lang_ref_reference_get: entry_point = ((InterpreterGenerator*)this)->generate_Reference_get_entry(); break;
|
|
default : ShouldNotReachHere(); break;
|
|
}
|
|
|
|
if (entry_point) {
|
|
return entry_point;
|
|
}
|
|
return ((InterpreterGenerator*)this)->generate_normal_entry();
|
|
}
|
|
|
|
InterpreterGenerator::InterpreterGenerator(StubQueue* code)
|
|
: CppInterpreterGenerator(code) {
|
|
generate_all(); // down here so it can be "virtual"
|
|
}
|
|
|
|
// How much stack a topmost interpreter method activation needs in words.
|
|
int AbstractInterpreter::size_top_interpreter_activation(Method* method) {
|
|
// Computation is in bytes not words to match layout_activation_impl
|
|
// below, but the return is in words.
|
|
|
|
//
|
|
// 0 [TOP_IJAVA_FRAME_ABI] \
|
|
// alignment (optional) \ |
|
|
// [operand stack / Java parameters] > stack | |
|
|
// [monitors] (optional) > monitors | |
|
|
// [PARENT_IJAVA_FRAME_ABI] \ | |
|
|
// [BytecodeInterpreter object] > interpreter \ | | |
|
|
// alignment (optional) | round | parent | round | top
|
|
// [Java result] (2 slots) > result | | | |
|
|
// [Java non-arg locals] \ locals | | | |
|
|
// [arg locals] / / / / /
|
|
//
|
|
|
|
int locals = method->max_locals() * BytesPerWord;
|
|
int interpreter = frame::interpreter_frame_cinterpreterstate_size_in_bytes();
|
|
int result = 2 * BytesPerWord;
|
|
|
|
int parent = round_to(interpreter + result + locals, 16) + frame::parent_ijava_frame_abi_size;
|
|
|
|
int stack = method->max_stack() * BytesPerWord;
|
|
int monitors = method->is_synchronized() ? frame::interpreter_frame_monitor_size_in_bytes() : 0;
|
|
int top = round_to(parent + monitors + stack, 16) + frame::top_ijava_frame_abi_size;
|
|
|
|
return (top / BytesPerWord);
|
|
}
|
|
|
|
void BytecodeInterpreter::layout_interpreterState(interpreterState to_fill,
|
|
frame* caller,
|
|
frame* current,
|
|
Method* method,
|
|
intptr_t* locals,
|
|
intptr_t* stack,
|
|
intptr_t* stack_base,
|
|
intptr_t* monitor_base,
|
|
intptr_t* frame_sp,
|
|
bool is_top_frame) {
|
|
// What about any vtable?
|
|
//
|
|
to_fill->_thread = JavaThread::current();
|
|
// This gets filled in later but make it something recognizable for now.
|
|
to_fill->_bcp = method->code_base();
|
|
to_fill->_locals = locals;
|
|
to_fill->_constants = method->constants()->cache();
|
|
to_fill->_method = method;
|
|
to_fill->_mdx = NULL;
|
|
to_fill->_stack = stack;
|
|
|
|
if (is_top_frame && JavaThread::current()->popframe_forcing_deopt_reexecution()) {
|
|
to_fill->_msg = deopt_resume2;
|
|
} else {
|
|
to_fill->_msg = method_resume;
|
|
}
|
|
to_fill->_result._to_call._bcp_advance = 0;
|
|
to_fill->_result._to_call._callee_entry_point = NULL; // doesn't matter to anyone
|
|
to_fill->_result._to_call._callee = NULL; // doesn't matter to anyone
|
|
to_fill->_prev_link = NULL;
|
|
|
|
if (caller->is_interpreted_frame()) {
|
|
interpreterState prev = caller->get_interpreterState();
|
|
|
|
// Support MH calls. Make sure the interpreter will return the right address:
|
|
// 1. Caller did ordinary interpreted->compiled call call: Set a prev_state
|
|
// which makes the CPP interpreter return to frame manager "return_from_interpreted_method"
|
|
// entry after finishing execution.
|
|
// 2. Caller did a MH call: If the caller has a MethodHandleInvoke in it's
|
|
// state (invariant: must be the caller of the bottom vframe) we used the
|
|
// "call_special" entry to do the call, meaning the arguments have not been
|
|
// popped from the stack. Therefore, don't enter a prev state in this case
|
|
// in order to return to "return_from_native" frame manager entry which takes
|
|
// care of popping arguments. Also, don't overwrite the MH.invoke Method in
|
|
// the prev_state in order to be able to figure out the number of arguments to
|
|
// pop.
|
|
// The parameter method can represent MethodHandle.invokeExact(...).
|
|
// The MethodHandleCompiler generates these synthetic Methods,
|
|
// including bytecodes, if an invokedynamic call gets inlined. In
|
|
// this case we want to return like from any other interpreted
|
|
// Java call, so we set _prev_link.
|
|
to_fill->_prev_link = prev;
|
|
|
|
if (*prev->_bcp == Bytecodes::_invokeinterface || *prev->_bcp == Bytecodes::_invokedynamic) {
|
|
prev->_result._to_call._bcp_advance = 5;
|
|
} else {
|
|
prev->_result._to_call._bcp_advance = 3;
|
|
}
|
|
}
|
|
to_fill->_oop_temp = NULL;
|
|
to_fill->_stack_base = stack_base;
|
|
// 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.
|
|
to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
|
|
to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
|
|
|
|
to_fill->_frame_bottom = frame_sp;
|
|
|
|
// PPC64 specific
|
|
to_fill->_last_Java_pc = NULL;
|
|
to_fill->_last_Java_fp = NULL;
|
|
to_fill->_last_Java_sp = frame_sp;
|
|
#ifdef ASSERT
|
|
to_fill->_self_link = to_fill;
|
|
to_fill->_native_fresult = 123456.789;
|
|
to_fill->_native_lresult = CONST64(0xdeafcafedeadc0de);
|
|
#endif
|
|
}
|
|
|
|
void BytecodeInterpreter::pd_layout_interpreterState(interpreterState istate,
|
|
address last_Java_pc,
|
|
intptr_t* last_Java_fp) {
|
|
istate->_last_Java_pc = last_Java_pc;
|
|
istate->_last_Java_fp = last_Java_fp;
|
|
}
|
|
|
|
// Computes monitor_size and top_frame_size in bytes.
|
|
static void frame_size_helper(int max_stack,
|
|
int monitors,
|
|
int& monitor_size,
|
|
int& top_frame_size) {
|
|
monitor_size = frame::interpreter_frame_monitor_size_in_bytes() * monitors;
|
|
top_frame_size = round_to(frame::interpreter_frame_cinterpreterstate_size_in_bytes()
|
|
+ monitor_size
|
|
+ max_stack * Interpreter::stackElementSize
|
|
+ 2 * Interpreter::stackElementSize,
|
|
frame::alignment_in_bytes)
|
|
+ frame::top_ijava_frame_abi_size;
|
|
}
|
|
|
|
// Returns number of stackElementWords needed for the interpreter frame with the
|
|
// given sections.
|
|
int AbstractInterpreter::size_activation(int max_stack,
|
|
int temps,
|
|
int extra_args,
|
|
int monitors,
|
|
int callee_params,
|
|
int callee_locals,
|
|
bool is_top_frame) {
|
|
int monitor_size = 0;
|
|
int top_frame_size = 0;
|
|
frame_size_helper(max_stack, monitors, monitor_size, top_frame_size);
|
|
|
|
int frame_size;
|
|
if (is_top_frame) {
|
|
frame_size = top_frame_size;
|
|
} else {
|
|
frame_size = round_to(frame::interpreter_frame_cinterpreterstate_size_in_bytes()
|
|
+ monitor_size
|
|
+ (temps - callee_params + callee_locals) * Interpreter::stackElementSize
|
|
+ 2 * Interpreter::stackElementSize,
|
|
frame::alignment_in_bytes)
|
|
+ frame::parent_ijava_frame_abi_size;
|
|
assert(extra_args == 0, "non-zero for top_frame only");
|
|
}
|
|
|
|
return frame_size / Interpreter::stackElementSize;
|
|
}
|
|
|
|
void AbstractInterpreter::layout_activation(Method* method,
|
|
int temps, // Number of slots on java expression stack in use.
|
|
int popframe_args,
|
|
int monitors, // Number of active monitors.
|
|
int caller_actual_parameters,
|
|
int callee_params,// Number of slots for callee parameters.
|
|
int callee_locals,// Number of slots for locals.
|
|
frame* caller,
|
|
frame* interpreter_frame,
|
|
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. However there is an
|
|
// exception. With the C++ based interpreter only the top most frame
|
|
// has a full sized expression stack. The 16 byte slop factor is
|
|
// both the abi scratch area and a place to hold a result from a
|
|
// callee on its way to the callers stack.
|
|
|
|
int monitor_size = 0;
|
|
int top_frame_size = 0;
|
|
frame_size_helper(method->max_stack(), monitors, monitor_size, top_frame_size);
|
|
|
|
intptr_t sp = (intptr_t)interpreter_frame->sp();
|
|
intptr_t fp = *(intptr_t *)sp;
|
|
assert(fp == (intptr_t)caller->sp(), "fp must match");
|
|
interpreterState cur_state =
|
|
(interpreterState)(fp - frame::interpreter_frame_cinterpreterstate_size_in_bytes());
|
|
|
|
// Now fill in the interpreterState object.
|
|
|
|
intptr_t* locals;
|
|
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.
|
|
interpreterState prev = caller->get_interpreterState();
|
|
// Calculate start of "locals" for MH calls. For MH calls, the
|
|
// current method() (= MH target) and prev->callee() (=
|
|
// MH.invoke*()) are different and especially have different
|
|
// signatures. To pop the argumentsof the caller, we must use
|
|
// the prev->callee()->size_of_arguments() because that's what
|
|
// the caller actually pushed. Currently, for synthetic MH
|
|
// calls (deoptimized from inlined MH calls), detected by
|
|
// is_method_handle_invoke(), we use the callee's arguments
|
|
// because here, the caller's and callee's signature match.
|
|
if (true /*!caller->is_at_mh_callsite()*/) {
|
|
locals = prev->stack() + method->size_of_parameters();
|
|
} else {
|
|
// Normal MH call.
|
|
locals = prev->stack() + prev->callee()->size_of_parameters();
|
|
}
|
|
} else {
|
|
bool is_deopted;
|
|
locals = (intptr_t*) (fp + ((method->max_locals() - 1) * BytesPerWord) +
|
|
frame::parent_ijava_frame_abi_size);
|
|
}
|
|
|
|
intptr_t* monitor_base = (intptr_t*) cur_state;
|
|
intptr_t* stack_base = (intptr_t*) ((intptr_t) monitor_base - monitor_size);
|
|
|
|
// Provide pop_frame capability on PPC64, add popframe_args.
|
|
// +1 because stack is always prepushed.
|
|
intptr_t* stack = (intptr_t*) ((intptr_t) stack_base - (temps + popframe_args + 1) * BytesPerWord);
|
|
|
|
BytecodeInterpreter::layout_interpreterState(cur_state,
|
|
caller,
|
|
interpreter_frame,
|
|
method,
|
|
locals,
|
|
stack,
|
|
stack_base,
|
|
monitor_base,
|
|
(intptr_t*)(((intptr_t)fp) - top_frame_size),
|
|
is_top_frame);
|
|
|
|
BytecodeInterpreter::pd_layout_interpreterState(cur_state, interpreter_return_address,
|
|
interpreter_frame->fp());
|
|
}
|
|
|
|
#endif // CC_INTERP
|