提交 e769d590 编写于 作者: D duke

Merge

......@@ -5,3 +5,4 @@ cbc8ad9dd0e085a607427ea35411990982f19a36 jdk7-b25
56652b46f328937f6b9b5130f1e4cd80f48868ef jdk7-b28
31e08f70e88d77c2053f91c21b49a04296bdc59a jdk7-b29
2dab2f712e1832c92acfa63ec0337048b9422c20 jdk7-b30
3300a35a0bd56d695b92fe0b34f03ebbfc939064 jdk7-b31
此差异已折叠。
......@@ -5,3 +5,4 @@ e84e9018bebbf3e5bafc5706e7882a15cb1c7d99 jdk7-b27
27509b7d21ed783b3f6eb7b7612781c675a30c2f jdk7-b28
8b71960f79ce0a6fb8ddfeec03f03d400a361747 jdk7-b29
c0252adbb2abbfdd6c35595429ac6fbdd98e20ac jdk7-b30
ef6af34d75a7b44e77083f1d4ee47631fa09d3b4 jdk7-b31
......@@ -5,3 +5,4 @@ e3d2692f8442e2d951166dc9bd9a330684754438 jdk7-b27
c14dab40ed9bf45ad21150bd70c9c80cdf655415 jdk7-b28
4f91c08b3e4498213a9c5a24898f7d9c38cf86fb jdk7-b29
d1605aabd0a15ecf93787c47de63073c33fba52d jdk7-b30
9c2ecc2ffb125f14fab3857fe7689598956348a0 jdk7-b31
......@@ -2414,8 +2414,20 @@ static bool linux_mprotect(char* addr, size_t size, int prot) {
return ::mprotect(bottom, size, prot) == 0;
}
bool os::protect_memory(char* addr, size_t size) {
return linux_mprotect(addr, size, PROT_READ);
// Set protections specified
bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
bool is_committed) {
unsigned int p = 0;
switch (prot) {
case MEM_PROT_NONE: p = PROT_NONE; break;
case MEM_PROT_READ: p = PROT_READ; break;
case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
default:
ShouldNotReachHere();
}
// is_committed is unused.
return linux_mprotect(addr, bytes, p);
}
bool os::guard_memory(char* addr, size_t size) {
......@@ -3704,8 +3716,9 @@ void os::make_polling_page_unreadable(void) {
// Mark the polling page as readable
void os::make_polling_page_readable(void) {
if( !protect_memory((char *)_polling_page, Linux::page_size()) )
if( !linux_mprotect((char *)_polling_page, Linux::page_size(), PROT_READ)) {
fatal("Could not enable polling page");
}
};
int os::active_processor_count() {
......
......@@ -2965,10 +2965,21 @@ static bool solaris_mprotect(char* addr, size_t bytes, int prot) {
return retVal == 0;
}
// Protect memory (make it read-only. (Used to pass readonly pages through
// Protect memory (Used to pass readonly pages through
// JNI GetArray<type>Elements with empty arrays.)
bool os::protect_memory(char* addr, size_t bytes) {
return solaris_mprotect(addr, bytes, PROT_READ);
bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
bool is_committed) {
unsigned int p = 0;
switch (prot) {
case MEM_PROT_NONE: p = PROT_NONE; break;
case MEM_PROT_READ: p = PROT_READ; break;
case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break;
case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
default:
ShouldNotReachHere();
}
// is_committed is unused.
return solaris_mprotect(addr, bytes, p);
}
// guard_memory and unguard_memory only happens within stack guard pages.
......
......@@ -2170,6 +2170,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
// Windows 98 reports faulting addresses incorrectly
if (!MacroAssembler::needs_explicit_null_check((intptr_t)addr) ||
!os::win32::is_nt()) {
return Handle_Exception(exceptionInfo,
SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL));
}
......@@ -2563,9 +2564,33 @@ bool os::release_memory(char* addr, size_t bytes) {
return VirtualFree(addr, 0, MEM_RELEASE) != 0;
}
bool os::protect_memory(char* addr, size_t bytes) {
// Set protections specified
bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
bool is_committed) {
unsigned int p = 0;
switch (prot) {
case MEM_PROT_NONE: p = PAGE_NOACCESS; break;
case MEM_PROT_READ: p = PAGE_READONLY; break;
case MEM_PROT_RW: p = PAGE_READWRITE; break;
case MEM_PROT_RWX: p = PAGE_EXECUTE_READWRITE; break;
default:
ShouldNotReachHere();
}
DWORD old_status;
return VirtualProtect(addr, bytes, PAGE_READONLY, &old_status) != 0;
// Strange enough, but on Win32 one can change protection only for committed
// memory, not a big deal anyway, as bytes less or equal than 64K
if (!is_committed && !commit_memory(addr, bytes)) {
fatal("cannot commit protection page");
}
// One cannot use os::guard_memory() here, as on Win32 guard page
// have different (one-shot) semantics, from MSDN on PAGE_GUARD:
//
// Pages in the region become guard pages. Any attempt to access a guard page
// causes the system to raise a STATUS_GUARD_PAGE exception and turn off
// the guard page status. Guard pages thus act as a one-time access alarm.
return VirtualProtect(addr, bytes, p, &old_status) != 0;
}
bool os::guard_memory(char* addr, size_t bytes) {
......
......@@ -27,12 +27,6 @@
#include <asm-sparc/traps.h>
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Since the linux kernel resides at the low end of
// user address space, no null pointer check is needed.
return offset < 0 || offset >= 0x100000;
}
void MacroAssembler::read_ccr_trap(Register ccr_save) {
// No implementation
breakpoint_trap();
......
......@@ -39,10 +39,3 @@ void MacroAssembler::get_thread(Register thread) {
movptr(thread, tls);
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Linux kernel guarantees that the first page is always unmapped. Don't
// assume anything more than that.
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
......@@ -65,22 +65,3 @@ void MacroAssembler::get_thread(Register thread) {
popq(rax);
}
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Exception handler checks the nmethod's implicit null checks table
// only when this method returns false.
if (UseCompressedOops) {
// The first page after heap_base is unmapped and
// the 'offset' is equal to [heap_base + offset] for
// narrow oop implicit null checks.
uintptr_t heap_base = (uintptr_t)Universe::heap_base();
if ((uintptr_t)offset >= heap_base) {
// Normalize offset for the next check.
offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
}
}
// Linux kernel guarantees that the first page is always unmapped. Don't
// assume anything more than that.
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
......@@ -28,18 +28,6 @@
#include <sys/trap.h> // For trap numbers
#include <v9/sys/psr_compat.h> // For V8 compatibility
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// The first page of virtual addresses is unmapped on SPARC.
// Thus, any access the VM makes through a null pointer with an offset of
// less than 4K will get a recognizable SIGSEGV, which the signal handler
// will transform into a NullPointerException.
// (Actually, the first 64K or so is unmapped, but it's simpler
// to depend only on the first 4K or so.)
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
void MacroAssembler::read_ccr_trap(Register ccr_save) {
// Execute a trap to get the PSR, mask and shift
// to get the condition codes.
......
......@@ -79,9 +79,3 @@ void MacroAssembler::get_thread(Register thread) {
if (thread != rax) popl(rax);
popl(thread);
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Identical to Sparc/Solaris code
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
......@@ -85,22 +85,3 @@ void MacroAssembler::get_thread(Register thread) {
popq(rax);
}
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Identical to Sparc/Solaris code
// Exception handler checks the nmethod's implicit null checks table
// only when this method returns false.
if (UseCompressedOops) {
// The first page after heap_base is unmapped and
// the 'offset' is equal to [heap_base + offset] for
// narrow oop implicit null checks.
uintptr_t heap_base = (uintptr_t)Universe::heap_base();
if ((uintptr_t)offset >= heap_base) {
// Normalize offset for the next check.
offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
}
}
bool offset_in_first_page = 0 <= offset && offset < os::vm_page_size();
return !offset_in_first_page;
}
......@@ -58,7 +58,3 @@ void MacroAssembler::get_thread(Register thread) {
"Thread Pointer Offset has not been initialized");
movl(thread, Address(thread, ThreadLocalStorage::get_thread_ptr_offset()));
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
return offset < 0 || (int)os::vm_page_size() <= offset;
}
......@@ -65,19 +65,3 @@ void MacroAssembler::get_thread(Register thread) {
popq(rax);
}
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Exception handler checks the nmethod's implicit null checks table
// only when this method returns false.
if (UseCompressedOops) {
// The first page after heap_base is unmapped and
// the 'offset' is equal to [heap_base + offset] for
// narrow oop implicit null checks.
uintptr_t heap_base = (uintptr_t)Universe::heap_base();
if ((uintptr_t)offset >= heap_base) {
// Normalize offset for the next check.
offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
}
}
return offset < 0 || os::vm_page_size() <= offset;
}
......@@ -246,6 +246,24 @@ void AbstractAssembler::block_comment(const char* comment) {
}
}
bool MacroAssembler::needs_explicit_null_check(intptr_t offset) {
// Exception handler checks the nmethod's implicit null checks table
// only when this method returns false.
#ifndef SPARC
// Sparc does not have based addressing
if (UseCompressedOops) {
// The first page after heap_base is unmapped and
// the 'offset' is equal to [heap_base + offset] for
// narrow oop implicit null checks.
uintptr_t heap_base = (uintptr_t)Universe::heap_base();
if ((uintptr_t)offset >= heap_base) {
// Normalize offset for the next check.
offset = (intptr_t)(pointer_delta((void*)offset, (void*)heap_base, 1));
}
}
#endif // SPARC
return offset < 0 || os::vm_page_size() <= offset;
}
#ifndef PRODUCT
void Label::print_instructions(MacroAssembler* masm) const {
......
......@@ -61,6 +61,8 @@ ParMarkBitMap::initialize(MemRegion covered_region)
if (_virtual_space != NULL) {
delete _virtual_space;
_virtual_space = NULL;
// Release memory reserved in the space.
rs.release();
}
return false;
}
......
......@@ -108,8 +108,8 @@ jint ParallelScavengeHeap::initialize() {
// size than is needed or wanted for the perm gen. Use the "compound
// alignment" ReservedSpace ctor to avoid having to use the same page size for
// all gens.
ReservedSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size,
og_align);
ReservedHeapSpace heap_rs(pg_max_size, pg_align, og_max_size + yg_max_size,
og_align);
os::trace_page_sizes("ps perm", pg_min_size, pg_max_size, pg_page_sz,
heap_rs.base(), pg_max_size);
os::trace_page_sizes("ps main", og_min_size + yg_min_size,
......
......@@ -422,6 +422,8 @@ ParallelCompactData::create_vspace(size_t count, size_t element_size)
return vspace;
}
delete vspace;
// Release memory reserved in the space.
rs.release();
}
return 0;
......
......@@ -71,13 +71,8 @@ bool PSVirtualSpace::contains(void* p) const {
void PSVirtualSpace::release() {
DEBUG_ONLY(PSVirtualSpaceVerifier this_verifier(this));
if (reserved_low_addr() != NULL) {
if (special()) {
os::release_memory_special(reserved_low_addr(), reserved_size());
} else {
(void)os::release_memory(reserved_low_addr(), reserved_size());
}
}
// This may not release memory it didn't reserve.
// Use rs.release() to release the underlying memory instead.
_reserved_low_addr = _reserved_high_addr = NULL;
_committed_low_addr = _committed_high_addr = NULL;
_special = false;
......
......@@ -222,8 +222,8 @@ char* GenCollectedHeap::allocate(size_t alignment,
*_total_reserved = total_reserved;
*_n_covered_regions = n_covered_regions;
*heap_rs = ReservedSpace(total_reserved, alignment,
UseLargePages, heap_address);
*heap_rs = ReservedHeapSpace(total_reserved, alignment,
UseLargePages, heap_address);
return heap_address;
}
......
......@@ -2173,8 +2173,7 @@ static char* get_bad_address() {
size_t size = os::vm_allocation_granularity();
bad_address = os::reserve_memory(size);
if (bad_address != NULL) {
os::commit_memory(bad_address, size);
os::protect_memory(bad_address, size);
os::protect_memory(bad_address, size, os::MEM_PROT_READ);
}
}
return bad_address;
......
......@@ -1176,8 +1176,7 @@ void Arguments::set_ergonomics_flags() {
// by ergonomics.
if (MaxHeapSize <= max_heap_for_compressed_oops()) {
if (FLAG_IS_DEFAULT(UseCompressedOops)) {
// Leave compressed oops off by default. Uncomment
// the following line to return it to default status.
// Turn off until bug is fixed.
// FLAG_SET_ERGO(bool, UseCompressedOops, true);
}
} else {
......
......@@ -922,8 +922,9 @@ void os::serialize_thread_states() {
// time and expensive page trap spinning, 'SerializePageLock' is used to block
// the mutator thread if such case is encountered. See bug 6546278 for details.
Thread::muxAcquire(&SerializePageLock, "serialize_thread_states");
os::protect_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
os::unguard_memory( (char *)os::get_memory_serialize_page(), os::vm_page_size() );
os::protect_memory((char *)os::get_memory_serialize_page(),
os::vm_page_size(), MEM_PROT_READ, /*is_committed*/true );
os::unguard_memory((char *)os::get_memory_serialize_page(), os::vm_page_size());
Thread::muxRelease(&SerializePageLock);
}
......
......@@ -193,7 +193,11 @@ class os: AllStatic {
static bool commit_memory(char* addr, size_t size, size_t alignment_hint);
static bool uncommit_memory(char* addr, size_t bytes);
static bool release_memory(char* addr, size_t bytes);
static bool protect_memory(char* addr, size_t bytes);
enum ProtType { MEM_PROT_NONE, MEM_PROT_READ, MEM_PROT_RW, MEM_PROT_RWX };
static bool protect_memory(char* addr, size_t bytes, ProtType prot,
bool is_committed = false);
static bool guard_memory(char* addr, size_t bytes);
static bool unguard_memory(char* addr, size_t bytes);
static char* map_memory(int fd, const char* file_name, size_t file_offset,
......
......@@ -28,12 +28,15 @@
// ReservedSpace
ReservedSpace::ReservedSpace(size_t size) {
initialize(size, 0, false, NULL);
initialize(size, 0, false, NULL, 0);
}
ReservedSpace::ReservedSpace(size_t size, size_t alignment,
bool large, char* requested_address) {
initialize(size, alignment, large, requested_address);
bool large,
char* requested_address,
const size_t noaccess_prefix) {
initialize(size+noaccess_prefix, alignment, large, requested_address,
noaccess_prefix);
}
char *
......@@ -105,7 +108,8 @@ char* ReservedSpace::reserve_and_align(const size_t reserve_size,
ReservedSpace::ReservedSpace(const size_t prefix_size,
const size_t prefix_align,
const size_t suffix_size,
const size_t suffix_align)
const size_t suffix_align,
const size_t noaccess_prefix)
{
assert(prefix_size != 0, "sanity");
assert(prefix_align != 0, "sanity");
......@@ -118,12 +122,16 @@ ReservedSpace::ReservedSpace(const size_t prefix_size,
assert((suffix_align & prefix_align - 1) == 0,
"suffix_align not divisible by prefix_align");
// Add in noaccess_prefix to prefix_size;
const size_t adjusted_prefix_size = prefix_size + noaccess_prefix;
const size_t size = adjusted_prefix_size + suffix_size;
// On systems where the entire region has to be reserved and committed up
// front, the compound alignment normally done by this method is unnecessary.
const bool try_reserve_special = UseLargePages &&
prefix_align == os::large_page_size();
if (!os::can_commit_large_page_memory() && try_reserve_special) {
initialize(prefix_size + suffix_size, prefix_align, true);
initialize(size, prefix_align, true, NULL, noaccess_prefix);
return;
}
......@@ -131,15 +139,19 @@ ReservedSpace::ReservedSpace(const size_t prefix_size,
_size = 0;
_alignment = 0;
_special = false;
_noaccess_prefix = 0;
// Assert that if noaccess_prefix is used, it is the same as prefix_align.
assert(noaccess_prefix == 0 ||
noaccess_prefix == prefix_align, "noaccess prefix wrong");
// Optimistically try to reserve the exact size needed.
const size_t size = prefix_size + suffix_size;
char* addr = os::reserve_memory(size, NULL, prefix_align);
if (addr == NULL) return;
// Check whether the result has the needed alignment (unlikely unless
// prefix_align == suffix_align).
const size_t ofs = size_t(addr) + prefix_size & suffix_align - 1;
const size_t ofs = size_t(addr) + adjusted_prefix_size & suffix_align - 1;
if (ofs != 0) {
// Wrong alignment. Release, allocate more space and do manual alignment.
//
......@@ -153,11 +165,11 @@ ReservedSpace::ReservedSpace(const size_t prefix_size,
}
const size_t extra = MAX2(ofs, suffix_align - ofs);
addr = reserve_and_align(size + extra, prefix_size, prefix_align,
addr = reserve_and_align(size + extra, adjusted_prefix_size, prefix_align,
suffix_size, suffix_align);
if (addr == NULL) {
// Try an even larger region. If this fails, address space is exhausted.
addr = reserve_and_align(size + suffix_align, prefix_size,
addr = reserve_and_align(size + suffix_align, adjusted_prefix_size,
prefix_align, suffix_size, suffix_align);
}
}
......@@ -165,10 +177,12 @@ ReservedSpace::ReservedSpace(const size_t prefix_size,
_base = addr;
_size = size;
_alignment = prefix_align;
_noaccess_prefix = noaccess_prefix;
}
void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
char* requested_address) {
char* requested_address,
const size_t noaccess_prefix) {
const size_t granularity = os::vm_allocation_granularity();
assert((size & granularity - 1) == 0,
"size not aligned to os::vm_allocation_granularity()");
......@@ -181,6 +195,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
_size = 0;
_special = false;
_alignment = 0;
_noaccess_prefix = 0;
if (size == 0) {
return;
}
......@@ -220,7 +235,8 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
// important. If available space is not detected, return NULL.
if (requested_address != 0) {
base = os::attempt_reserve_memory_at(size, requested_address);
base = os::attempt_reserve_memory_at(size,
requested_address-noaccess_prefix);
} else {
base = os::reserve_memory(size, NULL, alignment);
}
......@@ -259,6 +275,11 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large,
_base = base;
_size = size;
_alignment = MAX2(alignment, (size_t) os::vm_page_size());
_noaccess_prefix = noaccess_prefix;
// Assert that if noaccess_prefix is used, it is the same as alignment.
assert(noaccess_prefix == 0 ||
noaccess_prefix == _alignment, "noaccess prefix wrong");
assert(markOopDesc::encode_pointer_as_mark(_base)->decode_pointer() == _base,
"area must be distinguisable from marks for mark-sweep");
......@@ -274,6 +295,7 @@ ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment,
_base = base;
_size = size;
_alignment = alignment;
_noaccess_prefix = 0;
_special = special;
}
......@@ -320,17 +342,58 @@ size_t ReservedSpace::allocation_align_size_down(size_t size) {
void ReservedSpace::release() {
if (is_reserved()) {
char *real_base = _base - _noaccess_prefix;
const size_t real_size = _size + _noaccess_prefix;
if (special()) {
os::release_memory_special(_base, _size);
os::release_memory_special(real_base, real_size);
} else{
os::release_memory(_base, _size);
os::release_memory(real_base, real_size);
}
_base = NULL;
_size = 0;
_noaccess_prefix = 0;
_special = false;
}
}
void ReservedSpace::protect_noaccess_prefix(const size_t size) {
// If there is noaccess prefix, return.
if (_noaccess_prefix == 0) return;
assert(_noaccess_prefix >= (size_t)os::vm_page_size(),
"must be at least page size big");
// Protect memory at the base of the allocated region.
// If special, the page was committed (only matters on windows)
if (!os::protect_memory(_base, _noaccess_prefix, os::MEM_PROT_NONE,
_special)) {
fatal("cannot protect protection page");
}
_base += _noaccess_prefix;
_size -= _noaccess_prefix;
assert((size == _size) && ((uintptr_t)_base % _alignment == 0),
"must be exactly of required size and alignment");
}
ReservedHeapSpace::ReservedHeapSpace(size_t size, size_t alignment,
bool large, char* requested_address) :
ReservedSpace(size, alignment, large,
requested_address,
UseCompressedOops ? lcm(os::vm_page_size(), alignment) : 0) {
// Only reserved space for the java heap should have a noaccess_prefix
// if using compressed oops.
protect_noaccess_prefix(size);
}
ReservedHeapSpace::ReservedHeapSpace(const size_t prefix_size,
const size_t prefix_align,
const size_t suffix_size,
const size_t suffix_align) :
ReservedSpace(prefix_size, prefix_align, suffix_size, suffix_align,
UseCompressedOops ? lcm(os::vm_page_size(), prefix_align) : 0) {
protect_noaccess_prefix(prefix_size+suffix_size);
}
// VirtualSpace
......@@ -348,6 +411,7 @@ VirtualSpace::VirtualSpace() {
_lower_alignment = 0;
_middle_alignment = 0;
_upper_alignment = 0;
_special = false;
}
......@@ -402,7 +466,8 @@ VirtualSpace::~VirtualSpace() {
void VirtualSpace::release() {
(void)os::release_memory(low_boundary(), reserved_size());
// This does not release memory it never reserved.
// Caller must release via rs.release();
_low_boundary = NULL;
_high_boundary = NULL;
_low = NULL;
......
......@@ -29,13 +29,15 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC {
private:
char* _base;
size_t _size;
size_t _noaccess_prefix;
size_t _alignment;
bool _special;
// ReservedSpace
ReservedSpace(char* base, size_t size, size_t alignment, bool special);
void initialize(size_t size, size_t alignment, bool large,
char* requested_address = NULL);
char* requested_address,
const size_t noaccess_prefix);
// Release parts of an already-reserved memory region [addr, addr + len) to
// get a new region that has "compound alignment." Return the start of the
......@@ -59,13 +61,19 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC {
const size_t suffix_size,
const size_t suffix_align);
protected:
// Create protection page at the beginning of the space.
void protect_noaccess_prefix(const size_t size);
public:
// Constructor
ReservedSpace(size_t size);
ReservedSpace(size_t size, size_t alignment, bool large,
char* requested_address = NULL);
char* requested_address = NULL,
const size_t noaccess_prefix = 0);
ReservedSpace(const size_t prefix_size, const size_t prefix_align,
const size_t suffix_size, const size_t suffix_align);
const size_t suffix_size, const size_t suffix_align,
const size_t noaccess_prefix);
// Accessors
char* base() const { return _base; }
......@@ -73,6 +81,8 @@ class ReservedSpace VALUE_OBJ_CLASS_SPEC {
size_t alignment() const { return _alignment; }
bool special() const { return _special; }
size_t noaccess_prefix() const { return _noaccess_prefix; }
bool is_reserved() const { return _base != NULL; }
void release();
......@@ -104,6 +114,16 @@ ReservedSpace ReservedSpace::last_part(size_t partition_size)
return last_part(partition_size, alignment());
}
// Class encapsulating behavior specific of memory space reserved for Java heap
class ReservedHeapSpace : public ReservedSpace {
public:
// Constructor
ReservedHeapSpace(size_t size, size_t forced_base_alignment,
bool large, char* requested_address);
ReservedHeapSpace(const size_t prefix_size, const size_t prefix_align,
const size_t suffix_size, const size_t suffix_align);
};
// VirtualSpace is data structure for committing a previously reserved address range in smaller chunks.
class VirtualSpace VALUE_OBJ_CLASS_SPEC {
......
......@@ -5,3 +5,4 @@ fb57027902e04ecafceae31a605e69b436c23d57 jdk7-b26
02e4c5348592a8d7fc2cba28bc5f8e35c0e17277 jdk7-b28
e21f4266466cd1306b176aaa08b2cd8337a9be3d jdk7-b29
b6d6877c1155621a175dccd12dc14c54f938fb8b jdk7-b30
b7474b739d13bacd9972f88ac91f6350b7b0be12 jdk7-b31
......@@ -97,9 +97,6 @@ ifeq ($(PLATFORM), windows)
/D "J2SE_FTYPE=0x1L"
RES = $(OBJDIR)/$(PGRM).res
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
else
LDOUTPUT = -o #Have a space
LDDFLAGS += -lc
......
......@@ -55,9 +55,6 @@ LIBRARY = jaas_nt
EXTRA_LIBS += netapi32.lib user32.lib mpr.lib
endif #fdlibm
# code generates errors when compiled at warning level 3 and warnings are fatal
ifeq ($(ARCH_DATA_MODEL), 64)
COMPILER_WARNINGS_FATAL=false
endif # ARCH_DATA_MODEL
endif # windows
ifeq ($(PLATFORM), solaris)
......
......@@ -149,10 +149,9 @@ endif # ARCH
PIC_CODE_LARGE = -fPIC
PIC_CODE_SMALL = -fpic
GLOBAL_KPIC = $(PIC_CODE_LARGE)
CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS)
ifeq ($(ARCH), amd64)
CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS) -pipe
else
CFLAGS_COMMON += $(GLOBAL_KPIC) $(GCC_WARNINGS)
CFLAGS_COMMON += -pipe
endif
# Linux 64bit machines use Dwarf2, which can be HUGE, have fastdebug use -g1
......
......@@ -40,6 +40,9 @@
# LDLIBS (set $(EXTRA_LIBS) instead)
# LDLIBS_COMMON (set $(EXTRA_LIBS) instead)
# LINTFLAGS (set $(OTHER_LINTFLAGS) instead)
#
# Note: CPPFLAGS are used in C and C++ compiles.
#
# Get shared JDK settings
include $(JDK_MAKE_SHARED_DIR)/Defs.gmk
......@@ -112,6 +115,10 @@ endif
# Required with many of the source files.
# -mt Assume multi-threaded (important)
#
# The more unusual options to the Sun C compiler:
# +w Print more warnings
# +w2 Maximum warnings
#
#
# Debug flag for C and C++ compiler
......@@ -140,15 +147,34 @@ ifeq ($(FASTDEBUG), true)
CXXFLAGS_DEBUG_OPTION = -g0 $(CC_FASTDEBUG_OPT)
endif
CFLAGS_COMMON = -v -mt -L$(OBJDIR) -xc99=%none
CFLAGS_COMMON = -L$(OBJDIR)
# Do not allow C99 language features like declarations in code etc.
CFLAGS_COMMON += -xc99=%none
# Allow C++ comments in C code
CFLAGS_COMMON += -xCC
CFLAGS_COMMON += -errshort=tags
# Show error message tags on errors
CFLAGS_COMMON += -errshort=tags
CXXFLAGS_COMMON += -errtags=yes
# Optimization flags
CFLAGS_OPT = $(POPT)
# Debug version flags
CFLAGS_DBG = $(CFLAGS_DEBUG_OPTION)
CFLAGS_COMMON += -Xa $(CFLAGS_REQUIRED)
# Required C compiler flags
CFLAGS_COMMON += -Xa $(CFLAGS_REQUIRED)
# Maximum warnings all the time
CXXFLAGS_COMMON += +w
CFLAGS_COMMON += -v
# Assume MT behavior all the time (important)
CXXFLAGS_COMMON = -mt
CXXFLAGS_COMMON += -mt
CFLAGS_COMMON += -mt
# Assume no C++ exceptions are used
CXXFLAGS_COMMON += -features=no%except -DCC_NOEX
......@@ -237,8 +263,8 @@ LINTFLAGS_COMMON += $(LINT_XARCH_OPTION)
# OTHER_CFLAGS += -DPERTURBALOT
#
CPPFLAGS_COMMON = -D$(ARCH_FAMILY) -D__solaris__ -D_REENTRANT
CPPFLAGS_OPT =
CPPFLAGS_COMMON = -D__solaris__ -D$(ARCH_FAMILY)
CPPFLAGS_OPT = -DNDEBUG
CPPFLAGS_DBG = -DDEBUG
ifeq ($(ARCH_FAMILY), i586)
......
......@@ -283,7 +283,7 @@ CPPFLAGS_COMMON = -DWIN32 -DIAL -D_LITTLE_ENDIAN
ifeq ($(ARCH), amd64)
CPPFLAGS_COMMON += -D_AMD64_ -Damd64
else
CPPFLAGS_COMMON += -DWIN32 -D_X86_ -Dx86
CPPFLAGS_COMMON += -D_X86_ -Dx86
endif
CPPFLAGS_COMMON += -DWIN32_LEAN_AND_MEAN
......@@ -292,17 +292,24 @@ CPPFLAGS_COMMON += -DWIN32_LEAN_AND_MEAN
#
CFLAGS_COMMON += -Fd$(OBJDIR)/$(basename $(@F)).pdb -Fm$(OBJDIR)/$(basename $(@F)).map
#
# Use -wdNNNN to disable warning NNNN.
# C4800 is a warning about bool performance casts (can't make go away)
#
COMPILER_WARNINGS_TO_IGNORE = 4800
CFLAGS_COMMON += $(COMPILER_WARNINGS_TO_IGNORE:%=-wd%)
#
# Add warnings and extra on 64bit issues
#
ifeq ($(ARCH_DATA_MODEL), 64)
CFLAGS_COMMON += -Wp64
endif
CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL)
#
# Treat compiler warnings as errors, if requested
#
CFLAGS_COMMON += -W$(COMPILER_WARNING_LEVEL)
ifeq ($(COMPILER_WARNINGS_FATAL),true)
CFLAGS_COMMON += -WX
endif
......@@ -352,17 +359,9 @@ else
# BUILD_WIN_SA=1
# on the make command.
ifdef BUILD_WIN_SA
ifeq ($(ARCH), amd64)
INCLUDE_SA = true
else
INCLUDE_SA = true
endif
INCLUDE_SA = true
else
ifeq ($(ARCH), amd64)
INCLUDE_SA = false
else
INCLUDE_SA = false
endif
INCLUDE_SA = false
endif
endif
......@@ -404,7 +403,6 @@ ifdef JDK_UPDATE_VERSION
else
JDK_UPDATE_VER := 0
endif
JDK_VER = $(JDK_MINOR_VERSION),$(JDK_MICRO_VERSION),$(JDK_UPDATE_VER),$(COOKED_BUILD_NUMBER)
RC_FLAGS = /l 0x409 /r
......@@ -414,15 +412,23 @@ else
RC_FLAGS += $(MS_RC_DEBUG_OPTION)
endif
ifndef COPYRIGHT_YEAR
COPYRIGHT_YEAR = 2007
endif
# Values for the RC variables defined in RC_FLAGS
JDK_RC_BUILD_ID = $(FULL_VERSION)
JDK_RC_COMPANY = $(COMPANY_NAME)
JDK_RC_COMPONENT = $(PRODUCT_NAME) $(JDK_RC_PLATFORM_NAME) binary
JDK_RC_VER = \
$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER)
JDK_RC_COPYRIGHT = Copyright \xA9 $(COPYRIGHT_YEAR)
JDK_RC_NAME = \
$(PRODUCT_NAME) $(JDK_RC_PLATFORM_NAME) $(JDK_MINOR_VERSION) $(JDK_UPDATE_META_TAG)
JDK_RC_FVER = \
$(JDK_MINOR_VERSION),$(JDK_MICRO_VERSION),$(JDK_UPDATE_VER),$(COOKED_BUILD_NUMBER)
# J2SE name required here
RC_FLAGS += -d "J2SE_BUILD_ID=$(FULL_VERSION)" \
-d "J2SE_COMPANY=$(COMPANY_NAME)" \
-d "J2SE_COMPONENT=$(PRODUCT_NAME) Platform SE binary" \
-d "J2SE_VER=$(JDK_MINOR_VERSION).$(JDK_MICRO_VERSION).$(JDK_UPDATE_VER).$(COOKED_BUILD_NUMBER)" \
-d "J2SE_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \
-d "J2SE_NAME=$(PRODUCT_NAME) Platform SE $(JDK_MINOR_VERSION) $(JDK_UPDATE_META_TAG)" \
-d "J2SE_FVER=$(JDK_VER)"
RC_FLAGS += -d "J2SE_BUILD_ID=$(JDK_RC_BUILD_ID)" \
-d "J2SE_COMPANY=$(JDK_RC_COMPANY)" \
-d "J2SE_COMPONENT=$(JDK_RC_COMPONENT)" \
-d "J2SE_VER=$(JDK_RC_VER)" \
-d "J2SE_COPYRIGHT=$(JDK_RC_COPYRIGHT)" \
-d "J2SE_NAME=$(JDK_RC_NAME)" \
-d "J2SE_FVER=$(JDK_RC_FVER)"
......@@ -703,7 +703,7 @@ endif
ifdef ALT_COPYRIGHT_YEAR
COPYRIGHT_YEAR = $(ALT_COPYRIGHT_YEAR)
else
COPYRIGHT_YEAR = $(shell $(DATE) '+%Y')
COPYRIGHT_YEAR := $(shell $(DATE) '+%Y')
endif
# Install of imported file (JDK_IMPORT_PATH, or some other external location)
......
......@@ -73,23 +73,18 @@ ifeq ($(PLATFORM), linux)
REQUIRED_CC_VER = 4.0
REQUIRED_GCC_VER = 4.0.*
else
ifeq ($(ARCH_DATA_MODEL), 32)
# i586
REQUIRED_CC_VER = 3.2
REQUIRED_GCC_VER = 3.2.1*
REQUIRED_GCC_VER_INT = 3.2.1-7a
else
ifeq ($(ARCH), amd64)
# amd64
REQUIRED_CC_VER = 3.2
REQUIRED_GCC_VER = 3.2.*
endif
ifeq ($(ARCH), ia64)
# ia64
REQUIRED_CC_VER = 3.2
REQUIRED_GCC_VER = 2.9[56789].*
endif
endif
ifeq ($(ARCH_DATA_MODEL), 32)
REQUIRED_GCC_VER = 3.2.1*
REQUIRED_GCC_VER_INT = 3.2.1-7a
else
ifeq ($(ARCH), amd64)
REQUIRED_GCC_VER = 3.2.*
endif
ifeq ($(ARCH), ia64)
REQUIRED_GCC_VER = 2.9[56789].*
endif
endif
endif
# Option used to create a shared library
SHARED_LIBRARY_FLAG = -shared -mimpure-text
......
......@@ -107,7 +107,10 @@ JAVACFLAGS =
ifeq ($(DEBUG_CLASSFILES),true)
JAVACFLAGS += -g
endif
ifeq ($(COMPILER_WARNINGS_FATAL), true)
ifeq ($(JAVAC_MAX_WARNINGS), true)
JAVACFLAGS += -Xlint:all
endif
ifeq ($(JAVAC_WARNINGS_FATAL), true)
JAVACFLAGS += -Werror
endif
......@@ -180,7 +183,10 @@ endif
# The javac options supplied to the boot javac is limited. This compiler
# should only be used to build the 'make/tools' sources, which are not
# class files that end up in the classes directory.
ifeq ($(COMPILER_WARNINGS_FATAL), true)
ifeq ($(JAVAC_MAX_WARNINGS), true)
BOOT_JAVACFLAGS += -Xlint:all
endif
ifeq ($(JAVAC_WARNINGS_FATAL), true)
BOOT_JAVACFLAGS += -Werror
endif
BOOT_JAVACFLAGS += -encoding ascii
......
......@@ -188,16 +188,18 @@ ifndef MILESTONE
endif
# Default names
LAUNCHER_NAME = java
PRODUCT_NAME = Java(TM)
PRODUCT_SUFFIX = SE Runtime Environment
COMPANY_NAME = Sun Microsystems, Inc.
ifdef OPENJDK
LAUNCHER_NAME = openjdk
PRODUCT_NAME = OpenJDK
PRODUCT_SUFFIX = Runtime Environment
COMPANY_NAME =
JDK_RC_PLATFORM_NAME = Platform
COMPANY_NAME = N/A
else
LAUNCHER_NAME = java
PRODUCT_NAME = Java(TM)
PRODUCT_SUFFIX = SE Runtime Environment
JDK_RC_PLATFORM_NAME = Platform SE
COMPANY_NAME = Sun Microsystems, Inc.
endif
RUNTIME_NAME = $(PRODUCT_NAME) $(PRODUCT_SUFFIX)
......
......@@ -373,35 +373,41 @@ ifeq ($(PLATFORM), windows)
REQUIRED_DXSDK_VER = 0x0700
OS_VENDOR = Microsoft
# How much RAM does this machine have:
ifeq ($(USING_CYGWIN),true)
# CYGWIN has the 'free' utility
_MB_OF_MEMORY := \
$(shell free -m | grep Mem: | awk '{print $$2;}' )
else
# Windows 2000 has the mem utility, but two memory areas
# extended memory is what is beyond 1024M
_B_OF_EXT_MEMORY := \
$(shell mem 2> $(DEV_NULL) | grep 'total contiguous extended memory' | awk '{print $$1;}')
ifeq ($(_B_OF_EXT_MEMORY),)
_B_OF_MEMORY := \
$(shell mem 2> $(DEV_NULL) | grep 'total conventional memory' | awk '{print $$1;}')
ifeq ($(JDK_HAS_MEM_INFO),)
ifeq ($(USING_CYGWIN),true)
# CYGWIN has the 'free' utility
_MB_OF_MEMORY := \
$(shell free -m | grep Mem: | awk '{print $$2;}' )
else
_B_OF_MEMORY := \
$(shell expr 1048576 '+' $(_B_OF_EXT_MEMORY) 2> $(DEV_NULL))
# Windows 2000 has the mem utility, but two memory areas
# extended memory is what is beyond 1024M
_B_OF_EXT_MEMORY := \
$(shell mem 2> $(DEV_NULL) | \
grep 'total contiguous extended memory' | awk '{print $$1;}')
ifeq ($(_B_OF_EXT_MEMORY),)
_B_OF_MEMORY := \
$(shell mem 2> $(DEV_NULL) | \
grep 'total conventional memory' | awk '{print $$1;}')
else
_B_OF_MEMORY := \
$(shell expr 1048576 '+' $(_B_OF_EXT_MEMORY) 2> $(DEV_NULL))
endif
ifeq ($(_B_OF_MEMORY),)
# Windows 2003 has the systeminfo utility use it if mem doesn't work
_MB_OF_MEMORY := \
$(shell systeminfo 2> $(DEV_NULL) | \
grep 'Total Physical Memory:' | \
awk '{print $$4;}' | sed -e 's@,@@')
else
_MB_OF_MEMORY := $(shell expr $(_B_OF_MEMORY) '/' 1024 2> $(DEV_NULL))
endif
endif
ifeq ($(_B_OF_MEMORY),)
# Windows 2003 has the systeminfo utility use it if mem doesn't work
_MB_OF_MEMORY := \
$(shell systeminfo 2> $(DEV_NULL) | grep 'Total Physical Memory:' | awk '{print $$4;}' | sed -e 's@,@@')
ifeq ($(shell expr $(_MB_OF_MEMORY) '+' 0 2> $(DEV_NULL)), $(_MB_OF_MEMORY))
MB_OF_MEMORY := $(_MB_OF_MEMORY)
else
_MB_OF_MEMORY := $(shell expr $(_B_OF_MEMORY) '/' 1024 2> $(DEV_NULL))
MB_OF_MEMORY := 512
endif
endif
ifeq ($(shell expr $(_MB_OF_MEMORY) '+' 0 2> $(DEV_NULL)), $(_MB_OF_MEMORY))
MB_OF_MEMORY := $(_MB_OF_MEMORY)
else
MB_OF_MEMORY := 512
endif
endif
REQUIRED_ZIP_VER = 2.2
......@@ -446,30 +452,38 @@ endif
# system swapping during the build.
# If we don't know, assume 512. Subtract 128 from MB for VM MAX.
# Don't set VM max over 1024-128=896.
ifneq ($(MB_OF_MEMORY),)
LOW_MEMORY_MACHINE := $(shell \
if [ $(MB_OF_MEMORY) -le 512 ] ; then \
echo "true"; \
else \
echo "false"; \
fi)
MAX_VM_MEMORY := $(shell \
if [ $(MB_OF_MEMORY) -le 1024 ] ; then \
expr $(MB_OF_MEMORY) '-' 128 2> $(DEV_NULL) ; \
else \
echo "896"; \
fi)
MIN_VM_MEMORY := $(shell \
if [ $(MAX_VM_MEMORY) -le 128 ] ; then \
expr $(MAX_VM_MEMORY) '-' 8 2> $(DEV_NULL) ; \
else \
echo "128"; \
fi)
else
MB_OF_MEMORY := unknown
LOW_MEMORY_MACHINE := true
MAX_VM_MEMORY := 384
MIN_VM_MEMORY := 128
ifeq ($(JDK_HAS_MEM_INFO),)
JDK_HAS_MEM_INFO=true
export JDK_HAS_MEM_INFO
ifneq ($(MB_OF_MEMORY),)
LOW_MEMORY_MACHINE := $(shell \
if [ $(MB_OF_MEMORY) -le 512 ] ; then \
echo "true"; \
else \
echo "false"; \
fi)
MAX_VM_MEMORY := $(shell \
if [ $(MB_OF_MEMORY) -le 1024 ] ; then \
expr $(MB_OF_MEMORY) '-' 128 2> $(DEV_NULL) ; \
else \
echo "896"; \
fi)
MIN_VM_MEMORY := $(shell \
if [ $(MAX_VM_MEMORY) -le 128 ] ; then \
expr $(MAX_VM_MEMORY) '-' 8 2> $(DEV_NULL) ; \
else \
echo "128"; \
fi)
else
MB_OF_MEMORY := unknown
LOW_MEMORY_MACHINE := true
MAX_VM_MEMORY := 384
MIN_VM_MEMORY := 128
endif
export MB_OF_MEMORY
export LOW_MEMORY_MACHINE
export MAX_VM_MEMORY
export MIN_VM_MEMORY
endif
# If blanks in the username, use the first 4 words and pack them together
......
......@@ -46,8 +46,6 @@ ifeq ($(PLATFORM),windows)
_OPT = $(CC_NO_OPT)
OTHER_CFLAGS =
CPPFLAGS_DBG += -DLOGGING
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
#
......
......@@ -37,8 +37,6 @@ include $(BUILDDIR)/common/Defs.gmk
# windows compiler flags
ifeq ($(PLATFORM),windows)
CPPFLAGS_DBG += -DLOGGING
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
FILES_c = \
......
......@@ -37,8 +37,6 @@ include $(BUILDDIR)/common/Defs.gmk
# windows compiler flags
ifeq ($(PLATFORM),windows)
OTHER_CFLAGS =
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
# build directly into BINDIR...
LIB_LOCATION = $(BINDIR)
# Exported functions
......
......@@ -47,11 +47,6 @@ FILES_c = java_crw_demo.c
OTHER_INCLUDES = -I$(SRCDIR)
#
# This removes all asserts in the optimized version
#
CPPFLAGS_OPT += -DNDEBUG
#
# Library to compile.
#
......
......@@ -91,11 +91,6 @@ endif
#
INIT += $(LIBDIR)/jvm.hprof.txt
#
# This removes all asserts in the optimized version
#
CPPFLAGS_OPT += -DNDEBUG
#
# This puts logging code in
#
......
......@@ -115,9 +115,6 @@ ifeq ($(PLATFORM), windows)
-export:JLI_ManifestIterate \
-export:JLI_SetTraceLauncher
# Files from zlib built here do not compile with warning level 3
# if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
OTHER_INCLUDES += -I$(LAUNCHER_SHARE_SRC)
......
......@@ -94,8 +94,6 @@ include $(BUILDDIR)/common/Library.gmk
ifeq ($(PLATFORM), windows)
OTHER_LDLIBS = ws2_32.lib $(JVMLIB)
# Will not compile at warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
else
OTHER_LDLIBS = $(LIBSOCKET) -lnsl -ldl $(JVMLIB)
endif
......
......@@ -134,7 +134,6 @@ ifeq ($(PLATFORM),windows)
$(OBJDIR)/../../../java.lang/java/$(OBJDIRNAME)/FileDescriptor_md.obj
endif
ifeq ($(PLATFORM), linux)
COMPILER_WARNINGS_FATAL=true
OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -ljava -lnet -lpthread -ldl
endif
ifeq ($(PLATFORM), solaris)
......
......@@ -52,11 +52,6 @@ FILES_c = \
OTHER_INCLUDES = -I$(SRCDIR) -I$(PSRCDIR)
#
# This removes all asserts in the optimized version
#
CPPFLAGS_OPT += -DNDEBUG
#
# Library to compile.
#
......
......@@ -43,8 +43,6 @@ ifeq ($(PLATFORM), windows)
#
JAVALIB =
EXTRA_LIBS =
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
#
......
......@@ -49,9 +49,6 @@ FILES_export = \
ifneq ($(PLATFORM), windows)
OTHER_CFLAGS += -DUSE_MMAP
else
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
#
......
......@@ -52,11 +52,6 @@ ifneq ($(PLATFORM), windows)
OTHER_LDLIBS += -ldl
endif # PLATFORM
#
# This turns off all assert() checking in the optimized library
#
CPPFLAGS_OPT += -DNDEBUG
#
# This controls the ability to do logging in the library.
#
......
......@@ -36,13 +36,6 @@ FILES_m = mapfile-vers
include $(BUILDDIR)/common/Defs.gmk
# 64-bit windows does not build at -W3 if warnings are fatal
ifeq ($(PLATFORM), windows)
ifeq ($(ARCH_DATA_MODEL), 64)
COMPILER_WARNINGS_FATAL=false
endif
endif
FILES_c = \
SharedMemoryTransport.c \
SharedMemoryConnection.c \
......
......@@ -36,11 +36,6 @@ FILES_m = mapfile-vers
include $(BUILDDIR)/common/Defs.gmk
ifeq ($(PLATFORM), windows)
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
ifeq ($(PLATFORM), linux)
OTHER_LDLIBS += -lnsl $(LIBSOCKET) -lpthread
endif
......
......@@ -47,8 +47,6 @@ FILES_export = \
ifeq ($(PLATFORM), windows)
# Override the default version info with our own resource file (see 5043594)
VERSIONINFO_RESOURCE = $(CLOSED_SRC)/share/native/sun/java2d/cmm/kcms/cmm.rc
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
# Rules
......
......@@ -77,9 +77,6 @@ FILES_export = \
ifeq ($(PLATFORM), windows)
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
LDLIBS += user32.lib gdi32.lib $(OBJDIR)/../../../sun.awt/awt/$(OBJDIRNAME)/awt.lib
OTHER_CFLAGS += -DCC_NOEX
......
......@@ -64,9 +64,6 @@ FILES_export = \
ifeq ($(PLATFORM), windows)
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
# t2k imports several shared methods from fontmanager.dll
LDLIBS += user32.lib $(OBJDIR)/../../../sun.font/fontmanager/$(OBJDIRNAME)/fontmanager.lib
......
......@@ -69,11 +69,6 @@ ifneq ($(PLATFORM), windows)
INIT += $(ODBC_FAKE_LIBRARIES)
endif
ifeq ($(PLATFORM),windows)
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif
#
# Rules
#
......
......@@ -73,10 +73,5 @@ include $(BUILDDIR)/common/Library.gmk
#
vpath %.c $(SHARE_SRC)/native/$(PKGDIR)/image/jpeg
ifeq ($(PLATFORM), windows)
# Files built here do not compile with warning level 3 if warnings are fatal
COMPILER_WARNINGS_FATAL=false
endif # PLATFORM
CLASSES.export += java.io.InputStream
......@@ -492,14 +492,17 @@ eventFilterRestricted_passesFilter(JNIEnv *env,
char *sourceName = 0;
jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetSourceFileName)
(gdata->jvmti, clazz, &sourceName);
if (error == JVMTI_ERROR_NONE) {
if (sourceName == 0 || !patternStringMatch(sourceName, desiredNamePattern)) {
/* We have no match */
jvmtiDeallocate(sourceName);
return JNI_FALSE;
}
if (error == JVMTI_ERROR_NONE &&
sourceName != 0 &&
patternStringMatch(sourceName, desiredNamePattern)) {
// got a hit - report the event
jvmtiDeallocate(sourceName);
break;
}
// We have no match, we have no source file name,
// or we got a JVM TI error. Don't report the event.
jvmtiDeallocate(sourceName);
return JNI_FALSE;
}
break;
}
......
......@@ -686,7 +686,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
final String msg =
"Cannot convert SortedSet with non-null comparator: " +
comparator;
throw new OpenDataException(msg);
throw openDataException(msg, new IllegalArgumentException(msg));
}
}
final Object[] openArray = (Object[])
......@@ -800,7 +800,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
final String msg =
"Cannot convert SortedMap with non-null comparator: " +
comparator;
throw new OpenDataException(msg);
throw openDataException(msg, new IllegalArgumentException(msg));
}
}
final TabularType tabularType = (TabularType) getOpenType();
......
......@@ -25,7 +25,7 @@
package com.sun.jmx.mbeanserver;
import javax.management.DynamicMBean;
import javax.management.DynamicWrapperMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
......@@ -35,17 +35,7 @@ import javax.management.ObjectName;
*
* @since 1.6
*/
public interface DynamicMBean2 extends DynamicMBean {
/**
* The resource corresponding to this MBean. This is the object whose
* class name should be reflected by the MBean's
* getMBeanInfo().getClassName() for example. For a "plain"
* DynamicMBean it will be "this". For an MBean that wraps another
* object, like javax.management.StandardMBean, it will be the wrapped
* object.
*/
public Object getResource();
public interface DynamicMBean2 extends DynamicWrapperMBean {
/**
* The name of this MBean's class, as used by permission checks.
* This is typically equal to getResource().getClass().getName().
......
......@@ -25,23 +25,39 @@
package com.sun.jmx.mbeanserver;
import com.sun.jmx.remote.util.EnvHelp;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.management.AttributeNotFoundException;
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.DescriptorFields;
import javax.management.DescriptorKey;
import javax.management.DynamicMBean;
import javax.management.ImmutableDescriptor;
import javax.management.MBean;
import javax.management.MBeanInfo;
import javax.management.MXBean;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.remote.util.EnvHelp;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
......@@ -133,8 +149,12 @@ public class Introspector {
}
}
public static void checkCompliance(Class mbeanClass)
throws NotCompliantMBeanException {
public static void checkCompliance(Class<?> mbeanClass)
throws NotCompliantMBeanException {
// Check that @Resource is used correctly (if it used).
MBeanInjector.validate(mbeanClass);
// Is DynamicMBean?
//
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
......@@ -157,21 +177,39 @@ public class Introspector {
} catch (NotCompliantMBeanException e) {
mxbeanException = e;
}
// Is @MBean or @MXBean class?
// In fact we find @MBean or @MXBean as a hacky variant of
// getStandardMBeanInterface or getMXBeanInterface. If we get here
// then nothing worked.
final String msg =
"MBean class " + mbeanClass.getName() + " does not implement " +
"DynamicMBean, neither follows the Standard MBean conventions (" +
mbeanException.toString() + ") nor the MXBean conventions (" +
mxbeanException.toString() + ")";
"DynamicMBean; does not follow the Standard MBean conventions (" +
mbeanException.toString() + "); does not follow the MXBean conventions (" +
mxbeanException.toString() + "); and does not have or inherit the @" +
MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() +
" annotation";
throw new NotCompliantMBeanException(msg);
}
/**
* <p>Make a DynamicMBean out of the existing MBean object. The object
* may already be a DynamicMBean, or it may be a Standard MBean or
* MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p>
* @param mbean the object to convert to a DynamicMBean.
* @param <T> a type parameter defined for implementation convenience
* (which would have to be removed if this method were part of the public
* API).
* @return the converted DynamicMBean.
* @throws NotCompliantMBeanException if {@code mbean} is not a compliant
* MBean object, including the case where it is null.
*/
public static <T> DynamicMBean makeDynamicMBean(T mbean)
throws NotCompliantMBeanException {
if (mbean == null)
throw new NotCompliantMBeanException("Null MBean object");
if (mbean instanceof DynamicMBean)
return (DynamicMBean) mbean;
final Class mbeanClass = mbean.getClass();
final Class<?> mbeanClass = mbean.getClass();
Class<? super T> c = null;
try {
c = Util.cast(getStandardMBeanInterface(mbeanClass));
......@@ -270,7 +308,7 @@ public class Introspector {
* Return <code>null</code> if the MBean is a DynamicMBean,
* or if no MBean interface is found.
*/
public static Class getMBeanInterface(Class baseClass) {
public static Class<?> getMBeanInterface(Class<?> baseClass) {
// Check if the given class implements the MBean interface
// or the Dynamic MBean interface
if (isDynamic(baseClass)) return null;
......@@ -291,10 +329,12 @@ public class Introspector {
* @throws NotCompliantMBeanException The specified class is
* not a JMX compliant Standard MBean.
*/
public static Class getStandardMBeanInterface(Class baseClass)
throws NotCompliantMBeanException {
Class current = baseClass;
Class mbeanInterface = null;
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
if (baseClass.isAnnotationPresent(MBean.class))
return baseClass;
Class<? super T> current = baseClass;
Class<? super T> mbeanInterface = null;
while (current != null) {
mbeanInterface =
findMBeanInterface(current, current.getName());
......@@ -321,8 +361,10 @@ public class Introspector {
* @throws NotCompliantMBeanException The specified class is
* not a JMX compliant MXBean.
*/
public static Class getMXBeanInterface(Class baseClass)
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
if (hasMXBeanAnnotation(baseClass))
return baseClass;
try {
return MXBeanSupport.findMXBeanInterface(baseClass);
} catch (Exception e) {
......@@ -345,19 +387,24 @@ public class Introspector {
* ------------------------------------------
*/
static boolean hasMXBeanAnnotation(Class<?> c) {
MXBean m = c.getAnnotation(MXBean.class);
return (m != null && m.value());
}
/**
* Try to find the MBean interface corresponding to the class aName
* - i.e. <i>aName</i>MBean, from within aClass and its superclasses.
**/
private static Class findMBeanInterface(Class aClass, String aName) {
Class current = aClass;
private static <T> Class<? super T> findMBeanInterface(
Class<T> aClass, String aName) {
Class<? super T> current = aClass;
while (current != null) {
final Class[] interfaces = current.getInterfaces();
final Class<?>[] interfaces = current.getInterfaces();
final int len = interfaces.length;
for (int i=0;i<len;i++) {
final Class inter =
implementsMBean(interfaces[i], aName);
Class<? super T> inter = Util.cast(interfaces[i]);
inter = implementsMBean(inter, aName);
if (inter != null) return inter;
}
current = current.getSuperclass();
......@@ -365,6 +412,48 @@ public class Introspector {
return null;
}
public static String descriptionForElement(AnnotatedElement elmt) {
if (elmt == null)
return null;
Description d = elmt.getAnnotation(Description.class);
if (d == null)
return null;
return d.value();
}
public static String descriptionForParameter(
Annotation[] parameterAnnotations) {
for (Annotation a : parameterAnnotations) {
if (a instanceof Description)
return ((Description) a).value();
}
return null;
}
public static String nameForParameter(
Annotation[] parameterAnnotations) {
for (Annotation a : parameterAnnotations) {
Class<? extends Annotation> ac = a.annotationType();
// You'd really have to go out of your way to have more than
// one @Name annotation, so we don't check for that.
if (ac.getSimpleName().equals("Name")) {
try {
Method value = ac.getMethod("value");
if (value.getReturnType() == String.class &&
value.getParameterTypes().length == 0) {
return (String) value.invoke(a);
}
} catch (Exception e) {
MBEANSERVER_LOGGER.log(
Level.WARNING,
"Unexpected exception getting @" + ac.getName(),
e);
}
}
}
return null;
}
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
if (elmt == null)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
......@@ -372,41 +461,18 @@ public class Introspector {
return descriptorForAnnotations(annots);
}
public static Descriptor descriptorForAnnotation(Annotation annot) {
return descriptorForAnnotations(new Annotation[] {annot});
}
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
if (annots.length == 0)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
Map<String, Object> descriptorMap = new HashMap<String, Object>();
for (Annotation a : annots) {
Class<? extends Annotation> c = a.annotationType();
Method[] elements = c.getMethods();
for (Method element : elements) {
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
if (key != null) {
String name = key.value();
Object value;
try {
value = element.invoke(a);
} catch (RuntimeException e) {
// we don't expect this - except for possibly
// security exceptions?
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
// anyway...
//
throw e;
} catch (Exception e) {
// we don't expect this
throw new UndeclaredThrowableException(e);
}
value = annotationToField(value);
Object oldValue = descriptorMap.put(name, value);
if (oldValue != null && !equals(oldValue, value)) {
final String msg =
"Inconsistent values for descriptor field " + name +
" from annotations: " + value + " :: " + oldValue;
throw new IllegalArgumentException(msg);
}
}
}
if (a instanceof DescriptorFields)
addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a);
addAnnotationFieldsToMap(descriptorMap, a);
}
if (descriptorMap.isEmpty())
......@@ -415,6 +481,62 @@ public class Introspector {
return new ImmutableDescriptor(descriptorMap);
}
private static void addDescriptorFieldsToMap(
Map<String, Object> descriptorMap, DescriptorFields df) {
for (String field : df.value()) {
int eq = field.indexOf('=');
if (eq < 0) {
throw new IllegalArgumentException(
"@DescriptorFields string must contain '=': " +
field);
}
String name = field.substring(0, eq);
String value = field.substring(eq + 1);
addToMap(descriptorMap, name, value);
}
}
private static void addAnnotationFieldsToMap(
Map<String, Object> descriptorMap, Annotation a) {
Class<? extends Annotation> c = a.annotationType();
Method[] elements = c.getMethods();
for (Method element : elements) {
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
if (key != null) {
String name = key.value();
Object value;
try {
value = element.invoke(a);
} catch (RuntimeException e) {
// we don't expect this - except for possibly
// security exceptions?
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
// anyway...
throw e;
} catch (Exception e) {
// we don't expect this
throw new UndeclaredThrowableException(e);
}
if (!key.omitIfDefault() ||
!equals(value, element.getDefaultValue())) {
value = annotationToField(value);
addToMap(descriptorMap, name, value);
}
}
}
}
private static void addToMap(
Map<String, Object> descriptorMap, String name, Object value) {
Object oldValue = descriptorMap.put(name, value);
if (oldValue != null && !equals(oldValue, value)) {
final String msg =
"Inconsistent values for descriptor field " + name +
" from annotations: " + value + " :: " + oldValue;
throw new IllegalArgumentException(msg);
}
}
/**
* Throws a NotCompliantMBeanException or a SecurityException.
* @param notCompliant the class which was under examination
......@@ -473,8 +595,13 @@ public class Introspector {
// The only other possibility is that the value is another
// annotation, or that the language has evolved since this code
// was written. We don't allow for either of those currently.
// If it is indeed another annotation, then x will be a proxy
// with an unhelpful name like $Proxy2. So we extract the
// proxy's interface to use that in the exception message.
if (Proxy.isProxyClass(c))
c = c.getInterfaces()[0]; // array "can't be empty"
throw new IllegalArgumentException("Illegal type for annotation " +
"element: " + x.getClass().getName());
"element using @DescriptorKey: " + c.getName());
}
// This must be consistent with the check for duplicate field values in
......@@ -490,15 +617,15 @@ public class Introspector {
* @param c The interface to be tested
* @param clName The name of the class implementing this interface
*/
private static Class implementsMBean(Class c, String clName) {
private static <T> Class<? super T> implementsMBean(Class<T> c, String clName) {
String clMBeanName = clName + "MBean";
if (c.getName().equals(clMBeanName)) {
return c;
}
Class[] interfaces = c.getInterfaces();
Class<?>[] interfaces = c.getInterfaces();
for (int i = 0;i < interfaces.length; i++) {
if (interfaces[i].getName().equals(clMBeanName))
return interfaces[i];
return Util.cast(interfaces[i]);
}
return null;
......
......@@ -33,6 +33,10 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.MBean;
import javax.management.MXBean;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
/**
......@@ -125,18 +129,26 @@ class MBeanAnalyzer<M> {
for (Method m : methods) {
final String name = m.getName();
final int nParams = m.getParameterTypes().length;
final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class);
final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class);
if (managedOp && managedAttr) {
throw new NotCompliantMBeanException("Method " + name +
" has both @ManagedOperation and @ManagedAttribute");
}
final M cm = introspector.mFrom(m);
String attrName = "";
if (name.startsWith("get"))
attrName = name.substring(3);
else if (name.startsWith("is")
&& m.getReturnType() == boolean.class)
attrName = name.substring(2);
if (!managedOp) {
if (name.startsWith("get"))
attrName = name.substring(3);
else if (name.startsWith("is")
&& m.getReturnType() == boolean.class)
attrName = name.substring(2);
}
if (attrName.length() != 0 && nParams == 0
&& m.getReturnType() != void.class) {
&& m.getReturnType() != void.class && !managedOp) {
// It's a getter
// Check we don't have both isX and getX
AttrMethods<M> am = attrMap.get(attrName);
......@@ -153,7 +165,7 @@ class MBeanAnalyzer<M> {
attrMap.put(attrName, am);
} else if (name.startsWith("set") && name.length() > 3
&& nParams == 1 &&
m.getReturnType() == void.class) {
m.getReturnType() == void.class && !managedOp) {
// It's a setter
attrName = name.substring(3);
AttrMethods<M> am = attrMap.get(attrName);
......@@ -166,6 +178,9 @@ class MBeanAnalyzer<M> {
}
am.setter = cm;
attrMap.put(attrName, am);
} else if (managedAttr) {
throw new NotCompliantMBeanException("Method " + name +
" has @ManagedAttribute but is not a valid getter or setter");
} else {
// It's an operation
List<M> cms = opMap.get(name);
......
/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.mbeanserver;
import java.lang.ref.WeakReference;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.WeakHashMap;
import javax.annotation.Resource;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import static com.sun.jmx.mbeanserver.Util.newMap;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.management.SendNotification;
public class MBeanInjector {
private static Class<?>[] injectedClasses = {
MBeanServer.class, ObjectName.class, SendNotification.class,
};
public static void inject(Object mbean, MBeanServer mbs, ObjectName name)
throws Exception {
ClassInjector injector = injectorForClass(mbean.getClass());
injector.inject(mbean, MBeanServer.class, mbs);
injector.inject(mbean, ObjectName.class, name);
}
public static boolean injectsSendNotification(Object mbean)
throws NotCompliantMBeanException {
ClassInjector injector = injectorForClass(mbean.getClass());
return injector.injects(SendNotification.class);
}
public static void injectSendNotification(Object mbean, SendNotification sn)
throws Exception {
ClassInjector injector = injectorForClass(mbean.getClass());
injector.inject(mbean, SendNotification.class, sn);
}
public static void validate(Class<?> c) throws NotCompliantMBeanException {
injectorForClass(c);
}
private static class ClassInjector {
private Map<Class<?>, List<Field>> fields;
private Map<Class<?>, List<Method>> methods;
ClassInjector(Class<?> c) throws NotCompliantMBeanException {
fields = newMap();
methods = newMap();
Class<?> sup = c.getSuperclass();
ClassInjector supInjector;
if (sup == null) {
supInjector = null;
} else {
supInjector = injectorForClass(sup);
fields.putAll(supInjector.fields);
methods.putAll(supInjector.methods);
}
addMembers(c);
eliminateOverriddenMethods();
// If we haven't added any new fields or methods to what we
// inherited, then we can share the parent's maps.
if (supInjector != null) {
if (fields.equals(supInjector.fields))
fields = supInjector.fields;
if (methods.equals(supInjector.methods))
methods = supInjector.methods;
}
}
boolean injects(Class<?> c) {
return (fields.get(c) != null || methods.get(c) != null);
}
<T> void inject(Object instance, Class<T> type, T resource)
throws Exception {
List<Field> fs = fields.get(type);
if (fs != null) {
for (Field f : fs)
f.set(instance, resource);
}
List<Method> ms = methods.get(type);
if (ms != null) {
for (Method m : ms) {
try {
m.invoke(instance, resource);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof Error)
throw (Error) cause;
else
throw (Exception) cause;
}
}
}
}
private void eliminateOverriddenMethods() {
/* Covariant overriding is unlikely, but it is possible that the
* parent has a @Resource method that we override with another
* @Resource method. We don't want to invoke both methods,
* because polymorphism means we would actually invoke the same
* method twice.
*/
for (Map.Entry<Class<?>, List<Method>> entry : methods.entrySet()) {
List<Method> list = entry.getValue();
list = MBeanAnalyzer.eliminateCovariantMethods(list);
entry.setValue(list);
}
}
/*
* Find Fields or Methods within the given Class that we can inject
* resource references into. Suppose we want to know if a Field can get
* a reference to an ObjectName. We'll accept fields like this:
*
* @Resource
* private transient ObjectName name;
*
* or like this:
*
* @Resource(type = ObjectName.class)
* private transient Object name;
*
* but not like this:
*
* @Resource
* private transient Object name;
*
* (Plain @Resource is equivalent to @Resource(type = Object.class).)
*
* We don't want to inject into everything that might possibly accept
* an ObjectName reference, because examples like the last one above
* could also accept an MBeanServer reference or any other sort of
* reference.
*
* So we accept a Field if it has a @Resource annotation and either
* (a) its type is ObjectName or a subclass and its @Resource type is
* compatible with ObjectName (e.g. it is Object); or
* (b) its type is compatible with ObjectName and its @Resource type
* is exactly ObjectName. Fields that meet these criteria will not
* meet the same criteria with respect to other types such as MBeanServer.
*
* The same logic applies mutatis mutandis to Methods such as this:
*
* @Resource
* private void setObjectName1(ObjectName name)
* @Resource(type = Object.class)
* private void setObjectName2(Object name)
*/
private void addMembers(final Class<?> c)
throws NotCompliantMBeanException {
AccessibleObject[][] memberArrays =
AccessController.doPrivileged(
new PrivilegedAction<AccessibleObject[][]>() {
public AccessibleObject[][] run() {
return new AccessibleObject[][] {
c.getDeclaredFields(), c.getDeclaredMethods()
};
}
});
for (AccessibleObject[] members : memberArrays) {
for (final AccessibleObject member : members) {
Resource res = member.getAnnotation(Resource.class);
if (res == null)
continue;
final Field field;
final Method method;
final Class<?> memberType;
final int modifiers;
if (member instanceof Field) {
field = (Field) member;
memberType = field.getType();
modifiers = field.getModifiers();
method = null;
} else {
field = null;
method = (Method) member;
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length != 1) {
throw new NotCompliantMBeanException(
"@Resource method must have exactly 1 " +
"parameter: " + method);
}
if (method.getReturnType() != void.class) {
throw new NotCompliantMBeanException(
"@Resource method must return void: " +
method);
}
memberType = paramTypes[0];
modifiers = method.getModifiers();
}
if (Modifier.isStatic(modifiers)) {
throw new NotCompliantMBeanException(
"@Resource method or field cannot be static: " +
member);
}
for (Class<?> injectedClass : injectedClasses) {
Class<?>[] types = {memberType, res.type()};
boolean accept = false;
for (int i = 0; i < 2; i++) {
if (types[i] == injectedClass &&
types[1 - i].isAssignableFrom(injectedClass)) {
accept = true;
break;
}
}
if (accept) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
member.setAccessible(true);
return null;
}
});
addToMap(fields, injectedClass, field);
addToMap(methods, injectedClass, method);
}
}
}
}
}
private static <K, V> void addToMap(Map<K, List<V>> map, K key, V value) {
if (value == null)
return;
List<V> list = map.get(key);
if (list == null)
list = Collections.singletonList(value);
else {
if (list.size() == 1)
list = new ArrayList<V>(list);
list.add(value);
}
map.put(key, list);
}
}
private static synchronized ClassInjector injectorForClass(Class<?> c)
throws NotCompliantMBeanException {
WeakReference<ClassInjector> wr = injectorMap.get(c);
ClassInjector ci = (wr == null) ? null : wr.get();
if (ci == null) {
ci = new ClassInjector(c);
injectorMap.put(c, new WeakReference<ClassInjector>(ci));
}
return ci;
}
private static Map<Class<?>, WeakReference<ClassInjector>> injectorMap =
new WeakHashMap<Class<?>, WeakReference<ClassInjector>>();
}
......@@ -36,20 +36,28 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.MBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MXBean;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationInfo;
import javax.management.NotificationInfos;
import javax.management.ReflectionException;
/**
......@@ -153,6 +161,25 @@ abstract class MBeanIntrospector<M> {
abstract MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
M getter, M setter) throws IntrospectionException;
final String getAttributeDescription(
String attributeName, String defaultDescription,
Method getter, Method setter) throws IntrospectionException {
String g = Introspector.descriptionForElement(getter);
String s = Introspector.descriptionForElement(setter);
if (g == null) {
if (s == null)
return defaultDescription;
else
return s;
} else if (s == null || g.equals(s)) {
return g;
} else {
throw new IntrospectionException(
"Inconsistent @Description on getter and setter for " +
"attribute " + attributeName);
}
}
/**
* Construct an MBeanOperationInfo for the given operation based on
* the M it was derived from.
......@@ -184,8 +211,12 @@ abstract class MBeanIntrospector<M> {
}
void checkCompliance(Class<?> mbeanType) throws NotCompliantMBeanException {
if (!mbeanType.isInterface()) {
throw new NotCompliantMBeanException("Not an interface: " +
if (!mbeanType.isInterface() &&
!mbeanType.isAnnotationPresent(MBean.class) &&
!Introspector.hasMXBeanAnnotation(mbeanType)) {
throw new NotCompliantMBeanException("Not an interface and " +
"does not have @" + MBean.class.getSimpleName() +
" or @" + MXBean.class.getSimpleName() + " annotation: " +
mbeanType.getName());
}
}
......@@ -194,7 +225,12 @@ abstract class MBeanIntrospector<M> {
* Get the methods to be analyzed to build the MBean interface.
*/
List<Method> getMethods(final Class<?> mbeanType) throws Exception {
return Arrays.asList(mbeanType.getMethods());
if (mbeanType.isInterface())
return Arrays.asList(mbeanType.getMethods());
final List<Method> methods = newList();
getAnnotatedMethods(mbeanType, methods);
return methods;
}
final PerInterface<M> getPerInterface(Class<?> mbeanInterface)
......@@ -232,8 +268,11 @@ abstract class MBeanIntrospector<M> {
MBeanAnalyzer<M> analyzer) throws IntrospectionException {
final MBeanInfoMaker maker = new MBeanInfoMaker();
analyzer.visit(maker);
final String description =
final String defaultDescription =
"Information on the management interface of the MBean";
String description = Introspector.descriptionForElement(mbeanInterface);
if (description == null)
description = defaultDescription;
return maker.makeMBeanInfo(mbeanInterface, description);
}
......@@ -407,7 +446,15 @@ abstract class MBeanIntrospector<M> {
throws NotCompliantMBeanException {
MBeanInfo mbi =
getClassMBeanInfo(resource.getClass(), perInterface);
MBeanNotificationInfo[] notifs = findNotifications(resource);
MBeanNotificationInfo[] notifs;
try {
notifs = findNotifications(resource);
} catch (RuntimeException e) {
NotCompliantMBeanException x =
new NotCompliantMBeanException(e.getMessage());
x.initCause(e);
throw x;
}
Descriptor d = getSpecificMBeanDescriptor();
boolean anyNotifs = (notifs != null && notifs.length > 0);
if (!anyNotifs && ImmutableDescriptor.EMPTY_DESCRIPTOR.equals(d))
......@@ -460,13 +507,43 @@ abstract class MBeanIntrospector<M> {
}
}
/*
* Add to "methods" every public method that has the @ManagedAttribute
* or @ManagedOperation annotation, in the given class or any of
* its superclasses or superinterfaces.
*
* We always add superclass or superinterface methods first, so that
* the stable sort used by eliminateCovariantMethods will put the
* method from the most-derived class last. This means that we will
* see the version of the @ManagedAttribute (or ...Operation) annotation
* from that method, which might have a different description or whatever.
*/
private static void getAnnotatedMethods(Class<?> c, List<Method> methods)
throws Exception {
Class<?> sup = c.getSuperclass();
if (sup != null)
getAnnotatedMethods(sup, methods);
Class<?>[] intfs = c.getInterfaces();
for (Class<?> intf : intfs)
getAnnotatedMethods(intf, methods);
for (Method m : c.getMethods()) {
// We are careful not to add m if it is inherited from a parent
// class or interface, because duplicate methods lead to nasty
// behaviour in eliminateCovariantMethods.
if (m.getDeclaringClass() == c &&
(m.isAnnotationPresent(ManagedAttribute.class) ||
m.isAnnotationPresent(ManagedOperation.class)))
methods.add(m);
}
}
static MBeanNotificationInfo[] findNotifications(Object moi) {
if (!(moi instanceof NotificationBroadcaster))
return null;
MBeanNotificationInfo[] mbn =
((NotificationBroadcaster) moi).getNotificationInfo();
if (mbn == null || mbn.length == 0)
return null;
return findNotificationsFromAnnotations(moi.getClass());
MBeanNotificationInfo[] result =
new MBeanNotificationInfo[mbn.length];
for (int i = 0; i < mbn.length; i++) {
......@@ -478,11 +555,81 @@ abstract class MBeanIntrospector<M> {
return result;
}
private static MBeanNotificationInfo[] findNotificationsFromAnnotations(
Class<?> mbeanClass) {
Class<?> c = getAnnotatedNotificationInfoClass(mbeanClass);
if (c == null)
return null;
NotificationInfo ni = c.getAnnotation(NotificationInfo.class);
NotificationInfos nis = c.getAnnotation(NotificationInfos.class);
List<NotificationInfo> list = newList();
if (ni != null)
list.add(ni);
if (nis != null)
list.addAll(Arrays.asList(nis.value()));
if (list.isEmpty())
return null;
List<MBeanNotificationInfo> mbnis = newList();
for (NotificationInfo x : list) {
// The Descriptor includes any fields explicitly specified by
// x.descriptorFields(), plus any fields from the contained
// @Description annotation.
Descriptor d = new ImmutableDescriptor(x.descriptorFields());
d = ImmutableDescriptor.union(
d, Introspector.descriptorForAnnotation(x.description()));
MBeanNotificationInfo mbni = new MBeanNotificationInfo(
x.types(), x.notificationClass().getName(),
x.description().value(), d);
mbnis.add(mbni);
}
return mbnis.toArray(new MBeanNotificationInfo[mbnis.size()]);
}
private static final Map<Class<?>, WeakReference<Class<?>>>
annotatedNotificationInfoClasses = newWeakHashMap();
private static Class<?> getAnnotatedNotificationInfoClass(Class<?> baseClass) {
synchronized (annotatedNotificationInfoClasses) {
WeakReference<Class<?>> wr =
annotatedNotificationInfoClasses.get(baseClass);
if (wr != null)
return wr.get();
Class<?> c = null;
if (baseClass.isAnnotationPresent(NotificationInfo.class) ||
baseClass.isAnnotationPresent(NotificationInfos.class)) {
c = baseClass;
} else {
Class<?>[] intfs = baseClass.getInterfaces();
for (Class<?> intf : intfs) {
Class<?> c1 = getAnnotatedNotificationInfoClass(intf);
if (c1 != null) {
if (c != null) {
throw new IllegalArgumentException(
"Class " + baseClass.getName() + " inherits " +
"@NotificationInfo(s) from both " +
c.getName() + " and " + c1.getName());
}
c = c1;
}
}
}
// Record the result of the search. If no @NotificationInfo(s)
// were found, c is null, and we store a WeakReference(null).
// This prevents us from having to search again and fail again.
annotatedNotificationInfoClasses.put(baseClass,
new WeakReference<Class<?>>(c));
return c;
}
}
private static MBeanConstructorInfo[] findConstructors(Class<?> c) {
Constructor[] cons = c.getConstructors();
MBeanConstructorInfo[] mbc = new MBeanConstructorInfo[cons.length];
for (int i = 0; i < cons.length; i++) {
final String descr = "Public constructor of the MBean";
String descr = "Public constructor of the MBean";
Description d = cons[i].getAnnotation(Description.class);
if (d != null)
descr = d.value();
mbc[i] = new MBeanConstructorInfo(descr, cons[i]);
}
return mbc;
......
......@@ -263,10 +263,14 @@ public abstract class MBeanSupport<M>
return resource.getClass().getName();
}
public final Object getResource() {
public final Object getWrappedObject() {
return resource;
}
public final ClassLoader getWrappedClassLoader() {
return resource.getClass().getClassLoader();
}
public final Class<?> getMBeanInterface() {
return perInterface.getMBeanInterface();
}
......
......@@ -35,6 +35,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.WeakHashMap;
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
......@@ -43,6 +44,7 @@ import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
......@@ -180,7 +182,10 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
final boolean isWritable = (setter != null);
final boolean isIs = isReadable && getName(getter).startsWith("is");
final String description = attributeName;
final String description = getAttributeDescription(
attributeName, attributeName,
getter == null ? null : getter.getMethod(),
setter == null ? null : setter.getMethod());
final OpenType<?> openType;
final Type originalType;
......@@ -229,13 +234,17 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
MBeanOperationInfo getMBeanOperationInfo(String operationName,
ConvertingMethod operation) {
final Method method = operation.getMethod();
final String description = operationName;
String description = operationName;
/* Ideally this would be an empty string, but
OMBOperationInfo constructor forbids that. Also, we
could consult an annotation to get a useful
description. */
OMBOperationInfo constructor forbids that. */
Description d = method.getAnnotation(Description.class);
if (d != null)
description = d.value();
final int impact = MBeanOperationInfo.UNKNOWN;
int impact = MBeanOperationInfo.UNKNOWN;
ManagedOperation annot = method.getAnnotation(ManagedOperation.class);
if (annot != null)
impact = annot.impact().getCode();
final OpenType<?> returnType = operation.getOpenReturnType();
final Type originalReturnType = operation.getGenericReturnType();
......@@ -247,8 +256,15 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
boolean openParameterTypes = true;
Annotation[][] annots = method.getParameterAnnotations();
for (int i = 0; i < paramTypes.length; i++) {
final String paramName = "p" + i;
final String paramDescription = paramName;
String paramName = Introspector.nameForParameter(annots[i]);
if (paramName == null)
paramName = "p" + i;
String paramDescription =
Introspector.descriptionForParameter(annots[i]);
if (paramDescription == null)
paramDescription = paramName;
final OpenType<?> openType = paramTypes[i];
final Type originalType = originalParamTypes[i];
Descriptor descriptor =
......
......@@ -161,7 +161,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
synchronized (lock) {
this.mxbeanLookup = MXBeanLookup.Plain.lookupFor(server);
this.mxbeanLookup.addReference(name, getResource());
this.mxbeanLookup.addReference(name, getWrappedObject());
this.objectName = name;
}
}
......@@ -170,7 +170,7 @@ public class MXBeanSupport extends MBeanSupport<ConvertingMethod> {
public void unregister() {
synchronized (lock) {
if (mxbeanLookup != null) {
if (mxbeanLookup.removeReference(objectName, getResource()))
if (mxbeanLookup.removeReference(objectName, getWrappedObject()))
objectName = null;
}
// XXX: need to revisit the whole register/unregister logic in
......
/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.mbeanserver;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.DynamicWrapperMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.ReflectionException;
/**
* Create wrappers for DynamicMBean that implement NotificationEmitter
* and SendNotification.
*/
public class NotifySupport
implements DynamicMBean2, NotificationEmitter, MBeanRegistration {
private final DynamicMBean mbean;
private final NotificationBroadcasterSupport nbs;
public static DynamicMBean wrap(
DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
return new NotifySupport(mbean, nbs);
}
private NotifySupport(DynamicMBean mbean, NotificationBroadcasterSupport nbs) {
this.mbean = mbean;
this.nbs = nbs;
}
public static NotificationBroadcasterSupport getNB(DynamicMBean mbean) {
if (mbean instanceof NotifySupport)
return ((NotifySupport) mbean).nbs;
else
return null;
}
public String getClassName() {
if (mbean instanceof DynamicMBean2)
return ((DynamicMBean2) mbean).getClassName();
Object w = mbean;
if (w instanceof DynamicWrapperMBean)
w = ((DynamicWrapperMBean) w).getWrappedObject();
return w.getClass().getName();
}
public void preRegister2(MBeanServer mbs, ObjectName name) throws Exception {
if (mbean instanceof DynamicMBean2)
((DynamicMBean2) mbean).preRegister2(mbs, name);
}
public void registerFailed() {
if (mbean instanceof DynamicMBean2)
((DynamicMBean2) mbean).registerFailed();
}
public Object getWrappedObject() {
if (mbean instanceof DynamicWrapperMBean)
return ((DynamicWrapperMBean) mbean).getWrappedObject();
else
return mbean;
}
public ClassLoader getWrappedClassLoader() {
if (mbean instanceof DynamicWrapperMBean)
return ((DynamicWrapperMBean) mbean).getWrappedClassLoader();
else
return mbean.getClass().getClassLoader();
}
public Object getAttribute(String attribute) throws AttributeNotFoundException,
MBeanException,
ReflectionException {
return mbean.getAttribute(attribute);
}
public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
mbean.setAttribute(attribute);
}
public AttributeList setAttributes(AttributeList attributes) {
return mbean.setAttributes(attributes);
}
public Object invoke(String actionName, Object[] params, String[] signature)
throws MBeanException, ReflectionException {
return mbean.invoke(actionName, params, signature);
}
public MBeanInfo getMBeanInfo() {
return mbean.getMBeanInfo();
}
public AttributeList getAttributes(String[] attributes) {
return mbean.getAttributes(attributes);
}
public void removeNotificationListener(NotificationListener listener,
NotificationFilter filter,
Object handback) throws ListenerNotFoundException {
nbs.removeNotificationListener(listener, filter, handback);
}
public void removeNotificationListener(NotificationListener listener)
throws ListenerNotFoundException {
nbs.removeNotificationListener(listener);
}
public MBeanNotificationInfo[] getNotificationInfo() {
return nbs.getNotificationInfo();
}
public void addNotificationListener(NotificationListener listener,
NotificationFilter filter,
Object handback) {
nbs.addNotificationListener(listener, filter, handback);
}
public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
if (mbr() != null)
return mbr().preRegister(server, name);
else
return name;
}
public void postRegister(Boolean registrationDone) {
if (mbr() != null)
mbr().postRegister(registrationDone);
}
public void preDeregister() throws Exception {
if (mbr() != null)
mbr().preDeregister();
}
public void postDeregister() {
if (mbr() != null)
mbr().postDeregister();
}
private MBeanRegistration mbr() {
if (mbean instanceof MBeanRegistration)
return (MBeanRegistration) mbean;
else
return null;
}
}
......@@ -29,6 +29,7 @@ import com.sun.jmx.defaults.ServiceName;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
......@@ -39,7 +40,6 @@ import java.util.Set;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.RuntimeOperationsException;
......@@ -52,6 +52,27 @@ import javax.management.RuntimeOperationsException;
*/
public class Repository {
/**
* An interface that allows the caller to get some control
* over the registration.
* @see #addMBean
* @see #remove
*/
public interface RegistrationContext {
/**
* Called by {@link #addMBean}.
* Can throw a RuntimeOperationsException to cancel the
* registration.
*/
public void registering();
/**
* Called by {@link #remove}.
* Any exception thrown by this method will be ignored.
*/
public void unregistered();
}
// Private fields -------------------------------------------->
/**
......@@ -115,7 +136,6 @@ public class Repository {
/**
* Builds a new ObjectNamePattern object from an ObjectName pattern
* constituents.
* @param domain pattern.getDomain().
* @param propertyListPattern pattern.isPropertyListPattern().
* @param propertyValuePattern pattern.isPropertyValuePattern().
* @param canonicalProps pattern.getCanonicalKeyPropertyListString().
......@@ -216,16 +236,6 @@ public class Repository {
}
}
private void addNewDomMoi(final DynamicMBean object, final String dom,
final ObjectName name) {
final Map<String,NamedObject> moiTb =
new HashMap<String,NamedObject>();
moiTb.put(name.getCanonicalKeyPropertyListString(),
new NamedObject(name, object));
domainTb.put(dom, moiTb);
nbElements++;
}
/** Match a string against a shell-style pattern. The only pattern
characters recognised are <code>?</code>, standing for any one
character, and <code>*</code>, standing for any string of
......@@ -306,6 +316,50 @@ public class Repository {
}
}
private void addNewDomMoi(final DynamicMBean object,
final String dom,
final ObjectName name,
final RegistrationContext context) {
final Map<String,NamedObject> moiTb =
new HashMap<String,NamedObject>();
final String key = name.getCanonicalKeyPropertyListString();
addMoiToTb(object,name,key,moiTb,context);
domainTb.put(dom, moiTb);
nbElements++;
}
private void registering(RegistrationContext context) {
if (context == null) return;
try {
context.registering();
} catch (RuntimeOperationsException x) {
throw x;
} catch (RuntimeException x) {
throw new RuntimeOperationsException(x);
}
}
private void unregistering(RegistrationContext context, ObjectName name) {
if (context == null) return;
try {
context.unregistered();
} catch (Exception x) {
// shouldn't come here...
MBEANSERVER_LOGGER.log(Level.FINE,
"Unexpected exception while unregistering "+name,
x);
}
}
private void addMoiToTb(final DynamicMBean object,
final ObjectName name,
final String key,
final Map<String,NamedObject> moiTb,
final RegistrationContext context) {
registering(context);
moiTb.put(key,new NamedObject(name, object));
}
/**
* Retrieves the named object contained in repository
* from the given objectname.
......@@ -355,12 +409,12 @@ public class Repository {
domainTb = new HashMap<String,Map<String,NamedObject>>(5);
if (domain != null && domain.length() != 0)
this.domain = domain;
this.domain = domain.intern(); // we use == domain later on...
else
this.domain = ServiceName.DOMAIN;
// Creates an new hastable for the default domain
domainTb.put(this.domain.intern(), new HashMap<String,NamedObject>());
// Creates a new hashtable for the default domain
domainTb.put(this.domain, new HashMap<String,NamedObject>());
}
/**
......@@ -395,10 +449,21 @@ public class Repository {
/**
* Stores an MBean associated with its object name in the repository.
*
* @param object MBean to be stored in the repository.
* @param name MBean object name.
* @param object MBean to be stored in the repository.
* @param name MBean object name.
* @param context A registration context. If non null, the repository
* will call {@link RegistrationContext#registering()
* context.registering()} from within the repository
* lock, when it has determined that the {@code object}
* can be stored in the repository with that {@code name}.
* If {@link RegistrationContext#registering()
* context.registering()} throws an exception, the
* operation is abandonned, the MBean is not added to the
* repository, and a {@link RuntimeOperationsException}
* is thrown.
*/
public void addMBean(final DynamicMBean object, ObjectName name)
public void addMBean(final DynamicMBean object, ObjectName name,
final RegistrationContext context)
throws InstanceAlreadyExistsException {
if (MBEANSERVER_LOGGER.isLoggable(Level.FINER)) {
......@@ -431,7 +496,7 @@ public class Repository {
lock.writeLock().lock();
try {
// Domain cannot be JMImplementation if entry does not exists
// Domain cannot be JMImplementation if entry does not exist
if ( !to_default_domain &&
dom.equals("JMImplementation") &&
domainTb.containsKey("JMImplementation")) {
......@@ -440,21 +505,21 @@ public class Repository {
"Repository: domain name cannot be JMImplementation"));
}
// If domain not already exists, add it to the hash table
// If domain does not already exist, add it to the hash table
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (moiTb == null) {
addNewDomMoi(object, dom, name);
addNewDomMoi(object, dom, name, context);
return;
}
// Add instance if not already present
String cstr = name.getCanonicalKeyPropertyListString();
NamedObject elmt= moiTb.get(cstr);
if (elmt != null) {
throw new InstanceAlreadyExistsException(name.toString());
} else {
nbElements++;
moiTb.put(cstr, new NamedObject(name, object));
// Add instance if not already present
String cstr = name.getCanonicalKeyPropertyListString();
NamedObject elmt= moiTb.get(cstr);
if (elmt != null) {
throw new InstanceAlreadyExistsException(name.toString());
} else {
nbElements++;
addMoiToTb(object,name,cstr,moiTb,context);
}
}
} finally {
......@@ -533,7 +598,7 @@ public class Repository {
// ":*", ":[key=value],*" : names in defaultDomain
// "domain:*", "domain:[key=value],*" : names in the specified domain
// Surely one of the most frequent case ... query on the whole world
// Surely one of the most frequent cases ... query on the whole world
ObjectName name;
if (pattern == null ||
pattern.getCanonicalName().length() == 0 ||
......@@ -546,8 +611,7 @@ public class Repository {
// If pattern is not a pattern, retrieve this mbean !
if (!name.isPattern()) {
final NamedObject no;
no = retrieveNamedObject(name);
final NamedObject no = retrieveNamedObject(name);
if (no != null) result.add(no);
return result;
}
......@@ -577,12 +641,22 @@ public class Repository {
return result;
}
if (!name.isDomainPattern()) {
final Map<String,NamedObject> moiTb = domainTb.get(name.getDomain());
if (moiTb == null) return Collections.emptySet();
if (allNames)
result.addAll(moiTb.values());
else
addAllMatching(moiTb, result, namePattern);
return result;
}
// Pattern matching in the domain name (*, ?)
char[] dom2Match = name.getDomain().toCharArray();
for (String domain : domainTb.keySet()) {
char[] theDom = domain.toCharArray();
for (String dom : domainTb.keySet()) {
char[] theDom = dom.toCharArray();
if (wildmatch(theDom, dom2Match)) {
final Map<String,NamedObject> moiTb = domainTb.get(domain);
final Map<String,NamedObject> moiTb = domainTb.get(dom);
if (allNames)
result.addAll(moiTb.values());
else
......@@ -599,11 +673,21 @@ public class Repository {
* Removes an MBean from the repository.
*
* @param name name of the MBean to remove.
* @param context A registration context. If non null, the repository
* will call {@link RegistrationContext#unregistered()
* context.unregistered()} from within the repository
* lock, just after the mbean associated with
* {@code name} is removed from the repository.
* If {@link RegistrationContext#unregistered()
* context.unregistered()} is not expected to throw any
* exception. If it does, the exception is logged
* and swallowed.
*
* @exception InstanceNotFoundException The MBean does not exist in
* the repository.
*/
public void remove(final ObjectName name)
public void remove(final ObjectName name,
final RegistrationContext context)
throws InstanceNotFoundException {
// Debugging stuff
......@@ -645,6 +729,9 @@ public class Repository {
if (dom == domain)
domainTb.put(domain, new HashMap<String,NamedObject>());
}
unregistering(context,name);
} finally {
lock.writeLock().unlock();
}
......
......@@ -35,6 +35,7 @@ import javax.management.IntrospectionException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationBroadcaster;
import javax.management.NotificationBroadcasterSupport;
......@@ -118,22 +119,32 @@ class StandardMBeanIntrospector extends MBeanIntrospector<Method> {
@Override
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
Method getter, Method setter) {
final String description = "Attribute exposed for management";
try {
return new MBeanAttributeInfo(attributeName, description,
getter, setter);
} catch (IntrospectionException e) {
throw new RuntimeException(e); // should not happen
}
Method getter, Method setter) throws IntrospectionException {
String description = getAttributeDescription(
attributeName, "Attribute exposed for management",
getter, setter);
return new MBeanAttributeInfo(attributeName, description,
getter, setter);
}
@Override
MBeanOperationInfo getMBeanOperationInfo(String operationName,
Method operation) {
final String description = "Operation exposed for management";
return new MBeanOperationInfo(description, operation);
final String defaultDescription = "Operation exposed for management";
String description = Introspector.descriptionForElement(operation);
if (description == null)
description = defaultDescription;
int impact = MBeanOperationInfo.UNKNOWN;
ManagedOperation annot = operation.getAnnotation(ManagedOperation.class);
if (annot != null)
impact = annot.impact().getCode();
MBeanOperationInfo mboi = new MBeanOperationInfo(description, operation);
return new MBeanOperationInfo(
mboi.getName(), mboi.getDescription(), mboi.getSignature(),
mboi.getReturnType(), impact, mboi.getDescriptor());
}
@Override
......
......@@ -41,26 +41,24 @@ import javax.management.openmbean.MXBeanMappingFactory;
public class StandardMBeanSupport extends MBeanSupport<Method> {
/**
<p>Construct a Standard MBean that wraps the given resource using the
given Standard MBean interface.</p>
@param resource the underlying resource for the new MBean.
@param mbeanInterface the interface to be used to determine
the MBean's management interface.
@param <T> a type parameter that allows the compiler to check
that {@code resource} implements {@code mbeanInterface},
provided that {@code mbeanInterface} is a class constant like
{@code SomeMBean.class}.
@throws IllegalArgumentException if {@code resource} is null or
if it does not implement the class {@code mbeanInterface} or if
that class is not a valid Standard MBean interface.
*/
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterface)
* <p>Construct a Standard MBean that wraps the given resource using the
* given Standard MBean interface.</p>
*
* @param resource the underlying resource for the new MBean.
* @param mbeanInterfaceType the class or interface to be used to determine
* the MBean's management interface. An interface if this is a
* classic Standard MBean; a class if this is a {@code @ManagedResource}.
* @param <T> a type parameter that allows the compiler to check
* that {@code resource} implements {@code mbeanInterfaceType},
* provided that {@code mbeanInterfaceType} is a class constant like
* {@code SomeMBean.class}.
* @throws IllegalArgumentException if {@code resource} is null or
* if it does not implement the class {@code mbeanInterfaceType} or if
* that class is not a valid Standard MBean interface.
*/
public <T> StandardMBeanSupport(T resource, Class<T> mbeanInterfaceType)
throws NotCompliantMBeanException {
super(resource, mbeanInterface, (MXBeanMappingFactory) null);
super(resource, mbeanInterfaceType, (MXBeanMappingFactory) null);
}
@Override
......@@ -86,13 +84,14 @@ public class StandardMBeanSupport extends MBeanSupport<Method> {
@Override
public MBeanInfo getMBeanInfo() {
MBeanInfo mbi = super.getMBeanInfo();
Class<?> resourceClass = getResource().getClass();
if (StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
Class<?> resourceClass = getWrappedObject().getClass();
if (!getMBeanInterface().isInterface() ||
StandardMBeanIntrospector.isDefinitelyImmutableInfo(resourceClass))
return mbi;
return new MBeanInfo(mbi.getClassName(), mbi.getDescription(),
mbi.getAttributes(), mbi.getConstructors(),
mbi.getOperations(),
MBeanIntrospector.findNotifications(getResource()),
MBeanIntrospector.findNotifications(getWrappedObject()),
mbi.getDescriptor());
}
}
......@@ -38,6 +38,7 @@ import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.WeakHashMap;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
......@@ -71,6 +72,10 @@ public class Util {
return new LinkedHashMap<K, V>();
}
static <K, V> WeakHashMap<K, V> newWeakHashMap() {
return new WeakHashMap<K, V>();
}
static <E> Set<E> newSet() {
return new HashSet<E>();
}
......
......@@ -208,8 +208,9 @@ public class EventSetImpl extends ArrayList<Event> implements EventSet {
}
public String toString() {
return eventName() + "@" + location().toString() +
" in thread " + thread().name();
return eventName() + "@" +
((location() == null) ? " null" : location().toString()) +
" in thread " + thread().name();
}
}
......
......@@ -40,11 +40,12 @@ public class MonitorInfoImpl extends MirrorImpl
int stack_depth;
MonitorInfoImpl(VirtualMachine vm, ObjectReference mon,
ThreadReference thread, int dpth) {
ThreadReferenceImpl thread, int dpth) {
super(vm);
this.monitor = mon;
this.thread = thread;
this.stack_depth = dpth;
thread.addListener(this);
}
......
......@@ -35,12 +35,34 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
static final int SUSPEND_STATUS_SUSPENDED = 0x1;
static final int SUSPEND_STATUS_BREAK = 0x2;
private ThreadGroupReference threadGroup;
private int suspendedZombieCount = 0;
// This is cached only while the VM is suspended
private static class Cache extends ObjectReferenceImpl.Cache {
String name = null;
/*
* Some objects can only be created while a thread is suspended and are valid
* only while the thread remains suspended. Examples are StackFrameImpl
* and MonitorInfoImpl. When the thread resumes, these objects have to be
* marked as invalid so that their methods can throw
* InvalidStackFrameException if they are called. To do this, such objects
* register themselves as listeners of the associated thread. When the
* thread is resumed, its listeners are notified and mark themselves
* invalid.
* Also, note that ThreadReferenceImpl itself caches some info that
* is valid only as long as the thread is suspended. When the thread
* is resumed, that cache must be purged.
* Lastly, note that ThreadReferenceImpl and its super, ObjectReferenceImpl
* cache some info that is only valid as long as the entire VM is suspended.
* If _any_ thread is resumed, this cache must be purged. To handle this,
* both ThreadReferenceImpl and ObjectReferenceImpl register themselves as
* VMListeners so that they get notified when all threads are suspended and
* when any thread is resumed.
*/
// This is cached for the life of the thread
private ThreadGroupReference threadGroup;
// This is cached only while this one thread is suspended. Each time
// the thread is resumed, we clear this and start with a fresh one.
private static class LocalCache {
JDWP.ThreadReference.Status status = null;
List<StackFrame> frames = null;
int framesStart = -1;
......@@ -52,6 +74,17 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
boolean triedCurrentContended = false;
}
private LocalCache localCache;
private void resetLocalCache() {
localCache = new LocalCache();
}
// This is cached only while all threads in the VM are suspended
// Yes, someone could change the name of a thread while it is suspended.
private static class Cache extends ObjectReferenceImpl.Cache {
String name = null;
}
protected ObjectReferenceImpl.Cache newCache() {
return new Cache();
}
......@@ -59,8 +92,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
// Listeners - synchronized on vm.state()
private List<WeakReference<ThreadListener>> listeners = new ArrayList<WeakReference<ThreadListener>>();
ThreadReferenceImpl(VirtualMachine aVm, long aRef) {
super(aVm,aRef);
resetLocalCache();
vm.state().addListener(this);
}
......@@ -72,10 +107,24 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
* VMListener implementation
*/
public boolean vmNotSuspended(VMAction action) {
synchronized (vm.state()) {
processThreadAction(new ThreadAction(this,
ThreadAction.THREAD_RESUMABLE));
if (action.resumingThread() == null) {
// all threads are being resumed
synchronized (vm.state()) {
processThreadAction(new ThreadAction(this,
ThreadAction.THREAD_RESUMABLE));
}
}
/*
* Othewise, only one thread is being resumed:
* if it is us,
* we have already done our processThreadAction to notify our
* listeners when we processed the resume.
* if it is not us,
* we don't want to notify our listeners
* because we are not being resumed.
*/
return super.vmNotSuspended(action);
}
......@@ -191,23 +240,19 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
}
private JDWP.ThreadReference.Status jdwpStatus() {
JDWP.ThreadReference.Status status = null;
JDWP.ThreadReference.Status myStatus = localCache.status;
try {
Cache local = (Cache)getCache();
if (local != null) {
status = local.status;
}
if (status == null) {
status = JDWP.ThreadReference.Status.process(vm, this);
if (local != null) {
local.status = status;
if (myStatus == null) {
myStatus = JDWP.ThreadReference.Status.process(vm, this);
if ((myStatus.suspendStatus & SUSPEND_STATUS_SUSPENDED) != 0) {
// thread is suspended, we can cache the status.
localCache.status = myStatus;
}
}
} catch (JDWPException exc) {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
return status;
return myStatus;
}
public int status() {
......@@ -245,8 +290,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
public ThreadGroupReference threadGroup() {
/*
* Thread group can't change, so it's cached more conventionally
* than other things in this class.
* Thread group can't change, so it's cached once and for all.
*/
if (threadGroup == null) {
try {
......@@ -260,19 +304,10 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
}
public int frameCount() throws IncompatibleThreadStateException {
int frameCount = -1;
try {
Cache local = (Cache)getCache();
if (local != null) {
frameCount = local.frameCount;
}
if (frameCount == -1) {
frameCount = JDWP.ThreadReference.FrameCount
if (localCache.frameCount == -1) {
localCache.frameCount = JDWP.ThreadReference.FrameCount
.process(vm, this).frameCount;
if (local != null) {
local.frameCount = frameCount;
}
}
} catch (JDWPException exc) {
switch (exc.errorCode()) {
......@@ -283,7 +318,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
throw exc.toJDIException();
}
}
return frameCount;
return localCache.frameCount;
}
public List<StackFrame> frames() throws IncompatibleThreadStateException {
......@@ -297,23 +332,25 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
/**
* Is the requested subrange within what has been retrieved?
* local is known to be non-null
* local is known to be non-null. Should only be called from
* a sync method.
*/
private boolean isSubrange(Cache local,
int start, int length, List frames) {
if (start < local.framesStart) {
private boolean isSubrange(LocalCache localCache,
int start, int length) {
if (start < localCache.framesStart) {
return false;
}
if (length == -1) {
return (local.framesLength == -1);
return (localCache.framesLength == -1);
}
if (local.framesLength == -1) {
if ((start + length) > (local.framesStart + frames.size())) {
if (localCache.framesLength == -1) {
if ((start + length) > (localCache.framesStart +
localCache.frames.size())) {
throw new IndexOutOfBoundsException();
}
return true;
}
return ((start + length) <= (local.framesStart + local.framesLength));
return ((start + length) <= (localCache.framesStart + localCache.framesLength));
}
public List<StackFrame> frames(int start, int length)
......@@ -329,51 +366,42 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
* Private version of frames() allows "-1" to specify all
* remaining frames.
*/
private List<StackFrame> privateFrames(int start, int length)
synchronized private List<StackFrame> privateFrames(int start, int length)
throws IncompatibleThreadStateException {
List<StackFrame> frames = null;
try {
Cache local = (Cache)getCache();
if (local != null) {
frames = local.frames;
}
if (frames == null || !isSubrange(local, start, length, frames)) {
// Lock must be held while creating stack frames so if that two threads
// do this at the same time, one won't clobber the subset created by the other.
try {
if (localCache.frames == null || !isSubrange(localCache, start, length)) {
JDWP.ThreadReference.Frames.Frame[] jdwpFrames
= JDWP.ThreadReference.Frames.
process(vm, this, start, length).frames;
process(vm, this, start, length).frames;
int count = jdwpFrames.length;
frames = new ArrayList<StackFrame>(count);
// Lock must be held while creating stack frames.
// so that a resume will not resume a partially
// created stack.
synchronized (vm.state()) {
for (int i = 0; i<count; i++) {
if (jdwpFrames[i].location == null) {
throw new InternalException("Invalid frame location");
}
StackFrame frame = new StackFrameImpl(vm, this,
jdwpFrames[i].frameID,
jdwpFrames[i].location);
// Add to the frame list
frames.add(frame);
localCache.frames = new ArrayList<StackFrame>(count);
for (int i = 0; i<count; i++) {
if (jdwpFrames[i].location == null) {
throw new InternalException("Invalid frame location");
}
StackFrame frame = new StackFrameImpl(vm, this,
jdwpFrames[i].frameID,
jdwpFrames[i].location);
// Add to the frame list
localCache.frames.add(frame);
}
if (local != null) {
local.frames = frames;
local.framesStart = start;
local.framesLength = length;
}
localCache.framesStart = start;
localCache.framesLength = length;
return Collections.unmodifiableList(localCache.frames);
} else {
int fromIndex = start - local.framesStart;
int fromIndex = start - localCache.framesStart;
int toIndex;
if (length == -1) {
toIndex = frames.size() - fromIndex;
toIndex = localCache.frames.size() - fromIndex;
} else {
toIndex = fromIndex + length;
}
frames = frames.subList(fromIndex, toIndex);
return Collections.unmodifiableList(localCache.frames.subList(fromIndex, toIndex));
}
} catch (JDWPException exc) {
switch (exc.errorCode()) {
......@@ -384,28 +412,18 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
throw exc.toJDIException();
}
}
return Collections.unmodifiableList(frames);
}
public List<ObjectReference> ownedMonitors() throws IncompatibleThreadStateException {
List<ObjectReference> monitors = null;
try {
Cache local = (Cache)getCache();
if (local != null) {
monitors = local.ownedMonitors;
}
if (monitors == null) {
monitors = Arrays.asList(
if (localCache.ownedMonitors == null) {
localCache.ownedMonitors = Arrays.asList(
(ObjectReference[])JDWP.ThreadReference.OwnedMonitors.
process(vm, this).owned);
if (local != null) {
local.ownedMonitors = monitors;
if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
vm.printTrace(description() +
" temporarily caching owned monitors"+
" (count = " + monitors.size() + ")");
}
if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
vm.printTrace(description() +
" temporarily caching owned monitors"+
" (count = " + localCache.ownedMonitors.size() + ")");
}
}
} catch (JDWPException exc) {
......@@ -417,29 +435,22 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
throw exc.toJDIException();
}
}
return monitors;
return localCache.ownedMonitors;
}
public ObjectReference currentContendedMonitor()
throws IncompatibleThreadStateException {
ObjectReference monitor = null;
try {
Cache local = (Cache)getCache();
if (local != null && local.triedCurrentContended) {
monitor = local.contendedMonitor;
} else {
monitor = JDWP.ThreadReference.CurrentContendedMonitor.
if (localCache.contendedMonitor == null &&
!localCache.triedCurrentContended) {
localCache.contendedMonitor = JDWP.ThreadReference.CurrentContendedMonitor.
process(vm, this).monitor;
if (local != null) {
local.triedCurrentContended = true;
local.contendedMonitor = monitor;
if ((monitor != null) &&
((vm.traceFlags & vm.TRACE_OBJREFS) != 0)) {
vm.printTrace(description() +
" temporarily caching contended monitor"+
" (id = " + monitor.uniqueID() + ")");
}
localCache.triedCurrentContended = true;
if ((localCache.contendedMonitor != null) &&
((vm.traceFlags & vm.TRACE_OBJREFS) != 0)) {
vm.printTrace(description() +
" temporarily caching contended monitor"+
" (id = " + localCache.contendedMonitor.uniqueID() + ")");
}
}
} catch (JDWPException exc) {
......@@ -450,40 +461,31 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
throw exc.toJDIException();
}
}
return monitor;
return localCache.contendedMonitor;
}
public List<MonitorInfo> ownedMonitorsAndFrames() throws IncompatibleThreadStateException {
List<MonitorInfo> monitors = null;
try {
Cache local = (Cache)getCache();
if (local != null) {
monitors = local.ownedMonitorsInfo;
}
if (monitors == null) {
if (localCache.ownedMonitorsInfo == null) {
JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor[] minfo;
minfo = JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.process(vm, this).owned;
monitors = new ArrayList<MonitorInfo>(minfo.length);
localCache.ownedMonitorsInfo = new ArrayList<MonitorInfo>(minfo.length);
for (int i=0; i < minfo.length; i++) {
JDWP.ThreadReference.OwnedMonitorsStackDepthInfo.monitor mi =
minfo[i];
MonitorInfo mon = new MonitorInfoImpl(vm, minfo[i].monitor, this, minfo[i].stack_depth);
monitors.add(mon);
localCache.ownedMonitorsInfo.add(mon);
}
if (local != null) {
local.ownedMonitorsInfo = monitors;
if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
vm.printTrace(description() +
" temporarily caching owned monitors"+
" (count = " + monitors.size() + ")");
if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
vm.printTrace(description() +
" temporarily caching owned monitors"+
" (count = " + localCache.ownedMonitorsInfo.size() + ")");
}
}
}
} catch (JDWPException exc) {
switch (exc.errorCode()) {
case JDWP.Error.THREAD_NOT_SUSPENDED:
......@@ -493,7 +495,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
throw exc.toJDIException();
}
}
return monitors;
return localCache.ownedMonitorsInfo;
}
public void popFrames(StackFrame frame) throws IncompatibleThreadStateException {
......@@ -511,7 +513,7 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
}
public void forceEarlyReturn(Value returnValue) throws InvalidTypeException,
ClassNotLoadedException,
ClassNotLoadedException,
IncompatibleThreadStateException {
if (!vm.canForceEarlyReturn()) {
throw new UnsupportedOperationException(
......@@ -604,6 +606,9 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
iter.remove();
}
}
// Discard our local cache
resetLocalCache();
}
}
}
......@@ -38,10 +38,18 @@ class VMAction extends EventObject {
static final int VM_NOT_SUSPENDED = 2;
int id;
ThreadReference resumingThread;
VMAction(VirtualMachine vm, int id) {
this(vm, null, id);
}
// For id = VM_NOT_SUSPENDED, if resumingThread != null, then it is
// the only thread that is being resumed.
VMAction(VirtualMachine vm, ThreadReference resumingThread, int id) {
super(vm);
this.id = id;
this.resumingThread = resumingThread;
}
VirtualMachine vm() {
return (VirtualMachine)getSource();
......@@ -49,4 +57,8 @@ class VMAction extends EventObject {
int id() {
return id;
}
ThreadReference resumingThread() {
return resumingThread;
}
}
......@@ -115,17 +115,26 @@ class VMState {
return stream;
}
/**
* All threads are resuming
*/
void thaw() {
thaw(null);
}
/**
* Tell listeners to invalidate suspend-sensitive caches.
* If resumingThread != null, then only that thread is being
* resumed.
*/
synchronized void thaw() {
synchronized void thaw(ThreadReference resumingThread) {
if (cache != null) {
if ((vm.traceFlags & vm.TRACE_OBJREFS) != 0) {
vm.printTrace("Clearing VM suspended cache");
}
disableCache();
}
processVMAction(new VMAction(vm, VMAction.VM_NOT_SUSPENDED));
processVMAction(new VMAction(vm, resumingThread, VMAction.VM_NOT_SUSPENDED));
}
private synchronized void processVMAction(VMAction action) {
......
......@@ -146,8 +146,9 @@ class VirtualMachineImpl extends MirrorImpl
public boolean threadResumable(ThreadAction action) {
/*
* If any thread is resumed, the VM is considered not suspended.
* Just one thread is being resumed so pass it to thaw.
*/
state.thaw();
state.thaw(action.thread());
return true;
}
......
......@@ -191,7 +191,7 @@ public abstract class SelectionKey {
* @throws IllegalArgumentException
* If a bit in the set does not correspond to an operation that
* is supported by this key's channel, that is, if
* <tt>set & ~(channel().validOps()) != 0</tt>
* <tt>(ops & ~channel().validOps()) != 0</tt>
*
* @throws CancelledKeyException
* If this key has been cancelled
......
......@@ -192,6 +192,7 @@ class BinaryRelQueryExp extends QueryEval implements QueryExp {
return "(" + exp1 + ") " + relOpString() + " (" + exp2 + ")";
}
@Override
String toQueryString() {
return exp1 + " " + relOpString() + " " + exp2;
}
......
/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package javax.management;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ResourceBundle;
/**
* <p>The textual description of an MBean or part of an MBean. This
* description is intended to be displayed to users to help them
* understand what the MBean does. Ultimately it will be the value of
* the {@code getDescription()} method of an {@link MBeanInfo}, {@link
* MBeanAttributeInfo}, or similar.</p>
*
* <p>This annotation applies to Standard MBean interfaces and to
* MXBean interfaces, as well as to MBean classes defined using the
* {@link MBean @MBean} or {@link MXBean @MXBean} annotations. For
* example, a Standard MBean might be defined like this:</p>
*
* <pre>
* <b>{@code @Description}</b>("Application configuration")
* public interface ConfigurationMBean {
* <b>{@code @Description}</b>("Cache size in bytes")
* public int getCacheSize();
* public void setCacheSize(int size);
*
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
* "in milliseconds since 1 Jan 1970")
* public long getLastChangedTime();
*
* <b>{@code @Description}</b>("Save the configuration to a file")
* public void save(
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
* String fileName);
* }
* </pre>
*
* <p>The {@code MBeanInfo} for this MBean will have a {@link
* MBeanInfo#getDescription() getDescription()} that is {@code
* "Application configuration"}. It will contain an {@code
* MBeanAttributeInfo} for the {@code CacheSize} attribute that is
* defined by the methods {@code getCacheSize} and {@code
* setCacheSize}, and another {@code MBeanAttributeInfo} for {@code
* LastChangedTime}. The {@link MBeanAttributeInfo#getDescription()
* getDescription()} for {@code CacheSize} will be {@code "Cache size
* in bytes"}. Notice that there is no need to add a
* {@code @Description} to both {@code getCacheSize} and {@code
* setCacheSize} - either alone will do. But if you do add a
* {@code @Description} to both, it must be the same.</p>
*
* <p>The {@code MBeanInfo} will also contain an {@link
* MBeanOperationInfo} where {@link
* MBeanOperationInfo#getDescription() getDescription()} is {@code
* "Save the configuration to a file"}. This {@code
* MBeanOperationInfo} will contain an {@link MBeanParameterInfo}
* where {@link MBeanParameterInfo#getDescription() getDescription()}
* is {@code "Optional name of the file, or null for the default
* name"}.</p>
*
* <p>The {@code @Description} annotation can also be applied to the
* public constructors of the implementation class. Continuing the
* above example, the {@code Configuration} class implementing {@code
* ConfigurationMBean} might look like this:</p>
*
* <pre>
* public class Configuration implements ConfigurationMBean {
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
* public Configuration() {
* this(DEFAULT_FILE_NAME);
* }
*
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
* public Configuration(
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
* String fileName) {...}
* ...
* }
* </pre>
*
* <p>The {@code @Description} annotation also works in MBeans that
* are defined using the {@code @MBean} or {@code @MXBean} annotation
* on classes. Here is an alternative implementation of {@code
* Configuration} that does not use an {@code ConfigurationMBean}
* interface.</p>
*
* <pre>
* <b>{@code @MBean}</b>
* <b>{@code @Description}</b>("Application configuration")
* public class Configuration {
* <b>{@code @Description}</b>("A Configuration MBean with the default file name")
* public Configuration() {
* this(DEFAULT_FILE_NAME);
* }
*
* <b>{@code @Description}</b>("A Configuration MBean with a specified file name")
* public Configuration(
* <b>{@code @Description}</b>("Name of the file the configuration is stored in")
* String fileName) {...}
*
* <b>{@code @ManagedAttribute}</b>
* <b>{@code @Description}</b>("Cache size in bytes")
* public int getCacheSize() {...}
* <b>{@code @ManagedAttribute}</b>
* public void setCacheSize(int size) {...}
*
* <b>{@code @ManagedOperation}</b>
* <b>{@code @Description}</b>("Last time the configuration was changed, " +
* "in milliseconds since 1 Jan 1970")
* public long getLastChangedTime() {...}
*
* <b>{@code @ManagedOperation}</b>
* <b>{@code @Description}</b>("Save the configuration to a file")
* public void save(
* <b>{@code @Description}</b>("Optional name of the file, or null for the default name")
* String fileName) {...}
* ...
* }
* </pre>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER,
ElementType.TYPE})
public @interface Description {
/**
* <p>The description.</p>
*/
String value();
/**
* <p>The base name for the {@link ResourceBundle} in which the key given in
* the {@code descriptionResourceKey} field can be found, for example
* {@code "com.example.myapp.MBeanResources"}. If a non-default value
* is supplied for this element, it will appear in the
* <a href="Descriptor.html#descriptionResourceBundleBaseName"><!--
* -->{@code Descriptor}</a> for the annotated item.</p>
*/
@DescriptorKey(
value = "descriptionResourceBundleBaseName", omitIfDefault = true)
String bundleBaseName() default "";
/**
* <p>A resource key for the description of this element. In
* conjunction with the {@link #bundleBaseName bundleBaseName},
* this can be used to find a localized version of the description.
* If a non-default value
* is supplied for this element, it will appear in the
* <a href="Descriptor.html#descriptionResourceKey"><!--
* -->{@code Descriptor}</a> for the annotated item.</p>
*/
@DescriptorKey(value = "descriptionResourceKey", omitIfDefault = true)
String key() default "";
}
......@@ -38,6 +38,7 @@ import java.util.Arrays;
import java.util.ResourceBundle;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
import javax.management.openmbean.OpenMBeanParameterInfoSupport;
......@@ -117,21 +118,19 @@ import javax.management.openmbean.OpenType;
* deprecation, for example {@code "1.3 Replaced by the Capacity
* attribute"}.</td>
*
* <tr><td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
* <tr id="descriptionResourceBundleBaseName">
* <td>descriptionResource<br>BundleBaseName</td><td>String</td><td>Any</td>
*
* <td>The base name for the {@link ResourceBundle} in which the key given in
* the {@code descriptionResourceKey} field can be found, for example
* {@code "com.example.myapp.MBeanResources"}. The meaning of this
* field is defined by this specification but the field is not set or
* used by the JMX API itself.</td>
* {@code "com.example.myapp.MBeanResources"}.</td>
*
* <tr><td>descriptionResourceKey</td><td>String</td><td>Any</td>
* <tr id="descriptionResourceKey">
* <td>descriptionResourceKey</td><td>String</td><td>Any</td>
*
* <td>A resource key for the description of this element. In
* conjunction with the {@code descriptionResourceBundleBaseName},
* this can be used to find a localized version of the description.
* The meaning of this field is defined by this specification but the
* field is not set or used by the JMX API itself.</td>
* this can be used to find a localized version of the description.</td>
*
* <tr><td>enabled</td><td>String</td>
* <td>MBeanAttributeInfo<br>MBeanNotificationInfo<br>MBeanOperationInfo</td>
......@@ -216,6 +215,14 @@ import javax.management.openmbean.OpenType;
* StandardMBean} class will have this field in its MBeanInfo
* Descriptor.</td>
*
* <tr><td id="mxbeanMappingFactoryClass"><i>mxbeanMappingFactoryClass</i>
* </td><td>String</td>
* <td>MBeanInfo</td>
*
* <td>The name of the {@link MXBeanMappingFactory} class that was used for this
* MXBean, if it was not the {@linkplain MXBeanMappingFactory#DEFAULT default}
* one.</td>
*
* <tr><td><a name="openType"><i>openType</i></a><td>{@link OpenType}</td>
* <td>MBeanAttributeInfo<br>MBeanOperationInfo<br>MBeanParameterInfo</td>
*
......
/*
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package javax.management;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* <p>Annotation that adds fields to a {@link Descriptor}. This can be the
* Descriptor for an MBean, or for an attribute, operation, or constructor
* in an MBean, or for a parameter of an operation or constructor.</p>
*
* <p>Consider this Standard MBean interface, for example:</p>
*
* <pre>
* public interface CacheControlMBean {
* <b>&#64;DescriptorFields("units=bytes")</b>
* public long getCacheSize();
* }
* </pre>
*
* <p>When a Standard MBean is made using this interface, the usual rules
* mean that it will have an attribute called {@code CacheSize} of type
* {@code long}. The {@code DescriptorFields} annotation will ensure
* that the {@link MBeanAttributeInfo} for this attribute will have a
* {@code Descriptor} that has a field called {@code units} with
* corresponding value {@code bytes}.</p>
*
* <p>Similarly, if the interface looks like this:</p>
*
* <pre>
* public interface CacheControlMBean {
* <b>&#64;DescriptorFields({"units=bytes", "since=1.5"})</b>
* public long getCacheSize();
* }
* </pre>
*
* <p>then the resulting {@code Descriptor} will contain the following
* fields:</p>
*
* <table border="2">
* <tr><th>Name</th><th>Value</th></tr>
* <tr><td>units</td><td>"bytes"</td></tr>
* <tr><td>since</td><td>"1.5"</td></tr>
* </table>
*
* <p>The {@code @DescriptorFields} annotation can be applied to:</p>
*
* <ul>
* <li>a Standard MBean or MXBean interface;
* <li>a method in such an interface;
* <li>a parameter of a method in a Standard MBean or MXBean interface
* when that method is an operation (not a getter or setter for an attribute);
* <li>a public constructor in the class that implements a Standard MBean
* or MXBean;
* <li>a parameter in such a constructor.
* </ul>
*
* <p>Other uses of the annotation will either fail to compile or be
* ignored.</p>
*
* <p>Interface annotations are checked only on the exact interface
* that defines the management interface of a Standard MBean or an
* MXBean, not on its parent interfaces. Method annotations are
* checked only in the most specific interface in which the method
* appears; in other words, if a child interface overrides a method
* from a parent interface, only {@code @DescriptorFields} annotations in
* the method in the child interface are considered.
*
* <p>The Descriptor fields contributed in this way must be consistent
* with each other and with any fields contributed by {@link
* DescriptorKey &#64;DescriptorKey} annotations. That is, two
* different annotations, or two members of the same annotation, must
* not define a different value for the same Descriptor field. Fields
* from annotations on a getter method must also be consistent with
* fields from annotations on the corresponding setter method.</p>
*
* <p>The Descriptor resulting from these annotations will be merged
* with any Descriptor fields provided by the implementation, such as
* the <a href="Descriptor.html#immutableInfo">{@code
* immutableInfo}</a> field for an MBean. The fields from the annotations
* must be consistent with these fields provided by the implementation.</p>
*
* <h4>{@literal @DescriptorFields and @DescriptorKey}</h4>
*
* <p>The {@link DescriptorKey @DescriptorKey} annotation provides
* another way to use annotations to define Descriptor fields.
* <code>&#64;DescriptorKey</code> requires more work but is also more
* robust, because there is less risk of mistakes such as misspelling
* the name of the field or giving an invalid value.
* <code>&#64;DescriptorFields</code> is more convenient but includes
* those risks. <code>&#64;DescriptorFields</code> is more
* appropriate for occasional use, but for a Descriptor field that you
* add in many places, you should consider a purpose-built annotation
* using <code>&#64;DescriptorKey</code>.
*
* @since 1.7
*/
@Documented
@Inherited // for @MBean and @MXBean classes
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD,
ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DescriptorFields {
/**
* <p>The descriptor fields. Each element of the string looks like
* {@code "name=value"}.</p>
*/
public String[] value();
}
此差异已折叠。
......@@ -26,6 +26,7 @@
package javax.management;
import com.sun.jmx.mbeanserver.Introspector;
import com.sun.jmx.mbeanserver.MBeanInjector;
import com.sun.jmx.remote.util.ClassLogger;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
......@@ -130,6 +131,7 @@ public class JMX {
* </pre>
*
* @see javax.management.JMX.ProxyOptions
* @see javax.management.StandardMBean.Options
*/
public static class MBeanOptions implements Serializable, Cloneable {
private static final long serialVersionUID = -6380842449318177843L;
......@@ -739,4 +741,28 @@ public class JMX {
// exactly the string "MXBean" since that would mean there
// was no package name, which is pretty unlikely in practice.
}
/**
* <p>Test if an MBean can emit notifications. An MBean can emit
* notifications if either it implements {@link NotificationBroadcaster}
* (perhaps through its child interface {@link NotificationEmitter}), or
* it uses <a href="MBeanRegistration.html#injection">resource
* injection</a> to obtain an instance of {@link SendNotification}
* through which it can send notifications.</p>
*
* @param mbean an MBean object.
* @return true if the given object is a valid MBean that can emit
* notifications; false if the object is a valid MBean but that
* cannot emit notifications.
* @throws NotCompliantMBeanException if the given object is not
* a valid MBean.
*/
public static boolean isNotificationSource(Object mbean)
throws NotCompliantMBeanException {
if (mbean instanceof NotificationBroadcaster)
return true;
Object resource = (mbean instanceof DynamicWrapperMBean) ?
((DynamicWrapperMBean) mbean).getWrappedObject() : mbean;
return (MBeanInjector.injectsSendNotification(resource));
}
}
此差异已折叠。
......@@ -91,6 +91,7 @@ class NotQueryExp extends QueryEval implements QueryExp {
return "not (" + exp + ")";
}
@Override
String toQueryString() {
return "not (" + Query.toString(exp) + ")";
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册