This commit is contained in:
Niclas Adlertz 2014-09-25 23:37:41 +02:00
commit a15b864ec9
15 changed files with 396 additions and 123 deletions

View file

@ -308,3 +308,10 @@ intptr_t *frame::initial_deoptimization_info() {
// unused... but returns fp() to minimize changes introduced by 7087445 // unused... but returns fp() to minimize changes introduced by 7087445
return fp(); 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

View file

@ -343,7 +343,7 @@ bool frame::safe_for_sender(JavaThread *thread) {
// constructors // constructors
// Construct an unpatchable, deficient frame // 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 #ifdef _LP64
assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp"); assert( (((intptr_t)sp & (wordSize-1)) == 0), "frame constructor passed an invalid sp");
#endif #endif
@ -365,6 +365,10 @@ frame::frame(intptr_t* sp, unpatchable_t, address pc, CodeBlob* cb) {
#endif // ASSERT #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) : frame::frame(intptr_t* sp, intptr_t* younger_sp, bool younger_frame_is_interpreted) :
_sp(sp), _sp(sp),
_younger_sp(younger_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 { bool frame::is_interpreted_frame() const {
return Interpreter::contains(pc()); return Interpreter::contains(pc());
} }

View file

@ -163,6 +163,8 @@
enum unpatchable_t { unpatchable }; enum unpatchable_t { unpatchable };
frame(intptr_t* sp, unpatchable_t, address pc = NULL, CodeBlob* cb = NULL); 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 // 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). // (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. // Register windows are assumed to be flushed for the stack in question.

View file

@ -715,3 +715,10 @@ intptr_t* frame::real_fp() const {
assert(! is_compiled_frame(), "unknown compiled frame size"); assert(! is_compiled_frame(), "unknown compiled frame size");
return fp(); 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

View file

@ -187,6 +187,8 @@
frame(intptr_t* sp, intptr_t* fp); frame(intptr_t* sp, intptr_t* fp);
void init(intptr_t* sp, intptr_t* fp, address pc);
// accessors for the instance variables // accessors for the instance variables
// Note: not necessarily the real 'frame pointer' (see real_fp) // Note: not necessarily the real 'frame pointer' (see real_fp)
intptr_t* fp() const { return _fp; } intptr_t* fp() const { return _fp; }

View file

@ -41,7 +41,7 @@ inline frame::frame() {
_deopt_state = unknown; _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; _sp = sp;
_unextended_sp = sp; _unextended_sp = sp;
_fp = fp; _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) { inline frame::frame(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, address pc) {
_sp = sp; _sp = sp;
_unextended_sp = unextended_sp; _unextended_sp = unextended_sp;

View file

@ -438,3 +438,10 @@ intptr_t *frame::initial_deoptimization_info() {
// unused... but returns fp() to minimize changes introduced by 7087445 // unused... but returns fp() to minimize changes introduced by 7087445
return fp(); 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

View file

@ -265,7 +265,7 @@ frame os::current_frame() {
CAST_FROM_FN_PTR(address, os::current_frame)); CAST_FROM_FN_PTR(address, os::current_frame));
if (os::is_first_C_frame(&myframe)) { if (os::is_first_C_frame(&myframe)) {
// stack is not walkable // stack is not walkable
return frame(NULL, NULL, NULL); return frame(NULL, NULL, false);
} else { } else {
return os::get_sender_for_C_frame(&myframe); return os::get_sender_for_C_frame(&myframe);
} }

View file

@ -327,7 +327,7 @@ void Canonicalizer::do_ShiftOp (ShiftOp* x) {
if (t2->is_constant()) { if (t2->is_constant()) {
switch (t2->tag()) { switch (t2->tag()) {
case intTag : if (t2->as_IntConstant()->value() == 0) set_canonical(x->x()); return; 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(); default : ShouldNotReachHere();
} }
} }
@ -808,28 +808,41 @@ void Canonicalizer::do_ExceptionObject(ExceptionObject* x) {}
static bool match_index_and_scale(Instruction* instr, static bool match_index_and_scale(Instruction* instr,
Instruction** index, Instruction** index,
int* log2_scale, int* log2_scale) {
Instruction** instr_to_unpin) { // Skip conversion ops. This works only on 32bit because of the implicit l2i that the
*instr_to_unpin = NULL; // unsafe performs.
#ifndef _LP64
// Skip conversion ops
Convert* convert = instr->as_Convert(); 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(); instr = convert->value();
} }
#endif
ShiftOp* shift = instr->as_ShiftOp(); ShiftOp* shift = instr->as_ShiftOp();
if (shift != NULL) { if (shift != NULL) {
if (shift->is_pinned()) { if (shift->op() == Bytecodes::_lshl) {
*instr_to_unpin = shift; 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 shift value?
Constant* con = shift->y()->as_Constant(); Constant* con = shift->y()->as_Constant();
if (con == NULL) return false; if (con == NULL) return false;
// Well-known type and value? // Well-known type and value?
IntConstant* val = con->type()->as_IntConstant(); IntConstant* val = con->type()->as_IntConstant();
if (val == NULL) return false; assert(val != NULL, "Should be an int constant");
if (shift->x()->type() != intType) return false;
*index = shift->x(); *index = shift->x();
int tmp_scale = val->value(); int tmp_scale = val->value();
if (tmp_scale >= 0 && tmp_scale < 4) { if (tmp_scale >= 0 && tmp_scale < 4) {
@ -842,31 +855,42 @@ static bool match_index_and_scale(Instruction* instr,
ArithmeticOp* arith = instr->as_ArithmeticOp(); ArithmeticOp* arith = instr->as_ArithmeticOp();
if (arith != NULL) { if (arith != NULL) {
if (arith->is_pinned()) { // See if either arg is a known constant
*instr_to_unpin = arith; 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 // Check for integer multiply
if (arith->op() == Bytecodes::_imul) { if (arith->op() == Bytecodes::_lmul) {
// See if either arg is a known constant assert((*index)->type() == longType, "invalid input type");
Constant* con = arith->x()->as_Constant(); LongConstant* val = con->type()->as_LongConstant();
if (con != NULL) { assert(val != NULL, "expecting a long constant");
*index = arith->y(); 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 { } else {
con = arith->y()->as_Constant(); return false;
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;
} }
#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** base,
Instruction** index, Instruction** index,
int* log2_scale) { int* log2_scale) {
Instruction* instr_to_unpin = NULL;
ArithmeticOp* root = x->base()->as_ArithmeticOp(); ArithmeticOp* root = x->base()->as_ArithmeticOp();
if (root == NULL) return false; if (root == NULL) return false;
// Limit ourselves to addition for now // Limit ourselves to addition for now
if (root->op() != Bytecodes::_ladd) return false; if (root->op() != Bytecodes::_ladd) return false;
bool match_found = false;
// Try to find shift or scale op // 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(); *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(); *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(); 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 // pick base and index, setting scale at 1
*base = root->x(); *base = root->x();
*index = convert->value(); *index = convert->value();
*log2_scale = 0; *log2_scale = 0;
} else { match_found = true;
return false;
} }
} else { }
// doesn't match any expected sequences // The default solution
return false; 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 // If the value is pinned then it will be always be computed so

View file

@ -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) { void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) {
LIRItem base(x->base(), this); LIRItem base(x->base(), this);
LIRItem idx(this); LIRItem idx(this);
@ -2059,50 +2061,73 @@ void LIRGenerator::do_UnsafeGetRaw(UnsafeGetRaw* x) {
int log2_scale = 0; int log2_scale = 0;
if (x->has_index()) { if (x->has_index()) {
assert(x->index()->type()->tag() == intTag, "should not find non-int index");
log2_scale = x->log2_scale(); log2_scale = x->log2_scale();
} }
assert(!x->has_index() || idx.value() == x->index(), "should match"); assert(!x->has_index() || idx.value() == x->index(), "should match");
LIR_Opr base_op = base.result(); LIR_Opr base_op = base.result();
LIR_Opr index_op = idx.result();
#ifndef _LP64 #ifndef _LP64
if (x->base()->type()->tag() == longTag) { if (x->base()->type()->tag() == longTag) {
base_op = new_register(T_INT); base_op = new_register(T_INT);
__ convert(Bytecodes::_l2i, base.result(), base_op); __ 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 #endif
BasicType dst_type = x->basic_type(); BasicType dst_type = x->basic_type();
LIR_Opr index_op = idx.result();
LIR_Address* addr; LIR_Address* addr;
if (index_op->is_constant()) { if (index_op->is_constant()) {
assert(log2_scale == 0, "must not have a scale"); 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); addr = new LIR_Address(base_op, index_op->as_jint(), dst_type);
} else { } else {
#ifdef X86 #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); addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type);
#elif defined(ARM) #elif defined(ARM)
addr = generate_address(base_op, index_op, log2_scale, 0, dst_type); addr = generate_address(base_op, index_op, log2_scale, 0, dst_type);
#else #else
if (index_op->is_illegal() || log2_scale == 0) { 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); addr = new LIR_Address(base_op, index_op, dst_type);
} else { } else {
LIR_Opr tmp = new_pointer_register(); LIR_Opr tmp = new_pointer_register();
@ -2129,7 +2154,6 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) {
BasicType type = x->basic_type(); BasicType type = x->basic_type();
if (x->has_index()) { if (x->has_index()) {
assert(x->index()->type()->tag() == intTag, "should not find non-int index");
log2_scale = x->log2_scale(); log2_scale = x->log2_scale();
} }
@ -2152,38 +2176,39 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) {
set_no_result(x); set_no_result(x);
LIR_Opr base_op = base.result(); LIR_Opr base_op = base.result();
LIR_Opr index_op = idx.result();
#ifndef _LP64 #ifndef _LP64
if (x->base()->type()->tag() == longTag) { if (x->base()->type()->tag() == longTag) {
base_op = new_register(T_INT); base_op = new_register(T_INT);
__ convert(Bytecodes::_l2i, base.result(), base_op); __ 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 #endif
LIR_Opr index_op = idx.result();
if (log2_scale != 0) { if (log2_scale != 0) {
// temporary fix (platform dependent code without shift on Intel would be better) // temporary fix (platform dependent code without shift on Intel would be better)
index_op = new_pointer_register(); // TODO: ARM also allows embedded shift in the address
#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
__ shift_left(index_op, log2_scale, index_op); __ 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()); LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type());
__ move(value.result(), addr); __ move(value.result(), addr);

View file

@ -68,6 +68,15 @@ class frame VALUE_OBJ_CLASS_SPEC {
// Constructors // Constructors
frame(); 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 // Accessors
// pc: Returns the pc at which this frame will continue normally. // pc: Returns the pc at which this frame will continue normally.

View file

@ -653,6 +653,13 @@ void help() {
tty->print_cr(" pm(int pc) - print Method* given compiled PC"); tty->print_cr(" pm(int pc) - print Method* given compiled PC");
tty->print_cr(" findm(intptr_t pc) - finds Method*"); 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(" 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("misc.");
tty->print_cr(" flush() - flushes the log file"); tty->print_cr(" flush() - flushes the log file");
@ -665,3 +672,56 @@ void help() {
} }
#endif // !PRODUCT #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

View file

@ -263,4 +263,7 @@ NOT_PRODUCT(void test_error_handler();)
void pd_ps(frame f); void pd_ps(frame f);
void pd_obfuscate_location(char *buf, size_t buflen); 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 #endif // SHARE_VM_UTILITIES_DEBUG_HPP

View file

@ -577,7 +577,7 @@ void VMError::report(outputStream* st) {
STEP(120, "(printing native stack)" ) STEP(120, "(printing native stack)" )
if (_verbose) { if (_verbose) {
if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) { if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) {
// We have printed the native stack in platform-specific code // We have printed the native stack in platform-specific code
// Windows/x64 needs special handling. // Windows/x64 needs special handling.
@ -585,43 +585,7 @@ void VMError::report(outputStream* st) {
frame fr = _context ? os::fetch_frame_from_context(_context) frame fr = _context ? os::fetch_frame_from_context(_context)
: os::current_frame(); : os::current_frame();
// see if it's a valid frame print_native_stack(st, fr, _thread, buf, sizeof(buf));
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();
}
} }
} }

View 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();
}
}
}
}