class external_word_Relocation : public DataRelocation {
relocInfo::relocType type() { return relocInfo::external_word_type; }
public:
static RelocationHolder spec(address target) {
assert(target != NULL, "must not be null");
RelocationHolder rh = newHolder();
new(rh) external_word_Relocation(target);
return rh;
}
static RelocationHolder spec_for_immediate() {
RelocationHolder rh = newHolder();
new(rh) external_word_Relocation(NULL);
return rh;
}
static bool can_be_relocated(address target) {
return target != NULL && !is_reloc_index((intptr_t)target);
}
private:
address _target; // address in runtime
external_word_Relocation(address target) {
_target = target;
}
friend class RelocIterator;
external_word_Relocation() { }
public:
void pack_data_to(CodeSection* dest);
void unpack_data();
void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest);
address target(); // if _target==NULL, fetch addr from code stream
address value() { return target(); }
};
class internal_word_Relocation : public DataRelocation {
relocInfo::relocType type() { return relocInfo::internal_word_type; }
public:
static RelocationHolder spec(address target) {
assert(target != NULL, "must not be null");
RelocationHolder rh = newHolder();
new(rh) internal_word_Relocation(target);
return rh;
}
static RelocationHolder spec_for_immediate() {
RelocationHolder rh = newHolder();
new(rh) internal_word_Relocation(NULL);
return rh;
}
internal_word_Relocation(address target) {
_target = target;
_section = -1; // self-relative
}
protected:
address _target; // address in CodeBlob
int _section; // section providing base address, if any
friend class RelocIterator;
internal_word_Relocation() { }
enum { section_width = 2 }; // must equal CodeBuffer::sect_bits
public:
void pack_data_to(CodeSection* dest);
void unpack_data();
void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest);
address target(); // if _target==NULL, fetch addr from code stream
int section() { return _section; }
address value() { return target(); }
};
class section_word_Relocation : public internal_word_Relocation {
relocInfo::relocType type() { return relocInfo::section_word_type; }
public:
static RelocationHolder spec(address target, int section) {
RelocationHolder rh = newHolder();
new(rh) section_word_Relocation(target, section);
return rh;
}
section_word_Relocation(address target, int section) {
assert(target != NULL, "must not be null");
assert(section >= 0, "must be a valid section");
_target = target;
_section = section;
}
void unpack_data();
private:
friend class RelocIterator;
section_word_Relocation() { }
};
class poll_Relocation : public Relocation {
bool is_data() { return true; }
relocInfo::relocType type() { return relocInfo::poll_type; }
void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest);
};
class poll_return_Relocation : public Relocation {
bool is_data() { return true; }
relocInfo::relocType type() { return relocInfo::poll_return_type; }
void fix_relocation_after_move(const CodeBuffer* src, CodeBuffer* dest);
};
#define EACH_CASE(name) \
inline name##_Relocation* RelocIterator::name##_reloc() { \
assert(type() == relocInfo::name##_type, "type must agree"); \
name##_Relocation* r = new(_rh) name##_Relocation(); \
r->set_binding(this); \
r->name##_Relocation::unpack_data(); \
return r; \
}
APPLY_TO_RELOCATIONS(EACH_CASE);
#undef EACH_CASE
inline RelocIterator::RelocIterator(nmethod* nm, address begin, address limit) {
initialize(nm, begin, limit);
}
#endif // SHARE_VM_CODE_RELOCINFO_HPP
C:\hotspot-69087d08d473\src\share\vm/code/scopeDesc.cpp
#include "precompiled.hpp"
#include "code/debugInfoRec.hpp"
#include "code/pcDesc.hpp"
#include "code/scopeDesc.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(obj_decode_offset);
_reexecute = reexecute;
_return_oop = return_oop;
decode_body();
}
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(DebugInformationRecorder::serialized_null);
_reexecute = reexecute;
_return_oop = return_oop;
decode_body();
}
ScopeDesc::ScopeDesc(const ScopeDesc* parent) {
_code = parent->_code;
_decode_offset = parent->_sender_decode_offset;
_objects = parent->_objects;
_reexecute = false; //reexecute only applies to the first scope
_return_oop = false;
decode_body();
}
void ScopeDesc::decode_body() {
if (decode_offset() == DebugInformationRecorder::serialized_null) {
_sender_decode_offset = DebugInformationRecorder::serialized_null;
_method = _code->method();
_bci = InvocationEntryBci;
_locals_decode_offset = DebugInformationRecorder::serialized_null;
_expressions_decode_offset = DebugInformationRecorder::serialized_null;
_monitors_decode_offset = DebugInformationRecorder::serialized_null;
} else {
DebugInfoReadStream* stream = stream_at(decode_offset());
_sender_decode_offset = stream->read_int();
_method = stream->read_method();
_bci = stream->read_bci();
_locals_decode_offset = stream->read_int();
_expressions_decode_offset = stream->read_int();
_monitors_decode_offset = stream->read_int();
}
}
GrowableArray<ScopeValue*>* ScopeDesc::decode_scope_values(int decode_offset) {
if (decode_offset == DebugInformationRecorder::serialized_null) return NULL;
DebugInfoReadStream* stream = stream_at(decode_offset);
int length = stream->read_int();
GrowableArray<ScopeValue*>* result = new GrowableArray<ScopeValue*> (length);
for (int index = 0; index < length; index++) {
result->push(ScopeValue::read_from(stream));
}
return result;
}
GrowableArray<ScopeValue*>* ScopeDesc::decode_object_values(int decode_offset) {
if (decode_offset == DebugInformationRecorder::serialized_null) return NULL;
GrowableArray<ScopeValue*>* result = new GrowableArray<ScopeValue*>();
DebugInfoReadStream* stream = new DebugInfoReadStream(_code, decode_offset, result);
int length = stream->read_int();
for (int index = 0; index < length; index++) {
(void)ScopeValue::read_from(stream);
}
assert(result->length() == length, "inconsistent debug information");
return result;
}
GrowableArray<MonitorValue*>* ScopeDesc::decode_monitor_values(int decode_offset) {
if (decode_offset == DebugInformationRecorder::serialized_null) return NULL;
DebugInfoReadStream* stream = stream_at(decode_offset);
int length = stream->read_int();
GrowableArray<MonitorValue*>* result = new GrowableArray<MonitorValue*> (length);
for (int index = 0; index < length; index++) {
result->push(new MonitorValue(stream));
}
return result;
}
DebugInfoReadStream* ScopeDesc::stream_at(int decode_offset) const {
return new DebugInfoReadStream(_code, decode_offset, _objects);
}
GrowableArray<ScopeValue*>* ScopeDesc::locals() {
return decode_scope_values(_locals_decode_offset);
}
GrowableArray<ScopeValue*>* ScopeDesc::expressions() {
return decode_scope_values(_expressions_decode_offset);
}
GrowableArray<MonitorValue*>* ScopeDesc::monitors() {
return decode_monitor_values(_monitors_decode_offset);
}
GrowableArray<ScopeValue*>* ScopeDesc::objects() {
return _objects;
}
bool ScopeDesc::is_top() const {
return _sender_decode_offset == DebugInformationRecorder::serialized_null;
}
ScopeDesc* ScopeDesc::sender() const {
if (is_top()) return NULL;
return new ScopeDesc(this);
}
#ifndef PRODUCT
void ScopeDesc::print_value_on(outputStream* st) const {
tty->print(" ");
method()->print_short_name(st);
int lineno = method()->line_number_from_bci(bci());
if (lineno != -1) {
st->print_cr("@%d (line %d)", bci(), lineno);
} else {
st->print_cr("@%d", bci());
}
}
void ScopeDesc::print_on(outputStream* st) const {
print_on(st, NULL);
}
void ScopeDesc::print_on(outputStream* st, PcDesc* pd) const {
if (pd != NULL) {
tty->print_cr("ScopeDesc(pc=" PTR_FORMAT " offset=%x):", pd->real_pc(_code), pd->pc_offset());
}
print_value_on(st);
if (WizardMode) {
st->print("ScopeDesc[%d]@" PTR_FORMAT " ", _decode_offset, _code->content_begin());
st->print_cr(" offset: %d", _decode_offset);
st->print_cr(" bci: %d", bci());
st->print_cr(" reexecute: %s", should_reexecute() ? "true" : "false");
st->print_cr(" locals: %d", _locals_decode_offset);
st->print_cr(" stack: %d", _expressions_decode_offset);
st->print_cr(" monitor: %d", _monitors_decode_offset);
st->print_cr(" sender: %d", _sender_decode_offset);
}
{ GrowableArray<ScopeValue*>* l = ((ScopeDesc*) this)->locals();
if (l != NULL) {
tty->print_cr(" Locals");
for (int index = 0; index < l->length(); index++) {
st->print(" - l%d: ", index);
l->at(index)->print_on(st);
st->cr();
}
}
}
{ GrowableArray<ScopeValue*>* l = ((ScopeDesc*) this)->expressions();
if (l != NULL) {
st->print_cr(" Expression stack");
for (int index = 0; index < l->length(); index++) {
st->print(" - @%d: ", index);
l->at(index)->print_on(st);
st->cr();
}
}
}
{ GrowableArray<MonitorValue*>* l = ((ScopeDesc*) this)->monitors();
if (l != NULL) {
st->print_cr(" Monitor stack");
for (int index = 0; index < l->length(); index++) {
st->print(" - @%d: ", index);
l->at(index)->print_on(st);
st->cr();
}
}
}
#ifdef COMPILER2
if (DoEscapeAnalysis && is_top() && _objects != NULL) {
tty->print_cr("Objects");
for (int i = 0; i < _objects->length(); i++) {
ObjectValue* sv = (ObjectValue*) _objects->at(i);
tty->print(" - %d: ", sv->id());
sv->print_fields_on(tty);
tty->cr();
}
}
#endif // COMPILER2
}
#endif
void ScopeDesc::verify() {
ResourceMark rm;
guarantee(method()->is_method(), "type check");
{ GrowableArray<ScopeValue*>* l = expressions();
if (l != NULL) {
for (int index = 0; index < l->length(); index++) {
}
}
}
}
C:\hotspot-69087d08d473\src\share\vm/code/scopeDesc.hpp
#ifndef SHARE_VM_CODE_SCOPEDESC_HPP
#define SHARE_VM_CODE_SCOPEDESC_HPP
#include "code/debugInfo.hpp"
#include "code/pcDesc.hpp"
#include "oops/method.hpp"
#include "utilities/growableArray.hpp"
class SimpleScopeDesc : public StackObj {
private:
Method* _method;
int _bci;
public:
SimpleScopeDesc(nmethod* code,address pc) {
PcDesc* pc_desc = code->pc_desc_at(pc);
assert(pc_desc != NULL, "Must be able to find matching PcDesc");
DebugInfoReadStream buffer(code, pc_desc->scope_decode_offset());
int ignore_sender = buffer.read_int();
_method = buffer.read_method();
_bci = buffer.read_bci();
}
Method* method() { return _method; }
int bci() { return _bci; }
};
class ScopeDesc : public ResourceObj {
public:
ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop);
ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop);
Method* method() const { return _method; }
int bci() const { return _bci; }
bool should_reexecute() const { return _reexecute; }
bool return_oop() const { return _return_oop; }
GrowableArray<ScopeValue*>* locals();
GrowableArray<ScopeValue*>* expressions();
GrowableArray<MonitorValue*>* monitors();
GrowableArray<ScopeValue*>* objects();
ScopeDesc* sender() const;
int decode_offset() const { return _decode_offset; }
bool is_top() const;
bool is_equal(ScopeDesc* sd) const;
private:
ScopeDesc(const ScopeDesc* parent);
Method* _method;
int _bci;
bool _reexecute;
bool _return_oop;
int _decode_offset;
int _sender_decode_offset;
int _locals_decode_offset;
int _expressions_decode_offset;
int _monitors_decode_offset;
GrowableArray<ScopeValue*>* _objects;
const nmethod* _code;
void decode_body();
GrowableArray<ScopeValue*>* decode_scope_values(int decode_offset);
GrowableArray<MonitorValue*>* decode_monitor_values(int decode_offset);
GrowableArray<ScopeValue*>* decode_object_values(int decode_offset);
DebugInfoReadStream* stream_at(int decode_offset) const;
public:
void verify();
#ifndef PRODUCT
public:
void print_on(outputStream* st) const;
void print_on(outputStream* st, PcDesc* pd) const;
void print_value_on(outputStream* st) const;
#endif
};
#endif // SHARE_VM_CODE_SCOPEDESC_HPP
C:\hotspot-69087d08d473\src\share\vm/code/stubs.cpp
#include "precompiled.hpp"
#include "code/codeBlob.hpp"
#include "code/stubs.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/mutexLocker.hpp"
StubQueue::StubQueue(StubInterface* stub_interface, int buffer_size,
Mutex* lock, const char* name) : _mutex(lock) {
intptr_t size = round_to(buffer_size, 2*BytesPerWord);
BufferBlob* blob = BufferBlob::create(name, size);
if( blob == NULL) {
vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, err_msg("CodeCache: no room for %s", name));
}
_stub_interface = stub_interface;
_buffer_size = blob->content_size();
_buffer_limit = blob->content_size();
_stub_buffer = blob->content_begin();
_queue_begin = 0;
_queue_end = 0;
_number_of_stubs = 0;
register_queue(this);
}
StubQueue::~StubQueue() {
Unimplemented();
}
Stub* StubQueue::stub_containing(address pc) const {
if (contains(pc)) {
for (Stub* s = first(); s != NULL; s = next(s)) {
if (stub_contains(s, pc)) return s;
}
}
return NULL;
}
Stub* StubQueue::request_committed(int code_size) {
Stub* s = request(code_size);
CodeStrings strings;
if (s != NULL) commit(code_size, strings);
return s;
}
Stub* StubQueue::request(int requested_code_size) {
assert(requested_code_size > 0, "requested_code_size must be > 0");
if (_mutex != NULL) _mutex->lock();
Stub* s = current_stub();
int requested_size = round_to(stub_code_size_to_size(requested_code_size), CodeEntryAlignment);
if (requested_size <= available_space()) {
if (is_contiguous()) {
assert(_buffer_limit == _buffer_size, "buffer must be fully usable");
if (_queue_end + requested_size <= _buffer_size) {
CodeStrings strings;
stub_initialize(s, requested_size, strings);
return s;
} else {
assert(!is_empty(), "just checkin'");
_buffer_limit = _queue_end;
_queue_end = 0;
}
}
}
if (requested_size <= available_space()) {
assert(!is_contiguous(), "just checkin'");
assert(_buffer_limit <= _buffer_size, "queue invariant broken");
s = current_stub();
CodeStrings strings;
stub_initialize(s, requested_size, strings);
return s;
}
if (_mutex != NULL) _mutex->unlock();
return NULL;
}
void StubQueue::commit(int committed_code_size, CodeStrings& strings) {
assert(committed_code_size > 0, "committed_code_size must be > 0");
int committed_size = round_to(stub_code_size_to_size(committed_code_size), CodeEntryAlignment);
Stub* s = current_stub();
assert(committed_size <= stub_size(s), "committed size must not exceed requested size");
stub_initialize(s, committed_size, strings);
_queue_end += committed_size;
_number_of_stubs++;
if (_mutex != NULL) _mutex->unlock();
debug_only(stub_verify(s);)
}
void StubQueue::remove_first() {
if (number_of_stubs() == 0) return;
Stub* s = first();
debug_only(stub_verify(s);)
stub_finalize(s);
_queue_begin += stub_size(s);
assert(_queue_begin <= _buffer_limit, "sanity check");
if (_queue_begin == _queue_end) {
_queue_begin = 0;
_queue_end = 0;
_buffer_limit = _buffer_size;
} else if (_queue_begin == _buffer_limit) {
_buffer_limit = _buffer_size;
_queue_begin = 0;
}
_number_of_stubs--;
}
void StubQueue::remove_first(int n) {
int i = MIN2(n, number_of_stubs());
while (i-- > 0) remove_first();
}
void StubQueue::remove_all(){
debug_only(verify();)
remove_first(number_of_stubs());
assert(number_of_stubs() == 0, "sanity check");
}
enum { StubQueueLimit = 10 }; // there are only a few in the world
static StubQueue* registered_stub_queues[StubQueueLimit];
void StubQueue::register_queue(StubQueue* sq) {
for (int i = 0; i < StubQueueLimit; i++) {
if (registered_stub_queues[i] == NULL) {
registered_stub_queues[i] = sq;
return;
}
}
ShouldNotReachHere();
}
void StubQueue::queues_do(void f(StubQueue* sq)) {
for (int i = 0; i < StubQueueLimit; i++) {
if (registered_stub_queues[i] != NULL) {
f(registered_stub_queues[i]);
}
}
}
void StubQueue::stubs_do(void f(Stub* s)) {
debug_only(verify();)
MutexLockerEx lock(_mutex);
for (Stub* s = first(); s != NULL; s = next(s)) f(s);
}
void StubQueue::verify() {
if (_stub_buffer == NULL) return;
MutexLockerEx lock(_mutex);
guarantee(0 <= _buffer_size, "buffer size must be positive");
guarantee(0 <= _buffer_limit && _buffer_limit <= _buffer_size , "_buffer_limit out of bounds");
guarantee(0 <= _queue_begin && _queue_begin < _buffer_limit, "_queue_begin out of bounds");
guarantee(0 <= _queue_end && _queue_end <= _buffer_limit, "_queue_end out of bounds");
guarantee(_buffer_size % CodeEntryAlignment == 0, "_buffer_size not aligned");
guarantee(_buffer_limit % CodeEntryAlignment == 0, "_buffer_limit not aligned");
guarantee(_queue_begin % CodeEntryAlignment == 0, "_queue_begin not aligned");
guarantee(_queue_end % CodeEntryAlignment == 0, "_queue_end not aligned");
if (is_contiguous()) {
guarantee(_buffer_limit == _buffer_size, "_buffer_limit must equal _buffer_size");
}
int n = 0;
for (Stub* s = first(); s != NULL; s = next(s)) {
stub_verify(s);
n++;
}
guarantee(n == number_of_stubs(), "number of stubs inconsistent");
guarantee(_queue_begin != _queue_end || n == 0, "buffer indices must be the same");
}
void StubQueue::print() {
MutexLockerEx lock(_mutex);
for (Stub* s = first(); s != NULL; s = next(s)) {
stub_print(s);
}
}
C:\hotspot-69087d08d473\src\share\vm/code/stubs.hpp
#ifndef SHARE_VM_CODE_STUBS_HPP
#define SHARE_VM_CODE_STUBS_HPP
#include "asm/codeBuffer.hpp"
#include "memory/allocation.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_aix
# include "os_aix.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
class Stub VALUE_OBJ_CLASS_SPEC {
public:
void initialize(int size,
CodeStrings& strings) { ShouldNotCallThis(); } // called to initialize/specify the stub's size
void finalize() { ShouldNotCallThis(); } // called before the stub is deallocated
int size() const { ShouldNotCallThis(); return 0; } // must return the size provided by initialize
static int code_size_to_size(int code_size) { ShouldNotCallThis(); return 0; } // computes the size given the code size
address code_begin() const { ShouldNotCallThis(); return NULL; } // points to the first byte of the code
address code_end() const { ShouldNotCallThis(); return NULL; } // points to the first byte after the code
void verify() { ShouldNotCallThis(); } // verifies the Stub
void print() { ShouldNotCallThis(); } // prints some information about the stub
};
class StubInterface: public CHeapObj<mtCode> {
public:
virtual void initialize(Stub* self, int size,
CodeStrings& strings) = 0; // called after creation (called twice if allocated via (request, commit))
virtual void finalize(Stub* self) = 0; // called before deallocation
virtual int size(Stub* self) const = 0; // the total size of the stub in bytes (must be a multiple of CodeEntryAlignment)
virtual int code_size_to_size(int code_size) const = 0; // computes the total stub size in bytes given the code size in bytes
virtual address code_begin(Stub* self) const = 0; // points to the first code byte
virtual address code_end(Stub* self) const = 0; // points to the first byte after the code
virtual void verify(Stub* self) = 0; // verifies the stub
virtual void print(Stub* self) = 0; // prints information about the stub
};
#define DEF_STUB_INTERFACE(stub) \
class stub##Interface: public StubInterface { \
private: \
static stub* cast(Stub* self) { return (stub*)self; } \
\
public: \
virtual void initialize(Stub* self, int size, \
CodeStrings& strings) { cast(self)->initialize(size, strings); } \
virtual void finalize(Stub* self) { cast(self)->finalize(); } \
\
virtual int size(Stub* self) const { return cast(self)->size(); } \
virtual int code_size_to_size(int code_size) const { return stub::code_size_to_size(code_size); } \
\
virtual address code_begin(Stub* self) const { return cast(self)->code_begin(); } \
virtual address code_end(Stub* self) const { return cast(self)->code_end(); } \
\
virtual void verify(Stub* self) { cast(self)->verify(); } \
virtual void print(Stub* self) { cast(self)->print(); } \
};
class StubQueue: public CHeapObj<mtCode> {
friend class VMStructs;
private:
StubInterface* _stub_interface; // the interface prototype
address _stub_buffer; // where all stubs are stored
int _buffer_size; // the buffer size in bytes
int _buffer_limit; // the (byte) index of the actual buffer limit (_buffer_limit <= _buffer_size)
int _queue_begin; // the (byte) index of the first queue entry (word-aligned)
int _queue_end; // the (byte) index of the first entry after the queue (word-aligned)
int _number_of_stubs; // the number of buffered stubs
Mutex* const _mutex; // the lock used for a (request, commit) transaction
void check_index(int i) const { assert(0 <= i && i < _buffer_limit && i % CodeEntryAlignment == 0, "illegal index"); }
bool is_contiguous() const { return _queue_begin <= _queue_end; }
int index_of(Stub* s) const { int i = (address)s - _stub_buffer; check_index(i); return i; }
Stub* stub_at(int i) const { check_index(i); return (Stub*)(_stub_buffer + i); }
Stub* current_stub() const { return stub_at(_queue_end); }
void stub_initialize(Stub* s, int size,
CodeStrings& strings) { assert(size % CodeEntryAlignment == 0, "size not aligned"); _stub_interface->initialize(s, size, strings); }
void stub_finalize(Stub* s) { _stub_interface->finalize(s); }
int stub_size(Stub* s) const { return _stub_interface->size(s); }
bool stub_contains(Stub* s, address pc) const { return _stub_interface->code_begin(s) <= pc && pc < _stub_interface->code_end(s); }
int stub_code_size_to_size(int code_size) const { return _stub_interface->code_size_to_size(code_size); }
void stub_verify(Stub* s) { _stub_interface->verify(s); }
void stub_print(Stub* s) { _stub_interface->print(s); }
static void register_queue(StubQueue*);
public:
StubQueue(StubInterface* stub_interface, int buffer_size, Mutex* lock,
const char* name);
~StubQueue();
bool is_empty() const { return _queue_begin == _queue_end; }
int total_space() const { return _buffer_size - 1; }
int available_space() const { int d = _queue_begin - _queue_end - 1; return d < 0 ? d + _buffer_size : d; }
int used_space() const { return total_space() - available_space(); }
int number_of_stubs() const { return _number_of_stubs; }
bool contains(address pc) const { return _stub_buffer <= pc && pc < _stub_buffer + _buffer_limit; }
Stub* stub_containing(address pc) const;
address code_start() const { return _stub_buffer; }
address code_end() const { return _stub_buffer + _buffer_limit; }
Stub* request_committed(int code_size); // request a stub that provides exactly code_size space for code
Stub* request(int requested_code_size); // request a stub with a (maximum) code space - locks the queue
void commit (int committed_code_size,
CodeStrings& strings); // commit the previously requested stub - unlocks the queue
void remove_first(); // remove the first stub in the queue
void remove_first(int n); // remove the first n stubs in the queue
void remove_all(); // remove all stubs in the queue
static void queues_do(void f(StubQueue* s)); // call f with each StubQueue
void stubs_do(void f(Stub* s)); // call f with all stubs
Stub* first() const { return number_of_stubs() > 0 ? stub_at(_queue_begin) : NULL; }
Stub* next(Stub* s) const { int i = index_of(s) + stub_size(s);
if (i == _buffer_limit) i = 0;
return (i == _queue_end) ? NULL : stub_at(i);
}
address stub_code_begin(Stub* s) const { return _stub_interface->code_begin(s); }
address stub_code_end(Stub* s) const { return _stub_interface->code_end(s); }
void verify(); // verifies the stub queue
void print(); // prints information about the stub queue
};
#endif // SHARE_VM_CODE_STUBS_HPP
C:\hotspot-69087d08d473\src\share\vm/code/vmreg.cpp
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "code/vmreg.hpp"
VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)((ConcreteRegisterImpl::number_of_registers + 7) & ~7);
const int VMRegImpl::stack_slot_size = 4;
const int VMRegImpl::slots_per_word = wordSize / stack_slot_size;
const int VMRegImpl::register_count = ConcreteRegisterImpl::number_of_registers;
const char *VMRegImpl::regName[ConcreteRegisterImpl::number_of_registers];
void VMRegImpl::print_on(outputStream* st) const {
if( is_reg() ) {
assert( VMRegImpl::regName[value()], "" );
st->print("%s",VMRegImpl::regName[value()]);
} else if (is_stack()) {
int stk = value() - stack0->value();
st->print("[%d]", stk*4);
} else {
st->print("BAD!");
}
}
C:\hotspot-69087d08d473\src\share\vm/code/vmreg.hpp
#ifndef SHARE_VM_CODE_VMREG_HPP
#define SHARE_VM_CODE_VMREG_HPP
#include "memory/allocation.hpp"
#include "utilities/globalDefinitions.hpp"
#include "asm/register.hpp"
#ifdef COMPILER2
#include "opto/adlcVMDeps.hpp"
#include "utilities/ostream.hpp"
#if defined ADGLOBALS_MD_HPP
# include ADGLOBALS_MD_HPP
#elif defined TARGET_ARCH_MODEL_x86_32
# include "adfiles/adGlobals_x86_32.hpp"
#elif defined TARGET_ARCH_MODEL_x86_64
# include "adfiles/adGlobals_x86_64.hpp"
#elif defined TARGET_ARCH_MODEL_aarch64
# include "adfiles/adGlobals_aarch64.hpp"
#elif defined TARGET_ARCH_MODEL_sparc
# include "adfiles/adGlobals_sparc.hpp"
#elif defined TARGET_ARCH_MODEL_zero
# include "adfiles/adGlobals_zero.hpp"
#elif defined TARGET_ARCH_MODEL_ppc_64
# include "adfiles/adGlobals_ppc_64.hpp"
#endif
#endif
class VMRegImpl;
typedef VMRegImpl* VMReg;
class VMRegImpl {
friend class VMStructs;
friend class OptoReg;
private:
enum {
BAD_REG = -1
};
static VMReg stack0;
static const char *regName[];
static const int register_count;
public:
static VMReg as_VMReg(int val, bool bad_ok = false) { assert(val > BAD_REG || bad_ok, "invalid"); return (VMReg) (intptr_t) val; }
const char* name() {
if (is_reg()) {
return regName[value()];
} else if (!is_valid()) {
return "BAD";
} else {
return "STACKED REG";
}
}
static VMReg Bad() { return (VMReg) (intptr_t) BAD_REG; }
bool is_valid() const { return ((intptr_t) this) != BAD_REG; }
bool is_stack() const { return (intptr_t) this >= (intptr_t) stack0; }
bool is_reg() const { return is_valid() && !is_stack(); }
bool is_concrete();
static const int stack_slot_size;
static const int slots_per_word;
VMReg next() {
assert((is_reg() && value() < stack0->value() - 1) || is_stack(), "must be");
return (VMReg)(intptr_t)(value() + 1);
}
VMReg next(int i) {
assert((is_reg() && value() < stack0->value() - i) || is_stack(), "must be");
return (VMReg)(intptr_t)(value() + i);
}
VMReg prev() {
assert((is_stack() && value() > stack0->value()) || (is_reg() && value() != 0), "must be");
return (VMReg)(intptr_t)(value() - 1);
}
intptr_t value() const {return (intptr_t) this; }
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
VMReg bias(int offset) {
assert(is_stack(), "must be");
VMReg res = stack2reg(reg2stack() + offset);
assert(res->is_stack(), "must be");
return res;
}
static VMReg stack2reg( int idx ) {
return (VMReg) (intptr_t) (stack0->value() + idx);
}
uintptr_t reg2stack() {
assert( is_stack(), "Not a stack-based register" );
return value() - stack0->value();
}
static void set_regName();
#ifdef TARGET_ARCH_x86
# include "vmreg_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "vmreg_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "vmreg_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "vmreg_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "vmreg_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "vmreg_ppc.hpp"
#endif
};
class VMRegPair {
private:
VMReg _second;
VMReg _first;
public:
void set_bad ( ) { _second=VMRegImpl::Bad(); _first=VMRegImpl::Bad(); }
void set1 ( VMReg v ) { _second=VMRegImpl::Bad(); _first=v; }
void set2 ( VMReg v ) { _second=v->next(); _first=v; }
void set_pair( VMReg second, VMReg first ) { _second= second; _first= first; }
void set_ptr ( VMReg ptr ) {
#ifdef _LP64
_second = ptr->next();
#else
_second = VMRegImpl::Bad();
#endif
_first = ptr;
}
bool is_single_reg() const {
return (_first->is_valid()) && (_first->value() + 1 == _second->value());
}
bool is_adjacent_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
bool is_adjacent_aligned_on_stack(int alignment) const {
return (_first->is_stack() && (_first->value() + 1 == _second->value()) && ((_first->value() & (alignment-1)) == 0));
}
bool is_single_phys_reg() const {
return (_first->is_reg() && (_first->value() + 1 == _second->value()));
}
VMReg second() const { return _second; }
VMReg first() const { return _first; }
VMRegPair(VMReg s, VMReg f) { _second = s; _first = f; }
VMRegPair(VMReg f) { _second = VMRegImpl::Bad(); _first = f; }
VMRegPair() { _second = VMRegImpl::Bad(); _first = VMRegImpl::Bad(); }
};
#endif // SHARE_VM_CODE_VMREG_HPP
C:\hotspot-69087d08d473\src\share\vm/code/vtableStubs.cpp
#include "precompiled.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/disassembler.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/klassVtable.hpp"
#include "oops/oop.inline.hpp"
#include "prims/forte.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/sharedRuntime.hpp"
#ifdef COMPILER2
#include "opto/matcher.hpp"
#endif
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
address VtableStub::_chunk = NULL;
address VtableStub::_chunk_end = NULL;
VMReg VtableStub::_receiver_location = VMRegImpl::Bad();
void* VtableStub::operator new(size_t size, int code_size) throw() {
assert(size == sizeof(VtableStub), "mismatched size");
const int real_size = round_to(code_size + sizeof(VtableStub), wordSize);
const int chunk_factor = 32;
if (_chunk == NULL || _chunk + real_size > _chunk_end) {
const int bytes = chunk_factor * real_size + pd_code_alignment();
VtableBlob* blob = VtableBlob::create("vtable chunks", bytes);
if (blob == NULL) {
return NULL;
}
_chunk = blob->content_begin();
_chunk_end = _chunk + bytes;
Forte::register_stub("vtable stub", _chunk, _chunk_end);
align_chunk();
}
assert(_chunk + real_size <= _chunk_end, "bad allocation");
void* res = _chunk;
_chunk += real_size;
align_chunk();
return res;
}
void VtableStub::print_on(outputStream* st) const {
st->print("vtable stub (index = %d, receiver_location = %d, code = [" INTPTR_FORMAT ", " INTPTR_FORMAT "[)",
index(), receiver_location(), code_begin(), code_end());
}
VtableStub* VtableStubs::_table[VtableStubs::N];
int VtableStubs::_number_of_vtable_stubs = 0;
void VtableStubs::initialize() {
VtableStub::_receiver_location = SharedRuntime::name_for_receiver();
{
MutexLocker ml(VtableStubs_lock);
assert(_number_of_vtable_stubs == 0, "potential performance bug: VtableStubs initialized more than once");
assert(is_power_of_2(N), "N must be a power of 2");
for (int i = 0; i < N; i++) {
_table[i] = NULL;
}
}
}
address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) {
assert(vtable_index >= 0, "must be positive");
VtableStub* s = lookup(is_vtable_stub, vtable_index);
if (s == NULL) {
if (is_vtable_stub) {
s = create_vtable_stub(vtable_index);
} else {
s = create_itable_stub(vtable_index);
}
if (s == NULL) {
return NULL;
}
enter(is_vtable_stub, vtable_index, s);
if (PrintAdapterHandlers) {
tty->print_cr("Decoding VtableStub %s[%d]@%d",
is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location());
Disassembler::decode(s->code_begin(), s->code_end());
}
if (JvmtiExport::should_post_dynamic_code_generated()) {
JvmtiExport::post_dynamic_code_generated_while_holding_locks(is_vtable_stub? "vtable stub": "itable stub",
s->code_begin(), s->code_end());
}
}
return s->entry_point();
}
inline uint VtableStubs::hash(bool is_vtable_stub, int vtable_index){
int hash = ((vtable_index << 2) ^ VtableStub::receiver_location()->value()) + vtable_index;
return (is_vtable_stub ? ~hash : hash) & mask;
}
VtableStub* VtableStubs::lookup(bool is_vtable_stub, int vtable_index) {
MutexLocker ml(VtableStubs_lock);
unsigned hash = VtableStubs::hash(is_vtable_stub, vtable_index);
VtableStub* s = _table[hash];
while( s && !s->matches(is_vtable_stub, vtable_index)) s = s->next();
return s;
}
void VtableStubs::enter(bool is_vtable_stub, int vtable_index, VtableStub* s) {
MutexLocker ml(VtableStubs_lock);
assert(s->matches(is_vtable_stub, vtable_index), "bad vtable stub");
unsigned int h = VtableStubs::hash(is_vtable_stub, vtable_index);
s->set_next(_table[h]);
_table[h] = s;
_number_of_vtable_stubs++;
}
VtableStub* VtableStubs::entry_point(address pc) {
MutexLocker ml(VtableStubs_lock);
VtableStub* stub = (VtableStub*)(pc - VtableStub::entry_offset());
uint hash = VtableStubs::hash(stub->is_vtable_stub(), stub->index());
VtableStub* s;
for (s = _table[hash]; s != NULL && s != stub; s = s->next()) {}
if (s == stub) {
return s;
}
return NULL;
}
bool VtableStubs::contains(address pc) {
return stub_containing(pc) != NULL;
}
VtableStub* VtableStubs::stub_containing(address pc) {
for (int i = 0; i < N; i++) {
for (VtableStub* s = _table[i]; s != NULL; s = s->next()) {
if (s->contains(pc)) return s;
}
}
return NULL;
}
void vtableStubs_init() {
VtableStubs::initialize();
}
void VtableStubs::vtable_stub_do(void f(VtableStub*)) {
for (int i = 0; i < N; i++) {
for (VtableStub* s = _table[i]; s != NULL; s = s->next()) {
f(s);
}
}
}
#ifndef PRODUCT
extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index) {
ResourceMark rm;
HandleMark hm;
Klass* klass = receiver->klass();
InstanceKlass* ik = InstanceKlass::cast(klass);
klassVtable* vt = ik->vtable();
ik->print();
fatal(err_msg("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", "
"index %d (vtable length %d)",
(address)receiver, index, vt->length()));
}
#endif // Product
C:\hotspot-69087d08d473\src\share\vm/code/vtableStubs.hpp
#ifndef SHARE_VM_CODE_VTABLESTUBS_HPP
#define SHARE_VM_CODE_VTABLESTUBS_HPP
#include "code/vmreg.hpp"
#include "memory/allocation.hpp"
class VtableStub {
private:
friend class VtableStubs;
static address _chunk; // For allocation
static address _chunk_end; // For allocation
static VMReg _receiver_location; // Where to find receiver
VtableStub* _next; // Pointer to next entry in hash table
const short _index; // vtable index
short _ame_offset; // Where an AbstractMethodError might occur
short _npe_offset; // Where a NullPointerException might occur
bool _is_vtable_stub; // True if vtable stub, false, is itable stub
void* operator new(size_t size, int code_size) throw();
VtableStub(bool is_vtable_stub, int index)
: _next(NULL), _is_vtable_stub(is_vtable_stub),
_index(index), _ame_offset(-1), _npe_offset(-1) {}
VtableStub* next() const { return _next; }
int index() const { return _index; }
static VMReg receiver_location() { return _receiver_location; }
void set_next(VtableStub* n) { _next = n; }
public:
address code_begin() const { return (address)(this + 1); }
address code_end() const { return code_begin() + pd_code_size_limit(_is_vtable_stub); }
address entry_point() const { return code_begin(); }
static int entry_offset() { return sizeof(class VtableStub); }
bool matches(bool is_vtable_stub, int index) const {
return _index == index && _is_vtable_stub == is_vtable_stub;
}
bool contains(address pc) const { return code_begin() <= pc && pc < code_end(); }
private:
void set_exception_points(address npe_addr, address ame_addr) {
_npe_offset = npe_addr - code_begin();
_ame_offset = ame_addr - code_begin();
assert(is_abstract_method_error(ame_addr), "offset must be correct");
assert(is_null_pointer_exception(npe_addr), "offset must be correct");
assert(!is_abstract_method_error(npe_addr), "offset must be correct");
assert(!is_null_pointer_exception(ame_addr), "offset must be correct");
}
static int pd_code_size_limit(bool is_vtable_stub);
static int pd_code_alignment();
static void align_chunk() {
uintptr_t off = (uintptr_t)( _chunk + sizeof(VtableStub) ) % pd_code_alignment();
if (off != 0) _chunk += pd_code_alignment() - off;
}
public:
bool is_itable_stub() { return !_is_vtable_stub; }
bool is_vtable_stub() { return _is_vtable_stub; }
bool is_abstract_method_error(address epc) { return epc == code_begin()+_ame_offset; }
bool is_null_pointer_exception(address epc) { return epc == code_begin()+_npe_offset; }
void print_on(outputStream* st) const;
void print() const { print_on(tty); }
};
class VtableStubs : AllStatic {
public: // N must be public (some compilers need this for _table)
enum {
N = 256, // size of stub table; must be power of two
mask = N - 1
};
private:
static VtableStub* _table[N]; // table of existing stubs
static int _number_of_vtable_stubs; // number of stubs created so far (for statistics)
static VtableStub* create_vtable_stub(int vtable_index);
static VtableStub* create_itable_stub(int vtable_index);
static VtableStub* lookup (bool is_vtable_stub, int vtable_index);
static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s);
static inline uint hash (bool is_vtable_stub, int vtable_index);
static address find_stub (bool is_vtable_stub, int vtable_index);
public:
static address find_vtable_stub(int vtable_index) { return find_stub(true, vtable_index); }
static address find_itable_stub(int itable_index) { return find_stub(false, itable_index); }
static VtableStub* entry_point(address pc); // vtable stub entry point for a pc
static bool contains(address pc); // is pc within any stub?
static VtableStub* stub_containing(address pc); // stub containing pc or NULL
static int number_of_vtable_stubs() { return _number_of_vtable_stubs; }
static void initialize();
static void vtable_stub_do(void f(VtableStub*)); // iterates over all vtable stubs
};
#endif // SHARE_VM_CODE_VTABLESTUBS_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/abstractCompiler.cpp
#include "precompiled.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compileBroker.hpp"
#include "runtime/mutexLocker.hpp"
bool AbstractCompiler::should_perform_init() {
if (_compiler_state != initialized) {
MutexLocker only_one(CompileThread_lock);
if (_compiler_state == uninitialized) {
_compiler_state = initializing;
return true;
} else {
while (_compiler_state == initializing) {
CompileThread_lock->wait();
}
}
}
return false;
}
bool AbstractCompiler::should_perform_shutdown() {
MutexLocker only_one(CompileThread_lock);
_num_compiler_threads--;
assert (CompileBroker::is_compilation_disabled_forever(), "Must be set, otherwise thread waits forever");
if (_num_compiler_threads == 0) {
return true;
}
return false;
}
void AbstractCompiler::set_state(int state) {
MutexLocker only_one(CompileThread_lock);
_compiler_state = state;
CompileThread_lock->notify_all();
}
C:\hotspot-69087d08d473\src\share\vm/compiler/abstractCompiler.hpp
#ifndef SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP
#define SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP
#include "ci/compilerInterface.hpp"
class AbstractCompiler : public CHeapObj<mtCompiler> {
private:
volatile int _num_compiler_threads;
protected:
volatile int _compiler_state;
enum { uninitialized, initializing, initialized, failed, shut_down };
bool should_perform_init();
public:
AbstractCompiler() : _compiler_state(uninitialized), _num_compiler_threads(0) {}
bool should_perform_shutdown();
virtual const char* name() = 0;
virtual bool supports_native() { return true; }
virtual bool supports_osr () { return true; }
virtual bool can_compile_method(methodHandle method) { return true; }
#if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK))
virtual bool is_c1 () { return false; }
virtual bool is_c2 () { return false; }
virtual bool is_shark() { return false; }
#else
#ifdef COMPILER1
bool is_c1 () { return true; }
bool is_c2 () { return false; }
bool is_shark() { return false; }
#endif // COMPILER1
#ifdef COMPILER2
bool is_c1 () { return false; }
bool is_c2 () { return true; }
bool is_shark() { return false; }
#endif // COMPILER2
#ifdef SHARK
bool is_c1 () { return false; }
bool is_c2 () { return false; }
bool is_shark() { return true; }
#endif // SHARK
#endif // TIERED
virtual void initialize () = 0;
void set_num_compiler_threads(int num) { _num_compiler_threads = num; }
int num_compiler_threads() { return _num_compiler_threads; }
bool is_initialized() { return _compiler_state == initialized; }
bool is_failed () { return _compiler_state == failed;}
void set_state (int state);
void set_shut_down () { set_state(shut_down); }
virtual void compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
ShouldNotReachHere();
}
virtual void print_timers() {
ShouldNotReachHere();
}
};
#endif // SHARE_VM_COMPILER_ABSTRACTCOMPILER_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/compileBroker.cpp
#include "precompiled.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/methodData.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/os.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/sweeper.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/events.hpp"
#ifdef COMPILER1
#include "c1/c1_Compiler.hpp"
#endif
#ifdef COMPILER2
#include "opto/c2compiler.hpp"
#endif
#ifdef SHARK
#include "shark/sharkCompiler.hpp"
#endif
#ifdef DTRACE_ENABLED
#ifndef USDT2
HS_DTRACE_PROBE_DECL8(hotspot, method__compile__begin,
char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t);
HS_DTRACE_PROBE_DECL9(hotspot, method__compile__end,
char*, intptr_t, char*, intptr_t, char*, intptr_t, char*, intptr_t, bool);
#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
HS_DTRACE_PROBE8(hotspot, method__compile__begin, \
comp_name, strlen(comp_name), \
klass_name->bytes(), klass_name->utf8_length(), \
name->bytes(), name->utf8_length(), \
signature->bytes(), signature->utf8_length()); \
}
#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
HS_DTRACE_PROBE9(hotspot, method__compile__end, \
comp_name, strlen(comp_name), \
klass_name->bytes(), klass_name->utf8_length(), \
name->bytes(), name->utf8_length(), \
signature->bytes(), signature->utf8_length(), (success)); \
}
#else /* USDT2 */
#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
HOTSPOT_METHOD_COMPILE_BEGIN( \
comp_name, strlen(comp_name), \
(char *) klass_name->bytes(), klass_name->utf8_length(), \
(char *) name->bytes(), name->utf8_length(), \
(char *) signature->bytes(), signature->utf8_length()); \
}
#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success) \
{ \
Symbol* klass_name = (method)->klass_name(); \
Symbol* name = (method)->name(); \
Symbol* signature = (method)->signature(); \
HOTSPOT_METHOD_COMPILE_END( \
comp_name, strlen(comp_name), \
(char *) klass_name->bytes(), klass_name->utf8_length(), \
(char *) name->bytes(), name->utf8_length(), \
(char *) signature->bytes(), signature->utf8_length(), (success)); \
}
#endif /* USDT2 */
#else // ndef DTRACE_ENABLED
#define DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, comp_name)
#define DTRACE_METHOD_COMPILE_END_PROBE(method, comp_name, success)
#endif // ndef DTRACE_ENABLED
bool CompileBroker::_initialized = false;
volatile bool CompileBroker::_should_block = false;
volatile jint CompileBroker::_print_compilation_warning = 0;
volatile jint CompileBroker::_should_compile_new_jobs = run_compilation;
AbstractCompiler* CompileBroker::_compilers[2];
volatile jint CompileBroker::_compilation_id = 0;
volatile jint CompileBroker::_osr_compilation_id = 0;
int CompileBroker::_last_compile_type = no_compile;
int CompileBroker::_last_compile_level = CompLevel_none;
char CompileBroker::_last_method_compiled[CompileBroker::name_buffer_length];
PerfCounter* CompileBroker::_perf_total_compilation = NULL;
PerfCounter* CompileBroker::_perf_osr_compilation = NULL;
PerfCounter* CompileBroker::_perf_standard_compilation = NULL;
PerfCounter* CompileBroker::_perf_total_bailout_count = NULL;
PerfCounter* CompileBroker::_perf_total_invalidated_count = NULL;
PerfCounter* CompileBroker::_perf_total_compile_count = NULL;
PerfCounter* CompileBroker::_perf_total_osr_compile_count = NULL;
PerfCounter* CompileBroker::_perf_total_standard_compile_count = NULL;
PerfCounter* CompileBroker::_perf_sum_osr_bytes_compiled = NULL;
PerfCounter* CompileBroker::_perf_sum_standard_bytes_compiled = NULL;
PerfCounter* CompileBroker::_perf_sum_nmethod_size = NULL;
PerfCounter* CompileBroker::_perf_sum_nmethod_code_size = NULL;
PerfStringVariable* CompileBroker::_perf_last_method = NULL;
PerfStringVariable* CompileBroker::_perf_last_failed_method = NULL;
PerfStringVariable* CompileBroker::_perf_last_invalidated_method = NULL;
PerfVariable* CompileBroker::_perf_last_compile_type = NULL;
PerfVariable* CompileBroker::_perf_last_compile_size = NULL;
PerfVariable* CompileBroker::_perf_last_failed_type = NULL;
PerfVariable* CompileBroker::_perf_last_invalidated_type = NULL;
elapsedTimer CompileBroker::_t_total_compilation;
elapsedTimer CompileBroker::_t_osr_compilation;
elapsedTimer CompileBroker::_t_standard_compilation;
int CompileBroker::_total_bailout_count = 0;
int CompileBroker::_total_invalidated_count = 0;
int CompileBroker::_total_compile_count = 0;
int CompileBroker::_total_osr_compile_count = 0;
int CompileBroker::_total_standard_compile_count = 0;
int CompileBroker::_sum_osr_bytes_compiled = 0;
int CompileBroker::_sum_standard_bytes_compiled = 0;
int CompileBroker::_sum_nmethod_size = 0;
int CompileBroker::_sum_nmethod_code_size = 0;
long CompileBroker::_peak_compilation_time = 0;
CompileQueue* CompileBroker::_c2_compile_queue = NULL;
CompileQueue* CompileBroker::_c1_compile_queue = NULL;
GrowableArray<CompilerThread*>* CompileBroker::_compiler_threads = NULL;
class CompilationLog : public StringEventLog {
public:
CompilationLog() : StringEventLog("Compilation events") {
}
void log_compile(JavaThread* thread, CompileTask* task) {
StringLogMessage lm;
stringStream sstr = lm.stream();
task->print_compilation(&sstr, NULL, true);
log(thread, "%s", (const char*)lm);
}
void log_nmethod(JavaThread* thread, nmethod* nm) {
log(thread, "nmethod %d%s " INTPTR_FORMAT " code [" INTPTR_FORMAT ", " INTPTR_FORMAT "]",
nm->compile_id(), nm->is_osr_method() ? "%" : "",
p2i(nm), p2i(nm->code_begin()), p2i(nm->code_end()));
}
void log_failure(JavaThread* thread, CompileTask* task, const char* reason, const char* retry_message) {
StringLogMessage lm;
lm.print("%4d COMPILE SKIPPED: %s", task->compile_id(), reason);
if (retry_message != NULL) {
lm.append(" (%s)", retry_message);
}
lm.print("\n");
log(thread, "%s", (const char*)lm);
}
};
static CompilationLog* _compilation_log = NULL;
void compileBroker_init() {
if (LogEvents) {
_compilation_log = new CompilationLog();
}
}
CompileTaskWrapper::CompileTaskWrapper(CompileTask* task) {
CompilerThread* thread = CompilerThread::current();
thread->set_task(task);
CompileLog* log = thread->log();
if (log != NULL) task->log_task_start(log);
}
CompileTaskWrapper::~CompileTaskWrapper() {
CompilerThread* thread = CompilerThread::current();
CompileTask* task = thread->task();
CompileLog* log = thread->log();
if (log != NULL) task->log_task_done(log);
thread->set_task(NULL);
task->set_code_handle(NULL);
thread->set_env(NULL);
if (task->is_blocking()) {
MutexLocker notifier(task->lock(), thread);
task->mark_complete();
task->lock()->notify_all();
} else {
task->mark_complete();
CompileTask::free(task);
}
}
CompileTask* CompileTask::_task_free_list = NULL;
#ifdef ASSERT
int CompileTask::_num_allocated_tasks = 0;
#endif
CompileTask* CompileTask::allocate() {
MutexLocker locker(CompileTaskAlloc_lock);
CompileTask* task = NULL;
if (_task_free_list != NULL) {
task = _task_free_list;
_task_free_list = task->next();
task->set_next(NULL);
} else {
task = new CompileTask();
DEBUG_ONLY(_num_allocated_tasks++;)
assert (_num_allocated_tasks < 10000, "Leaking compilation tasks?");
task->set_next(NULL);
task->set_is_free(true);
}
assert(task->is_free(), "Task must be free.");
task->set_is_free(false);
return task;
}
void CompileTask::free(CompileTask* task) {
MutexLocker locker(CompileTaskAlloc_lock);
if (!task->is_free()) {
task->set_code(NULL);
assert(!task->lock()->is_locked(), "Should not be locked when freed");
JNIHandles::destroy_global(task->_method_holder);
JNIHandles::destroy_global(task->_hot_method_holder);
task->set_is_free(true);
task->set_next(_task_free_list);
_task_free_list = task;
}
}
void CompileTask::initialize(int compile_id,
methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment,
bool is_blocking) {
assert(!_lock->is_locked(), "bad locking");
_compile_id = compile_id;
_method = method();
_method_holder = JNIHandles::make_global(method->method_holder()->klass_holder());
_osr_bci = osr_bci;
_is_blocking = is_blocking;
_comp_level = comp_level;
_num_inlined_bytecodes = 0;
_is_complete = false;
_is_success = false;
_code_handle = NULL;
_hot_method = NULL;
_hot_method_holder = NULL;
_hot_count = hot_count;
_time_queued = 0; // tidy
_comment = comment;
_failure_reason = NULL;
if (LogCompilation) {
_time_queued = os::elapsed_counter();
if (hot_method.not_null()) {
if (hot_method == method) {
_hot_method = _method;
} else {
_hot_method = hot_method();
_hot_method_holder = JNIHandles::make_global(hot_method->method_holder()->klass_holder());
}
}
}
_next = NULL;
}
nmethod* CompileTask::code() const {
if (_code_handle == NULL) return NULL;
return _code_handle->code();
}
void CompileTask::set_code(nmethod* nm) {
if (_code_handle == NULL && nm == NULL) return;
guarantee(_code_handle != NULL, "");
_code_handle->set_code(nm);
if (nm == NULL) _code_handle = NULL; // drop the handle also
}
void CompileTask::mark_on_stack() {
_method->set_on_stack(true);
if (_hot_method != NULL) {
_hot_method->set_on_stack(true);
}
}
void CompileTask::print() {
tty->print("<CompileTask compile_id=%d ", _compile_id);
tty->print("method=");
_method->print_name(tty);
tty->print_cr(" osr_bci=%d is_blocking=%s is_complete=%s is_success=%s>",
_osr_bci, bool_to_str(_is_blocking),
bool_to_str(_is_complete), bool_to_str(_is_success));
}
void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) {
st->print("%s:", CompileBroker::compiler_name(comp_level()));
print_compilation(st);
}
void CompileTask::print_line() {
ttyLocker ttyl; // keep the following output all in one block
if (CIPrintCompilerName) tty->print("%s:", CompileBroker::compiler_name(comp_level()));
print_compilation();
}
void CompileTask::print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
bool is_osr_method, int osr_bci, bool is_blocking,
const char* msg, bool short_form) {
if (!short_form) {
st->print("%7d ", (int) st->time_stamp().milliseconds()); // print timestamp
}
st->print("%4d ", compile_id); // print compilation number
bool is_synchronized = false;
bool has_exception_handler = false;
bool is_native = false;
if (method != NULL) {
is_synchronized = method->is_synchronized();
has_exception_handler = method->has_exception_handler();
is_native = method->is_native();
}
const char compile_type = is_osr_method ? '%' : ' ';
const char sync_char = is_synchronized ? 's' : ' ';
const char exception_char = has_exception_handler ? '!' : ' ';
const char blocking_char = is_blocking ? 'b' : ' ';
const char native_char = is_native ? 'n' : ' ';
st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char);
if (TieredCompilation) {
if (comp_level != -1) st->print("%d ", comp_level);
else st->print("- ");
}
st->print(" "); // more indent
if (method == NULL) {
st->print("(method)");
} else {
method->print_short_name(st);
if (is_osr_method) {
st->print(" @ %d", osr_bci);
}
if (method->is_native())
st->print(" (native)");
else
st->print(" (%d bytes)", method->code_size());
}
if (msg != NULL) {
st->print(" %s", msg);
}
if (!short_form) {
st->cr();
}
}
void CompileTask::print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg) {
st->print(" "); // print timestamp
st->print(" "); // print compilation number
if (method->is_loaded()) {
const char sync_char = method->is_synchronized() ? 's' : ' ';
const char exception_char = method->has_exception_handlers() ? '!' : ' ';
const char monitors_char = method->has_monitor_bytecodes() ? 'm' : ' ';
st->print(" %c%c%c ", sync_char, exception_char, monitors_char);
} else {
st->print(" "); // print method attributes
}
if (TieredCompilation) {
st->print(" ");
}
st->print(" "); // more indent
st->print(" "); // initial inlining indent
for (int i = 0; i < inline_level; i++) st->print(" ");
st->print("@ %d ", bci); // print bci
method->print_short_name(st);
if (method->is_loaded())
st->print(" (%d bytes)", method->code_size());
else
st->print(" (not loaded)");
if (msg != NULL) {
st->print(" %s", msg);
}
st->cr();
}
void CompileTask::print_inline_indent(int inline_level, outputStream* st) {
st->print(" "); // print timestamp
st->print(" "); // print compilation number
st->print(" "); // print method attributes
if (TieredCompilation) {
st->print(" ");
}
st->print(" "); // more indent
st->print(" "); // initial inlining indent
for (int i = 0; i < inline_level; i++) st->print(" ");
}
void CompileTask::print_compilation(outputStream* st, const char* msg, bool short_form) {
bool is_osr_method = osr_bci() != InvocationEntryBci;
print_compilation_impl(st, method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form);
}
void CompileTask::log_task(xmlStream* log) {
Thread* thread = Thread::current();
methodHandle method(thread, this->method());
ResourceMark rm(thread);
log->print(" compile_id='%d'", _compile_id);
if (_osr_bci != CompileBroker::standard_entry_bci) {
log->print(" compile_kind='osr'"); // same as nmethod::compile_kind
} // else compile_kind='c2c'
if (!method.is_null()) log->method(method);
if (_osr_bci != CompileBroker::standard_entry_bci) {
log->print(" osr_bci='%d'", _osr_bci);
}
if (_comp_level != CompLevel_highest_tier) {
log->print(" level='%d'", _comp_level);
}
if (_is_blocking) {
log->print(" blocking='1'");
}
log->stamp();
}
void CompileTask::log_task_queued() {
Thread* thread = Thread::current();
ttyLocker ttyl;
ResourceMark rm(thread);
xtty->begin_elem("task_queued");
log_task(xtty);
if (_comment != NULL) {
xtty->print(" comment='%s'", _comment);
}
if (_hot_method != NULL) {
methodHandle hot(thread, _hot_method);
methodHandle method(thread, _method);
if (hot() != method()) {
xtty->method(hot);
}
}
if (_hot_count != 0) {
xtty->print(" hot_count='%d'", _hot_count);
}
xtty->end_elem();
}
void CompileTask::log_task_start(CompileLog* log) {
log->begin_head("task");
log_task(log);
log->end_head();
}
void CompileTask::log_task_done(CompileLog* log) {
Thread* thread = Thread::current();
methodHandle method(thread, this->method());
ResourceMark rm(thread);
if (!_is_success) {
const char* reason = _failure_reason != NULL ? _failure_reason : "unknown";
log->elem("failure reason='%s'", reason);
}
nmethod* nm = code();
log->begin_elem("task_done success='%d' nmsize='%d' count='%d'",
_is_success, nm == NULL ? 0 : nm->content_size(),
method->invocation_count());
int bec = method->backedge_count();
if (bec != 0) log->print(" backedge_count='%d'", bec);
if (_num_inlined_bytecodes != 0) {
log->print(" inlined_bytes='%d'", _num_inlined_bytecodes);
}
log->stamp();
log->end_elem();
log->tail("task");
log->clear_identities(); // next task will have different CI
if (log->unflushed_count() > 2000) {
log->flush();
}
log->mark_file_end();
}
void CompileQueue::add(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
assert(!CompileBroker::is_compilation_disabled_forever(), "Do not add task if compilation is turned off forever");
task->set_next(NULL);
task->set_prev(NULL);
if (_last == NULL) {
assert(_first == NULL, "queue is empty");
_first = task;
_last = task;
} else {
assert(_last->next() == NULL, "not last");
_last->set_next(task);
task->set_prev(_last);
_last = task;
}
++_size;
task->method()->set_queued_for_compilation();
NOT_PRODUCT(print();)
if (LogCompilation && xtty != NULL) {
task->log_task_queued();
}
lock()->notify_all();
}
void CompileQueue::free_all() {
MutexLocker mu(lock());
CompileTask* next = _first;
while (next != NULL) {
CompileTask* current = next;
next = current->next();
{
MutexLocker ct_lock(current->lock());
current->lock()->notify();
}
CompileTask::free(current);
}
_first = NULL;
lock()->notify_all();
}
CompileTask* CompileQueue::get() {
NMethodSweeper::possibly_sweep();
MutexLocker locker(lock());
while (_first == NULL) {
if (CompileBroker::is_compilation_disabled_forever()) {
return NULL;
}
if (UseCodeCacheFlushing && !CompileBroker::should_compile_new_jobs()) {
long wait_time = NmethodSweepCheckInterval * 1000;
if (FLAG_IS_DEFAULT(NmethodSweepCheckInterval)) {
wait_time = 100 * CICompilerCount;
}
bool timeout = lock()->wait(!Mutex::_no_safepoint_check_flag, wait_time);
if (timeout) {
MutexUnlocker ul(lock());
NMethodSweeper::possibly_sweep();
}
} else {
lock()->wait(!Mutex::_no_safepoint_check_flag, 5*1000);
}
}
if (CompileBroker::is_compilation_disabled_forever()) {
return NULL;
}
CompileTask* task;
{
No_Safepoint_Verifier nsv;
task = CompilationPolicy::policy()->select_task(this);
}
if (task != NULL) {
remove(task);
}
purge_stale_tasks(); // may temporarily release MCQ lock
return task;
}
void CompileQueue::purge_stale_tasks() {
assert(lock()->owned_by_self(), "must own lock");
if (_first_stale != NULL) {
CompileTask* head = _first_stale;
_first_stale = NULL;
{
MutexUnlocker ul(lock());
for (CompileTask* task = head; task != NULL; ) {
CompileTask* next_task = task->next();
CompileTaskWrapper ctw(task); // Frees the task
task->set_failure_reason("stale task");
task = next_task;
}
}
}
}
void CompileQueue::remove(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
if (task->prev() != NULL) {
task->prev()->set_next(task->next());
} else {
assert(task == _first, "Sanity");
_first = task->next();
}
if (task->next() != NULL) {
task->next()->set_prev(task->prev());
} else {
assert(task == _last, "Sanity");
_last = task->prev();
}
--_size;
}
void CompileQueue::remove_and_mark_stale(CompileTask* task) {
assert(lock()->owned_by_self(), "must own lock");
remove(task);
task->set_next(_first_stale);
task->set_prev(NULL);
_first_stale = task;
}
void CompileQueue::mark_on_stack() {
CompileTask* task = _first;
while (task != NULL) {
task->mark_on_stack();
task = task->next();
}
}
#ifndef PRODUCT
void CompileQueue::print() {
if (CIPrintCompileQueue) {
ttyLocker ttyl;
tty->print_cr("Contents of %s", name());
tty->print_cr("----------------------");
CompileTask* task = _first;
while (task != NULL) {
task->print_line();
task = task->next();
}
tty->print_cr("----------------------");
}
}
#endif // PRODUCT
CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) {
_current_method[0] = '\0';
_compile_type = CompileBroker::no_compile;
if (UsePerfData) {
ResourceMark rm;
const char* thread_i = (instance == -1) ? thread_name :
PerfDataManager::name_space(thread_name, instance);
char* name = PerfDataManager::counter_name(thread_i, "method");
_perf_current_method =
PerfDataManager::create_string_variable(SUN_CI, name,
cmname_buffer_length,
_current_method, CHECK);
name = PerfDataManager::counter_name(thread_i, "type");
_perf_compile_type = PerfDataManager::create_variable(SUN_CI, name,
PerfData::U_None,
(jlong)_compile_type,
CHECK);
name = PerfDataManager::counter_name(thread_i, "time");
_perf_time = PerfDataManager::create_counter(SUN_CI, name,
PerfData::U_Ticks, CHECK);
name = PerfDataManager::counter_name(thread_i, "compiles");
_perf_compiles = PerfDataManager::create_counter(SUN_CI, name,
PerfData::U_Events, CHECK);
}
}
void CompileBroker::compilation_init() {
_last_method_compiled[0] = '\0';
if (!UseCompiler) {
return;
}
#ifndef SHARK
int c1_count = CompilationPolicy::policy()->compiler_count(CompLevel_simple);
int c2_count = CompilationPolicy::policy()->compiler_count(CompLevel_full_optimization);
#ifdef COMPILER1
if (c1_count > 0) {
_compilers[0] = new Compiler();
}
#endif // COMPILER1
#ifdef COMPILER2
if (c2_count > 0) {
_compilers[1] = new C2Compiler();
}
#endif // COMPILER2
#else // SHARK
int c1_count = 0;
int c2_count = 1;
_compilers[1] = new SharkCompiler();
#endif // SHARK
init_compiler_threads(c1_count, c2_count);
{
EXCEPTION_MARK;
_perf_total_compilation =
PerfDataManager::create_counter(JAVA_CI, "totalTime",
PerfData::U_Ticks, CHECK);
}
if (UsePerfData) {
EXCEPTION_MARK;
_perf_osr_compilation =
PerfDataManager::create_counter(SUN_CI, "osrTime",
PerfData::U_Ticks, CHECK);
_perf_standard_compilation =
PerfDataManager::create_counter(SUN_CI, "standardTime",
PerfData::U_Ticks, CHECK);
_perf_total_bailout_count =
PerfDataManager::create_counter(SUN_CI, "totalBailouts",
PerfData::U_Events, CHECK);
_perf_total_invalidated_count =
PerfDataManager::create_counter(SUN_CI, "totalInvalidates",
PerfData::U_Events, CHECK);
_perf_total_compile_count =
PerfDataManager::create_counter(SUN_CI, "totalCompiles",
PerfData::U_Events, CHECK);
_perf_total_osr_compile_count =
PerfDataManager::create_counter(SUN_CI, "osrCompiles",
PerfData::U_Events, CHECK);
_perf_total_standard_compile_count =
PerfDataManager::create_counter(SUN_CI, "standardCompiles",
PerfData::U_Events, CHECK);
_perf_sum_osr_bytes_compiled =
PerfDataManager::create_counter(SUN_CI, "osrBytes",
PerfData::U_Bytes, CHECK);
_perf_sum_standard_bytes_compiled =
PerfDataManager::create_counter(SUN_CI, "standardBytes",
PerfData::U_Bytes, CHECK);
_perf_sum_nmethod_size =
PerfDataManager::create_counter(SUN_CI, "nmethodSize",
PerfData::U_Bytes, CHECK);
_perf_sum_nmethod_code_size =
PerfDataManager::create_counter(SUN_CI, "nmethodCodeSize",
PerfData::U_Bytes, CHECK);
_perf_last_method =
PerfDataManager::create_string_variable(SUN_CI, "lastMethod",
CompilerCounters::cmname_buffer_length,
"", CHECK);
_perf_last_failed_method =
PerfDataManager::create_string_variable(SUN_CI, "lastFailedMethod",
CompilerCounters::cmname_buffer_length,
"", CHECK);
_perf_last_invalidated_method =
PerfDataManager::create_string_variable(SUN_CI, "lastInvalidatedMethod",
CompilerCounters::cmname_buffer_length,
"", CHECK);
_perf_last_compile_type =
PerfDataManager::create_variable(SUN_CI, "lastType",
PerfData::U_None,
(jlong)CompileBroker::no_compile,
CHECK);
_perf_last_compile_size =
PerfDataManager::create_variable(SUN_CI, "lastSize",
PerfData::U_Bytes,
(jlong)CompileBroker::no_compile,
CHECK);
_perf_last_failed_type =
PerfDataManager::create_variable(SUN_CI, "lastFailedType",
PerfData::U_None,
(jlong)CompileBroker::no_compile,
CHECK);
_perf_last_invalidated_type =
PerfDataManager::create_variable(SUN_CI, "lastInvalidatedType",
PerfData::U_None,
(jlong)CompileBroker::no_compile,
CHECK);
}
_initialized = true;
}
CompilerThread* CompileBroker::make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters,
AbstractCompiler* comp, TRAPS) {
CompilerThread* compiler_thread = NULL;
Klass* k =
SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(),
true, CHECK_0);
instanceKlassHandle klass (THREAD, k);
instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_0);
Handle string = java_lang_String::create_from_str(name, CHECK_0);
Handle thread_group (THREAD, Universe::system_thread_group());
JavaValue result(T_VOID);
JavaCalls::call_special(&result, thread_oop,
klass,
vmSymbols::object_initializer_name(),
vmSymbols::threadgroup_string_void_signature(),
thread_group,
string,
CHECK_0);
{
MutexLocker mu(Threads_lock, THREAD);
compiler_thread = new CompilerThread(queue, counters);
if (compiler_thread == NULL || compiler_thread->osthread() == NULL){
vm_exit_during_initialization("java.lang.OutOfMemoryError",
"unable to create new native thread");
}
java_lang_Thread::set_thread(thread_oop(), compiler_thread);
java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
int native_prio = CompilerThreadPriority;
if (native_prio == -1) {
if (UseCriticalCompilerThreadPriority) {
native_prio = os::java_to_os_priority[CriticalPriority];
} else {
native_prio = os::java_to_os_priority[NearMaxPriority];
}
}
os::set_native_priority(compiler_thread, native_prio);
java_lang_Thread::set_daemon(thread_oop());
compiler_thread->set_threadObj(thread_oop());
compiler_thread->set_compiler(comp);
Threads::add(compiler_thread);
Thread::start(compiler_thread);
}
os::yield(); // make sure that the compiler thread is started early (especially helpful on SOLARIS)
return compiler_thread;
}
void CompileBroker::init_compiler_threads(int c1_compiler_count, int c2_compiler_count) {
EXCEPTION_MARK;
#if !defined(ZERO) && !defined(SHARK)
assert(c2_compiler_count > 0 || c1_compiler_count > 0, "No compilers?");
#endif // !ZERO && !SHARK
if (c2_compiler_count > 0) {
_c2_compile_queue = new CompileQueue("C2 CompileQueue", MethodCompileQueue_lock);
_compilers[1]->set_num_compiler_threads(c2_compiler_count);
}
if (c1_compiler_count > 0) {
_c1_compile_queue = new CompileQueue("C1 CompileQueue", MethodCompileQueue_lock);
_compilers[0]->set_num_compiler_threads(c1_compiler_count);
}
int compiler_count = c1_compiler_count + c2_compiler_count;
_compiler_threads =
new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<CompilerThread*>(compiler_count, true);
char name_buffer[256];
for (int i = 0; i < c2_compiler_count; i++) {
sprintf(name_buffer, "C2 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c2_compile_queue, counters, _compilers[1], CHECK);
_compiler_threads->append(new_thread);
}
for (int i = c2_compiler_count; i < compiler_count; i++) {
sprintf(name_buffer, "C1 CompilerThread%d", i);
CompilerCounters* counters = new CompilerCounters("compilerThread", i, CHECK);
CompilerThread* new_thread = make_compiler_thread(name_buffer, _c1_compile_queue, counters, _compilers[0], CHECK);
_compiler_threads->append(new_thread);
}
if (UsePerfData) {
PerfDataManager::create_constant(SUN_CI, "threads", PerfData::U_Bytes, compiler_count, CHECK);
}
}
void CompileBroker::mark_on_stack() {
assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
if (_c2_compile_queue != NULL) {
_c2_compile_queue->mark_on_stack();
}
if (_c1_compile_queue != NULL) {
_c1_compile_queue->mark_on_stack();
}
}
void CompileBroker::compile_method_base(methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment,
Thread* thread) {
if (!_initialized) {
return;
}
guarantee(!method->is_abstract(), "cannot compile abstract methods");
assert(method->method_holder()->oop_is_instance(),
"sanity check");
assert(!method->method_holder()->is_not_initialized(),
"method holder must be initialized");
assert(!method->is_method_handle_intrinsic(), "do not enqueue these guys");
if (CIPrintRequests) {
tty->print("request: ");
method->print_short_name(tty);
if (osr_bci != InvocationEntryBci) {
tty->print(" osr_bci: %d", osr_bci);
}
tty->print(" comment: %s count: %d", comment, hot_count);
if (!hot_method.is_null()) {
tty->print(" hot: ");
if (hot_method() != method()) {
hot_method->print_short_name(tty);
} else {
tty->print("yes");
}
}
tty->cr();
}
if (compilation_is_complete(method, osr_bci, comp_level)) {
return;
}
#ifndef PRODUCT
if (osr_bci != -1 && !FLAG_IS_DEFAULT(OSROnlyBCI)) {
if ((OSROnlyBCI > 0) ? (OSROnlyBCI != osr_bci) : (-OSROnlyBCI == osr_bci)) {
return;
}
}
#endif
if (compilation_is_in_queue(method)) {
return;
}
if (InstanceRefKlass::owns_pending_list_lock(JavaThread::current())) {
return;
}
if (TieredCompilation) {
method->get_method_counters(thread);
}
CompileTask* task = NULL;
bool blocking = false;
CompileQueue* queue = compile_queue(comp_level);
{
MutexLocker locker(queue->lock(), thread);
if (compilation_is_in_queue(method)) {
return;
}
if (compilation_is_complete(method, osr_bci, comp_level)) {
return;
}
int compile_id = assign_compile_id(method, osr_bci);
if (compile_id == 0) {
return;
}
blocking = is_compile_blocking();
task = create_compile_task(queue,
compile_id, method,
osr_bci, comp_level,
hot_method, hot_count, comment,
blocking);
}
if (blocking) {
wait_for_completion(task);
}
}
nmethod* CompileBroker::compile_method(methodHandle method, int osr_bci,
int comp_level,
methodHandle hot_method, int hot_count,
const char* comment, Thread* THREAD) {
assert(method->method_holder()->oop_is_instance(), "not an instance method");
assert(osr_bci == InvocationEntryBci || (0 <= osr_bci && osr_bci < method->code_size()), "bci out of range");
assert(!method->is_abstract() && (osr_bci == InvocationEntryBci || !method->is_native()), "cannot compile abstract/native methods");
assert(!method->method_holder()->is_not_initialized(), "method holder must be initialized");
assert(WhiteBoxAPI || TieredCompilation || comp_level == CompLevel_highest_tier, "only CompLevel_highest_tier must be used in non-tiered");
AbstractCompiler *comp = CompileBroker::compiler(comp_level);
if (comp == NULL || !comp->can_compile_method(method) ||
compilation_is_prohibited(method, osr_bci, comp_level)) {
return NULL;
}
if (osr_bci == InvocationEntryBci) {
nmethod* method_code = method->code();
if (method_code != NULL) {
if (compilation_is_complete(method, osr_bci, comp_level)) {
return method_code;
}
}
if (method->is_not_compilable(comp_level)) {
return NULL;
}
} else {
#ifndef TIERED
assert(comp_level == CompLevel_highest_tier,
"all OSR compiles are assumed to be at a single compilation lavel");
#endif // TIERED
nmethod* nm = method->lookup_osr_nmethod_for(osr_bci, comp_level, false);
if (nm != NULL) return nm;
if (method->is_not_osr_compilable(comp_level)) return NULL;
}
assert(!HAS_PENDING_EXCEPTION, "No exception should be present");
if (comp->is_c2() || comp->is_shark()) {
method->constants()->resolve_string_constants(CHECK_AND_CLEAR_NULL);
Method::load_signature_classes(method, CHECK_AND_CLEAR_NULL);
}
if (method->is_native() && !method->is_method_handle_intrinsic()) {
bool in_base_library;
address adr = NativeLookup::lookup(method, in_base_library, THREAD);
if (HAS_PENDING_EXCEPTION) {
method->set_not_compilable(); // implies is_not_osr_compilable()
CLEAR_PENDING_EXCEPTION;
return NULL;
}
assert(method->has_native_function(), "must have native code by now");
}
if (method->is_old()) {
return NULL;
}
if (JvmtiExport::should_post_compiled_method_load()) {
method->jmethod_id();
}
if (method->is_native()) {
if (!PreferInterpreterNativeStubs || method->is_method_handle_intrinsic()) {
AdapterHandlerLibrary::create_native_wrapper(method);
} else {
return NULL;
}
} else {
if (!should_compile_new_jobs()) {
CompilationPolicy::policy()->delay_compilation(method());
return NULL;
}
compile_method_base(method, osr_bci, comp_level, hot_method, hot_count, comment, THREAD);
}
return osr_bci == InvocationEntryBci ? method->code() : method->lookup_osr_nmethod_for(osr_bci, comp_level, false);
}
bool CompileBroker::compilation_is_complete(methodHandle method,
int osr_bci,
int comp_level) {
bool is_osr = (osr_bci != standard_entry_bci);
if (is_osr) {
if (method->is_not_osr_compilable(comp_level)) {
return true;
} else {
nmethod* result = method->lookup_osr_nmethod_for(osr_bci, comp_level, true);
return (result != NULL);
}
} else {
if (method->is_not_compilable(comp_level)) {
return true;
} else {
nmethod* result = method->code();
if (result == NULL) return false;
return comp_level == result->comp_level();
}
}
}
bool CompileBroker::compilation_is_in_queue(methodHandle method) {
return method->queued_for_compilation();
}
bool CompileBroker::compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level) {
bool is_native = method->is_native();
AbstractCompiler *comp = compiler(comp_level);
if (is_native &&
(!CICompileNatives || comp == NULL || !comp->supports_native())) {
method->set_not_compilable_quietly(comp_level);
return true;
}
bool is_osr = (osr_bci != standard_entry_bci);
if (is_osr &&
(!CICompileOSR || comp == NULL || !comp->supports_osr())) {
method->set_not_osr_compilable(comp_level);
return true;
}
bool quietly;
if (CompilerOracle::should_exclude(method, quietly)) {
if (!quietly) {
ResourceMark rm;
tty->print("### Excluding %s:%s",
method->is_native() ? "generation of native wrapper" : "compile",
(method->is_static() ? " static" : ""));
method->print_short_name(tty);
tty->cr();
}
method->set_not_compilable(CompLevel_all, !quietly, "excluded by CompilerOracle");
}
return false;
}
int CompileBroker::assign_compile_id(methodHandle method, int osr_bci) {
#ifdef ASSERT
bool is_osr = (osr_bci != standard_entry_bci);
int id;
if (method->is_native()) {
assert(!is_osr, "can't be osr");
return Atomic::add(1, &_compilation_id);
} else if (CICountOSR && is_osr) {
id = Atomic::add(1, &_osr_compilation_id);
if (CIStartOSR <= id && id < CIStopOSR) {
return id;
}
} else {
id = Atomic::add(1, &_compilation_id);
if (CIStart <= id && id < CIStop) {
return id;
}
}
method->set_not_compilable_quietly();
return 0;
#else
return Atomic::add(1, &_compilation_id);
#endif
}
bool CompileBroker::is_compile_blocking() {
assert(!InstanceRefKlass::owns_pending_list_lock(JavaThread::current()), "possible deadlock");
return !BackgroundCompilation;
}
void CompileBroker::preload_classes(methodHandle method, TRAPS) {
ShouldNotReachHere();
}
CompileTask* CompileBroker::create_compile_task(CompileQueue* queue,
int compile_id,
methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment,
bool blocking) {
CompileTask* new_task = CompileTask::allocate();
new_task->initialize(compile_id, method, osr_bci, comp_level,
hot_method, hot_count, comment,
blocking);
queue->add(new_task);
return new_task;
}
void CompileBroker::wait_for_completion(CompileTask* task) {
if (CIPrintCompileQueue) {
ttyLocker ttyl;
tty->print_cr("BLOCKING FOR COMPILE");
}
assert(task->is_blocking(), "can only wait on blocking task");
JavaThread* thread = JavaThread::current();
thread->set_blocked_on_compilation(true);
methodHandle method(thread, task->method());
{
MutexLocker waiter(task->lock(), thread);
while (!task->is_complete() && !is_compilation_disabled_forever()) {
task->lock()->wait();
}
}
thread->set_blocked_on_compilation(false);
if (is_compilation_disabled_forever()) {
CompileTask::free(task);
return;
}
assert(task->is_complete(), "Compilation should have completed");
assert(task->code_handle() == NULL, "must be reset");
CompileTask::free(task);
}
bool CompileBroker::init_compiler_runtime() {
CompilerThread* thread = CompilerThread::current();
AbstractCompiler* comp = thread->compiler();
guarantee(comp != NULL, "Compiler object must exist");
int system_dictionary_modification_counter;
{
MutexLocker locker(Compile_lock, thread);
system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
}
{
ThreadToNativeFromVM ttn(thread);
ciEnv ci_env(NULL, system_dictionary_modification_counter);
ci_env.cache_jvmti_state();
ci_env.cache_dtrace_flags();
ThreadInVMfromNative tv(thread);
ResetNoHandleMark rnhm;
if (!comp->is_shark()) {
comp->initialize();
}
}
if (comp->is_failed()) {
disable_compilation_forever();
shutdown_compiler_runtime(comp, thread);
return false;
}
if (comp->is_c1() && (thread->get_buffer_blob() == NULL)) {
warning("Initialization of %s thread failed (no space to run compilers)", thread->name());
return false;
}
return true;
}
void CompileBroker::shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread) {
if (thread->get_buffer_blob() != NULL) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
CodeCache::free(thread->get_buffer_blob());
}
if (comp->should_perform_shutdown()) {
warning("%s initialization failed. Shutting down all compilers", comp->name());
comp->set_shut_down();
if (_c1_compile_queue != NULL) {
_c1_compile_queue->free_all();
}
if (_c2_compile_queue != NULL) {
_c2_compile_queue->free_all();
}
UseCompiler = false;
UseInterpreter = true;
}
}
void CompileBroker::compiler_thread_loop() {
CompilerThread* thread = CompilerThread::current();
CompileQueue* queue = thread->queue();
ResourceMark rm;
if (!ciObjectFactory::is_initialized()) {
ASSERT_IN_VM;
MutexLocker only_one (CompileThread_lock, thread);
if (!ciObjectFactory::is_initialized()) {
ciObjectFactory::initialize();
}
}
if (LogCompilation) {
init_compiler_thread_log();
}
CompileLog* log = thread->log();
if (log != NULL) {
log->begin_elem("start_compile_thread name='%s' thread='" UINTX_FORMAT "' process='%d'",
thread->name(),
os::current_thread_id(),
os::current_process_id());
log->stamp();
log->end_elem();
}
if (!init_compiler_runtime()) {
return;
}
while (!is_compilation_disabled_forever()) {
HandleMark hm(thread);
if (CodeCache::unallocated_capacity() < CodeCacheMinimumFreeSpace) {
handle_full_code_cache();
}
CompileTask* task = queue->get();
if (task == NULL) {
continue;
}
if( CompilerThreadHintNoPreempt )
os::hint_no_preempt();
CompilerCounters* counters = ((CompilerThread*)thread)->counters();
PerfTraceTimedEvent(counters->time_counter(), counters->compile_counter());
CompileTaskWrapper ctw(task);
nmethodLocker result_handle; // (handle for the nmethod produced by this task)
task->set_code_handle(&result_handle);
methodHandle method(thread, task->method());
if (method()->number_of_breakpoints() == 0) {
if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) {
invoke_compiler_on_method(task);
} else {
method->clear_queued_for_compilation();
task->set_failure_reason("compilation is disabled");
}
}
}
shutdown_compiler_runtime(thread->compiler(), thread);
}
void CompileBroker::init_compiler_thread_log() {
CompilerThread* thread = CompilerThread::current();
char file_name[4*K];
FILE* fp = NULL;
intx thread_id = os::current_thread_id();
for (int try_temp_dir = 1; try_temp_dir >= 0; try_temp_dir--) {
const char* dir = (try_temp_dir ? os::get_temp_directory() : NULL);
if (dir == NULL) {
jio_snprintf(file_name, sizeof(file_name), "hs_c" UINTX_FORMAT "_pid%u.log",
thread_id, os::current_process_id());
} else {
jio_snprintf(file_name, sizeof(file_name),
"%s%shs_c" UINTX_FORMAT "_pid%u.log", dir,
os::file_separator(), thread_id, os::current_process_id());
}
fp = fopen(file_name, "wt");
if (fp != NULL) {
if (LogCompilation && Verbose) {
tty->print_cr("Opening compilation log %s", file_name);
}
CompileLog* log = new(ResourceObj::C_HEAP, mtCompiler) CompileLog(file_name, fp, thread_id);
if (log == NULL) {
fclose(fp);
return;
}
thread->init_log(log);
if (xtty != NULL) {
ttyLocker ttyl;
xtty->elem("thread_logfile thread='" INTX_FORMAT "' filename='%s'", thread_id, file_name);
}
return;
}
}
warning("Cannot open log file: %s", file_name);
}
void CompileBroker::set_should_block() {
assert(Threads_lock->owner() == Thread::current(), "must have threads lock");
assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint already");
#ifndef PRODUCT
if (PrintCompilation && (Verbose || WizardMode))
tty->print_cr("notifying compiler thread pool to block");
#endif
_should_block = true;
}
void CompileBroker::maybe_block() {
if (_should_block) {
#ifndef PRODUCT
if (PrintCompilation && (Verbose || WizardMode))
tty->print_cr("compiler thread " INTPTR_FORMAT " poll detects block request", p2i(Thread::current()));
#endif
ThreadInVMfromNative tivfn(JavaThread::current());
}
}
static void codecache_print(bool detailed)
{
ResourceMark rm;
stringStream s;
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
CodeCache::print_summary(&s, detailed);
}
ttyLocker ttyl;
tty->print("%s", s.as_string());
}
static void post_compilation_event(EventCompilation* event, CompileTask* task) {
assert(event != NULL, "invariant");
assert(event->should_commit(), "invariant");
event->set_method(task->method());
event->set_compileId(task->compile_id());
event->set_compileLevel(task->comp_level());
event->set_succeded(task->is_success());
event->set_isOsr(task->osr_bci() != CompileBroker::standard_entry_bci);
event->set_codeSize((task->code() == NULL) ? 0 : task->code()->total_size());
event->set_inlinedBytes(task->num_inlined_bytecodes());
event->commit();
}
void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
if (PrintCompilation) {
ResourceMark rm;
task->print_line();
}
elapsedTimer time;
CompilerThread* thread = CompilerThread::current();
ResourceMark rm(thread);
if (LogEvents) {
_compilation_log->log_compile(thread, task);
}
uint compile_id = task->compile_id();
int osr_bci = task->osr_bci();
bool is_osr = (osr_bci != standard_entry_bci);
bool should_log = (thread->log() != NULL);
bool should_break = false;
int task_level = task->comp_level();
{
methodHandle method(thread, task->method());
should_break = check_break_at(method, compile_id, is_osr);
if (should_log && !CompilerOracle::should_log(method)) {
should_log = false;
}
assert(!method->is_native(), "no longer compile natives");
set_last_compile(thread, method, is_osr, task_level);
DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level));
}
push_jni_handle_block();
Method* target_handle = task->method();
int compilable = ciEnv::MethodCompilable;
{
int system_dictionary_modification_counter;
{
MutexLocker locker(Compile_lock, thread);
system_dictionary_modification_counter = SystemDictionary::number_of_modifications();
}
NoHandleMark nhm;
ThreadToNativeFromVM ttn(thread);
ciEnv ci_env(task, system_dictionary_modification_counter);
if (should_break) {
ci_env.set_break_at_compile(true);
}
if (should_log) {
ci_env.set_log(thread->log());
}
assert(thread->env() == &ci_env, "set by ci_env");
ci_env.cache_jvmti_state();
ci_env.cache_dtrace_flags();
ciMethod* target = ci_env.get_method_from_handle(target_handle);
TraceTime t1("compilation", &time);
EventCompilation event;
AbstractCompiler *comp = compiler(task_level);
if (comp == NULL) {
ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
} else {
comp->compile_method(&ci_env, target, osr_bci);
}
if (!ci_env.failing() && task->code() == NULL) {
ci_env.record_method_not_compilable("compile failed", !TieredCompilation);
}
compilable = ci_env.compilable();
if (ci_env.failing()) {
const char* failure_reason = ci_env.failure_reason();
const char* retry_message = ci_env.retry_message();
task->set_failure_reason(failure_reason);
if (_compilation_log != NULL) {
_compilation_log->log_failure(thread, task, ci_env.failure_reason(), retry_message);
}
if (PrintCompilation) {
FormatBufferResource msg = retry_message != NULL ?
err_msg_res("COMPILE SKIPPED: %s (%s)", ci_env.failure_reason(), retry_message) :
err_msg_res("COMPILE SKIPPED: %s", ci_env.failure_reason());
task->print_compilation(tty, msg);
}
EventCompilationFailure event;
if (event.should_commit()) {
event.set_compileId(compile_id);
event.set_failureMessage(failure_reason);
event.commit();
}
if (AbortVMOnCompilationFailure) {
if (compilable == ciEnv::MethodCompilable_not_at_tier) {
fatal(err_msg("Not compilable at tier %d: %s", task_level, failure_reason));
}
if (compilable == ciEnv::MethodCompilable_never) {
fatal(err_msg("Never compilable: %s", failure_reason));
}
}
} else {
task->mark_success();
task->set_num_inlined_bytecodes(ci_env.num_inlined_bytecodes());
if (_compilation_log != NULL) {
nmethod* code = task->code();
if (code != NULL) {
_compilation_log->log_nmethod(thread, code);
}
}
}
assert(task->compile_id() != CICrashAt, "just as planned");
if (event.should_commit()) {
post_compilation_event(&event, task);
}
}
pop_jni_handle_block();
methodHandle method(thread, task->method());
DTRACE_METHOD_COMPILE_END_PROBE(method, compiler_name(task_level), task->is_success());
collect_statistics(thread, time, task);
if (PrintCompilation && PrintCompilation2) {
tty->print("%7d ", (int) tty->time_stamp().milliseconds()); // print timestamp
tty->print("%4d ", compile_id); // print compilation number
tty->print("%s ", (is_osr ? "%" : " "));
if (task->code() != NULL) {
tty->print("size: %d(%d) ", task->code()->total_size(), task->code()->insts_size());
}
tty->print_cr("time: %d inlined: %d bytes", (int)time.milliseconds(), task->num_inlined_bytecodes());
}
if (PrintCodeCacheOnCompilation)
codecache_print(/* detailed= */ false);
switch (compilable) {
case ciEnv::MethodCompilable_never:
if (is_osr)
method->set_not_osr_compilable_quietly();
else
method->set_not_compilable_quietly();
break;
case ciEnv::MethodCompilable_not_at_tier:
if (is_osr)
method->set_not_osr_compilable_quietly(task_level);
else
method->set_not_compilable_quietly(task_level);
break;
}
method->clear_queued_for_compilation();
#ifdef ASSERT
if (CollectedHeap::fired_fake_oom()) {
tty->print_cr("*** Shutting down VM after successful fake OOM");
vm_exit(0);
}
#endif
}
void CompileBroker::handle_full_code_cache() {
UseInterpreter = true;
if (UseCompiler || AlwaysCompileLoopMethods ) {
if (xtty != NULL) {
ResourceMark rm;
stringStream s;
CodeCache::log_state(&s);
ttyLocker ttyl;
xtty->begin_elem("code_cache_full");
xtty->print("%s", s.as_string());
xtty->stamp();
xtty->end_elem();
}
CodeCache::report_codemem_full();
#ifndef PRODUCT
if (CompileTheWorld || ExitOnFullCodeCache) {
codecache_print(/* detailed= */ true);
before_exit(JavaThread::current());
exit_globals(); // will delete tty
vm_direct_exit(CompileTheWorld ? 0 : 1);
}
#endif
if (UseCodeCacheFlushing) {
if (CompileBroker::set_should_compile_new_jobs(CompileBroker::stop_compilation)) {
NMethodSweeper::log_sweep("disable_compiler");
}
ThreadInVMfromUnknown in_vm;
NMethodSweeper::possibly_sweep();
} else {
disable_compilation_forever();
}
if (should_print_compiler_warning()) {
warning("CodeCache is full. Compiler has been disabled.");
warning("Try increasing the code cache size using -XX:ReservedCodeCacheSize=");
codecache_print(/* detailed= */ true);
}
}
}
void CompileBroker::set_last_compile(CompilerThread* thread, methodHandle method, bool is_osr, int comp_level) {
ResourceMark rm;
char* method_name = method->name()->as_C_string();
strncpy(_last_method_compiled, method_name, CompileBroker::name_buffer_length);
_last_method_compiled[CompileBroker::name_buffer_length - 1] = '\0'; // ensure null terminated
char current_method[CompilerCounters::cmname_buffer_length];
size_t maxLen = CompilerCounters::cmname_buffer_length;
if (UsePerfData) {
const char* class_name = method->method_holder()->name()->as_C_string();
size_t s1len = strlen(class_name);
size_t s2len = strlen(method_name);
if (s1len + s2len + 2 > maxLen) {
if (s2len + 2 > maxLen) {
class_name += s1len; // null string
}
else {
class_name += ((s1len + s2len + 2) - maxLen);
}
}
jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name);
}
if (CICountOSR && is_osr) {
_last_compile_type = osr_compile;
} else {
_last_compile_type = normal_compile;
}
_last_compile_level = comp_level;
if (UsePerfData) {
CompilerCounters* counters = thread->counters();
counters->set_current_method(current_method);
counters->set_compile_type((jlong)_last_compile_type);
}
}
void CompileBroker::push_jni_handle_block() {
JavaThread* thread = JavaThread::current();
JNIHandleBlock* java_handles = thread->active_handles();
JNIHandleBlock* compile_handles = JNIHandleBlock::allocate_block(thread);
assert(compile_handles != NULL && java_handles != NULL, "should not be NULL");
compile_handles->set_pop_frame_link(java_handles); // make sure java handles get gc'd.
thread->set_active_handles(compile_handles);
}
void CompileBroker::pop_jni_handle_block() {
JavaThread* thread = JavaThread::current();
JNIHandleBlock* compile_handles = thread->active_handles();
JNIHandleBlock* java_handles = compile_handles->pop_frame_link();
thread->set_active_handles(java_handles);
compile_handles->set_pop_frame_link(NULL);
JNIHandleBlock::release_block(compile_handles, thread); // may block
}
bool CompileBroker::check_break_at(methodHandle method, int compile_id, bool is_osr) {
if (CICountOSR && is_osr && (compile_id == CIBreakAtOSR)) {
return true;
} else if( CompilerOracle::should_break_at(method) ) { // break when compiling
return true;
} else {
return (compile_id == CIBreakAt);
}
}
void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task) {
bool success = task->is_success();
methodHandle method (thread, task->method());
uint compile_id = task->compile_id();
bool is_osr = (task->osr_bci() != standard_entry_bci);
nmethod* code = task->code();
CompilerCounters* counters = thread->counters();
assert(code == NULL || code->is_locked_by_vm(), "will survive the MutexLocker");
MutexLocker locker(CompileStatistics_lock);
if (!success) {
_total_bailout_count++;
if (UsePerfData) {
_perf_last_failed_method->set_value(counters->current_method());
_perf_last_failed_type->set_value(counters->compile_type());
_perf_total_bailout_count->inc();
}
} else if (code == NULL) {
if (UsePerfData) {
_perf_last_invalidated_method->set_value(counters->current_method());
_perf_last_invalidated_type->set_value(counters->compile_type());
_perf_total_invalidated_count->inc();
}
_total_invalidated_count++;
} else {
_perf_total_compilation->inc(time.ticks());
_t_total_compilation.add(time);
_peak_compilation_time = time.milliseconds() > _peak_compilation_time ? time.milliseconds() : _peak_compilation_time;
if (CITime) {
if (is_osr) {
_t_osr_compilation.add(time);
_sum_osr_bytes_compiled += method->code_size() + task->num_inlined_bytecodes();
} else {
_t_standard_compilation.add(time);
_sum_standard_bytes_compiled += method->code_size() + task->num_inlined_bytecodes();
}
}
if (UsePerfData) {
_perf_last_method->set_value(counters->current_method());
_perf_last_compile_type->set_value(counters->compile_type());
_perf_last_compile_size->set_value(method->code_size() +
task->num_inlined_bytecodes());
if (is_osr) {
_perf_osr_compilation->inc(time.ticks());
_perf_sum_osr_bytes_compiled->inc(method->code_size() + task->num_inlined_bytecodes());
} else {
_perf_standard_compilation->inc(time.ticks());
_perf_sum_standard_bytes_compiled->inc(method->code_size() + task->num_inlined_bytecodes());
}
}
if (CITimeEach) {
float bytes_per_sec = 1.0 * (method->code_size() + task->num_inlined_bytecodes()) / time.seconds();
tty->print_cr("%3d seconds: %f bytes/sec : %f (bytes %d + %d inlined)",
compile_id, time.seconds(), bytes_per_sec, method->code_size(), task->num_inlined_bytecodes());
}
_sum_nmethod_size += code->total_size();
_sum_nmethod_code_size += code->insts_size();
_total_compile_count++;
if (UsePerfData) {
_perf_sum_nmethod_size->inc( code->total_size());
_perf_sum_nmethod_code_size->inc(code->insts_size());
_perf_total_compile_count->inc();
}
if (is_osr) {
if (UsePerfData) _perf_total_osr_compile_count->inc();
_total_osr_compile_count++;
} else {
if (UsePerfData) _perf_total_standard_compile_count->inc();
_total_standard_compile_count++;
}
}
if (UsePerfData) counters->set_current_method("");
}
const char* CompileBroker::compiler_name(int comp_level) {
AbstractCompiler *comp = CompileBroker::compiler(comp_level);
if (comp == NULL) {
return "no compiler";
} else {
return (comp->name());
}
}
void CompileBroker::print_times() {
tty->cr();
tty->print_cr("Accumulated compiler times (for compiled methods only)");
tty->print_cr("------------------------------------------------");
tty->print_cr(" Total compilation time : %6.3f s", CompileBroker::_t_total_compilation.seconds());
tty->print_cr(" Standard compilation : %6.3f s, Average : %2.3f",
CompileBroker::_t_standard_compilation.seconds(),
CompileBroker::_t_standard_compilation.seconds() / CompileBroker::_total_standard_compile_count);
tty->print_cr(" On stack replacement : %6.3f s, Average : %2.3f", CompileBroker::_t_osr_compilation.seconds(), CompileBroker::_t_osr_compilation.seconds() / CompileBroker::_total_osr_compile_count);
AbstractCompiler *comp = compiler(CompLevel_simple);
if (comp != NULL) {
comp->print_timers();
}
comp = compiler(CompLevel_full_optimization);
if (comp != NULL) {
comp->print_timers();
}
tty->cr();
tty->print_cr(" Total compiled methods : %6d methods", CompileBroker::_total_compile_count);
tty->print_cr(" Standard compilation : %6d methods", CompileBroker::_total_standard_compile_count);
tty->print_cr(" On stack replacement : %6d methods", CompileBroker::_total_osr_compile_count);
int tcb = CompileBroker::_sum_osr_bytes_compiled + CompileBroker::_sum_standard_bytes_compiled;
tty->print_cr(" Total compiled bytecodes : %6d bytes", tcb);
tty->print_cr(" Standard compilation : %6d bytes", CompileBroker::_sum_standard_bytes_compiled);
tty->print_cr(" On stack replacement : %6d bytes", CompileBroker::_sum_osr_bytes_compiled);
int bps = (int)(tcb / CompileBroker::_t_total_compilation.seconds());
tty->print_cr(" Average compilation speed: %6d bytes/s", bps);
tty->cr();
tty->print_cr(" nmethod code size : %6d bytes", CompileBroker::_sum_nmethod_code_size);
tty->print_cr(" nmethod total size : %6d bytes", CompileBroker::_sum_nmethod_size);
}
void CompileBroker::print_last_compile() {
if ( _last_compile_level != CompLevel_none &&
compiler(_last_compile_level) != NULL &&
_last_method_compiled != NULL &&
_last_compile_type != no_compile) {
if (_last_compile_type == osr_compile) {
tty->print_cr("Last parse: [osr]%d+++(%d) %s",
_osr_compilation_id, _last_compile_level, _last_method_compiled);
} else {
tty->print_cr("Last parse: %d+++(%d) %s",
_compilation_id, _last_compile_level, _last_method_compiled);
}
}
}
void CompileBroker::print_compiler_threads_on(outputStream* st) {
#ifndef PRODUCT
st->print_cr("Compiler thread printing unimplemented.");
st->cr();
#endif
}
C:\hotspot-69087d08d473\src\share\vm/compiler/compileBroker.hpp
#ifndef SHARE_VM_COMPILER_COMPILEBROKER_HPP
#define SHARE_VM_COMPILER_COMPILEBROKER_HPP
#include "ci/compilerInterface.hpp"
#include "compiler/abstractCompiler.hpp"
#include "runtime/perfData.hpp"
class nmethod;
class nmethodLocker;
class CompileTask : public CHeapObj<mtCompiler> {
friend class VMStructs;
private:
static CompileTask* _task_free_list;
#ifdef ASSERT
static int _num_allocated_tasks;
#endif
Monitor* _lock;
uint _compile_id;
Method* _method;
jobject _method_holder;
int _osr_bci;
bool _is_complete;
bool _is_success;
bool _is_blocking;
int _comp_level;
int _num_inlined_bytecodes;
nmethodLocker* _code_handle; // holder of eventual result
CompileTask* _next, *_prev;
bool _is_free;
jlong _time_queued; // in units of os::elapsed_counter()
Method* _hot_method; // which method actually triggered this task
jobject _hot_method_holder;
int _hot_count; // information about its invocation counter
const char* _comment; // more info about the task
const char* _failure_reason;
public:
CompileTask() {
_lock = new Monitor(Mutex::nonleaf+2, "CompileTaskLock");
}
void initialize(int compile_id, methodHandle method, int osr_bci, int comp_level,
methodHandle hot_method, int hot_count, const char* comment,
bool is_blocking);
static CompileTask* allocate();
static void free(CompileTask* task);
int compile_id() const { return _compile_id; }
Method* method() const { return _method; }
int osr_bci() const { return _osr_bci; }
bool is_complete() const { return _is_complete; }
bool is_blocking() const { return _is_blocking; }
bool is_success() const { return _is_success; }
nmethodLocker* code_handle() const { return _code_handle; }
void set_code_handle(nmethodLocker* l) { _code_handle = l; }
nmethod* code() const; // _code_handle->code()
void set_code(nmethod* nm); // _code_handle->set_code(nm)
Monitor* lock() const { return _lock; }
void mark_complete() { _is_complete = true; }
void mark_success() { _is_success = true; }
int comp_level() { return _comp_level;}
void set_comp_level(int comp_level) { _comp_level = comp_level;}
int num_inlined_bytecodes() const { return _num_inlined_bytecodes; }
void set_num_inlined_bytecodes(int n) { _num_inlined_bytecodes = n; }
CompileTask* next() const { return _next; }
void set_next(CompileTask* next) { _next = next; }
CompileTask* prev() const { return _prev; }
void set_prev(CompileTask* prev) { _prev = prev; }
bool is_free() const { return _is_free; }
void set_is_free(bool val) { _is_free = val; }
private:
static void print_compilation_impl(outputStream* st, Method* method, int compile_id, int comp_level,
bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false,
const char* msg = NULL, bool short_form = false);
public:
void print_compilation(outputStream* st = tty, const char* msg = NULL, bool short_form = false);
static void print_compilation(outputStream* st, const nmethod* nm, const char* msg = NULL, bool short_form = false) {
print_compilation_impl(st, nm->method(), nm->compile_id(), nm->comp_level(),
nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false,
msg, short_form);
}
static void print_inlining(outputStream* st, ciMethod* method, int inline_level, int bci, const char* msg = NULL);
static void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) {
print_inlining(tty, method, inline_level, bci, msg);
}
void mark_on_stack();
static void print_inline_indent(int inline_level, outputStream* st = tty);
void print();
void print_line();
void print_line_on_error(outputStream* st, char* buf, int buflen);
void log_task(xmlStream* log);
void log_task_queued();
void log_task_start(CompileLog* log);
void log_task_done(CompileLog* log);
void set_failure_reason(const char* reason) {
_failure_reason = reason;
}
};
class CompilerCounters : public CHeapObj<mtCompiler> {
public:
enum {
cmname_buffer_length = 160
};
private:
char _current_method[cmname_buffer_length];
PerfStringVariable* _perf_current_method;
int _compile_type;
PerfVariable* _perf_compile_type;
PerfCounter* _perf_time;
PerfCounter* _perf_compiles;
public:
CompilerCounters(const char* name, int instance, TRAPS);
void set_current_method(const char* method) {
strncpy(_current_method, method, (size_t)cmname_buffer_length-1);
_current_method[cmname_buffer_length-1] = '\0';
if (UsePerfData) _perf_current_method->set_value(method);
}
char* current_method() { return _current_method; }
void set_compile_type(int compile_type) {
_compile_type = compile_type;
if (UsePerfData) _perf_compile_type->set_value((jlong)compile_type);
}
int compile_type() { return _compile_type; }
PerfCounter* time_counter() { return _perf_time; }
PerfCounter* compile_counter() { return _perf_compiles; }
};
class CompileQueue : public CHeapObj<mtCompiler> {
private:
const char* _name;
Monitor* _lock;
CompileTask* _first;
CompileTask* _last;
CompileTask* _first_stale;
int _size;
void purge_stale_tasks();
public:
CompileQueue(const char* name, Monitor* lock) {
_name = name;
_lock = lock;
_first = NULL;
_last = NULL;
_size = 0;
_first_stale = NULL;
}
const char* name() const { return _name; }
Monitor* lock() const { return _lock; }
void add(CompileTask* task);
void remove(CompileTask* task);
void remove_and_mark_stale(CompileTask* task);
CompileTask* first() { return _first; }
CompileTask* last() { return _last; }
CompileTask* get();
bool is_empty() const { return _first == NULL; }
int size() const { return _size; }
void mark_on_stack();
void free_all();
NOT_PRODUCT (void print();)
~CompileQueue() {
assert (is_empty(), " Compile Queue must be empty");
}
};
class CompileTaskWrapper : StackObj {
public:
CompileTaskWrapper(CompileTask* task);
~CompileTaskWrapper();
};
class CompileBroker: AllStatic {
friend class Threads;
friend class CompileTaskWrapper;
public:
enum {
name_buffer_length = 100
};
enum { no_compile, normal_compile, osr_compile, native_compile };
static int assign_compile_id (methodHandle method, int osr_bci);
private:
static bool _initialized;
static volatile bool _should_block;
static volatile jint _should_compile_new_jobs;
static AbstractCompiler* _compilers[2];
static volatile jint _compilation_id;
static volatile jint _osr_compilation_id;
static int _last_compile_type;
static int _last_compile_level;
static char _last_method_compiled[name_buffer_length];
static CompileQueue* _c2_compile_queue;
static CompileQueue* _c1_compile_queue;
static GrowableArray<CompilerThread*>* _compiler_threads;
static PerfCounter* _perf_total_compilation;
static PerfCounter* _perf_native_compilation;
static PerfCounter* _perf_osr_compilation;
static PerfCounter* _perf_standard_compilation;
static PerfCounter* _perf_total_bailout_count;
static PerfCounter* _perf_total_invalidated_count;
static PerfCounter* _perf_total_compile_count;
static PerfCounter* _perf_total_native_compile_count;
static PerfCounter* _perf_total_osr_compile_count;
static PerfCounter* _perf_total_standard_compile_count;
static PerfCounter* _perf_sum_osr_bytes_compiled;
static PerfCounter* _perf_sum_standard_bytes_compiled;
static PerfCounter* _perf_sum_nmethod_size;
static PerfCounter* _perf_sum_nmethod_code_size;
static PerfStringVariable* _perf_last_method;
static PerfStringVariable* _perf_last_failed_method;
static PerfStringVariable* _perf_last_invalidated_method;
static PerfVariable* _perf_last_compile_type;
static PerfVariable* _perf_last_compile_size;
static PerfVariable* _perf_last_failed_type;
static PerfVariable* _perf_last_invalidated_type;
static elapsedTimer _t_total_compilation;
static elapsedTimer _t_osr_compilation;
static elapsedTimer _t_standard_compilation;
static int _total_compile_count;
static int _total_bailout_count;
static int _total_invalidated_count;
static int _total_native_compile_count;
static int _total_osr_compile_count;
static int _total_standard_compile_count;
static int _sum_osr_bytes_compiled;
static int _sum_standard_bytes_compiled;
static int _sum_nmethod_size;
static int _sum_nmethod_code_size;
static long _peak_compilation_time;
static volatile jint _print_compilation_warning;
static CompilerThread* make_compiler_thread(const char* name, CompileQueue* queue, CompilerCounters* counters, AbstractCompiler* comp, TRAPS);
static void init_compiler_threads(int c1_compiler_count, int c2_compiler_count);
static bool compilation_is_prohibited(methodHandle method, int osr_bci, int comp_level);
static bool is_compile_blocking ();
static void preload_classes (methodHandle method, TRAPS);
static CompileTask* create_compile_task(CompileQueue* queue,
int compile_id,
methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment,
bool blocking);
static void wait_for_completion(CompileTask* task);
static void invoke_compiler_on_method(CompileTask* task);
static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level);
static void push_jni_handle_block();
static void pop_jni_handle_block();
static bool check_break_at(methodHandle method, int compile_id, bool is_osr);
static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task);
static void compile_method_base(methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment,
Thread* thread);
static CompileQueue* compile_queue(int comp_level) {
if (is_c2_compile(comp_level)) return _c2_compile_queue;
if (is_c1_compile(comp_level)) return _c1_compile_queue;
return NULL;
}
static bool init_compiler_runtime();
static void shutdown_compiler_runtime(AbstractCompiler* comp, CompilerThread* thread);
public:
enum {
standard_entry_bci = InvocationEntryBci
};
static AbstractCompiler* compiler(int comp_level) {
if (is_c2_compile(comp_level)) return _compilers[1]; // C2
if (is_c1_compile(comp_level)) return _compilers[0]; // C1
return NULL;
}
static bool compilation_is_complete(methodHandle method, int osr_bci, int comp_level);
static bool compilation_is_in_queue(methodHandle method);
static int queue_size(int comp_level) {
CompileQueue *q = compile_queue(comp_level);
return q != NULL ? q->size() : 0;
}
static void compilation_init();
static void init_compiler_thread_log();
static nmethod* compile_method(methodHandle method,
int osr_bci,
int comp_level,
methodHandle hot_method,
int hot_count,
const char* comment, Thread* thread);
static void compiler_thread_loop();
static uint get_compilation_id() { return _compilation_id; }
static void set_should_block();
static void maybe_block();
enum {
stop_compilation = 0,
run_compilation = 1,
shutdown_compilaton = 2
};
static bool should_compile_new_jobs() { return UseCompiler && (_should_compile_new_jobs == run_compilation); }
static bool set_should_compile_new_jobs(jint new_state) {
jint old = Atomic::cmpxchg(new_state, &_should_compile_new_jobs, 1-new_state);
return (old == (1-new_state));
}
static void disable_compilation_forever() {
UseCompiler = false;
AlwaysCompileLoopMethods = false;
Atomic::xchg(shutdown_compilaton, &_should_compile_new_jobs);
}
static bool is_compilation_disabled_forever() {
return _should_compile_new_jobs == shutdown_compilaton;
}
static void handle_full_code_cache();
static bool should_print_compiler_warning() {
jint old = Atomic::cmpxchg(1, &_print_compilation_warning, 0);
return old == 0;
}
static jlong total_compilation_ticks() {
return _perf_total_compilation != NULL ? _perf_total_compilation->get_value() : 0;
}
static void mark_on_stack();
static void print_times();
static void print_last_compile();
static void print_compiler_threads_on(outputStream* st);
static const char* compiler_name(int comp_level);
static int get_total_compile_count() { return _total_compile_count; }
static int get_total_bailout_count() { return _total_bailout_count; }
static int get_total_invalidated_count() { return _total_invalidated_count; }
static int get_total_native_compile_count() { return _total_native_compile_count; }
static int get_total_osr_compile_count() { return _total_osr_compile_count; }
static int get_total_standard_compile_count() { return _total_standard_compile_count; }
static int get_sum_osr_bytes_compiled() { return _sum_osr_bytes_compiled; }
static int get_sum_standard_bytes_compiled() { return _sum_standard_bytes_compiled; }
static int get_sum_nmethod_size() { return _sum_nmethod_size;}
static int get_sum_nmethod_code_size() { return _sum_nmethod_code_size; }
static long get_peak_compilation_time() { return _peak_compilation_time; }
static long get_total_compilation_time() { return _t_total_compilation.milliseconds(); }
};
#endif // SHARE_VM_COMPILER_COMPILEBROKER_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/compileLog.cpp
#include "precompiled.hpp"
#include "ci/ciMethod.hpp"
#include "compiler/compileLog.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/method.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
CompileLog* CompileLog::_first = NULL;
CompileLog::CompileLog(const char* file_name, FILE* fp, intx thread_id)
: _context(_context_buffer, sizeof(_context_buffer))
{
initialize(new(ResourceObj::C_HEAP, mtCompiler) fileStream(fp, true));
_file_end = 0;
_thread_id = thread_id;
_identities_limit = 0;
_identities_capacity = 400;
_identities = NEW_C_HEAP_ARRAY(char, _identities_capacity, mtCompiler);
_file = NEW_C_HEAP_ARRAY(char, strlen(file_name)+1, mtCompiler);
strcpy((char*)_file, file_name);
{ MutexLocker locker(CompileTaskAlloc_lock);
_next = _first;
_first = this;
}
}
CompileLog::~CompileLog() {
delete _out; // Close fd in fileStream::~fileStream()
_out = NULL;
unlink(_file);
FREE_C_HEAP_ARRAY(char, _identities, mtCompiler);
FREE_C_HEAP_ARRAY(char, _file, mtCompiler);
}
void CompileLog::see_tag(const char* tag, bool push) {
if (_context.size() > 0 && _out != NULL) {
_out->write(_context.base(), _context.size());
_context.reset();
}
xmlStream::see_tag(tag, push);
}
void CompileLog::pop_tag(const char* tag) {
_context.reset(); // toss any context info.
xmlStream::pop_tag(tag);
}
int CompileLog::identify(ciBaseObject* obj) {
if (obj == NULL) return 0;
int id = obj->ident();
if (id < 0) return id;
if (id < _identities_limit && _identities[id] != 0) return id;
if (id >= _identities_capacity) {
int new_cap = _identities_capacity * 2;
if (new_cap <= id) new_cap = id + 100;
_identities = REALLOC_C_HEAP_ARRAY(char, _identities, new_cap, mtCompiler);
_identities_capacity = new_cap;
}
while (id >= _identities_limit) {
_identities[_identities_limit++] = 0;
}
assert(id < _identities_limit, "oob");
_identities[id] = 1; // mark
if (obj->is_metadata()) {
ciMetadata* mobj = obj->as_metadata();
if (mobj->is_klass()) {
ciKlass* klass = mobj->as_klass();
begin_elem("klass id='%d'", id);
name(klass->name());
if (!klass->is_loaded()) {
print(" unloaded='1'");
} else {
print(" flags='%d'", klass->modifier_flags());
}
end_elem();
} else if (mobj->is_method()) {
ciMethod* method = mobj->as_method();
ciSignature* sig = method->signature();
identify(sig->return_type());
for (int i = 0; i < sig->count(); i++) {
identify(sig->type_at(i));
}
begin_elem("method id='%d' holder='%d'",
id, identify(method->holder()));
name(method->name());
print(" return='%d'", identify(sig->return_type()));
if (sig->count() > 0) {
print(" arguments='");
for (int i = 0; i < sig->count(); i++) {
print((i == 0) ? "%d" : " %d", identify(sig->type_at(i)));
}
print("'");
}
if (!method->is_loaded()) {
print(" unloaded='1'");
} else {
print(" flags='%d'", (jchar) method->flags().as_int());
print(" bytes='%d'", method->code_size());
method->log_nmethod_identity(this);
print(" iicount='%d'", method->interpreter_invocation_count());
}
end_elem();
} else if (mobj->is_type()) {
BasicType type = mobj->as_type()->basic_type();
elem("type id='%d' name='%s'", id, type2name(type));
} else {
elem("unknown id='%d'", id);
ShouldNotReachHere();
}
} else if (obj->is_symbol()) {
begin_elem("symbol id='%d'", id);
name(obj->as_symbol());
end_elem();
} else {
elem("unknown id='%d'", id);
}
return id;
}
void CompileLog::name(ciSymbol* name) {
if (name == NULL) return;
print(" name='");
name->print_symbol_on(text()); // handles quoting conventions
print("'");
}
void CompileLog::clear_identities() {
_identities_limit = 0;
}
void CompileLog::finish_log_on_error(outputStream* file, char* buf, int buflen) {
static bool called_exit = false;
if (called_exit) return;
called_exit = true;
CompileLog* log = _first;
while (log != NULL) {
log->flush();
const char* partial_file = log->file();
int partial_fd = open(partial_file, O_RDONLY);
if (partial_fd != -1) {
file->print_raw("<compilation_log thread='");
jio_snprintf(buf, buflen, UINTX_FORMAT, log->thread_id());
file->print_raw(buf);
file->print_raw_cr("'>");
size_t nr; // number read into buf from partial log
julong to_read = log->_file_end;
while (to_read > 0) {
if (to_read < (julong)buflen)
nr = (size_t)to_read;
else nr = buflen;
nr = read(partial_fd, buf, (int)nr);
if (nr <= 0) break;
to_read -= (julong)nr;
file->write(buf, nr);
}
bool saw_slop = false;
int end_cdata = 0; // state machine [0..2] watching for too many "]]"
while ((nr = read(partial_fd, buf, buflen)) > 0) {
if (!saw_slop) {
file->print_raw_cr("<fragment>");
file->print_raw_cr("<![CDATA[");
saw_slop = true;
}
const char* bufp; // pointer into buf
size_t nw; // number written in each pass of the following loop:
for (bufp = buf; nr > 0; nr -= nw, bufp += nw) {
for (nw = 0; nw < nr; nw++) {
switch (bufp[nw]) {
case ']':
if (end_cdata < 2) end_cdata += 1; // saturating counter
continue; // keep scanning
case '>':
if (end_cdata == 2) break; // found CDATA delimiter!
default:
end_cdata = 0;
continue; // keep scanning
}
break;
}
file->write(bufp, nw);
if (nw < nr) {
file->print_raw("]]><![CDATA[");
end_cdata = 0; // reset state machine
}
}
}
if (saw_slop) {
file->print_raw_cr("]]>");
file->print_raw_cr("</fragment>");
}
file->print_raw_cr("</compilation_log>");
close(partial_fd);
}
CompileLog* next_log = log->_next;
delete log; // Removes partial file
log = next_log;
}
_first = NULL;
}
void CompileLog::finish_log(outputStream* file) {
char buf[4 * K];
finish_log_on_error(file, buf, sizeof(buf));
}
void CompileLog::inline_success(const char* reason) {
begin_elem("inline_success reason='");
text("%s", reason);
end_elem("'");
}
void CompileLog::inline_fail(const char* reason) {
begin_elem("inline_fail reason='");
text("%s", reason);
end_elem("'");
}
void CompileLog::set_context(const char* format, ...) {
va_list ap;
va_start(ap, format);
clear_context();
_context.print("<");
_context.vprint(format, ap);
_context.print_cr("/>");
va_end(ap);
}
void CompileLog::code_cache_state() {
begin_elem("code_cache");
CodeCache::log_state(this);
end_elem("%s", "");
}
C:\hotspot-69087d08d473\src\share\vm/compiler/compileLog.hpp
#ifndef SHARE_VM_COMPILER_COMPILELOG_HPP
#define SHARE_VM_COMPILER_COMPILELOG_HPP
#include "utilities/xmlstream.hpp"
class ciBaseObject;
class ciObject;
class ciMetadata;
class ciSymbol;
class CompileLog : public xmlStream {
private:
const char* _file; // name of file where XML goes
julong _file_end; // last good end of file
intx _thread_id; // which compile thread
stringStream _context; // optional, killable context marker
char _context_buffer[100];
char* _identities; // array of boolean
int _identities_limit;
int _identities_capacity;
CompileLog* _next; // static chain of all logs
static CompileLog* _first; // head of static chain
void va_tag(bool push, const char* format, va_list ap) ATTRIBUTE_PRINTF(3, 0);
public:
CompileLog(const char* file_name, FILE* fp, intx thread_id);
~CompileLog();
intx thread_id() { return _thread_id; }
const char* file() { return _file; }
stringStream* context() { return &_context; }
void clear_context() { context()->reset(); }
void set_context(const char* format, ...) ATTRIBUTE_PRINTF(2, 3);
void name(ciSymbol* s); // name='s'
void name(Symbol* s) { xmlStream::name(s); }
int identify(ciBaseObject* obj);
void clear_identities();
void inline_fail (const char* reason);
void inline_success(const char* reason);
virtual void see_tag(const char* tag, bool push);
virtual void pop_tag(const char* tag);
void mark_file_end() { _file_end = out()->count(); }
void code_cache_state();
static void finish_log(outputStream* out);
static void finish_log_on_error(outputStream* out, char *buf, int buflen);
};
#endif // SHARE_VM_COMPILER_COMPILELOG_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/compilerOracle.cpp
#include "precompiled.hpp"
#include "compiler/compilerOracle.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/klass.hpp"
#include "oops/method.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/jniHandles.hpp"
class MethodMatcher : public CHeapObj<mtCompiler> {
public:
enum Mode {
Exact,
Prefix = 1,
Suffix = 2,
Substring = Prefix | Suffix,
Any,
Unknown = -1
};
protected:
Symbol* _class_name;
Symbol* _method_name;
Symbol* _signature;
Mode _class_mode;
Mode _method_mode;
MethodMatcher* _next;
static bool match(Symbol* candidate, Symbol* match, Mode match_mode);
Symbol* class_name() const { return _class_name; }
Symbol* method_name() const { return _method_name; }
Symbol* signature() const { return _signature; }
public:
MethodMatcher(Symbol* class_name, Mode class_mode,
Symbol* method_name, Mode method_mode,
Symbol* signature, MethodMatcher* next);
MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next);
MethodMatcher* find(methodHandle method) {
Symbol* class_name = method->method_holder()->name();
Symbol* method_name = method->name();
for (MethodMatcher* current = this; current != NULL; current = current->_next) {
if (match(class_name, current->class_name(), current->_class_mode) &&
match(method_name, current->method_name(), current->_method_mode) &&
(current->signature() == NULL || current->signature() == method->signature())) {
return current;
}
}
return NULL;
}
bool match(methodHandle method) {
return find(method) != NULL;
}
MethodMatcher* next() const { return _next; }
static void print_symbol(Symbol* h, Mode mode) {
ResourceMark rm;
if (mode == Suffix || mode == Substring || mode == Any) {
tty->print("*");
}
if (mode != Any) {
h->print_symbol_on(tty);
}
if (mode == Prefix || mode == Substring) {
tty->print("*");
}
}
void print_base() {
print_symbol(class_name(), _class_mode);
tty->print(".");
print_symbol(method_name(), _method_mode);
if (signature() != NULL) {
tty->print(" ");
signature()->print_symbol_on(tty);
}
}
virtual void print() {
print_base();
tty->cr();
}
};
MethodMatcher::MethodMatcher(Symbol* class_name, Symbol* method_name, MethodMatcher* next) {
_class_name = class_name;
_method_name = method_name;
_next = next;
_class_mode = MethodMatcher::Exact;
_method_mode = MethodMatcher::Exact;
_signature = NULL;
}
MethodMatcher::MethodMatcher(Symbol* class_name, Mode class_mode,
Symbol* method_name, Mode method_mode,
Symbol* signature, MethodMatcher* next):
_class_mode(class_mode)
, _method_mode(method_mode)
, _next(next)
, _class_name(class_name)
, _method_name(method_name)
, _signature(signature) {
}
bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) {
if (match_mode == Any) {
return true;
}
if (match_mode == Exact) {
return candidate == match;
}
ResourceMark rm;
const char * candidate_string = candidate->as_C_string();
const char * match_string = match->as_C_string();
switch (match_mode) {
case Prefix:
return strstr(candidate_string, match_string) == candidate_string;
case Suffix: {
size_t clen = strlen(candidate_string);
size_t mlen = strlen(match_string);
return clen >= mlen && strcmp(candidate_string + clen - mlen, match_string) == 0;
}
case Substring:
return strstr(candidate_string, match_string) != NULL;
default:
return false;
}
}
enum OptionType {
IntxType,
UintxType,
BoolType,
CcstrType,
UnknownType
};
template<typename T>
static OptionType get_type_for() {
return UnknownType;
};
template<> OptionType get_type_for<intx>() {
return IntxType;
}
template<> OptionType get_type_for<uintx>() {
return UintxType;
}
template<> OptionType get_type_for<bool>() {
return BoolType;
}
template<> OptionType get_type_for<ccstr>() {
return CcstrType;
}
template<typename T>
static const T copy_value(const T value) {
return value;
}
template<> const ccstr copy_value<ccstr>(const ccstr value) {
return (const ccstr)strdup(value);
}
template <typename T>
class TypedMethodOptionMatcher : public MethodMatcher {
const char* _option;
OptionType _type;
const T _value;
public:
TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode,
Symbol* method_name, Mode method_mode,
Symbol* signature, const char* opt,
const T value, MethodMatcher* next) :
MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next),
_type(get_type_for<T>()), _value(copy_value<T>(value)) {
_option = strdup(opt);
}
~TypedMethodOptionMatcher() {
free((void*)_option);
}
TypedMethodOptionMatcher* match(methodHandle method, const char* opt) {
TypedMethodOptionMatcher* current = this;
while (current != NULL) {
current = (TypedMethodOptionMatcher*)current->find(method);
if (current == NULL) {
return NULL;
}
if (strcmp(current->_option, opt) == 0) {
return current;
}
current = current->next();
}
return NULL;
}
TypedMethodOptionMatcher* next() {
return (TypedMethodOptionMatcher*)_next;
}
OptionType get_type(void) {
return _type;
};
T value() { return _value; }
void print() {
ttyLocker ttyl;
print_base();
tty->print(" %s", _option);
tty->print(" <unknown option type>");
tty->cr();
}
};
template<>
void TypedMethodOptionMatcher<intx>::print() {
ttyLocker ttyl;
print_base();
tty->print(" intx %s", _option);
tty->print(" = " INTX_FORMAT, _value);
tty->cr();
};
template<>
void TypedMethodOptionMatcher<uintx>::print() {
ttyLocker ttyl;
print_base();
tty->print(" uintx %s", _option);
tty->print(" = " UINTX_FORMAT, _value);
tty->cr();
};
template<>
void TypedMethodOptionMatcher<bool>::print() {
ttyLocker ttyl;
print_base();
tty->print(" bool %s", _option);
tty->print(" = %s", _value ? "true" : "false");
tty->cr();
};
template<>
void TypedMethodOptionMatcher<ccstr>::print() {
ttyLocker ttyl;
print_base();
tty->print(" const char* %s", _option);
tty->print(" = '%s'", _value);
tty->cr();
};
enum OracleCommand {
UnknownCommand = -1,
OracleFirstCommand = 0,
BreakCommand = OracleFirstCommand,
PrintCommand,
ExcludeCommand,
InlineCommand,
DontInlineCommand,
CompileOnlyCommand,
LogCommand,
OptionCommand,
QuietCommand,
HelpCommand,
OracleCommandCount
};
static const char * command_names[] = {
"break",
"print",
"exclude",
"inline",
"dontinline",
"compileonly",
"log",
"option",
"quiet",
"help"
};
class MethodMatcher;
static MethodMatcher* lists[OracleCommandCount] = { 0, };
static bool check_predicate(OracleCommand command, methodHandle method) {
return ((lists[command] != NULL) &&
!method.is_null() &&
lists[command]->match(method));
}
static MethodMatcher* add_predicate(OracleCommand command,
Symbol* class_name, MethodMatcher::Mode c_mode,
Symbol* method_name, MethodMatcher::Mode m_mode,
Symbol* signature) {
assert(command != OptionCommand, "must use add_option_string");
if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL)
tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged.");
lists[command] = new MethodMatcher(class_name, c_mode, method_name, m_mode, signature, lists[command]);
return lists[command];
}
template<typename T>
static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode,
Symbol* method_name, MethodMatcher::Mode m_mode,
Symbol* signature,
const char* option,
T value) {
lists[OptionCommand] = new TypedMethodOptionMatcher<T>(class_name, c_mode, method_name, m_mode,
signature, option, value, lists[OptionCommand]);
return lists[OptionCommand];
}
template<typename T>
static bool get_option_value(methodHandle method, const char* option, T& value) {
TypedMethodOptionMatcher<T>* m;
if (lists[OptionCommand] != NULL
&& (m = ((TypedMethodOptionMatcher<T>*)lists[OptionCommand])->match(method, option)) != NULL
&& m->get_type() == get_type_for<T>()) {
value = m->value();
return true;
} else {
return false;
}
}
bool CompilerOracle::has_option_string(methodHandle method, const char* option) {
bool value = false;
get_option_value(method, option, value);
return value;
}
template<typename T>
bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) {
return ::get_option_value(method, option, value);
}
template bool CompilerOracle::has_option_value<intx>(methodHandle method, const char* option, intx& value);
template bool CompilerOracle::has_option_value<uintx>(methodHandle method, const char* option, uintx& value);
template bool CompilerOracle::has_option_value<bool>(methodHandle method, const char* option, bool& value);
template bool CompilerOracle::has_option_value<ccstr>(methodHandle method, const char* option, ccstr& value);
bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
quietly = true;
if (lists[ExcludeCommand] != NULL) {
if (lists[ExcludeCommand]->match(method)) {
quietly = _quiet;
return true;
}
}
if (lists[CompileOnlyCommand] != NULL) {
return !lists[CompileOnlyCommand]->match(method);
}
return false;
}
bool CompilerOracle::should_inline(methodHandle method) {
return (check_predicate(InlineCommand, method));
}
bool CompilerOracle::should_not_inline(methodHandle method) {
return (check_predicate(DontInlineCommand, method));
}
bool CompilerOracle::should_print(methodHandle method) {
return (check_predicate(PrintCommand, method));
}
bool CompilerOracle::should_log(methodHandle method) {
if (!LogCompilation) return false;
if (lists[LogCommand] == NULL) return true; // by default, log all
return (check_predicate(LogCommand, method));
}
bool CompilerOracle::should_break_at(methodHandle method) {
return check_predicate(BreakCommand, method);
}
static OracleCommand parse_command_name(const char * line, int* bytes_read) {
assert(ARRAY_SIZE(command_names) == OracleCommandCount,
"command_names size mismatch");
char command[33];
int result = sscanf(line, "%32[a-z]%n", command, bytes_read);
for (uint i = 0; i < ARRAY_SIZE(command_names); i++) {
if (strcmp(command, command_names[i]) == 0) {
return (OracleCommand)i;
}
}
return UnknownCommand;
}
static void usage() {
tty->print_cr(" CompileCommand and the CompilerOracle allows simple control over");
tty->print_cr(" what's allowed to be compiled. The standard supported directives");
tty->print_cr(" are exclude and compileonly. The exclude directive stops a method");
tty->print_cr(" from being compiled and compileonly excludes all methods except for");
tty->print_cr(" the ones mentioned by compileonly directives. The basic form of");
tty->print_cr(" all commands is a command name followed by the name of the method");
tty->print_cr(" in one of two forms: the standard class file format as in");
tty->print_cr(" class/name.methodName or the PrintCompilation format");
tty->print_cr(" class.name::methodName. The method name can optionally be followed");
tty->print_cr(" by a space then the signature of the method in the class file");
tty->print_cr(" format. Otherwise the directive applies to all methods with the");
tty->print_cr(" same name and class regardless of signature. Leading and trailing");
tty->print_cr(" *'s in the class and/or method name allows a small amount of");
tty->print_cr(" wildcarding. ");
tty->cr();
tty->print_cr(" Examples:");
tty->cr();
tty->print_cr(" exclude java/lang/StringBuffer.append");
tty->print_cr(" compileonly java/lang/StringBuffer.toString ()Ljava/lang/String;");
tty->print_cr(" exclude java/lang/String*.*");
tty->print_cr(" exclude *.toString");
}
#define RANGEBASE "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$_<>" \
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" \
"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" \
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" \
"\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" \
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" \
"\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" \
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef" \
"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
#define RANGE0 "[*" RANGEBASE "]"
#define RANGESLASH "[*" RANGEBASE "/]"
static MethodMatcher::Mode check_mode(char name[], const char*& error_msg) {
int match = MethodMatcher::Exact;
while (name[0] == '*') {
match |= MethodMatcher::Suffix;
strcpy(name, name + 1);
}
if (strcmp(name, "*") == 0) return MethodMatcher::Any;
size_t len = strlen(name);
while (len > 0 && name[len - 1] == '*') {
match |= MethodMatcher::Prefix;
name[--len] = '\0';
}
if (strstr(name, "*") != NULL) {
error_msg = " Embedded * not allowed";
return MethodMatcher::Unknown;
}
return (MethodMatcher::Mode)match;
}
static bool scan_line(const char * line,
char class_name[], MethodMatcher::Mode* c_mode,
char method_name[], MethodMatcher::Mode* m_mode,
int* bytes_read, const char*& error_msg) {
error_msg = NULL;
if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) {
return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown;
}
return false;
}
static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read,
Symbol* c_name, MethodMatcher::Mode c_match,
Symbol* m_name, MethodMatcher::Mode m_match,
Symbol* signature,
char* errorbuf, const int buf_size) {
total_bytes_read = 0;
int bytes_read = 0;
char flag[256];
if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", flag, &bytes_read) == 1) {
line += bytes_read;
total_bytes_read += bytes_read;
if (strcmp(type, "intx") == 0) {
intx value;
if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) {
total_bytes_read += bytes_read;
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value);
} else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type);
}
} else if (strcmp(type, "uintx") == 0) {
uintx value;
if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) {
total_bytes_read += bytes_read;
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value);
} else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
}
} else if (strcmp(type, "ccstr") == 0) {
ResourceMark rm;
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) {
total_bytes_read += bytes_read;
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value);
} else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
}
} else if (strcmp(type, "ccstrlist") == 0) {
ResourceMark rm;
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
char* next_value = value;
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) {
total_bytes_read += bytes_read;
line += bytes_read;
next_value += bytes_read;
char* end_value = next_value-1;
while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) {
total_bytes_read += bytes_read;
line += bytes_read;
next_value += bytes_read;
end_value = next_value-1;
}
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value);
} else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
}
} else if (strcmp(type, "bool") == 0) {
char value[256];
if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) {
if (strcmp(value, "true") == 0) {
total_bytes_read += bytes_read;
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true);
} else if (strcmp(value, "false") == 0) {
total_bytes_read += bytes_read;
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false);
} else {
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
}
} else {
jio_snprintf(errorbuf, sizeof(errorbuf), " Value cannot be read for flag %s of type %s", flag, type);
}
} else {
jio_snprintf(errorbuf, sizeof(errorbuf), " Type %s not supported ", type);
}
} else {
jio_snprintf(errorbuf, sizeof(errorbuf), " Flag name for type %s should be alphanumeric ", type);
}
return NULL;
}
void CompilerOracle::parse_from_line(char* line) {
if (line[0] == '\0') return;
if (line[0] == '#') return;
bool have_colon = (strstr(line, "::") != NULL);
for (char* lp = line; *lp != '\0'; lp++) {
if (have_colon) {
if (*lp == '.') *lp = '/'; // dots build the package prefix
if (*lp == ':') *lp = ' ';
}
if (*lp == ',' || *lp == '.') *lp = ' ';
}
char* original_line = line;
int bytes_read;
OracleCommand command = parse_command_name(line, &bytes_read);
line += bytes_read;
ResourceMark rm;
if (command == UnknownCommand) {
ttyLocker ttyl;
tty->print_cr("CompilerOracle: unrecognized line");
tty->print_cr(" \"%s\"", original_line);
return;
}
if (command == QuietCommand) {
_quiet = true;
return;
}
if (command == HelpCommand) {
usage();
return;
}
MethodMatcher::Mode c_match = MethodMatcher::Exact;
MethodMatcher::Mode m_match = MethodMatcher::Exact;
char class_name[256];
char method_name[256];
char sig[1024];
char errorbuf[1024];
const char* error_msg = NULL; // description of first error that appears
MethodMatcher* match = NULL;
if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) {
EXCEPTION_MARK;
Symbol* c_name = SymbolTable::new_symbol(class_name, CHECK);
Symbol* m_name = SymbolTable::new_symbol(method_name, CHECK);
Symbol* signature = NULL;
line += bytes_read;
if (1 == sscanf(line, "%*[ \t](%254[[);/" RANGEBASE "]%n", sig + 1, &bytes_read)) {
sig[0] = '(';
line += bytes_read;
signature = SymbolTable::new_symbol(sig, CHECK);
}
if (command == OptionCommand) {
char option[256]; // stores flag for Type (1) and type of Type (2)
while (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) {
if (match != NULL && !_quiet) {
ttyLocker ttyl;
tty->print("CompilerOracle: %s ", command_names[command]);
match->print();
}
line += bytes_read;
if (strcmp(option, "intx") == 0
|| strcmp(option, "uintx") == 0
|| strcmp(option, "bool") == 0
|| strcmp(option, "ccstr") == 0
|| strcmp(option, "ccstrlist") == 0
) {
match = scan_flag_and_value(option, line, bytes_read,
c_name, c_match, m_name, m_match, signature,
errorbuf, sizeof(errorbuf));
if (match == NULL) {
error_msg = errorbuf;
break;
}
line += bytes_read;
} else {
match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true);
}
} // while(
} else {
match = add_predicate(command, c_name, c_match, m_name, m_match, signature);
}
}
ttyLocker ttyl;
if (error_msg != NULL) {
tty->print_cr("CompilerOracle: unrecognized line");
tty->print_cr(" \"%s\"", original_line);
if (error_msg != NULL) {
tty->print_cr("%s", error_msg);
}
} else {
bytes_read = 0;
sscanf(line, "%*[ \t]%n", &bytes_read);
if (line[bytes_read] != '\0') {
tty->print_cr("CompilerOracle: unrecognized line");
tty->print_cr(" \"%s\"", original_line);
tty->print_cr(" Unrecognized text %s after command ", line);
} else if (match != NULL && !_quiet) {
tty->print("CompilerOracle: %s ", command_names[command]);
match->print();
}
}
}
static const char* default_cc_file = ".hotspot_compiler";
static const char* cc_file() {
#ifdef ASSERT
if (CompileCommandFile == NULL)
return default_cc_file;
#endif
return CompileCommandFile;
}
bool CompilerOracle::has_command_file() {
return cc_file() != NULL;
}
bool CompilerOracle::_quiet = false;
void CompilerOracle::parse_from_file() {
assert(has_command_file(), "command file must be specified");
FILE* stream = fopen(cc_file(), "rt");
if (stream == NULL) return;
char token[1024];
int pos = 0;
int c = getc(stream);
while(c != EOF && pos < (int)(sizeof(token)-1)) {
if (c == '\n') {
token[pos++] = '\0';
parse_from_line(token);
pos = 0;
} else {
token[pos++] = c;
}
c = getc(stream);
}
token[pos++] = '\0';
parse_from_line(token);
fclose(stream);
}
void CompilerOracle::parse_from_string(const char* str, void (*parse_line)(char*)) {
char token[1024];
int pos = 0;
const char* sp = str;
int c = *sp++;
while (c != '\0' && pos < (int)(sizeof(token)-1)) {
if (c == '\n') {
token[pos++] = '\0';
parse_line(token);
pos = 0;
} else {
token[pos++] = c;
}
c = *sp++;
}
token[pos++] = '\0';
parse_line(token);
}
void CompilerOracle::append_comment_to_file(const char* message) {
assert(has_command_file(), "command file must be specified");
fileStream stream(fopen(cc_file(), "at"));
stream.print("# ");
for (int index = 0; message[index] != '\0'; index++) {
stream.put(message[index]);
if (message[index] == '\n') stream.print("# ");
}
stream.cr();
}
void CompilerOracle::append_exclude_to_file(methodHandle method) {
assert(has_command_file(), "command file must be specified");
fileStream stream(fopen(cc_file(), "at"));
stream.print("exclude ");
method->method_holder()->name()->print_symbol_on(&stream);
stream.print(".");
method->name()->print_symbol_on(&stream);
method->signature()->print_symbol_on(&stream);
stream.cr();
stream.cr();
}
void compilerOracle_init() {
CompilerOracle::parse_from_string(CompileCommand, CompilerOracle::parse_from_line);
CompilerOracle::parse_from_string(CompileOnly, CompilerOracle::parse_compile_only);
if (CompilerOracle::has_command_file()) {
CompilerOracle::parse_from_file();
} else {
struct stat buf;
if (os::stat(default_cc_file, &buf) == 0) {
warning("%s file is present but has been ignored. "
"Run with -XX:CompileCommandFile=%s to load the file.",
default_cc_file, default_cc_file);
}
}
if (lists[PrintCommand] != NULL) {
if (PrintAssembly) {
warning("CompileCommand and/or %s file contains 'print' commands, but PrintAssembly is also enabled", default_cc_file);
} else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) {
warning("printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output");
DebugNonSafepoints = true;
}
}
}
void CompilerOracle::parse_compile_only(char * line) {
int i;
char name[1024];
const char* className = NULL;
const char* methodName = NULL;
bool have_colon = (strstr(line, "::") != NULL);
char method_sep = have_colon ? ':' : '.';
if (Verbose) {
tty->print_cr("%s", line);
}
ResourceMark rm;
while (*line != '\0') {
MethodMatcher::Mode c_match = MethodMatcher::Exact;
MethodMatcher::Mode m_match = MethodMatcher::Exact;
for (i = 0;
i < 1024 && *line != '\0' && *line != method_sep && *line != ',' && !isspace(*line);
line++, i++) {
name[i] = *line;
if (name[i] == '.') name[i] = '/'; // package prefix uses '/'
}
if (i > 0) {
char* newName = NEW_RESOURCE_ARRAY( char, i + 1);
if (newName == NULL)
return;
strncpy(newName, name, i);
newName[i] = '\0';
if (className == NULL) {
className = newName;
c_match = MethodMatcher::Prefix;
} else {
methodName = newName;
}
}
if (*line == method_sep) {
if (className == NULL) {
className = "";
c_match = MethodMatcher::Any;
} else {
if (strchr(className, '/') != NULL) {
c_match = MethodMatcher::Exact;
} else {
c_match = MethodMatcher::Suffix;
}
}
} else {
if (className == NULL) {
ShouldNotReachHere();
} else {
if (strchr(className, '/') != NULL) {
c_match = MethodMatcher::Prefix;
} else if (className[0] == '\0') {
c_match = MethodMatcher::Any;
} else {
c_match = MethodMatcher::Substring;
}
}
}
if (*line == ',' || *line == '\0' || (line[0] == '.' && line[1] == '\0')) {
if (methodName == NULL) {
methodName = "";
if (*line != method_sep) {
m_match = MethodMatcher::Any;
}
}
EXCEPTION_MARK;
Symbol* c_name = SymbolTable::new_symbol(className, CHECK);
Symbol* m_name = SymbolTable::new_symbol(methodName, CHECK);
Symbol* signature = NULL;
add_predicate(CompileOnlyCommand, c_name, c_match, m_name, m_match, signature);
if (PrintVMOptions) {
tty->print("CompileOnly: compileonly ");
lists[CompileOnlyCommand]->print();
}
className = NULL;
methodName = NULL;
}
line = *line == '\0' ? line : line + 1;
}
}
C:\hotspot-69087d08d473\src\share\vm/compiler/compilerOracle.hpp
#ifndef SHARE_VM_COMPILER_COMPILERORACLE_HPP
#define SHARE_VM_COMPILER_COMPILERORACLE_HPP
#include "memory/allocation.hpp"
#include "oops/oopsHierarchy.hpp"
class CompilerOracle : AllStatic {
private:
static bool _quiet;
public:
static bool has_command_file();
static void parse_from_file();
static bool should_exclude(methodHandle method, bool& quietly);
static bool should_inline(methodHandle method);
static bool should_not_inline(methodHandle method);
static bool should_print(methodHandle method);
static bool should_log(methodHandle method);
static bool should_break_at(methodHandle method);
static bool has_option_string(methodHandle method, const char * option);
template<typename T>
static bool has_option_value(methodHandle method, const char* option, T& value);
static void parse_from_string(const char* command_string, void (*parser)(char*));
static void parse_from_line(char* line);
static void parse_compile_only(char * line);
static void append_comment_to_file(const char* message);
static void append_exclude_to_file(methodHandle method);
};
#endif // SHARE_VM_COMPILER_COMPILERORACLE_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/disassembler.cpp
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "code/codeCache.hpp"
#include "compiler/disassembler.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "memory/cardTableModRefBS.hpp"
#include "runtime/fprofiler.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
#ifdef TARGET_ARCH_x86
# include "depChecker_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "depChecker_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "depChecker_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "depChecker_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "depChecker_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "depChecker_ppc.hpp"
#endif
#ifdef SHARK
#include "shark/sharkEntry.hpp"
#endif
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
void* Disassembler::_library = NULL;
bool Disassembler::_tried_to_load_library = false;
Disassembler::decode_func_virtual Disassembler::_decode_instructions_virtual = NULL;
Disassembler::decode_func Disassembler::_decode_instructions = NULL;
static const char hsdis_library_name[] = "hsdis-" HOTSPOT_LIB_ARCH;
static const char decode_instructions_virtual_name[] = "decode_instructions_virtual";
static const char decode_instructions_name[] = "decode_instructions";
static bool use_new_version = true;
#define COMMENT_COLUMN 40 LP64_ONLY(+8) /*could be an option*/
#define BYTES_COMMENT ";..." /* funky byte display comment */
bool Disassembler::load_library() {
if (_decode_instructions_virtual != NULL || _decode_instructions != NULL) {
return true;
}
if (_tried_to_load_library) {
return false;
}
char ebuf[1024];
char buf[JVM_MAXPATHLEN];
os::jvm_path(buf, sizeof(buf));
int jvm_offset = -1;
int lib_offset = -1;
{
const char* base = buf;
const char* p = strrchr(buf, *os::file_separator());
if (p != NULL) lib_offset = p - base + 1;
p = strstr(p ? p : base, "jvm");
if (p != NULL) jvm_offset = p - base;
}
if (jvm_offset >= 0) {
strcpy(&buf[jvm_offset], hsdis_library_name);
strcat(&buf[jvm_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
if (_library == NULL) {
strcpy(&buf[lib_offset], hsdis_library_name);
strcat(&buf[lib_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library == NULL) {
buf[lib_offset - 1] = '\0';
const char* p = strrchr(buf, *os::file_separator());
if (p != NULL) {
lib_offset = p - buf + 1;
strcpy(&buf[lib_offset], hsdis_library_name);
strcat(&buf[lib_offset], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
}
}
}
if (_library == NULL) {
strcpy(&buf[0], hsdis_library_name);
strcat(&buf[0], os::dll_file_extension());
_library = os::dll_load(buf, ebuf, sizeof ebuf);
}
if (_library != NULL) {
_decode_instructions_virtual = CAST_TO_FN_PTR(Disassembler::decode_func_virtual,
os::dll_lookup(_library, decode_instructions_virtual_name));
}
if (_decode_instructions_virtual == NULL) {
_decode_instructions = CAST_TO_FN_PTR(Disassembler::decode_func,
os::dll_lookup(_library, decode_instructions_name));
use_new_version = false;
} else {
use_new_version = true;
}
_tried_to_load_library = true;
if (_decode_instructions_virtual == NULL && _decode_instructions == NULL) {
tty->print_cr("Could not load %s; %s; %s", buf,
((_library != NULL)
? "entry point is missing"
: (WizardMode || PrintMiscellaneous)
? (const char*)ebuf
: "library not loadable"),
"PrintAssembly is disabled");
return false;
}
tty->print_cr("Loaded disassembler from %s", buf);
return true;
}
class decode_env {
private:
nmethod* _nm;
CodeBlob* _code;
CodeStrings _strings;
outputStream* _output;
address _start, _end;
char _option_buf[512];
char _print_raw;
bool _print_pc;
bool _print_bytes;
address _cur_insn;
int _total_ticks;
int _bytes_per_line; // arch-specific formatting option
static bool match(const char* event, const char* tag) {
size_t taglen = strlen(tag);
if (strncmp(event, tag, taglen) != 0)
return false;
char delim = event[taglen];
return delim == '\0' || delim == ' ' || delim == '/' || delim == '=';
}
void collect_options(const char* p) {
if (p == NULL || p[0] == '\0') return;
size_t opt_so_far = strlen(_option_buf);
if (opt_so_far + 1 + strlen(p) + 1 > sizeof(_option_buf)) return;
char* fillp = &_option_buf[opt_so_far];
if (opt_so_far > 0) *fillp++ = ',';
strcat(fillp, p);
char* q = fillp;
while ((q = strpbrk(q, " \t\n")) != NULL)
}
void print_insn_labels();
void print_insn_bytes(address pc0, address pc);
void print_address(address value);
public:
decode_env(CodeBlob* code, outputStream* output, CodeStrings c = CodeStrings());
address decode_instructions(address start, address end);
void start_insn(address pc) {
_cur_insn = pc;
output()->bol();
print_insn_labels();
}
void end_insn(address pc) {
address pc0 = cur_insn();
outputStream* st = output();
if (_print_bytes && pc > pc0)
print_insn_bytes(pc0, pc);
if (_nm != NULL) {
_nm->print_code_comment_on(st, COMMENT_COLUMN, pc0, pc);
}
if (total_ticks() != 0) {
address bucket_pc = FlatProfiler::bucket_start_for(pc);
if (bucket_pc != NULL && bucket_pc > pc0 && bucket_pc <= pc) {
int bucket_count = FlatProfiler::bucket_count_for(pc0);
if (bucket_count != 0) {
st->bol();
st->print_cr("%3.1f%% [%d]", bucket_count*100.0/total_ticks(), bucket_count);
}
}
}
st->cr();
}
address handle_event(const char* event, address arg);
outputStream* output() { return _output; }
address cur_insn() { return _cur_insn; }
int total_ticks() { return _total_ticks; }
void set_total_ticks(int n) { _total_ticks = n; }
const char* options() { return _option_buf; }
};
decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) :
_nm((code != NULL && code->is_nmethod()) ? (nmethod*)code : NULL),
_code(code),
_strings(),
_output(output ? output : tty),
_start(NULL),
_end(NULL),
_print_raw(0),
_print_pc(true),
_print_bytes(false),
_cur_insn(NULL),
_total_ticks(0),
_bytes_per_line(Disassembler::pd_instruction_alignment())
{
memset(_option_buf, 0, sizeof(_option_buf));
_strings.copy(c);
collect_options(Disassembler::pd_cpu_opts());
collect_options(PrintAssemblyOptions);
if (strstr(options(), "hsdis-")) {
if (strstr(options(), "hsdis-print-raw"))
_print_raw = (strstr(options(), "xml") ? 2 : 1);
if (strstr(options(), "hsdis-print-pc"))
_print_pc = !_print_pc;
if (strstr(options(), "hsdis-print-bytes"))
_print_bytes = !_print_bytes;
}
if (strstr(options(), "help")) {
tty->print_cr("PrintAssemblyOptions help:");
tty->print_cr(" hsdis-print-raw test plugin by requesting raw output");
tty->print_cr(" hsdis-print-raw-xml test plugin by requesting raw xml");
tty->print_cr(" hsdis-print-pc turn off PC printing (on by default)");
tty->print_cr(" hsdis-print-bytes turn on instruction byte output");
tty->print_cr("combined options: %s", options());
}
}
address decode_env::handle_event(const char* event, address arg) {
if (match(event, "insn")) {
start_insn(arg);
} else if (match(event, "/insn")) {
end_insn(arg);
} else if (match(event, "addr")) {
if (arg != NULL) {
print_address(arg);
return arg;
}
} else if (match(event, "mach")) {
static char buffer[32] = { 0, };
if (strcmp(buffer, (const char*)arg) != 0 ||
strlen((const char*)arg) > sizeof(buffer) - 1) {
strncpy(buffer, (const char*)arg, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0';
output()->print_cr("[Disassembling for mach='%s']", arg);
}
} else if (match(event, "format bytes-per-line")) {
_bytes_per_line = (int) (intptr_t) arg;
} else {
}
return NULL;
}
void decode_env::print_address(address adr) {
outputStream* st = _output;
if (adr == NULL) {
st->print("NULL");
return;
}
int small_num = (int)(intptr_t)adr;
if ((intptr_t)adr == (intptr_t)small_num
&& -1 <= small_num && small_num <= 9) {
st->print("%d", small_num);
return;
}
if (Universe::is_fully_initialized()) {
if (StubRoutines::contains(adr)) {
StubCodeDesc* desc = StubCodeDesc::desc_for(adr);
if (desc == NULL)
desc = StubCodeDesc::desc_for(adr + frame::pc_return_offset);
if (desc != NULL) {
st->print("Stub::%s", desc->name());
if (desc->begin() != adr)
st->print("%+d 0x%p",adr - desc->begin(), adr);
else if (WizardMode) st->print(" " PTR_FORMAT, adr);
return;
}
st->print("Stub::<unknown> " PTR_FORMAT, adr);
return;
}
BarrierSet* bs = Universe::heap()->barrier_set();
if (bs->kind() == BarrierSet::CardTableModRef &&
adr == (address)((CardTableModRefBS*)(bs))->byte_map_base) {
st->print("word_map_base");
if (WizardMode) st->print(" " INTPTR_FORMAT, (intptr_t)adr);
return;
}
oop obj;
if (_nm != NULL
&& (obj = _nm->embeddedOop_at(cur_insn())) != NULL
&& (address) obj == adr
&& Universe::heap()->is_in(obj)
&& Universe::heap()->is_in(obj->klass())) {
julong c = st->count();
obj->print_value_on(st);
if (st->count() == c) {
st->print("(a %s)", obj->klass()->external_name());
}
return;
}
}
st->print(PTR_FORMAT, adr);
}
void decode_env::print_insn_labels() {
address p = cur_insn();
outputStream* st = output();
CodeBlob* cb = _code;
if (cb != NULL) {
cb->print_block_comment(st, p);
}
_strings.print_block_comment(st, (intptr_t)(p - _start));
if (_print_pc) {
st->print(" " PTR_FORMAT ": ", p);
}
}
void decode_env::print_insn_bytes(address pc, address pc_limit) {
outputStream* st = output();
size_t incr = 1;
size_t perline = _bytes_per_line;
if ((size_t) Disassembler::pd_instruction_alignment() >= sizeof(int)
&& !((uintptr_t)pc % sizeof(int))
&& !((uintptr_t)pc_limit % sizeof(int))) {
incr = sizeof(int);
if (perline % incr) perline += incr - (perline % incr);
}
while (pc < pc_limit) {
st->move_to(COMMENT_COLUMN);
address pc0 = pc;
address pc1 = pc + perline;
if (pc1 > pc_limit) pc1 = pc_limit;
for (; pc < pc1; pc += incr) {
if (pc == pc0)
st->print(BYTES_COMMENT);
else if ((uint)(pc - pc0) % sizeof(int) == 0)
st->print(" "); // put out a space on word boundaries
if (incr == sizeof(int))
st->print("%08lx", *(int*)pc);
else st->print("%02x", (*pc)&0xFF);
}
st->cr();
}
}
static void* event_to_env(void* env_pv, const char* event, void* arg) {
decode_env* env = (decode_env*) env_pv;
return env->handle_event(event, (address) arg);
}
ATTRIBUTE_PRINTF(2, 3)
static int printf_to_env(void* env_pv, const char* format, ...) {
decode_env* env = (decode_env*) env_pv;
outputStream* st = env->output();
size_t flen = strlen(format);
const char* raw = NULL;
if (flen == 0) return 0;
if (flen == 1 && format[0] == '\n') { st->bol(); return 1; }
if (flen < 2 ||
strchr(format, '%') == NULL) {
raw = format;
} else if (format[0] == '%' && format[1] == '%' &&
strchr(format+2, '%') == NULL) {
flen--;
raw = format+1;
}
if (raw != NULL) {
st->print_raw(raw, (int) flen);
return (int) flen;
}
va_list ap;
va_start(ap, format);
julong cnt0 = st->count();
st->vprint(format, ap);
julong cnt1 = st->count();
va_end(ap);
return (int)(cnt1 - cnt0);
}
address decode_env::decode_instructions(address start, address end) {
_start = start; _end = end;
assert(((((intptr_t)start | (intptr_t)end) % Disassembler::pd_instruction_alignment()) == 0), "misaligned insn addr");
const int show_bytes = false; // for disassembler debugging
if (!Disassembler::can_decode()) {
return NULL;
}
if (_print_raw) {
FILE* out = stdout;
FILE* xmlout = (_print_raw > 1 ? out : NULL);
return use_new_version ?
(address)
(*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
start, end - start,
NULL, (void*) xmlout,
NULL, (void*) out,
options(), 0/*nice new line*/)
:
(address)
(*Disassembler::_decode_instructions)(start, end,
NULL, (void*) xmlout,
NULL, (void*) out,
options());
}
return use_new_version ?
(address)
(*Disassembler::_decode_instructions_virtual)((uintptr_t)start, (uintptr_t)end,
start, end - start,
&event_to_env, (void*) this,
&printf_to_env, (void*) this,
options(), 0/*nice new line*/)
:
(address)
(*Disassembler::_decode_instructions)(start, end,
&event_to_env, (void*) this,
&printf_to_env, (void*) this,
options());
}
void Disassembler::decode(CodeBlob* cb, outputStream* st) {
ttyLocker ttyl;
if (!load_library()) return;
decode_env env(cb, st);
env.output()->print_cr("Decoding CodeBlob " PTR_FORMAT, cb);
env.decode_instructions(cb->code_begin(), cb->code_end());
}
void Disassembler::decode(address start, address end, outputStream* st, CodeStrings c) {
ttyLocker ttyl;
if (!load_library()) return;
decode_env env(CodeCache::find_blob_unsafe(start), st, c);
env.decode_instructions(start, end);
}
void Disassembler::decode(nmethod* nm, outputStream* st) {
ttyLocker ttyl;
if (!load_library()) return;
decode_env env(nm, st);
env.output()->print_cr("Decoding compiled method " PTR_FORMAT ":", nm);
env.output()->print_cr("Code:");
#ifdef SHARK
SharkEntry* entry = (SharkEntry *) nm->code_begin();
unsigned char* p = entry->code_start();
unsigned char* end = entry->code_limit();
#else
unsigned char* p = nm->code_begin();
unsigned char* end = nm->code_end();
#endif // SHARK
if (FlatProfiler::bucket_start_for(p) != NULL) {
unsigned char* p1 = p;
int total_bucket_count = 0;
while (p1 < end) {
unsigned char* p0 = p1;
p1 += pd_instruction_alignment();
address bucket_pc = FlatProfiler::bucket_start_for(p1);
if (bucket_pc != NULL && bucket_pc > p0 && bucket_pc <= p1)
total_bucket_count += FlatProfiler::bucket_count_for(p0);
}
env.set_total_ticks(total_bucket_count);
}
if (nm->consts_size() > 0) {
nm->print_nmethod_labels(env.output(), nm->consts_begin());
int offset = 0;
for (address p = nm->consts_begin(); p < nm->consts_end(); p += 4, offset += 4) {
if ((offset % 8) == 0) {
env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT " " PTR64_FORMAT, p, offset, *((int32_t*) p), *((int64_t*) p));
} else {
env.output()->print_cr(" " PTR_FORMAT " (offset: %4d): " PTR32_FORMAT, p, offset, *((int32_t*) p));
}
}
}
env.decode_instructions(p, end);
}
C:\hotspot-69087d08d473\src\share\vm/compiler/disassembler.hpp
#ifndef SHARE_VM_COMPILER_DISASSEMBLER_HPP
#define SHARE_VM_COMPILER_DISASSEMBLER_HPP
#include "asm/codeBuffer.hpp"
#include "runtime/globals.hpp"
#ifdef TARGET_OS_FAMILY_linux
# include "os_linux.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_solaris
# include "os_solaris.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_windows
# include "os_windows.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_aix
# include "os_aix.inline.hpp"
#endif
#ifdef TARGET_OS_FAMILY_bsd
# include "os_bsd.inline.hpp"
#endif
class decode_env;
class Disassembler {
friend class decode_env;
private:
typedef void* (*decode_func_virtual)(uintptr_t start_va, uintptr_t end_va,
unsigned char* buffer, uintptr_t length,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options,
int newline);
typedef void* (*decode_func)(void* start_va, void* end_va,
void* (*event_callback)(void*, const char*, void*),
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
const char* options);
static void* _library;
static bool _tried_to_load_library;
static decode_func_virtual _decode_instructions_virtual;
static decode_func _decode_instructions;
static bool load_library();
#ifdef TARGET_ARCH_x86
# include "disassembler_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "disassembler_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "disassembler_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "disassembler_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "disassembler_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "disassembler_ppc.hpp"
#endif
public:
static bool can_decode() {
return (_decode_instructions_virtual != NULL) ||
(_decode_instructions != NULL) ||
load_library();
}
static void decode(CodeBlob *cb, outputStream* st = NULL);
static void decode(nmethod* nm, outputStream* st = NULL);
static void decode(address begin, address end, outputStream* st = NULL, CodeStrings c = CodeStrings());
};
#endif // SHARE_VM_COMPILER_DISASSEMBLER_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/methodLiveness.cpp
#include "precompiled.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodBlocks.hpp"
#include "ci/ciStreams.hpp"
#include "compiler/methodLiveness.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/bitMap.inline.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
#ifndef PRODUCT
class BitCounter: public BitMapClosure {
private:
int _count;
public:
BitCounter() : _count(0) {}
virtual bool do_bit(size_t offset) {
_count++;
return true;
}
int count() {
return _count;
}
};
long MethodLiveness::_total_bytes = 0;
int MethodLiveness::_total_methods = 0;
long MethodLiveness::_total_blocks = 0;
int MethodLiveness::_max_method_blocks = 0;
long MethodLiveness::_total_edges = 0;
int MethodLiveness::_max_block_edges = 0;
long MethodLiveness::_total_exc_edges = 0;
int MethodLiveness::_max_block_exc_edges = 0;
long MethodLiveness::_total_method_locals = 0;
int MethodLiveness::_max_method_locals = 0;
long MethodLiveness::_total_locals_queried = 0;
long MethodLiveness::_total_live_locals_queried = 0;
long MethodLiveness::_total_visits = 0;
#endif
elapsedTimer MethodLiveness::_time_build_graph;
elapsedTimer MethodLiveness::_time_gen_kill;
elapsedTimer MethodLiveness::_time_flow;
elapsedTimer MethodLiveness::_time_query;
elapsedTimer MethodLiveness::_time_total;
MethodLiveness::MethodLiveness(Arena* arena, ciMethod* method)
#ifdef COMPILER1
: _bci_block_start((uintptr_t*)arena->Amalloc((method->code_size() >> LogBitsPerByte) + 1), method->code_size())
#endif
{
_arena = arena;
_method = method;
_bit_map_size_bits = method->max_locals();
_bit_map_size_words = (_bit_map_size_bits / sizeof(unsigned int)) + 1;
#ifdef COMPILER1
_bci_block_start.clear();
#endif
}
void MethodLiveness::compute_liveness() {
#ifndef PRODUCT
if (TraceLivenessGen) {
tty->print_cr("################################################################");
tty->print("# Computing liveness information for ");
method()->print_short_name();
}
if (TimeLivenessAnalysis) _time_total.start();
#endif
{
TraceTime buildGraph(NULL, &_time_build_graph, TimeLivenessAnalysis);
init_basic_blocks();
}
{
TraceTime genKill(NULL, &_time_gen_kill, TimeLivenessAnalysis);
init_gen_kill();
}
{
TraceTime flow(NULL, &_time_flow, TimeLivenessAnalysis);
propagate_liveness();
}
#ifndef PRODUCT
if (TimeLivenessAnalysis) _time_total.stop();
if (TimeLivenessAnalysis) {
_total_bytes += method()->code_size();
_total_methods++;
int num_blocks = _block_count;
_total_blocks += num_blocks;
_max_method_blocks = MAX2(num_blocks,_max_method_blocks);
for (int i=0; i<num_blocks; i++) {
BasicBlock *block = _block_list[i];
int numEdges = block->_normal_predecessors->length();
int numExcEdges = block->_exception_predecessors->length();
_total_edges += numEdges;
_total_exc_edges += numExcEdges;
_max_block_edges = MAX2(numEdges,_max_block_edges);
_max_block_exc_edges = MAX2(numExcEdges,_max_block_exc_edges);
}
int numLocals = _bit_map_size_bits;
_total_method_locals += numLocals;
_max_method_locals = MAX2(numLocals,_max_method_locals);
}
#endif
}
void MethodLiveness::init_basic_blocks() {
bool bailout = false;
int method_len = method()->code_size();
ciMethodBlocks *mblocks = method()->get_method_blocks();
_block_map = new (arena()) GrowableArray<BasicBlock*>(arena(), method_len, method_len, NULL);
_block_count = mblocks->num_blocks();
_block_list = (BasicBlock **) arena()->Amalloc(sizeof(BasicBlock *) * _block_count);
GrowableArray<BasicBlock*>* jsr_exit_list = new GrowableArray<BasicBlock*>(5);
GrowableArray<BasicBlock*>* ret_list = new GrowableArray<BasicBlock*>(5);
for (int blk = 0; blk < _block_count; blk++) {
ciBlock *cib = mblocks->block(blk);
int start_bci = cib->start_bci();
_block_list[blk] = new (arena()) BasicBlock(this, start_bci, cib->limit_bci());
_block_map->at_put(start_bci, _block_list[blk]);
#ifdef COMPILER1
_bci_block_start.set_bit(start_bci);
#endif // COMPILER1
}
ciBytecodeStream bytes(method());
for (int blk = 0; blk < _block_count; blk++) {
BasicBlock *current_block = _block_list[blk];
int bci = mblocks->block(blk)->control_bci();
if (bci == ciBlock::fall_through_bci) {
int limit = current_block->limit_bci();
if (limit < method_len) {
BasicBlock *next = _block_map->at(limit);
assert( next != NULL, "must be a block immediately following this one.");
next->add_normal_predecessor(current_block);
}
continue;
}
bytes.reset_to_bci(bci);
Bytecodes::Code code = bytes.next();
BasicBlock *dest;
assert (current_block != NULL, "we must have a current block");
switch (code) {
case Bytecodes::_ifeq:
case Bytecodes::_ifne:
case Bytecodes::_iflt:
case Bytecodes::_ifge:
case Bytecodes::_ifgt:
case Bytecodes::_ifle:
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
case Bytecodes::_ifnull:
case Bytecodes::_ifnonnull:
dest = _block_map->at(bytes.next_bci());
assert(dest != NULL, "must be a block immediately following this one.");
dest->add_normal_predecessor(current_block);
dest = _block_map->at(bytes.get_dest());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
break;
case Bytecodes::_goto:
dest = _block_map->at(bytes.get_dest());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
break;
case Bytecodes::_goto_w:
dest = _block_map->at(bytes.get_far_dest());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
break;
case Bytecodes::_tableswitch:
{
Bytecode_tableswitch tableswitch(&bytes);
int len = tableswitch.length();
dest = _block_map->at(bci + tableswitch.default_offset());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
while (--len >= 0) {
dest = _block_map->at(bci + tableswitch.dest_offset_at(len));
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
}
break;
}
case Bytecodes::_lookupswitch:
{
Bytecode_lookupswitch lookupswitch(&bytes);
int npairs = lookupswitch.number_of_pairs();
dest = _block_map->at(bci + lookupswitch.default_offset());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
while(--npairs >= 0) {
LookupswitchPair pair = lookupswitch.pair_at(npairs);
dest = _block_map->at( bci + pair.offset());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
}
break;
}
case Bytecodes::_jsr:
{
assert(bytes.is_wide()==false, "sanity check");
dest = _block_map->at(bytes.get_dest());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
BasicBlock *jsrExit = _block_map->at(current_block->limit_bci());
assert(jsrExit != NULL, "jsr return bci must start a block.");
jsr_exit_list->append(jsrExit);
break;
}
case Bytecodes::_jsr_w:
{
dest = _block_map->at(bytes.get_far_dest());
assert(dest != NULL, "branch desination must start a block.");
dest->add_normal_predecessor(current_block);
BasicBlock *jsrExit = _block_map->at(current_block->limit_bci());
assert(jsrExit != NULL, "jsr return bci must start a block.");
jsr_exit_list->append(jsrExit);
break;
}
case Bytecodes::_wide:
assert(false, "wide opcodes should not be seen here");
break;
case Bytecodes::_athrow:
case Bytecodes::_ireturn:
case Bytecodes::_lreturn:
case Bytecodes::_freturn:
case Bytecodes::_dreturn:
case Bytecodes::_areturn:
case Bytecodes::_return:
break;
case Bytecodes::_ret:
ret_list->append(current_block);
break;
case Bytecodes::_breakpoint:
bailout = true;
break;
default:
break;
}
}
int ret_list_len = ret_list->length();
int jsr_exit_list_len = jsr_exit_list->length();
if (ret_list_len > 0 && jsr_exit_list_len > 0) {
for (int i = jsr_exit_list_len - 1; i >= 0; i--) {
BasicBlock *jsrExit = jsr_exit_list->at(i);
for (int i = ret_list_len - 1; i >= 0; i--) {
jsrExit->add_normal_predecessor(ret_list->at(i));
}
}
}
for (int b=_block_count-1; b >= 0; b--) {
BasicBlock *block = _block_list[b];
int block_start = block->start_bci();
int block_limit = block->limit_bci();
ciExceptionHandlerStream handlers(method());
for (; !handlers.is_done(); handlers.next()) {
ciExceptionHandler* handler = handlers.handler();
int start = handler->start();
int limit = handler->limit();
int handler_bci = handler->handler_bci();
int intersect_start = MAX2(block_start, start);
int intersect_limit = MIN2(block_limit, limit);
if (intersect_start < intersect_limit) {
_block_map->at(handler_bci)->add_exception_predecessor(block);
if (handler->is_catch_all()) {
if (intersect_start == block_start && intersect_limit == block_limit) {
break;
}
}
}
}
}
}
void MethodLiveness::init_gen_kill() {
for (int i=_block_count-1; i >= 0; i--) {
_block_list[i]->compute_gen_kill(method());
}
}
void MethodLiveness::propagate_liveness() {
int num_blocks = _block_count;
BasicBlock *block;
_work_list = NULL;
for (int i = 0; i < num_blocks; i++) {
block = _block_list[i];
block->set_next(_work_list);
block->set_on_work_list(true);
_work_list = block;
}
while ((block = work_list_get()) != NULL) {
block->propagate(this);
NOT_PRODUCT(_total_visits++;)
}
}
void MethodLiveness::work_list_add(BasicBlock *block) {
if (!block->on_work_list()) {
block->set_next(_work_list);
block->set_on_work_list(true);
_work_list = block;
}
}
MethodLiveness::BasicBlock *MethodLiveness::work_list_get() {
BasicBlock *block = _work_list;
if (block != NULL) {
block->set_on_work_list(false);
_work_list = block->next();
}
return block;
}
MethodLivenessResult MethodLiveness::get_liveness_at(int entry_bci) {
int bci = entry_bci;
bool is_entry = false;
if (entry_bci == InvocationEntryBci) {
is_entry = true;
bci = 0;
}
MethodLivenessResult answer((BitMap::bm_word_t*)NULL,0);
if (_block_count > 0) {
if (TimeLivenessAnalysis) _time_total.start();
if (TimeLivenessAnalysis) _time_query.start();
assert( 0 <= bci && bci < method()->code_size(), "bci out of range" );
BasicBlock *block = _block_map->at(bci);
int t = bci;
while (block == NULL && t > 0) {
block = _block_map->at(--t);
}
assert( block != NULL, "invalid bytecode index; must be instruction index" );
assert(bci >= block->start_bci() && bci < block->limit_bci(), "block must contain bci.");
answer = block->get_liveness_at(method(), bci);
if (is_entry && method()->is_synchronized() && !method()->is_static()) {
answer.at_put(0, true);
}
#ifndef PRODUCT
if (TraceLivenessQuery) {
tty->print("Liveness query of ");
method()->print_short_name();
tty->print(" @ %d : result is ", bci);
answer.print_on(tty);
}
if (TimeLivenessAnalysis) _time_query.stop();
if (TimeLivenessAnalysis) _time_total.stop();
#endif
}
#ifndef PRODUCT
if (TimeLivenessAnalysis) {
_total_locals_queried += _bit_map_size_bits;
BitCounter counter;
answer.iterate(&counter);
_total_live_locals_queried += counter.count();
}
#endif
return answer;
}
#ifndef PRODUCT
void MethodLiveness::print_times() {
tty->print_cr ("Accumulated liveness analysis times/statistics:");
tty->print_cr ("-----------------------------------------------");
tty->print_cr (" Total : %3.3f sec.", _time_total.seconds());
tty->print_cr (" Build graph : %3.3f sec. (%2.2f%%)", _time_build_graph.seconds(),
_time_build_graph.seconds() * 100 / _time_total.seconds());
tty->print_cr (" Gen / Kill : %3.3f sec. (%2.2f%%)", _time_gen_kill.seconds(),
_time_gen_kill.seconds() * 100 / _time_total.seconds());
tty->print_cr (" Dataflow : %3.3f sec. (%2.2f%%)", _time_flow.seconds(),
_time_flow.seconds() * 100 / _time_total.seconds());
tty->print_cr (" Query : %3.3f sec. (%2.2f%%)", _time_query.seconds(),
_time_query.seconds() * 100 / _time_total.seconds());
tty->print_cr (" #bytes : %8d (%3.0f bytes per sec)",
_total_bytes,
_total_bytes / _time_total.seconds());
tty->print_cr (" #methods : %8d (%3.0f methods per sec)",
_total_methods,
_total_methods / _time_total.seconds());
tty->print_cr (" avg locals : %3.3f max locals : %3d",
(float)_total_method_locals / _total_methods,
_max_method_locals);
tty->print_cr (" avg blocks : %3.3f max blocks : %3d",
(float)_total_blocks / _total_methods,
_max_method_blocks);
tty->print_cr (" avg bytes : %3.3f",
(float)_total_bytes / _total_methods);
tty->print_cr (" #blocks : %8d",
_total_blocks);
tty->print_cr (" avg normal predecessors : %3.3f max normal predecessors : %3d",
(float)_total_edges / _total_blocks,
_max_block_edges);
tty->print_cr (" avg exception predecessors : %3.3f max exception predecessors : %3d",
(float)_total_exc_edges / _total_blocks,
_max_block_exc_edges);
tty->print_cr (" avg visits : %3.3f",
(float)_total_visits / _total_blocks);
tty->print_cr (" #locals queried : %8d #live : %8d %%live : %2.2f%%",
_total_locals_queried,
_total_live_locals_queried,
100.0 * _total_live_locals_queried / _total_locals_queried);
}
#endif
MethodLiveness::BasicBlock::BasicBlock(MethodLiveness *analyzer, int start, int limit) :
_gen((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()),
analyzer->bit_map_size_bits()),
_kill((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()),
analyzer->bit_map_size_bits()),
_entry((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()),
analyzer->bit_map_size_bits()),
_normal_exit((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()),
analyzer->bit_map_size_bits()),
_exception_exit((uintptr_t*)analyzer->arena()->Amalloc(BytesPerWord * analyzer->bit_map_size_words()),
analyzer->bit_map_size_bits()),
_last_bci(-1) {
_analyzer = analyzer;
_start_bci = start;
_limit_bci = limit;
_normal_predecessors =
new (analyzer->arena()) GrowableArray<MethodLiveness::BasicBlock*>(analyzer->arena(), 5, 0, NULL);
_exception_predecessors =
new (analyzer->arena()) GrowableArray<MethodLiveness::BasicBlock*>(analyzer->arena(), 5, 0, NULL);
_normal_exit.clear();
_exception_exit.clear();
_entry.clear();
_gen.clear();
_kill.clear();
}
MethodLiveness::BasicBlock *MethodLiveness::BasicBlock::split(int split_bci) {
int start = _start_bci;
int limit = _limit_bci;
if (TraceLivenessGen) {
tty->print_cr(" ** Splitting block (%d,%d) at %d", start, limit, split_bci);
}
GrowableArray<BasicBlock*>* save_predecessors = _normal_predecessors;
assert (start < split_bci && split_bci < limit, "improper split");
BasicBlock *first_half = new (_analyzer->arena()) BasicBlock(_analyzer, start, split_bci);
_normal_predecessors = first_half->_normal_predecessors;
_start_bci = split_bci;
add_normal_predecessor(first_half);
first_half->_normal_predecessors = save_predecessors;
return first_half;
}
void MethodLiveness::BasicBlock::compute_gen_kill(ciMethod* method) {
ciBytecodeStream bytes(method);
bytes.reset_to_bci(start_bci());
bytes.set_max_bci(limit_bci());
compute_gen_kill_range(&bytes);
}
void MethodLiveness::BasicBlock::compute_gen_kill_range(ciBytecodeStream *bytes) {
_gen.clear();
_kill.clear();
while (bytes->next() != ciBytecodeStream::EOBC()) {
compute_gen_kill_single(bytes);
}
}
void MethodLiveness::BasicBlock::compute_gen_kill_single(ciBytecodeStream *instruction) {
int localNum;
switch (instruction->cur_bc()) {
case Bytecodes::_nop:
case Bytecodes::_goto:
case Bytecodes::_goto_w:
case Bytecodes::_aconst_null:
case Bytecodes::_new:
case Bytecodes::_iconst_m1:
case Bytecodes::_iconst_0:
case Bytecodes::_iconst_1:
case Bytecodes::_iconst_2:
case Bytecodes::_iconst_3:
case Bytecodes::_iconst_4:
case Bytecodes::_iconst_5:
case Bytecodes::_fconst_0:
case Bytecodes::_fconst_1:
case Bytecodes::_fconst_2:
case Bytecodes::_bipush:
case Bytecodes::_sipush:
case Bytecodes::_lconst_0:
case Bytecodes::_lconst_1:
case Bytecodes::_dconst_0:
case Bytecodes::_dconst_1:
case Bytecodes::_ldc2_w:
case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_iaload:
case Bytecodes::_faload:
case Bytecodes::_baload:
case Bytecodes::_caload:
case Bytecodes::_saload:
case Bytecodes::_laload:
case Bytecodes::_daload:
case Bytecodes::_aaload:
case Bytecodes::_iastore:
case Bytecodes::_fastore:
case Bytecodes::_bastore:
case Bytecodes::_castore:
case Bytecodes::_sastore:
case Bytecodes::_lastore:
case Bytecodes::_dastore:
case Bytecodes::_aastore:
case Bytecodes::_pop:
case Bytecodes::_pop2:
case Bytecodes::_dup:
case Bytecodes::_dup_x1:
case Bytecodes::_dup_x2:
case Bytecodes::_dup2:
case Bytecodes::_dup2_x1:
case Bytecodes::_dup2_x2:
case Bytecodes::_swap:
case Bytecodes::_iadd:
case Bytecodes::_fadd:
case Bytecodes::_isub:
case Bytecodes::_fsub:
case Bytecodes::_imul:
case Bytecodes::_fmul:
case Bytecodes::_idiv:
case Bytecodes::_fdiv:
case Bytecodes::_irem:
case Bytecodes::_frem:
case Bytecodes::_ishl:
case Bytecodes::_ishr:
case Bytecodes::_iushr:
case Bytecodes::_iand:
case Bytecodes::_ior:
case Bytecodes::_ixor:
case Bytecodes::_l2f:
case Bytecodes::_l2i:
case Bytecodes::_d2f:
case Bytecodes::_d2i:
case Bytecodes::_fcmpl:
case Bytecodes::_fcmpg:
case Bytecodes::_ladd:
case Bytecodes::_dadd:
case Bytecodes::_lsub:
case Bytecodes::_dsub:
case Bytecodes::_lmul:
case Bytecodes::_dmul:
case Bytecodes::_ldiv:
case Bytecodes::_ddiv:
case Bytecodes::_lrem:
case Bytecodes::_drem:
case Bytecodes::_land:
case Bytecodes::_lor:
case Bytecodes::_lxor:
case Bytecodes::_ineg:
case Bytecodes::_fneg:
case Bytecodes::_i2f:
case Bytecodes::_f2i:
case Bytecodes::_i2c:
case Bytecodes::_i2s:
case Bytecodes::_i2b:
case Bytecodes::_lneg:
case Bytecodes::_dneg:
case Bytecodes::_l2d:
case Bytecodes::_d2l:
case Bytecodes::_lshl:
case Bytecodes::_lshr:
case Bytecodes::_lushr:
case Bytecodes::_i2l:
case Bytecodes::_i2d:
case Bytecodes::_f2l:
case Bytecodes::_f2d:
case Bytecodes::_lcmp:
case Bytecodes::_dcmpl:
case Bytecodes::_dcmpg:
case Bytecodes::_ifeq:
case Bytecodes::_ifne:
case Bytecodes::_iflt:
case Bytecodes::_ifge:
case Bytecodes::_ifgt:
case Bytecodes::_ifle:
case Bytecodes::_tableswitch:
case Bytecodes::_ireturn:
case Bytecodes::_freturn:
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_lreturn:
case Bytecodes::_dreturn:
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
case Bytecodes::_jsr:
case Bytecodes::_jsr_w:
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
case Bytecodes::_getfield:
case Bytecodes::_putfield:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokeinterface:
case Bytecodes::_invokedynamic:
case Bytecodes::_newarray:
case Bytecodes::_anewarray:
case Bytecodes::_checkcast:
case Bytecodes::_arraylength:
case Bytecodes::_instanceof:
case Bytecodes::_athrow:
case Bytecodes::_areturn:
case Bytecodes::_monitorenter:
case Bytecodes::_monitorexit:
case Bytecodes::_ifnull:
case Bytecodes::_ifnonnull:
case Bytecodes::_multianewarray:
case Bytecodes::_lookupswitch:
break;
case Bytecodes::_return:
if (instruction->method()->intrinsic_id() == vmIntrinsics::_Object_init) {
load_one(0);
}
break;
case Bytecodes::_lload:
case Bytecodes::_dload:
load_two(instruction->get_index());
break;
case Bytecodes::_lload_0:
case Bytecodes::_dload_0:
load_two(0);
break;
case Bytecodes::_lload_1:
case Bytecodes::_dload_1:
load_two(1);
break;
case Bytecodes::_lload_2:
case Bytecodes::_dload_2:
load_two(2);
break;
case Bytecodes::_lload_3:
case Bytecodes::_dload_3:
load_two(3);
break;
case Bytecodes::_iload:
case Bytecodes::_iinc:
case Bytecodes::_fload:
case Bytecodes::_aload:
case Bytecodes::_ret:
load_one(instruction->get_index());
break;
case Bytecodes::_iload_0:
case Bytecodes::_fload_0:
case Bytecodes::_aload_0:
load_one(0);
break;
case Bytecodes::_iload_1:
case Bytecodes::_fload_1:
case Bytecodes::_aload_1:
load_one(1);
break;
case Bytecodes::_iload_2:
case Bytecodes::_fload_2:
case Bytecodes::_aload_2:
load_one(2);
break;
case Bytecodes::_iload_3:
case Bytecodes::_fload_3:
case Bytecodes::_aload_3:
load_one(3);
break;
case Bytecodes::_lstore:
case Bytecodes::_dstore:
store_two(localNum = instruction->get_index());
break;
case Bytecodes::_lstore_0:
case Bytecodes::_dstore_0:
store_two(0);
break;
case Bytecodes::_lstore_1:
case Bytecodes::_dstore_1:
store_two(1);
break;
case Bytecodes::_lstore_2:
case Bytecodes::_dstore_2:
store_two(2);
break;
case Bytecodes::_lstore_3:
case Bytecodes::_dstore_3:
store_two(3);
break;
case Bytecodes::_istore:
case Bytecodes::_fstore:
case Bytecodes::_astore:
store_one(instruction->get_index());
break;
case Bytecodes::_istore_0:
case Bytecodes::_fstore_0:
case Bytecodes::_astore_0:
store_one(0);
break;
case Bytecodes::_istore_1:
case Bytecodes::_fstore_1:
case Bytecodes::_astore_1:
store_one(1);
break;
case Bytecodes::_istore_2:
case Bytecodes::_fstore_2:
case Bytecodes::_astore_2:
store_one(2);
break;
case Bytecodes::_istore_3:
case Bytecodes::_fstore_3:
case Bytecodes::_astore_3:
store_one(3);
break;
case Bytecodes::_wide:
fatal("Iterator should skip this bytecode");
break;
default:
tty->print("unexpected opcode: %d\n", instruction->cur_bc());
ShouldNotReachHere();
break;
}
}
void MethodLiveness::BasicBlock::load_two(int local) {
load_one(local);
load_one(local+1);
}
void MethodLiveness::BasicBlock::load_one(int local) {
if (!_kill.at(local)) {
_gen.at_put(local, true);
}
}
void MethodLiveness::BasicBlock::store_two(int local) {
store_one(local);
store_one(local+1);
}
void MethodLiveness::BasicBlock::store_one(int local) {
if (!_gen.at(local)) {
_kill.at_put(local, true);
}
}
void MethodLiveness::BasicBlock::propagate(MethodLiveness *ml) {
_entry.set_union(_normal_exit);
_entry.set_difference(_kill);
_entry.set_union(_gen);
_entry.set_union(_exception_exit);
if (TraceLivenessGen) {
tty->print_cr(" ** Visiting block at %d **", start_bci());
print_on(tty);
}
int i;
for (i=_normal_predecessors->length()-1; i>=0; i--) {
BasicBlock *block = _normal_predecessors->at(i);
if (block->merge_normal(_entry)) {
ml->work_list_add(block);
}
}
for (i=_exception_predecessors->length()-1; i>=0; i--) {
BasicBlock *block = _exception_predecessors->at(i);
if (block->merge_exception(_entry)) {
ml->work_list_add(block);
}
}
}
bool MethodLiveness::BasicBlock::merge_normal(BitMap other) {
return _normal_exit.set_union_with_result(other);
}
bool MethodLiveness::BasicBlock::merge_exception(BitMap other) {
return _exception_exit.set_union_with_result(other);
}
MethodLivenessResult MethodLiveness::BasicBlock::get_liveness_at(ciMethod* method, int bci) {
MethodLivenessResult answer(NEW_RESOURCE_ARRAY(BitMap::bm_word_t, _analyzer->bit_map_size_words()),
_analyzer->bit_map_size_bits());
answer.set_is_valid();
#ifndef ASSERT
if (bci == start_bci()) {
answer.set_from(_entry);
return answer;
}
#endif
#ifdef ASSERT
ResourceMark rm;
BitMap g(_gen.size()); g.set_from(_gen);
BitMap k(_kill.size()); k.set_from(_kill);
#endif
if (_last_bci != bci || trueInDebug) {
ciBytecodeStream bytes(method);
bytes.reset_to_bci(bci);
bytes.set_max_bci(limit_bci());
compute_gen_kill_range(&bytes);
assert(_last_bci != bci ||
(g.is_same(_gen) && k.is_same(_kill)), "cached computation is incorrect");
_last_bci = bci;
}
answer.clear();
answer.set_union(_normal_exit);
answer.set_difference(_kill);
answer.set_union(_gen);
answer.set_union(_exception_exit);
#ifdef ASSERT
if (bci == start_bci()) {
assert(answer.is_same(_entry), "optimized answer must be accurate");
}
#endif
return answer;
}
#ifndef PRODUCT
void MethodLiveness::BasicBlock::print_on(outputStream *os) const {
os->print_cr("===================================================================");
os->print_cr(" Block start: %4d, limit: %4d", _start_bci, _limit_bci);
os->print (" Normal predecessors (%2d) @", _normal_predecessors->length());
int i;
for (i=0; i < _normal_predecessors->length(); i++) {
os->print(" %4d", _normal_predecessors->at(i)->start_bci());
}
os->cr();
os->print (" Exceptional predecessors (%2d) @", _exception_predecessors->length());
for (i=0; i < _exception_predecessors->length(); i++) {
os->print(" %4d", _exception_predecessors->at(i)->start_bci());
}
os->cr();
os->print (" Normal Exit : ");
_normal_exit.print_on(os);
os->print (" Gen : ");
_gen.print_on(os);
os->print (" Kill : ");
_kill.print_on(os);
os->print (" Exception Exit: ");
_exception_exit.print_on(os);
os->print (" Entry : ");
_entry.print_on(os);
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/compiler/methodLiveness.hpp
#ifndef SHARE_VM_COMPILER_METHODLIVENESS_HPP
#define SHARE_VM_COMPILER_METHODLIVENESS_HPP
#include "utilities/bitMap.hpp"
#include "utilities/growableArray.hpp"
class ciMethod;
class MethodLivenessResult : public BitMap {
private:
bool _is_valid;
public:
MethodLivenessResult(BitMap::bm_word_t* map, idx_t size_in_bits)
: BitMap(map, size_in_bits)
, _is_valid(false)
{}
MethodLivenessResult(idx_t size_in_bits)
: BitMap(size_in_bits)
, _is_valid(false)
{}
void set_is_valid() { _is_valid = true; }
bool is_valid() { return _is_valid; }
};
class MethodLiveness : public ResourceObj {
public:
class BasicBlock : public ResourceObj {
private:
friend class MethodLiveness;
MethodLiveness* _analyzer;
int _start_bci;
int _limit_bci;
BitMap _entry;
BitMap _normal_exit;
BitMap _exception_exit;
BitMap _gen;
BitMap _kill;
int _last_bci;
GrowableArray<BasicBlock*>* _normal_predecessors;
GrowableArray<BasicBlock*>* _exception_predecessors;
BasicBlock *_next;
bool _on_work_list;
bool merge_normal(BitMap other);
bool merge_exception(BitMap other);
void compute_gen_kill_range(ciBytecodeStream *bytes);
void compute_gen_kill_single(ciBytecodeStream *instruction);
void load_one(int local);
void load_two(int local);
void store_one(int local);
void store_two(int local);
BasicBlock(MethodLiveness *analyzer, int start, int limit);
int start_bci() const { return _start_bci; }
int limit_bci() const { return _limit_bci; }
void set_limit_bci(int limit) { _limit_bci = limit; }
BasicBlock *next() const { return _next; }
void set_next(BasicBlock *next) { _next = next; }
bool on_work_list() const { return _on_work_list; }
void set_on_work_list(bool val) { _on_work_list = val; }
void add_normal_predecessor(BasicBlock *pred) {
_normal_predecessors->append_if_missing(pred);
}
void add_exception_predecessor(BasicBlock *pred) {
_exception_predecessors->append_if_missing(pred);
}
BasicBlock *split(int splitBci);
void compute_gen_kill(ciMethod* method);
void propagate(MethodLiveness *ml);
MethodLivenessResult get_liveness_at(ciMethod* method, int bci);
void print_on(outputStream *os) const PRODUCT_RETURN;
}; // End of MethodLiveness::BasicBlock
private:
ciMethod* _method;
ciMethod* method() const { return _method; }
Arena* _arena;
Arena* arena() const { return _arena; }
int _code_size;
int _bit_map_size_bits;
int _bit_map_size_words;
BasicBlock **_block_list;
int _block_count;
GrowableArray<BasicBlock*>* _block_map;
BasicBlock *_work_list;
#ifdef COMPILER1
BitMap _bci_block_start;
#endif // COMPILER1
void init_basic_blocks();
void init_gen_kill();
void propagate_liveness();
friend class MethodLiveness::BasicBlock;
int bit_map_size_bits() const { return _bit_map_size_bits; }
int bit_map_size_words() const { return _bit_map_size_words; }
BasicBlock *work_list_get();
void work_list_add(BasicBlock *block);
static elapsedTimer _time_build_graph;
static elapsedTimer _time_gen_kill;
static elapsedTimer _time_flow;
static elapsedTimer _time_query;
static elapsedTimer _time_total;
#ifndef PRODUCT
static long _total_bytes;
static int _total_methods;
static long _total_blocks;
static int _max_method_blocks;
static long _total_edges;
static int _max_block_edges;
static long _total_exc_edges;
static int _max_block_exc_edges;
static long _total_method_locals;
static int _max_method_locals;
static long _total_locals_queried;
static long _total_live_locals_queried;
static long _total_visits;
#endif
public:
MethodLiveness(Arena* arena, ciMethod* method);
void compute_liveness();
MethodLivenessResult get_liveness_at(int bci);
#ifdef COMPILER1
const BitMap get_bci_block_start() const { return _bci_block_start; }
#endif // COMPILER1
static void print_times() PRODUCT_RETURN;
};
#endif // SHARE_VM_COMPILER_METHODLIVENESS_HPP
C:\hotspot-69087d08d473\src\share\vm/compiler/oopMap.cpp
#include "precompiled.hpp"
#include "code/codeBlob.hpp"
#include "code/codeCache.hpp"
#include "code/nmethod.hpp"
#include "code/scopeDesc.hpp"
#include "compiler/oopMap.hpp"
#include "gc_interface/collectedHeap.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/signature.hpp"
#ifdef COMPILER1
#include "c1/c1_Defs.hpp"
#endif
OopMapStream::OopMapStream(OopMap* oop_map) {
if(oop_map->omv_data() == NULL) {
_stream = new CompressedReadStream(oop_map->write_stream()->buffer());
} else {
_stream = new CompressedReadStream(oop_map->omv_data());
}
_mask = OopMapValue::type_mask_in_place;
_size = oop_map->omv_count();
_position = 0;
_valid_omv = false;
}
OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) {
if(oop_map->omv_data() == NULL) {
_stream = new CompressedReadStream(oop_map->write_stream()->buffer());
} else {
_stream = new CompressedReadStream(oop_map->omv_data());
}
_mask = oop_types_mask;
_size = oop_map->omv_count();
_position = 0;
_valid_omv = false;
}
void OopMapStream::find_next() {
while(_position++ < _size) {
_omv.read_from(_stream);
if(((int)_omv.type() & _mask) > 0) {
_valid_omv = true;
return;
}
}
_valid_omv = false;
}
OopMap::OopMap(int frame_size, int arg_count) {
set_write_stream(new CompressedWriteStream(32));
set_omv_data(NULL);
set_omv_count(0);
#ifdef ASSERT
_locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count;
_locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;
#endif
}
OopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) {
set_write_stream(new CompressedWriteStream(source->omv_count() * 2));
set_omv_data(NULL);
set_omv_count(0);
set_offset(source->offset());
#ifdef ASSERT
_locs_length = source->_locs_length;
_locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length);
for(int i = 0; i < _locs_length; i++) _locs_used[i] = OopMapValue::unused_value;
#endif
for (OopMapStream oms(source); !oms.is_done(); oms.next()) {
OopMapValue omv = oms.current();
omv.write_on(write_stream());
increment_count();
}
}
OopMap* OopMap::deep_copy() {
return new OopMap(_deep_copy_token, this);
}
void OopMap::copy_to(address addr) {
memcpy(addr,this,sizeof(OopMap));
memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position());
OopMap* new_oop = (OopMap*)addr;
new_oop->set_omv_data_size(write_stream()->position());
new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap)));
new_oop->set_write_stream(NULL);
}
int OopMap::heap_size() const {
int size = sizeof(OopMap);
int align = sizeof(void *) - 1;
if(write_stream() != NULL) {
size += write_stream()->position();
} else {
size += omv_data_size();
}
size = ((size+align) & ~align);
return size;
}
void OopMap::set_xxx(VMReg reg, OopMapValue::oop_types x, VMReg optional) {
assert(reg->value() < _locs_length, "too big reg value for stack size");
assert( _locs_used[reg->value()] == OopMapValue::unused_value, "cannot insert twice" );
debug_only( _locs_used[reg->value()] = x; )
OopMapValue o(reg, x);
if(x == OopMapValue::callee_saved_value) {
assert(optional->is_reg(), "Trying to callee save a stack location");
o.set_content_reg(optional);
} else if(x == OopMapValue::derived_oop_value) {
o.set_content_reg(optional);
}
o.write_on(write_stream());
increment_count();
}
void OopMap::set_oop(VMReg reg) {
set_xxx(reg, OopMapValue::oop_value, VMRegImpl::Bad());
}
void OopMap::set_value(VMReg reg) {
if (ZapDeadCompiledLocals)
set_xxx(reg, OopMapValue::value_value, VMRegImpl::Bad());
}
void OopMap::set_narrowoop(VMReg reg) {
set_xxx(reg, OopMapValue::narrowoop_value, VMRegImpl::Bad());
}
void OopMap::set_callee_saved(VMReg reg, VMReg caller_machine_register ) {
set_xxx(reg, OopMapValue::callee_saved_value, caller_machine_register);
}
void OopMap::set_derived_oop(VMReg reg, VMReg derived_from_local_register ) {
if( reg == derived_from_local_register ) {
set_oop(reg);
} else {
set_xxx(reg, OopMapValue::derived_oop_value, derived_from_local_register);
}
}
OopMapSet::OopMapSet() {
set_om_size(MinOopMapAllocation);
set_om_count(0);
OopMap** temp = NEW_RESOURCE_ARRAY(OopMap*, om_size());
set_om_data(temp);
}
void OopMapSet::grow_om_data() {
int new_size = om_size() * 2;
OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size);
memcpy(new_data,om_data(),om_size() * sizeof(OopMap*));
set_om_size(new_size);
set_om_data(new_data);
}
void OopMapSet::copy_to(address addr) {
address temp = addr;
int align = sizeof(void *) - 1;
memcpy(addr,this,sizeof(OopMapSet));
temp += sizeof(OopMapSet);
temp = (address)((intptr_t)(temp + align) & ~align);
OopMapSet* new_set = (OopMapSet*)addr;
new_set->set_om_data((OopMap**)temp);
temp += (om_count() * sizeof(OopMap*));
for(int i=0; i < om_count(); i++) {
OopMap* map = at(i);
map->copy_to((address)temp);
new_set->set(i,(OopMap*)temp);
temp += map->heap_size();
}
new_set->set_om_size(-1);
}
void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) {
assert(om_size() != -1,"Cannot grow a fixed OopMapSet");
if(om_count() >= om_size()) {
grow_om_data();
}
map->set_offset(pc_offset);
#ifdef ASSERT
if(om_count() > 0) {
OopMap* last = at(om_count()-1);
if (last->offset() == map->offset() ) {
fatal("OopMap inserted twice");
}
if(last->offset() > map->offset()) {
tty->print_cr( "WARNING, maps not sorted: pc[%d]=%d, pc[%d]=%d",
om_count(),last->offset(),om_count()+1,map->offset());
}
}
#endif // ASSERT
set(om_count(),map);
increment_count();
}
int OopMapSet::heap_size() const {
int size = sizeof(OopMap);
int align = sizeof(void *) - 1;
size = ((size+align) & ~align);
size += om_count() * sizeof(OopMap*);
for(int i=0; i < om_count(); i++) {
size += at(i)->heap_size();
}
return size;
}
OopMap* OopMapSet::singular_oop_map() {
guarantee(om_count() == 1, "Make sure we only have a single gc point");
return at(0);
}
OopMap* OopMapSet::find_map_at_offset(int pc_offset) const {
int i, len = om_count();
assert( len > 0, "must have pointer maps" );
for( i = 0; i < len; i++) {
if( at(i)->offset() >= pc_offset )
break;
}
assert( i < len, "oopmap not found" );
OopMap* m = at(i);
assert( m->offset() == pc_offset, "oopmap not found" );
return m;
}
class DoNothingClosure: public OopClosure {
public:
void do_oop(oop* p) {}
void do_oop(narrowOop* p) {}
};
static DoNothingClosure do_nothing;
static void add_derived_oop(oop* base, oop* derived) {
#ifndef TIERED
COMPILER1_PRESENT(ShouldNotReachHere();)
#endif // TIERED
#ifdef COMPILER2
DerivedPointerTable::add(derived, base);
#endif // COMPILER2
}
#ifndef PRODUCT
static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) {
tty->print_cr("------ ");
CodeBlob* cb = fr->cb();
OopMapSet* maps = cb->oop_maps();
OopMap* map = cb->oop_map_for_return_address(fr->pc());
map->print();
if( cb->is_nmethod() ) {
nmethod* nm = (nmethod*)cb;
if (nm->is_native_method()) {
tty->print("bci: 0 (native)");
} else {
ScopeDesc* scope = nm->scope_desc_at(fr->pc());
tty->print("bci: %d ",scope->bci());
}
}
tty->cr();
fr->print_on(tty);
tty->print(" ");
cb->print_value_on(tty); tty->cr();
reg_map->print();
tty->print_cr("------ ");
}
#endif // PRODUCT
void OopMapSet::oops_do(const frame *fr, const RegisterMap* reg_map, OopClosure* f) {
all_do(fr, reg_map, f, add_derived_oop, &do_nothing);
}
void OopMapSet::all_do(const frame *fr, const RegisterMap *reg_map,
OopClosure* oop_fn, void derived_oop_fn(oop*, oop*),
OopClosure* value_fn) {
CodeBlob* cb = fr->cb();
assert(cb != NULL, "no codeblob");
NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);)
OopMapSet* maps = cb->oop_maps();
OopMap* map = cb->oop_map_for_return_address(fr->pc());
assert(map != NULL, "no ptr map found");
OopMapValue omv;
{
OopMapStream oms(map,OopMapValue::derived_oop_value);
if (!oms.is_done()) {
#ifndef TIERED
COMPILER1_PRESENT(ShouldNotReachHere();)
#endif // !TIERED
MutexLockerEx x(DerivedPointerTableGC_lock, Mutex::_no_safepoint_check_flag);
do {
omv = oms.current();
oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
if ( loc != NULL ) {
oop *derived_loc = loc;
oop *base_loc = fr->oopmapreg_to_location(omv.content_reg(), reg_map);
if (base_loc != NULL && *base_loc != (oop)NULL && !Universe::is_narrow_oop_base(*base_loc)) {
derived_oop_fn(base_loc, derived_loc);
}
}
oms.next();
} while (!oms.is_done());
}
}
int mask = OopMapValue::oop_value | OopMapValue::value_value | OopMapValue::narrowoop_value;
{
for (OopMapStream oms(map,mask); !oms.is_done(); oms.next()) {
omv = oms.current();
oop* loc = fr->oopmapreg_to_location(omv.reg(),reg_map);
if ( loc != NULL ) {
if ( omv.type() == OopMapValue::oop_value ) {
oop val = *loc;
if (val == (oop)NULL || Universe::is_narrow_oop_base(val)) {
continue;
}
#ifdef ASSERT
if ((((uintptr_t)loc & (sizeof(*loc)-1)) != 0) ||
!Universe::heap()->is_in_or_null(*loc)) {
tty->print_cr("# Found non oop pointer. Dumping state at failure");
trace_codeblob_maps(fr, reg_map);
omv.print();
tty->print_cr("register r");
omv.reg()->print();
tty->print_cr("loc = %p *loc = %p\n", loc, (address)*loc);
assert(Universe::heap()->is_in_or_null(*loc), "found non oop pointer");
}
#endif // ASSERT
oop_fn->do_oop(loc);
} else if ( omv.type() == OopMapValue::value_value ) {
assert((*loc) == (oop)NULL || !Universe::is_narrow_oop_base(*loc),
"found invalid value pointer");
value_fn->do_oop(loc);
} else if ( omv.type() == OopMapValue::narrowoop_value ) {
narrowOop *nl = (narrowOop*)loc;
#ifndef VM_LITTLE_ENDIAN
if (!omv.reg()->is_stack()) {
nl = (narrowOop*)((address)nl + 4);
}
#endif
oop_fn->do_oop(nl);
}
}
}
}
}
void OopMapSet::update_register_map(const frame *fr, RegisterMap *reg_map) {
ResourceMark rm;
CodeBlob* cb = fr->cb();
assert(cb != NULL, "no codeblob");
assert( reg_map->_update_for_id == NULL || fr->is_older(reg_map->_update_for_id),
"already updated this map; do not 'update' it twice!" );
debug_only(reg_map->_update_for_id = fr->id());
assert((reg_map->include_argument_oops() ||
!cb->caller_must_gc_arguments(reg_map->thread())),
"include_argument_oops should already be set");
address pc = fr->pc();
OopMap* map = cb->oop_map_for_return_address(pc);
assert(map != NULL, "no ptr map found");
DEBUG_ONLY(int nof_callee = 0;)
for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) {
OopMapValue omv = oms.current();
VMReg reg = omv.content_reg();
oop* loc = fr->oopmapreg_to_location(omv.reg(), reg_map);
reg_map->set_location(reg, (address) loc);
DEBUG_ONLY(nof_callee++;)
}
#ifdef COMPILER2
assert(cb->is_compiled_by_c1() || !cb->is_runtime_stub() ||
(nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT),
"must save all");
#endif // COMPILER2
}
#ifndef PRODUCT
bool OopMap::has_derived_pointer() const {
#ifndef TIERED
COMPILER1_PRESENT(return false);
#endif // !TIERED
#ifdef COMPILER2
OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value);
return oms.is_done();
#else
return false;
#endif // COMPILER2
}
#endif //PRODUCT
static
void print_register_type(OopMapValue::oop_types x, VMReg optional,
outputStream* st) {
switch( x ) {
case OopMapValue::oop_value:
st->print("Oop");
break;
case OopMapValue::value_value:
st->print("Value");
break;
case OopMapValue::narrowoop_value:
st->print("NarrowOop");
break;
case OopMapValue::callee_saved_value:
st->print("Callers_");
optional->print_on(st);
break;
case OopMapValue::derived_oop_value:
st->print("Derived_oop_");
optional->print_on(st);
break;
default:
ShouldNotReachHere();
}
}
void OopMapValue::print_on(outputStream* st) const {
reg()->print_on(st);
st->print("=");
print_register_type(type(),content_reg(),st);
st->print(" ");
}
void OopMap::print_on(outputStream* st) const {
OopMapValue omv;
st->print("OopMap{");
for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) {
omv = oms.current();
omv.print_on(st);
}
st->print("off=%d}", (int) offset());
}
void OopMapSet::print_on(outputStream* st) const {
int i, len = om_count();
st->print_cr("OopMapSet contains %d OopMaps\n",len);
for( i = 0; i < len; i++) {
OopMap* m = at(i);
st->print_cr("#%d ",i);
m->print_on(st);
st->cr();
}
}
#ifdef COMPILER2
class DerivedPointerEntry : public CHeapObj<mtCompiler> {
private:
oop* _location; // Location of derived pointer (also pointing to the base)
intptr_t _offset; // Offset from base pointer
public:
DerivedPointerEntry(oop* location, intptr_t offset) { _location = location; _offset = offset; }
oop* location() { return _location; }
intptr_t offset() { return _offset; }
};
GrowableArray<DerivedPointerEntry*>* DerivedPointerTable::_list = NULL;
bool DerivedPointerTable::_active = false;
void DerivedPointerTable::clear() {
assert (!_active, "should not be active");
assert(_list == NULL || _list->length() == 0, "table not empty");
if (_list == NULL) {
_list = new (ResourceObj::C_HEAP, mtCompiler) GrowableArray<DerivedPointerEntry*>(10, true); // Allocated on C heap
}
_active = true;
}
sssssssss22
最新推荐文章于 2024-08-01 08:23:29 发布