bytecodeTracer.cpp revision 1522
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "incls/_precompiled.incl"
#include "incls/_bytecodeTracer.cpp.incl"
#ifndef PRODUCT
// Standard closure for BytecodeTracer: prints the current bytecode
// and its attributes using bytecode-specific information.
class BytecodePrinter: public BytecodeClosure {
private:
// %%% This field is not GC-ed, and so can contain garbage
// between critical sections. Use only pointer-comparison
// operations on the pointer, except within a critical section.
// (Also, ensure that occasional false positives are benign.)
bool _is_wide;
int get_index_u2_cpcache() { int i=Bytes::get_native_u2(_next_pc); _next_pc+=2; return i + constantPoolOopDesc::CPCACHE_INDEX_TAG; }
public:
BytecodePrinter() {
_is_wide = false;
}
// This method is called while executing the raw bytecodes, so none of
// the adjustments that BytecodeStream performs applies.
if (_current_method != method()) {
// Need an explicit lock or a different solution.
// It is possible for this block to be skipped, if a garbage
// _current_method pointer happens to have the same bits as
// the incoming method. We could lose a line of trace output.
// This is acceptable in a debug-only feature.
_current_method = method();
}
if (is_wide()) {
// bcp wasn't advanced if previous bytecode was _wide.
} else {
}
if (Verbose) {
} else {
}
// Set is_wide for the next one, since the caller of this doesn't skip
// the next bytecode.
}
// Used for methodOop::print_codes(). The input bcp comes from
// BytecodeStream, which will skip wide bytecodes.
_current_method = method();
// Set is_wide
if (is_wide()) {
}
// Print bytecode index and name
if (is_wide()) {
} else {
}
}
};
// Implementation of BytecodeTracer
// %%% This set_closure thing seems overly general, given that
// nobody uses it. Also, if BytecodePrinter weren't hidden
// then methodOop could use instances of it directly and it
// would be easier to remove races on _current_method and bcp.
// Since this is not product functionality, we can defer cleanup.
static BytecodePrinter std_closure;
return &::std_closure;
}
void BytecodeTracer::trace(methodHandle method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) {
// The ttyLocker also prevents races between two threads
// trying to use the single instance of BytecodePrinter.
// Using the ttyLocker prevents the system from coming to
// a safepoint within this code, which is sensitive to methodOop
// movement.
//
// There used to be a leaf mutex here, but the ttyLocker will
// work just as well, as long as the printing operations never block.
//
// We put the locker on the static trace method, not the
// virtual one, because the clients of this module go through
// the static method.
}
}
}
char buf[40];
} else {
}
}
} else {
}
}
//climit = cache->length(); // %%% private!
size -= sizeof(constantPoolCacheOopDesc);
size /= sizeof(ConstantPoolCacheEntry);
}
}
if (i >= 0 && i < climit) {
return false;
}
goto check_cache_index;
} else {
return false;
}
}
goto check_cache_index;
}
if (i >= 0 && i < ilimit) {
cp_index = i;
return true;
}
return false;
#ifdef ASSERT
{
i -= CPCACHE_INDEX_TAG;
} else {
return false;
}
}
#endif //ASSERT
if (i >= 0 && i < climit) {
return false;
}
goto check_cp_index;
}
return false;
}
int orig_i = i;
} else if (tag.is_unresolved_string()) {
} else if (tag.is_unresolved_klass()) {
} else if (tag.is_method_type()) {
} else if (tag.is_method_handle()) {
} else {
}
}
int orig_i = i;
}
int nt_index = -1;
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_NameAndType:
break;
default:
return;
}
st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string());
}
// Show attributes of pre-rewritten codes
// If the code doesn't have any fields there's nothing to print.
// note this is ==1 because the tableswitch and lookupswitch are
// zero size (for some reason) and we want to print stuff out for them.
return;
}
switch(code) {
// Java specific bytecodes only matter.
break;
break;
} else {
}
break;
} else {
}
break;
break;
{ int index = get_index_special();
}
break;
assert(false, "Unidentified basic type");
}
}
break;
case Bytecodes::_anewarray: {
int klass_index = get_index_u2();
}
break;
case Bytecodes::_multianewarray: {
int klass_index = get_index_u2();
int nof_dims = get_index_u1();
}
break;
case Bytecodes::_ifnonnull:
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
break;
break;
case Bytecodes::_tableswitch:
{ align();
for (int i = 0; i < len; i++) {
}
int first = true;
}
}
break;
case Bytecodes::_lookupswitch:
{ align();
for (int i = 0; i < len; i++) {
};
bool first = true;
}
}
break;
case Bytecodes::_putstatic:
case Bytecodes::_getstatic:
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
break;
case Bytecodes::_invokeinterface:
{ int i = get_index_u2_cpcache();
int n = get_index_u1();
get_byte(); // ignore zero byte
print_field_or_method(i, st);
}
break;
case Bytecodes::_invokedynamic:
break;
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
{ int i = get_index_u2();
}
break;
// length is zero not one, but printed with no more info.
break;
default:
break;
}
}
}
}
}
#endif // PRODUCT