mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
Merge
This commit is contained in:
commit
a15b864ec9
15 changed files with 396 additions and 123 deletions
|
@ -308,3 +308,10 @@ intptr_t *frame::initial_deoptimization_info() {
|
|||
// unused... but returns fp() to minimize changes introduced by 7087445
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp), _unextended_sp((intptr_t*)sp) {
|
||||
find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -343,7 +343,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
|
|||
// constructors
|
||||
|
||||
// Construct an unpatchable, deficient frame
|
||||
frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
||||
void frame::init(intptr_t* sp, address pc, CodeBlob* cb) {
|
||||
#ifdef _LP64
|
||||
assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp");
|
||||
#endif
|
||||
|
@ -365,6 +365,10 @@ frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
|||
#endif // ASSERT
|
||||
}
|
||||
|
||||
frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
|
||||
init(sp, pc, cb);
|
||||
}
|
||||
|
||||
frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) :
|
||||
_sp(sp),
|
||||
_younger_sp(younger_sp),
|
||||
|
@ -419,6 +423,13 @@ frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpret
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
init((intptr_t*)sp, (address)pc, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool frame::is_interpreted_frame() const {
|
||||
return Interpreter::contains(pc());
|
||||
}
|
||||
|
|
|
@ -163,6 +163,8 @@
|
|||
enum unpatchable_t { unpatchable };
|
||||
frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL);
|
||||
|
||||
void init(intptr_t* sp, address pc, CodeBlob* cb);
|
||||
|
||||
// Walk from sp outward looking for old_sp, and return old_sp's predecessor
|
||||
// (i.e. return the sp from the frame where old_sp is the fp).
|
||||
// Register windows are assumed to be flushed for the stack in question.
|
||||
|
|
|
@ -715,3 +715,10 @@ intptr_t* frame::real_fp() const {
|
|||
assert(! is_compiled_frame(), "unknown compiled frame size");
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
init((intptr_t*)sp, (intptr_t*)fp, (address)pc);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -187,6 +187,8 @@
|
|||
|
||||
frame(intptr_t* sp, intptr_t* fp);
|
||||
|
||||
void init(intptr_t* sp, intptr_t* fp, address pc);
|
||||
|
||||
// accessors for the instance variables
|
||||
// Note: not necessarily the real 'frame pointer' (see real_fp)
|
||||
intptr_t* fp() const { return _fp; }
|
||||
|
|
|
@ -41,7 +41,7 @@ inline frame::frame() {
|
|||
_deopt_state = unknown;
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
_sp = sp;
|
||||
_unextended_sp = sp;
|
||||
_fp = fp;
|
||||
|
@ -59,6 +59,10 @@ inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
|||
}
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* fp, address pc) {
|
||||
init(sp, fp, pc);
|
||||
}
|
||||
|
||||
inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
|
||||
_sp = sp;
|
||||
_unextended_sp = unextended_sp;
|
||||
|
|
|
@ -438,3 +438,10 @@ intptr_t *frame::initial_deoptimization_info() {
|
|||
// unused... but returns fp() to minimize changes introduced by 7087445
|
||||
return fp();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
frame::frame(void* sp, void* fp, void* pc) {
|
||||
Unimplemented();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -265,7 +265,7 @@ frame os::current_frame() {
|
|||
CAST_FROM_FN_PTR(address, os::current_frame));
|
||||
if (os::is_first_C_frame(&myframe)) {
|
||||
// stack is not walkable
|
||||
return frame(NULL, NULL, NULL);
|
||||
return frame(NULL, NULL, false);
|
||||
} else {
|
||||
return os::get_sender_for_C_frame(&myframe);
|
||||
}
|
||||
|
|
|
@ -327,7 +327,7 @@ void Canonicalizer::do_ShiftOp (ShiftOp* x) {
|
|||
if (t2->is_constant()) {
|
||||
switch (t2->tag()) {
|
||||
case intTag : if (t2->as_IntConstant()->value() == 0) set_canonical(x->x()); return;
|
||||
case longTag : if (t2->as_IntConstant()->value() == 0) set_canonical(x->x()); return;
|
||||
case longTag : if (t2->as_LongConstant()->value() == (jlong)0) set_canonical(x->x()); return;
|
||||
default : ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
@ -808,28 +808,41 @@ void Canonicalizer::do_ExceptionObject(ExceptionObject* x) {}
|
|||
|
||||
static bool match_index_and_scale(Instruction* instr,
|
||||
Instruction** index,
|
||||
int* log2_scale,
|
||||
Instruction** instr_to_unpin) {
|
||||
*instr_to_unpin = NULL;
|
||||
|
||||
// Skip conversion ops
|
||||
int* log2_scale) {
|
||||
// Skip conversion ops. This works only on 32bit because of the implicit l2i that the
|
||||
// unsafe performs.
|
||||
#ifndef _LP64
|
||||
Convert* convert = instr->as_Convert();
|
||||
if (convert != NULL) {
|
||||
if (convert != NULL && convert->op() == Bytecodes::_i2l) {
|
||||
assert(convert->value()->type() == intType, "invalid input type");
|
||||
instr = convert->value();
|
||||
}
|
||||
#endif
|
||||
|
||||
ShiftOp* shift = instr->as_ShiftOp();
|
||||
if (shift != NULL) {
|
||||
if (shift->is_pinned()) {
|
||||
*instr_to_unpin = shift;
|
||||
if (shift->op() == Bytecodes::_lshl) {
|
||||
assert(shift->x()->type() == longType, "invalid input type");
|
||||
} else {
|
||||
#ifndef _LP64
|
||||
if (shift->op() == Bytecodes::_ishl) {
|
||||
assert(shift->x()->type() == intType, "invalid input type");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Constant shift value?
|
||||
Constant* con = shift->y()->as_Constant();
|
||||
if (con == NULL) return false;
|
||||
// Well-known type and value?
|
||||
IntConstant* val = con->type()->as_IntConstant();
|
||||
if (val == NULL) return false;
|
||||
if (shift->x()->type() != intType) return false;
|
||||
assert(val != NULL, "Should be an int constant");
|
||||
|
||||
*index = shift->x();
|
||||
int tmp_scale = val->value();
|
||||
if (tmp_scale >= 0 && tmp_scale < 4) {
|
||||
|
@ -842,31 +855,42 @@ static bool match_index_and_scale(Instruction* instr,
|
|||
|
||||
ArithmeticOp* arith = instr->as_ArithmeticOp();
|
||||
if (arith != NULL) {
|
||||
if (arith->is_pinned()) {
|
||||
*instr_to_unpin = arith;
|
||||
// See if either arg is a known constant
|
||||
Constant* con = arith->x()->as_Constant();
|
||||
if (con != NULL) {
|
||||
*index = arith->y();
|
||||
} else {
|
||||
con = arith->y()->as_Constant();
|
||||
if (con == NULL) return false;
|
||||
*index = arith->x();
|
||||
}
|
||||
long const_value;
|
||||
// Check for integer multiply
|
||||
if (arith->op() == Bytecodes::_imul) {
|
||||
// See if either arg is a known constant
|
||||
Constant* con = arith->x()->as_Constant();
|
||||
if (con != NULL) {
|
||||
*index = arith->y();
|
||||
if (arith->op() == Bytecodes::_lmul) {
|
||||
assert((*index)->type() == longType, "invalid input type");
|
||||
LongConstant* val = con->type()->as_LongConstant();
|
||||
assert(val != NULL, "expecting a long constant");
|
||||
const_value = val->value();
|
||||
} else {
|
||||
#ifndef _LP64
|
||||
if (arith->op() == Bytecodes::_imul) {
|
||||
assert((*index)->type() == intType, "invalid input type");
|
||||
IntConstant* val = con->type()->as_IntConstant();
|
||||
assert(val != NULL, "expecting an int constant");
|
||||
const_value = val->value();
|
||||
} else {
|
||||
con = arith->y()->as_Constant();
|
||||
if (con == NULL) return false;
|
||||
*index = arith->x();
|
||||
}
|
||||
if ((*index)->type() != intType) return false;
|
||||
// Well-known type and value?
|
||||
IntConstant* val = con->type()->as_IntConstant();
|
||||
if (val == NULL) return false;
|
||||
switch (val->value()) {
|
||||
case 1: *log2_scale = 0; return true;
|
||||
case 2: *log2_scale = 1; return true;
|
||||
case 4: *log2_scale = 2; return true;
|
||||
case 8: *log2_scale = 3; return true;
|
||||
default: return false;
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
switch (const_value) {
|
||||
case 1: *log2_scale = 0; return true;
|
||||
case 2: *log2_scale = 1; return true;
|
||||
case 4: *log2_scale = 2; return true;
|
||||
case 8: *log2_scale = 3; return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -879,29 +903,37 @@ static bool match(UnsafeRawOp* x,
|
|||
Instruction** base,
|
||||
Instruction** index,
|
||||
int* log2_scale) {
|
||||
Instruction* instr_to_unpin = NULL;
|
||||
ArithmeticOp* root = x->base()->as_ArithmeticOp();
|
||||
if (root == NULL) return false;
|
||||
// Limit ourselves to addition for now
|
||||
if (root->op() != Bytecodes::_ladd) return false;
|
||||
|
||||
bool match_found = false;
|
||||
// Try to find shift or scale op
|
||||
if (match_index_and_scale(root->y(), index, log2_scale, &instr_to_unpin)) {
|
||||
if (match_index_and_scale(root->y(), index, log2_scale)) {
|
||||
*base = root->x();
|
||||
} else if (match_index_and_scale(root->x(), index, log2_scale, &instr_to_unpin)) {
|
||||
match_found = true;
|
||||
} else if (match_index_and_scale(root->x(), index, log2_scale)) {
|
||||
*base = root->y();
|
||||
} else if (root->y()->as_Convert() != NULL) {
|
||||
match_found = true;
|
||||
} else if (NOT_LP64(root->y()->as_Convert() != NULL) LP64_ONLY(false)) {
|
||||
// Skipping i2l works only on 32bit because of the implicit l2i that the unsafe performs.
|
||||
// 64bit needs a real sign-extending conversion.
|
||||
Convert* convert = root->y()->as_Convert();
|
||||
if (convert->op() == Bytecodes::_i2l && convert->value()->type() == intType) {
|
||||
if (convert->op() == Bytecodes::_i2l) {
|
||||
assert(convert->value()->type() == intType, "should be an int");
|
||||
// pick base and index, setting scale at 1
|
||||
*base = root->x();
|
||||
*index = convert->value();
|
||||
*log2_scale = 0;
|
||||
} else {
|
||||
return false;
|
||||
match_found = true;
|
||||
}
|
||||
} else {
|
||||
// doesn't match any expected sequences
|
||||
return false;
|
||||
}
|
||||
// The default solution
|
||||
if (!match_found) {
|
||||
*base = root->x();
|
||||
*index = root->y();
|
||||
*log2_scale = 0;
|
||||
}
|
||||
|
||||
// If the value is pinned then it will be always be computed so
|
||||
|
|
|
@ -2045,6 +2045,8 @@ void LIRGenerator::do_RoundFP(RoundFP* x) {
|
|||
}
|
||||
}
|
||||
|
||||
// Here UnsafeGetRaw may have x->base() and x->index() be int or long
|
||||
// on both 64 and 32 bits. Expecting x->base() to be always long on 64bit.
|
||||
void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) {
|
||||
LIRItem base(x->base(), this);
|
||||
LIRItem idx(this);
|
||||
|
@ -2059,50 +2061,73 @@ void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) {
|
|||
|
||||
int log2_scale = 0;
|
||||
if (x->has_index()) {
|
||||
assert(x->index()->type()->tag() == intTag, "should not find non-int index");
|
||||
log2_scale = x->log2_scale();
|
||||
}
|
||||
|
||||
assert(!x->has_index() || idx.value() == x->index(), "should match");
|
||||
|
||||
LIR_Opr base_op = base.result();
|
||||
LIR_Opr index_op = idx.result();
|
||||
#ifndef _LP64
|
||||
if (x->base()->type()->tag() == longTag) {
|
||||
base_op = new_register(T_INT);
|
||||
__ convert(Bytecodes::_l2i, base.result(), base_op);
|
||||
} else {
|
||||
assert(x->base()->type()->tag() == intTag, "must be");
|
||||
}
|
||||
if (x->has_index()) {
|
||||
if (x->index()->type()->tag() == longTag) {
|
||||
LIR_Opr long_index_op = index_op;
|
||||
if (x->index()->type()->is_constant()) {
|
||||
long_index_op = new_register(T_LONG);
|
||||
__ move(index_op, long_index_op);
|
||||
}
|
||||
index_op = new_register(T_INT);
|
||||
__ convert(Bytecodes::_l2i, long_index_op, index_op);
|
||||
} else {
|
||||
assert(x->index()->type()->tag() == intTag, "must be");
|
||||
}
|
||||
}
|
||||
// At this point base and index should be all ints.
|
||||
assert(base_op->type() == T_INT && !base_op->is_constant(), "base should be an non-constant int");
|
||||
assert(!x->has_index() || index_op->type() == T_INT, "index should be an int");
|
||||
#else
|
||||
if (x->has_index()) {
|
||||
if (x->index()->type()->tag() == intTag) {
|
||||
if (!x->index()->type()->is_constant()) {
|
||||
index_op = new_register(T_LONG);
|
||||
__ convert(Bytecodes::_i2l, idx.result(), index_op);
|
||||
}
|
||||
} else {
|
||||
assert(x->index()->type()->tag() == longTag, "must be");
|
||||
if (x->index()->type()->is_constant()) {
|
||||
index_op = new_register(T_LONG);
|
||||
__ move(idx.result(), index_op);
|
||||
}
|
||||
}
|
||||
}
|
||||
// At this point base is a long non-constant
|
||||
// Index is a long register or a int constant.
|
||||
// We allow the constant to stay an int because that would allow us a more compact encoding by
|
||||
// embedding an immediate offset in the address expression. If we have a long constant, we have to
|
||||
// move it into a register first.
|
||||
assert(base_op->type() == T_LONG && !base_op->is_constant(), "base must be a long non-constant");
|
||||
assert(!x->has_index() || (index_op->type() == T_INT && index_op->is_constant()) ||
|
||||
(index_op->type() == T_LONG && !index_op->is_constant()), "unexpected index type");
|
||||
#endif
|
||||
|
||||
BasicType dst_type = x->basic_type();
|
||||
LIR_Opr index_op = idx.result();
|
||||
|
||||
LIR_Address* addr;
|
||||
if (index_op->is_constant()) {
|
||||
assert(log2_scale == 0, "must not have a scale");
|
||||
assert(index_op->type() == T_INT, "only int constants supported");
|
||||
addr = new LIR_Address(base_op, index_op->as_jint(), dst_type);
|
||||
} else {
|
||||
#ifdef X86
|
||||
#ifdef _LP64
|
||||
if (!index_op->is_illegal() && index_op->type() == T_INT) {
|
||||
LIR_Opr tmp = new_pointer_register();
|
||||
__ convert(Bytecodes::_i2l, index_op, tmp);
|
||||
index_op = tmp;
|
||||
}
|
||||
#endif
|
||||
addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type);
|
||||
#elif defined(ARM)
|
||||
addr = generate_address(base_op, index_op, log2_scale, 0, dst_type);
|
||||
#else
|
||||
if (index_op->is_illegal() || log2_scale == 0) {
|
||||
#ifdef _LP64
|
||||
if (!index_op->is_illegal() && index_op->type() == T_INT) {
|
||||
LIR_Opr tmp = new_pointer_register();
|
||||
__ convert(Bytecodes::_i2l, index_op, tmp);
|
||||
index_op = tmp;
|
||||
}
|
||||
#endif
|
||||
addr = new LIR_Address(base_op, index_op, dst_type);
|
||||
} else {
|
||||
LIR_Opr tmp = new_pointer_register();
|
||||
|
@ -2129,7 +2154,6 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) {
|
|||
BasicType type = x->basic_type();
|
||||
|
||||
if (x->has_index()) {
|
||||
assert(x->index()->type()->tag() == intTag, "should not find non-int index");
|
||||
log2_scale = x->log2_scale();
|
||||
}
|
||||
|
||||
|
@ -2152,38 +2176,39 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) {
|
|||
set_no_result(x);
|
||||
|
||||
LIR_Opr base_op = base.result();
|
||||
LIR_Opr index_op = idx.result();
|
||||
|
||||
#ifndef _LP64
|
||||
if (x->base()->type()->tag() == longTag) {
|
||||
base_op = new_register(T_INT);
|
||||
__ convert(Bytecodes::_l2i, base.result(), base_op);
|
||||
} else {
|
||||
assert(x->base()->type()->tag() == intTag, "must be");
|
||||
}
|
||||
if (x->has_index()) {
|
||||
if (x->index()->type()->tag() == longTag) {
|
||||
index_op = new_register(T_INT);
|
||||
__ convert(Bytecodes::_l2i, idx.result(), index_op);
|
||||
}
|
||||
}
|
||||
// At this point base and index should be all ints and not constants
|
||||
assert(base_op->type() == T_INT && !base_op->is_constant(), "base should be an non-constant int");
|
||||
assert(!x->has_index() || (index_op->type() == T_INT && !index_op->is_constant()), "index should be an non-constant int");
|
||||
#else
|
||||
if (x->has_index()) {
|
||||
if (x->index()->type()->tag() == intTag) {
|
||||
index_op = new_register(T_LONG);
|
||||
__ convert(Bytecodes::_i2l, idx.result(), index_op);
|
||||
}
|
||||
}
|
||||
// At this point base and index are long and non-constant
|
||||
assert(base_op->type() == T_LONG && !base_op->is_constant(), "base must be a non-constant long");
|
||||
assert(!x->has_index() || (index_op->type() == T_LONG && !index_op->is_constant()), "index must be a non-constant long");
|
||||
#endif
|
||||
|
||||
LIR_Opr index_op = idx.result();
|
||||
if (log2_scale != 0) {
|
||||
// temporary fix (platform dependent code without shift on Intel would be better)
|
||||
index_op = new_pointer_register();
|
||||
#ifdef _LP64
|
||||
if(idx.result()->type() == T_INT) {
|
||||
__ convert(Bytecodes::_i2l, idx.result(), index_op);
|
||||
} else {
|
||||
#endif
|
||||
// TODO: ARM also allows embedded shift in the address
|
||||
__ move(idx.result(), index_op);
|
||||
#ifdef _LP64
|
||||
}
|
||||
#endif
|
||||
// TODO: ARM also allows embedded shift in the address
|
||||
__ shift_left(index_op, log2_scale, index_op);
|
||||
}
|
||||
#ifdef _LP64
|
||||
else if(!index_op->is_illegal() && index_op->type() == T_INT) {
|
||||
LIR_Opr tmp = new_pointer_register();
|
||||
__ convert(Bytecodes::_i2l, index_op, tmp);
|
||||
index_op = tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type());
|
||||
__ move(value.result(), addr);
|
||||
|
|
|
@ -68,6 +68,15 @@ class frame VALUE_OBJ_CLASS_SPEC {
|
|||
// Constructors
|
||||
frame();
|
||||
|
||||
#ifndef PRODUCT
|
||||
// This is a generic constructor which is only used by pns() in debug.cpp.
|
||||
// pns (i.e. print native stack) uses this constructor to create a starting
|
||||
// frame for stack walking. The implementation of this constructor is platform
|
||||
// dependent (i.e. SPARC doesn't need an 'fp' argument an will ignore it) but
|
||||
// we want to keep the signature generic because pns() is shared code.
|
||||
frame(void* sp, void* fp, void* pc);
|
||||
#endif
|
||||
|
||||
// Accessors
|
||||
|
||||
// pc: Returns the pc at which this frame will continue normally.
|
||||
|
|
|
@ -653,6 +653,13 @@ void help() {
|
|||
tty->print_cr(" pm(int pc) - print Method* given compiled PC");
|
||||
tty->print_cr(" findm(intptr_t pc) - finds Method*");
|
||||
tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
|
||||
tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g.");
|
||||
tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or");
|
||||
tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or");
|
||||
tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or");
|
||||
tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC");
|
||||
tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()");
|
||||
tty->print_cr(" - in dbx do 'frame 1' before calling pns()");
|
||||
|
||||
tty->print_cr("misc.");
|
||||
tty->print_cr(" flush() - flushes the log file");
|
||||
|
@ -665,3 +672,56 @@ void help() {
|
|||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
||||
void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size) {
|
||||
|
||||
// see if it's a valid frame
|
||||
if (fr.pc()) {
|
||||
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
|
||||
|
||||
int count = 0;
|
||||
while (count++ < StackPrintLimit) {
|
||||
fr.print_on_error(st, buf, buf_size);
|
||||
st->cr();
|
||||
// Compiled code may use EBP register on x86 so it looks like
|
||||
// non-walkable C frame. Use frame.sender() for java frames.
|
||||
if (t && t->is_Java_thread()) {
|
||||
// Catch very first native frame by using stack address.
|
||||
// For JavaThread stack_base and stack_size should be set.
|
||||
if (!t->on_local_stack((address)(fr.real_fp() + 1))) {
|
||||
break;
|
||||
}
|
||||
if (fr.is_java_frame() || fr.is_native_frame() || fr.is_runtime_frame()) {
|
||||
RegisterMap map((JavaThread*)t, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > StackPrintLimit) {
|
||||
st->print_cr("...<more frames>...");
|
||||
}
|
||||
|
||||
st->cr();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
||||
extern "C" void pns(void* sp, void* fp, void* pc) { // print native stack
|
||||
Command c("pns");
|
||||
static char buf[O_BUFLEN];
|
||||
Thread* t = ThreadLocalStorage::get_thread_slow();
|
||||
// Call generic frame constructor (certain arguments may be ignored)
|
||||
frame fr(sp, fp, pc);
|
||||
print_native_stack(tty, fr, t, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
#endif // !PRODUCT
|
||||
|
|
|
@ -263,4 +263,7 @@ NOT_PRODUCT(void test_error_handler();)
|
|||
void pd_ps(frame f);
|
||||
void pd_obfuscate_location(char *buf, size_t buflen);
|
||||
|
||||
class outputStream;
|
||||
void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int buf_size);
|
||||
|
||||
#endif // SHARE_VM_UTILITIES_DEBUG_HPP
|
||||
|
|
|
@ -577,7 +577,7 @@ void VMError::report(outputStream* st) {
|
|||
|
||||
STEP(120, "(printing native stack)" )
|
||||
|
||||
if (_verbose) {
|
||||
if (_verbose) {
|
||||
if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) {
|
||||
// We have printed the native stack in platform-specific code
|
||||
// Windows/x64 needs special handling.
|
||||
|
@ -585,43 +585,7 @@ void VMError::report(outputStream* st) {
|
|||
frame fr = _context ? os::fetch_frame_from_context(_context)
|
||||
: os::current_frame();
|
||||
|
||||
// see if it's a valid frame
|
||||
if (fr.pc()) {
|
||||
st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
|
||||
|
||||
|
||||
int count = 0;
|
||||
while (count++ < StackPrintLimit) {
|
||||
fr.print_on_error(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
// Compiled code may use EBP register on x86 so it looks like
|
||||
// non-walkable C frame. Use frame.sender() for java frames.
|
||||
if (_thread && _thread->is_Java_thread()) {
|
||||
// Catch very first native frame by using stack address.
|
||||
// For JavaThread stack_base and stack_size should be set.
|
||||
if (!_thread->on_local_stack((address)(fr.sender_sp() + 1))) {
|
||||
break;
|
||||
}
|
||||
if (fr.is_java_frame()) {
|
||||
RegisterMap map((JavaThread*)_thread, false); // No update
|
||||
fr = fr.sender(&map);
|
||||
} else {
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
} else {
|
||||
// is_first_C_frame() does only simple checks for frame pointer,
|
||||
// it will pass if java compiled code has a pointer in EBP.
|
||||
if (os::is_first_C_frame(&fr)) break;
|
||||
fr = os::get_sender_for_C_frame(&fr);
|
||||
}
|
||||
}
|
||||
|
||||
if (count > StackPrintLimit) {
|
||||
st->print_cr("...<more frames>...");
|
||||
}
|
||||
|
||||
st->cr();
|
||||
}
|
||||
print_native_stack(st, fr, _thread, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
140
hotspot/test/compiler/unsafe/UnsafeRaw.java
Normal file
140
hotspot/test/compiler/unsafe/UnsafeRaw.java
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8058744
|
||||
* @summary Invalid pattern-matching of address computations in raw unsafe
|
||||
* @library /testlibrary
|
||||
* @run main/othervm -Xbatch UnsafeRaw
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.Utils;
|
||||
import java.util.Random;
|
||||
|
||||
public class UnsafeRaw {
|
||||
public static class Tests {
|
||||
public static int int_index(sun.misc.Unsafe unsafe, long base, int index) throws Exception {
|
||||
return unsafe.getInt(base + (index << 2));
|
||||
}
|
||||
public static int long_index(sun.misc.Unsafe unsafe, long base, long index) throws Exception {
|
||||
return unsafe.getInt(base + (index << 2));
|
||||
}
|
||||
public static int int_index_back_ashift(sun.misc.Unsafe unsafe, long base, int index) throws Exception {
|
||||
return unsafe.getInt(base + (index >> 2));
|
||||
}
|
||||
public static int int_index_back_lshift(sun.misc.Unsafe unsafe, long base, int index) throws Exception {
|
||||
return unsafe.getInt(base + (index >>> 2));
|
||||
}
|
||||
public static int long_index_back_ashift(sun.misc.Unsafe unsafe, long base, long index) throws Exception {
|
||||
return unsafe.getInt(base + (index >> 2));
|
||||
}
|
||||
public static int long_index_back_lshift(sun.misc.Unsafe unsafe, long base, long index) throws Exception {
|
||||
return unsafe.getInt(base + (index >>> 2));
|
||||
}
|
||||
public static int int_const_12345678_index(sun.misc.Unsafe unsafe, long base) throws Exception {
|
||||
int idx4 = 0x12345678;
|
||||
return unsafe.getInt(base + idx4);
|
||||
}
|
||||
public static int long_const_1234567890abcdef_index(sun.misc.Unsafe unsafe, long base) throws Exception {
|
||||
long idx5 = 0x1234567890abcdefL;
|
||||
return unsafe.getInt(base + idx5);
|
||||
}
|
||||
public static int int_index_mul(sun.misc.Unsafe unsafe, long base, int index) throws Exception {
|
||||
return unsafe.getInt(base + (index * 4));
|
||||
}
|
||||
public static int long_index_mul(sun.misc.Unsafe unsafe, long base, long index) throws Exception {
|
||||
return unsafe.getInt(base + (index * 4));
|
||||
}
|
||||
public static int int_index_mul_scale_16(sun.misc.Unsafe unsafe, long base, int index) throws Exception {
|
||||
return unsafe.getInt(base + (index * 16));
|
||||
}
|
||||
public static int long_index_mul_scale_16(sun.misc.Unsafe unsafe, long base, long index) throws Exception {
|
||||
return unsafe.getInt(base + (index * 16));
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
sun.misc.Unsafe unsafe = Utils.getUnsafe();
|
||||
final int array_size = 128;
|
||||
final int element_size = 4;
|
||||
final int magic = 0x12345678;
|
||||
|
||||
Random rnd = new Random();
|
||||
|
||||
long array = unsafe.allocateMemory(array_size * element_size); // 128 ints
|
||||
long addr = array + array_size * element_size / 2; // something in the middle to work with
|
||||
unsafe.putInt(addr, magic);
|
||||
for (int j = 0; j < 100000; j++) {
|
||||
if (Tests.int_index(unsafe, addr, 0) != magic) throw new Exception();
|
||||
if (Tests.long_index(unsafe, addr, 0) != magic) throw new Exception();
|
||||
if (Tests.int_index_mul(unsafe, addr, 0) != magic) throw new Exception();
|
||||
if (Tests.long_index_mul(unsafe, addr, 0) != magic) throw new Exception();
|
||||
{
|
||||
long idx1 = rnd.nextLong();
|
||||
long addr1 = addr - (idx1 << 2);
|
||||
if (Tests.long_index(unsafe, addr1, idx1) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
long idx2 = rnd.nextLong();
|
||||
long addr2 = addr - (idx2 >> 2);
|
||||
if (Tests.long_index_back_ashift(unsafe, addr2, idx2) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
long idx3 = rnd.nextLong();
|
||||
long addr3 = addr - (idx3 >>> 2);
|
||||
if (Tests.long_index_back_lshift(unsafe, addr3, idx3) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
long idx4 = 0x12345678;
|
||||
long addr4 = addr - idx4;
|
||||
if (Tests.int_const_12345678_index(unsafe, addr4) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
long idx5 = 0x1234567890abcdefL;
|
||||
long addr5 = addr - idx5;
|
||||
if (Tests.long_const_1234567890abcdef_index(unsafe, addr5) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
int idx6 = rnd.nextInt();
|
||||
long addr6 = addr - (idx6 >> 2);
|
||||
if (Tests.int_index_back_ashift(unsafe, addr6, idx6) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
int idx7 = rnd.nextInt();
|
||||
long addr7 = addr - (idx7 >>> 2);
|
||||
if (Tests.int_index_back_lshift(unsafe, addr7, idx7) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
int idx8 = rnd.nextInt();
|
||||
long addr8 = addr - (idx8 * 16);
|
||||
if (Tests.int_index_mul_scale_16(unsafe, addr8, idx8) != magic) throw new Exception();
|
||||
}
|
||||
{
|
||||
long idx9 = rnd.nextLong();
|
||||
long addr9 = addr - (idx9 * 16);
|
||||
if (Tests.long_index_mul_scale_16(unsafe, addr9, idx9) != magic) throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue